Repository navigation
fix(doctor): name the recovery each pending adoption state accepts for a pinned literal override - #467
Merged
Conversation
…r a pinned literal override An interrupted preparation stop (pending operation, no publication) and an interrupted retained command of an active adoption both reported the pending switch step 'hack config adopt --recover --rollback', which each of those states refuses. Doctor and the --fix note now name 'hack config adopt --recover --stop' and 'hack down --recover' there. A busy refusal over a pending switch now names the step that state accepts instead of only the generic interrupted-lock recovery, which completes the switch and refuses a literal override. Refs HACK-1414 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups to #448 (HACK-1391). Refs HACK-1414
Root cause
After #448,
hack doctor(and thehack doctor --fix"Kept ..." note) told the user to runhack config adopt --recover --rollbackfor every pending adoption. That step only works for one kind of pending state:publication.phaseisswitchingorrolling-back):--recover --rollbackworks.withPreparationStop(... run: async () => 7), sopendingOperationis set andpublicationis null): no switch exists yet, sorepairPublicationrefuses--recover --rollback, and plain--rollbackrefuses as busy. Onlyhack config adopt --recover --stopmoves this state on. That retry then refuses to publish over the literal override and journals the switch that--recover --rollbackreleases.pendingOperationset over an active publication, which is what thedoctor --fixpending fixture uses):--recover --rollbackrefuses there too (the publication is active, not pending). Onlyhack down --recoversettles it. After that, plain--rollbackworks.The selector only saw
inspectLegacyComposeAdoptionSelection's coarsepending, so it could not tell these three states apart.Item (3): a repeated
--recover --stopafter the first literal-env refusal getsE_LEGACY_ADOPTION_BUSY("busy or requires explicit interrupted-lock recovery"). That interrupted-lock recovery is plainhack config adopt --recover, which completes the switch, and completing it refuses the bound literal override. So following the suggestion led to a second refusal.Fix
src/lib/native-compose-adoption-marker.ts: newinspectLegacyComposeAdoptionSelectionDetailreturns the status pluspending: "switch" | "preparation-stop" | "retained-operation" | null. It uses the same reads and refusals as before, andinspectLegacyComposeAdoptionSelectionnow wraps it with the same result.src/lib/compose-env-at-rest.ts:ComposeEnvAtRestReport.adoptionPendingis nowfalse | LegacyComposeAdoptionPending.adoptedComposeEnvOverrideNextStepnames the first command each kind accepts. There are two new fixed steps:INTERRUPTED_PREPARATION_...(hack config adopt --recover --stop, then--recover --rollback) andINTERRUPTED_OPERATION_...(hack down --recover, thenhack config adopt --rollback). The pending-switch and settled wording are unchanged. Unreadable state is still treated as bound and not pending.src/commands/config-adopt.ts: whenhack config adoptrefuses withE_LEGACY_ADOPTION_BUSYover a pending switch, the message now adds the step that state accepts. That step is--recover --rollbackwhen the bound override holds literal values, and otherwise--recoverto complete or--recover --rollbackto restore. The code (E_CONFIG_INVALID), the store message, and every refusal are unchanged. The added text is fixed and contains no values.docs/reference/native-compose-adoption.md: documents the per-state doctor step and the busy next step.Tests
tests/native-compose-adoption-generation.test.ts(HACK-1318 CLI test), in the interrupted-preparation-stop state, before any recovery:--recover --rollback --jsonand--rollback --jsonboth exit non-zero and leave the receipt byte-identical.inspectComposeEnvAtRestreportsadoptionPending: "preparation-stop".checkComposeEnvOverrideAtRestnameshack config adopt --recover --stopfirst, not the pending-switch step.--recover --stopmessage is the BUSY message plusPENDING_LITERAL_SWITCH_BUSY_NEXT_STEP, and it does not suggest plain--recover. The test's existing tail still shows plain--recoverrefusing and--recover --rollbackreleasing.tests/doctor-fix-adopted-project.test.ts: new pending (retained-operation) fixture with a literal override. It asserts the exactKept .hack/.internal/compose.env.override.yml: ... <INTERRUPTED_OPERATION step>note, no settled step, no--recover --rollback, no canary, and the file and receipt unchanged.tests/compose-env-at-rest.test.ts: the selector and description for the preparation-stop and retained-operation kinds; the switch test is updated to"switch".Mutation proofs (each fails the named test; the tree was restored after each):
preparation-stop(the behavior before this fix)--recover --rollbackstep) and the HACK-1414 unit testdoctor.tsnote usesadoptedComposeEnvOverrideNextStep({ adoptionPending: false })--fixHACK-1414 testadoptionRefusalMessagealways returns the bare store message--recover --stopmessage)preparation-stop--fixHACK-1414 testEvidence
mise x bun@1.4.2),bun install --frozen-lockfile, bun.lock unchanged.HACK_SECRETS_DISABLE_KEYCHAIN_FALLBACK=1, a DOCKER_HOST pointing at a non-existent socket, and stub engines only:bun run --cwd packages/cli typecheck: 0 errors. Rootbun run typecheck: 2/2.bun run check(includesprivacy:check): ok, 2/2 tasks.bun test tests/compose-env-at-rest.test.ts tests/doctor-fix-adopted-project.test.ts: 22 pass, 0 fail.bun test tests/native-compose-adoption-generation.test.ts -t HACK-1318 --timeout 120000(serial): pass. One earlier run under a load average of about 200 failed one existing exit-code assertion and passed on rerun (HACK-1367 load sensitivity).gitleaks dirover agit log -p origin/next..HEADexport): no leaks found.testjob at this head (pending at the time of writing).Gaps
hack down --recoveras the retained-operation step comes from the store contract and the existing retained recovery tests. This PR does not runhack down --recoverend to end in the doctor fixture.leaveRetainedSourceBindOperationPending(tests/helpers/retained-source-bind-adoption.ts) can tripE_LEGACY_ADOPTION_DEADLINE. The new--fixtest uses that helper, and so does the existing HACK-1311 doctor test, which failed once locally that way. The helper was not changed here.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.