Skip to content

Retain typed failure custody for refused board-v2 migration-prepare - #4812

Merged
EHotwagner merged 2 commits into
mainfrom
routine/migration-prepare-failure-custody-4730
Oct 23, 2026
Merged

EHotwagner merged 2 commits into
mainfrom
routine/migration-prepare-failure-custody-4730

Conversation

@EHotwagner

@EHotwagner EHotwagner commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Refs #4730. This is a source-only correction for the #4730 process finding. It doesn't close the Outcome.

Problem

board-v2 migration-prepare wrote its prepared report only on success. Failure custody (terminal.json) exists only for migration-apply. A prepare refusal returned exit 3 with the shared stderr "inspect private original invocation evidence", but no such evidence existed. During #4759 this left the original prepare refusal's cause Unknown.

Change

  • Once prepare owns a new report path (the new-output preconditions passed), any refusal writes a private 0600 REPORT.prepare-failure.json (fs.gg.board-v2.migration-prepare-failure/1). It records:
    • stage (scope-read, scope-parse, executing-identity, native-preparation or prepared-report-write);
    • the bounded failureCode;
    • the typed errorClass and the existing allowlisted reason (migrationFailureReason);
    • the exception type name only;
    • preparedReportPresent;
    • failedAt from the injected clock;
    • nativeMutationDispatched:false and automaticRetry:false.
  • Exception messages, paths and response bytes are never copied.
  • A pre-existing failure record (or a directory at the report path) now refuses the new preparation, and the existing record isn't rewritten. Refusals before ownership write nothing.
  • Apply, readback, retry semantics, exit codes and stderr text are unchanged.
  • tests/coord-board-v2-cli-join/INSPECT.md documents the record.

Evidence

  • 3 new tests drive the actual runMigrationWithConnection path: transport refusal; drift between the two stable collections; an unexpected read exception (its private message is not copied); success, and the unowned/collision refusals. All 3 fail on the base and pass here.
  • coord-board-v2-cli-join: 78/78 passed locally; tests/signature-doc-siting/run.sh 90/90 after the review repair (the /// on a private binding became //; the prepare-failure output is documented in the .fsi).

Limit. If the report's parent directory isn't private, the private-write rule also blocks the failure record. That case still yields only exit 3.

Not done. Packaging, publication and installed caller adoption remain separate, under their own release route.

🤖 Generated with Claude Code

EHotwagner and others added 2 commits October 23, 2026 08:31
MigrationPrepare previously wrote only its prepared report on success; a
refusal returned exit 3 while the shared stderr pointed callers at private
invocation evidence that never existed for prepare (#4730 finding).

Once prepare owns a new report path, any refusal now writes a private 0600
REPORT.prepare-failure.json with the stage, bounded failure code, typed
error class and allowlisted reason, exception type name only, report
presence and the injected-clock time. Messages, paths and response bytes
are not copied. A pre-existing failure record refuses the new preparation
unchanged. No retry, apply or readback semantics change.

Refs #4730

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lure custody in the signature

Review of 1860ef6: the /// comment on a private binding in an
implementation file with a sibling .fsi failed signature-doc-siting.
Also pin zero native reads for unowned prepare refusals, including a
directory at the report path.

Refs #4730

Co-Authored-By: Claude Opus 5.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