Skip to content

feat(lifecycle): legal recorded backward transitions — frame→discover (RFC item #3) - #180

Merged
LaPaGaYo merged 1 commit into
mainfrom
feat/lifecycle-backward-transitions
Jun 20, 2026
Merged

LaPaGaYo merged 1 commit into
mainfrom
feat/lifecycle-backward-transitions

Conversation

@LaPaGaYo

Copy link
Copy Markdown
Owner

Summary

RFC item #3 — legal, recorded backward transitions (Hole 3 + addition D). The lifecycle was forward-only at the early stages, so frame→discover threw Illegal Nexus transition, which forced the operator-attested fabrication workaround the RFC documents. This makes evidence-driven retreat a first-class, recorded primitive: a backward edge is legal only when accompanied by a non-empty, matching justification — honest and auditable rather than illegal-or-faked.

What shipped

  • lib/nexus/governance/backtrack.ts (pure): BACKTRACK_EDGES (reverse of the early forward spine — discover←frame, frame←plan, plan←handoff) + evaluateBacktrack (allowed only when the edge is recognized AND a matching, non-empty justification is recorded) + fail-soft readBacktrackJustification + the canonical path helper.
  • lib/nexus/commands/discover.ts: the bespoke →discover guard now permits a retreat when a justification is recorded at .planning/current/discover/backtrack-justification.json. An allowed retreat reuses the existing run (run-id continuity), reset to the discover stage by nextLedger — recorded via previous_stage + command_history.

Design (confirmed v1)

  • File-based justification {from,to,reason} — symmetric with the decomposition record (operator-authored, command-gated, auditable). Does not duplicate the existing forward-legal fix-cycle edges (review/qa→build), which are plain legal_predecessors.
  • Additive / conservative: forward-only is unchanged; backward requires the explicit justification. Existing flows (no justification) throw exactly as before.
  • Flagship-only wiring: v1 wires frame→discover end-to-end. plan→frame and handoff→plan are recognized in BACKTRACK_EDGES but their command-guard wiring (via assertLegalTransition, touching frame.ts/plan.ts) is a documented follow-on — those guards differ (plan has none today), so wiring them is its own bounded change.

Verification

  • backtrack unit tests: 8/8 (edges; eval allow/deny/edge-mismatch/empty-reason; reader valid/absent/malformed fail-soft).
  • discover integration test: frame→discover throws without a justification; with one, it succeeds continuing the same run (previous_stage=frame, run_id stable).
  • typecheck:check baseline 0, 0 new; full unit gate exit 0, 0 fail markers on re-run (run 1 = known fresh-worktree Phase 5.5 manifest race). Behavior-preservation holds: closeout-rollover + same-stage re-discover are unaffected.

RFC backlog after this

#1 decomposition ✅ shipped · #2 lanes (unblocked) · #3 backward transitions → this PR (flagship) · #4 spike (deferred) · #5 → Problem A. This also gives Problem C (lifecycle re-entry) its mechanism — it now folds into completing #3 (wire plan→frame/handoff→plan).

🤖 Generated with Claude Code

… (RFC item #3)

Hole 3: the lifecycle was forward-only at the early stages, so `frame→discover`
threw "Illegal Nexus transition", forcing the operator-attested fabrication
workaround. This makes evidence-driven retreat a first-class, RECORDED primitive.

- lib/nexus/governance/backtrack.ts: pure BACKTRACK_EDGES (reverse of the early
  forward spine: discover←frame, frame←plan, plan←handoff) + evaluateBacktrack
  (allowed only when the edge is recognized AND a matching, non-empty justification
  is recorded) + fail-soft readBacktrackJustification + the canonical path helper.
- lib/nexus/commands/discover.ts: the bespoke `→discover` guard now permits a
  retreat when a justification is recorded at
  .planning/current/discover/backtrack-justification.json; an allowed retreat
  REUSES the existing run (run-id continuity), reset to the discover stage by
  nextLedger — recorded via previous_stage + command_history.

Design (per the confirmed v1):
- File-based justification {from,to,reason}, symmetric with the decomposition
  record (operator-authored, command-gated, auditable).
- Additive/conservative: forward-only is unchanged; backward requires the explicit
  justification. Existing flows (no justification) throw exactly as before.
- v1 wires the flagship frame→discover; plan→frame and handoff→plan are recognized
  in BACKTRACK_EDGES but their command-guard wiring (via assertLegalTransition,
  touching frame.ts/plan.ts) is a documented follow-on.

Verification (Iron Law 1):
- backtrack unit tests: 8/8 (edges, eval allow/deny/mismatch/empty-reason, reader
  valid/absent/malformed fail-soft).
- discover integration test: frame→discover throws without a justification, and
  with one succeeds continuing the SAME run (previous_stage=frame, run_id stable).
- typecheck:check baseline 0, 0 new; full unit gate exit 0, 0 fail markers on
  re-run — behavior-preservation holds (closeout-rollover + same-stage re-discover
  unaffected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

E2E Evals: ✅ PASS

0/0 tests passed | $0 total cost | parallel matrix jobs

Suite Result Status Cost

pull_request: ubuntu-latest fallback; workflow_dispatch: configured suite runners | Docker: pre-baked toolchain + deps | wall clock ≈ slowest suite

@LaPaGaYo
LaPaGaYo merged commit 982a497 into main Jun 20, 2026
21 checks passed
@LaPaGaYo
LaPaGaYo deleted the feat/lifecycle-backward-transitions branch June 20, 2026 15:44
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