fix(adapter): a HEALED dirty-schema migration must not republish bd's Error: line while exiting 0 - #75
Conversation
… `Error:` line
`doctor --quick` detected a dirty dolt schema migration, dropped, retried,
succeeded, printed `All 35 assumptions hold` and exited 0 -- with this on
stderr (evidence committed on main at
docs/lanes/wp6-error-regex-scope/evidence/pr70-doctor-quick.run1-transient.stderr.txt):
project 'contract...': bd init hit a dirty schema migration -- dropping
and retrying once: [mysql] ... busy buffer
Error: failed to open Dolt store: failed to initialize schema: ...
An error announcement beside exit 0 is exactly the silent-failure shape
`tests/_util.assert_no_silent_failure` exists to forbid, so a run that
recovered CORRECTLY could fail any CLI-tier test, intermittently, with a
real-looking message.
Root cause, and it is not what the report assumed: bd's stderr is not
escaping around us. That `Error:` line is INSIDE our own `logger.warning`.
The call interpolated `blob.strip()[:300]`, and `blob` is multi-line.
Proof from the committed evidence rather than from reasoning -- the quoted
text spanning those two lines is exactly 300 characters and stops
mid-sentence at "run 'bd dolt commit' to", the slice boundary, not bd's
own line ending. We printed it, on a path where nothing ultimately failed.
Fix: `_quote_handled_output`, used ONLY where this module handled and
recovered from a condition. It flattens the blob to one line (a multi-line
quote puts `Error:` at the start of a line of OUR stderr, which is where it
reads as ours) and attributes each announcement to its source rather than
asserting it -- `Error:` becomes `[bd Error]`. The word survives, the
detail survives, only the impersonation ends. Truncation moves from the
bare `[:300]` slice to `truncate_status`, which cuts on a word boundary and
marks itself.
Deliberately NOT merged with `_clean_bd_error`: that one builds the text of
a real failure on its way to a non-zero exit, which SHOULD announce loudly.
The failure path is untouched, and a test pins that bd's own announcement
still reaches stderr there.
Applied at both handled call sites in the file -- the dirty-schema self-heal
in `Workspace.create`, and the best-effort cleanup of a partially-moved item
in `move_item`, which quoted a foreign blob the same way on a path whose
caller continues.
tests/unit/test_handled_output_is_not_an_announcement.py drives the real
`Workspace.create` heal path with a scripted `bd init`, so the condition
that was observed ONCE and never reproduced is now deterministic with no bd,
no dolt and no network. Against the parent commit it fails with
`('error-colon', 'Error:')` and reproduces the recorded stderr byte for
byte, including the 300-character cut. Both directions are in that one file:
a genuine double failure still raises, still exits non-zero, and still
carries bd's announcement.
Does not touch `assert_no_silent_failure`: wp6's predicate is correct and
its own suite stays green (36 passed with this file).
Refs: model_performance-kxk (discovered-from model_performance-wp6)
…rs, doctor 37/37)
Manager verification — FIX. Merging. And the item's premise was wrong in a way that made the fix smaller.Head The root cause is not what the item said, and I verified that rather than taking itThe item (and my own goal text) asserted bd's error announcement was "passed straight through to logger.warning(
"project %r: bd init hit a dirty schema migration -- dropping and retrying once: %s",
name, blob.strip()[:300], # adapter.py — Workspace.create self-heal
)
A second instance of the same defect class was found in the same file ( Fail-before, reproduced against current mainGates
The one cli failure is One thing done right that is easy to miss
wp6's option (1) (parseable-channel redesign) is NOT required for this defect and was correctly |
Fixes
model_performance-kxk(discovered-frommodel_performance-wp6).The leak
amplifier-work-tracker doctor --quickdetected a dirty dolt schema migration, dropped, retried,succeeded, printed
All 35 assumptions holdand exited 0 — with this on stderr (evidencecommitted on main at
docs/lanes/wp6-error-regex-scope/evidence/pr70-doctor-quick.run1-transient.stderr.txt):An error announcement beside exit 0 is exactly the silent-failure shape
tests/_util.assert_no_silent_failureexists to forbid. Since #74 (802c204) that predicate matchesannouncement shapes and
Error:is the first one, so a run that recovered correctly could failany CLI-tier test — intermittently, with a real-looking message.
Root cause — not what the report assumed
bd's stderr is not escaping around us. That
Error:line is inside our ownlogger.warning.The call interpolated
blob.strip()[:300], andblobis bd's multi-line stderr, so line 2 of thequoted blob became line 2 of our stderr.
Proof from the committed evidence rather than from reasoning: the quoted text spanning those two
lines is exactly 300 characters and stops mid-sentence at
run 'bd dolt commit' to— the sliceboundary, not a line bd chose to end.
That finding is what makes this cheap: reproducing the leak never required reproducing the dirty
store.
The fix
_quote_handled_output(blob)— used only where this module handled and recovered from acondition:
Error:at the start of a line of our stderr,which is where it reads as ours.
Error:→[bd Error]. The word survives (greppable), thedetail survives (diagnostic), only the impersonation ends.
Truncation moves from the bare
[:300]slice to the existingtruncate_status(word boundary,explicit
...[truncated]marker) — the same fragment problem that helper already solved.The recovery stays visible. Going quiet would also satisfy the check and would be the wrong fix.
Applied at both handled call sites in the file:
Workspace.create's dirty-schema self-heal (thereported one) and
move_item's best-effort cleanup of a partially-moved item, which quoted a foreignblob the same way on a path whose caller continues.
Deliberately not merged with
_clean_bd_error. That one builds the text of a real failure on itsway to a non-zero exit, which should announce loudly. The failure path is untouched.
Fail-before, deterministic
tests/unit/test_handled_output_is_not_an_announcement.pydrives the realWorkspace.createheal path with a scripted
bd init— no bd, no dolt, no network. Against the parent commit(10 failed / 3 passed,
docs/lanes/kxk-healed-migration-stderr/evidence/fail-before.txt):The reproduced string ends at the same 300-character cut as the recorded incident. The condition
was observed once and never reproduced; it is now deterministic.
Both directions are pinned
A fix that only proved the healed run is quiet could have been achieved by swallowing everything.
Same file therefore also pins that a genuine double failure still raises, still exits non-zero,
and still carries bd's own announcement — with
assert_no_silent_failurecorrectly not firing there.tests/_util.pyis not touched: wp6's predicate is correct and its own suite(
tests/unit/test_error_announcement_detection.py, 23 tests) stays green, unmodified.The defusal covers all five shapes in
_util._ERROR_ANNOUNCEMENT_RES, not just the observed one.Product code cannot import a test helper, so the coupling is closed from the test side:
test_every_known_announcement_shape_has_a_samplegoes red if a shape is added to the predicatewithout a matching defusal sample.
Verification
make test-unitmake test-integrationmake test-climodel_performance-jyg, see belowmake test-ledgermake ledger-mutate→ proven 15 / 15make test-modulemake checkThe tier-3 failure is
model_performance-jyg, verified rather than assumed:test_doctor_quick_succeeds_against_the_real_installed_bddies at the earlierassert result.returncode == 0because[FAIL] sweeps.alivereports no heartbeat — the isolatedtest root has none. It never reaches
assert_no_silent_failure. Same command on this branch againstthe real workspace root:
37/37, measured.
error_announcement()over that whole captured output returnsNone.Not in scope
root cause is our own interpolation, so there is no channel-separation problem to solve. It remains
an open owner-level output-contract question.
assert_no_silent_failure.Spend: $0.00 against a $0 authority. Lane note and evidence:
docs/lanes/kxk-healed-migration-stderr/.