Skip to content

feat(zcash_local_net): pin the zainod child's logging env and bound the readiness wait#283

Open
zancas wants to merge 1 commit into
devfrom
feat/zainod-logging-env-contract
Open

feat(zcash_local_net): pin the zainod child's logging env and bound the readiness wait#283
zancas wants to merge 1 commit into
devfrom
feat/zainod-logging-env-contract

Conversation

@zancas

@zancas zancas commented Jul 20, 2026

Copy link
Copy Markdown
Member

The harness reads zainod's log as an API: launch::wait's readiness scan matches the Zaino Indexer started successfully. line, and the indexer-convergence barrier parses the Syncing block, height: N markers. Both are info-level tracing events, and zainod's filter falls back to info only when RUST_LOG is unset — a set-but-empty or restrictive ambient value silences those targets, after which the readiness scan and every convergence wait hang. Zingolib hit exactly this failure (zingolabs/zingolib#2488, fixed on its side by zingolabs/zingolib#2487): a container task forwarded RUST_LOG set-but-empty, and every scenario setup stalled unboundedly, costing three days of misattributed forensics.

This change makes the launcher own its child's logging environment, closing the class rather than the instance:

  • LaunchSpec gains an env field carried through both artifact sources — host mode pins it on the Command, container mode emits --env run flags — and its construction is deduplicated into daemon / one_shot / bare constructors.
  • The zainod launcher pins RUST_LOG=info unconditionally. Debugging rides the new ZLN_ZAINOD_RUST_LOG knob, whose value is composed with the guard directives zainodlib=info,zaino_state=info appended after it, so even a restrictive debug filter cannot silence the lines the harness parses.
  • Silence now fails loudly instead of hanging: the previously unbounded readiness scan gives up after 300 seconds with the new LaunchError::ReadinessTimeout (generous, because a container-mode launch may pull an image inside the same run invocation), and a convergence timeout over a log that never carried a single marker returns the new IndexerSyncError::IndexerSilent — both errors name the silenced-logging diagnosis instead of presenting as anonymous timeouts.

The requirements document (zingolib-zainod-logging-env-spec.md) is committed alongside, with a delivery note recording how each known unknown resolved — in particular that the marker targets are zainodlib and zaino_state, and that the ambient-state acceptance matrix is enforced by construction (the pin overrides inherited env in both modes) and pinned by unit tests on the spawn-command seam.

Verification: cargo check --all-targets clean, cargo clippy --all-targets adds no warnings beyond the four pre-existing on dev, and cargo nextest run --package zcash_local_net --lib passes 76/76 including the new composition and command-shape pins. The process-spawning integration suite (zainod_converges_to_validator_tip_after_generate_blocks and siblings) was not run in this environment; it should run in CI or a binary-provisioned checkout before merge.

🤖 Generated with Claude Code

…he readiness wait

The harness reads zainod's log as an API: launch::wait's readiness
scan matches the "Zaino Indexer started successfully." line, and the
indexer-convergence barrier parses the "Syncing block, height: N"
markers. Both are info-level tracing events, and zainod's filter
falls back to info only when RUST_LOG is UNSET — a set-but-empty or
restrictive ambient value silences the targets, after which the
readiness scan and every convergence wait hang. Zingolib hit exactly
this (zingolabs/zingolib#2488): a container task forwarded RUST_LOG
set-but-empty and every scenario setup stalled unboundedly.

The launcher now owns its child's logging env. LaunchSpec gains an
env field carried through both artifact sources (host mode pins it on
the Command, container mode emits --env run flags), and the zainod
launcher pins RUST_LOG=info unconditionally. Debugging rides the new
ZLN_ZAINOD_RUST_LOG knob, whose value is composed with the guard
directives zainodlib=info,zaino_state=info appended, so even a
restrictive debug filter cannot silence the lines the harness parses.
LaunchSpec construction is deduplicated into daemon/one_shot/bare
constructors while at it.

Silence also fails loudly now instead of hanging or masquerading.
launch::wait's indicator scan, previously unbounded, gives up after
300 seconds with the new LaunchError::ReadinessTimeout naming the
silenced-logging suspect. The convergence barrier distinguishes a
starved observation channel from a lagging indexer: a timeout over a
log that never carried a single marker returns the new
IndexerSyncError::IndexerSilent, which names the pin and the
passthrough knob.

The requirements and their resolution are recorded in
zingolib-zainod-logging-env-spec.md, committed alongside.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant