@open-agent-toolkit/cli 0.2.72 → 0.2.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/assets/agents/oat-reviewer.md +4 -3
  2. package/assets/agents/recon-worker.md +42 -8
  3. package/assets/bundle-metadata.json +1 -1
  4. package/assets/docs/cli-utilities/configuration.md +3 -56
  5. package/assets/docs/cli-utilities/tool-packs.md +4 -4
  6. package/assets/docs/contributing/code.md +2 -2
  7. package/assets/docs/contributing/index.md +0 -1
  8. package/assets/docs/reference/cli-reference.md +1 -1
  9. package/assets/docs/reference/troubleshooting.md +17 -40
  10. package/assets/docs/workflows/projects/artifacts.md +16 -34
  11. package/assets/docs/workflows/projects/lifecycle.md +20 -19
  12. package/assets/docs/workflows/skills/explainer-kit.md +180 -440
  13. package/assets/docs/workflows/skills/index.md +1 -2
  14. package/assets/docs/workflows/skills/recon.md +114 -23
  15. package/assets/public-package-versions.json +4 -4
  16. package/assets/skills/explainer-kit/SKILL.md +96 -171
  17. package/assets/skills/explainer-kit/recipes/engineer-tour.json +1 -22
  18. package/assets/skills/explainer-kit/recipes/program-recap.json +1 -29
  19. package/assets/skills/explainer-kit/recipes/project-explainer.json +1 -22
  20. package/assets/skills/explainer-kit/recipes/project-recap.v2.json +1 -43
  21. package/assets/skills/explainer-kit/references/fact-base-contract.md +76 -101
  22. package/assets/skills/explainer-kit/references/recap-authoring.md +99 -0
  23. package/assets/skills/explainer-kit/schemas/manifest.schema.json +13 -135
  24. package/assets/skills/explainer-kit/scripts/bundle.mjs +712 -0
  25. package/assets/skills/explainer-kit/scripts/lib/claim-subject.mjs +40 -0
  26. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +113 -1504
  27. package/assets/skills/explainer-kit/scripts/lib/failure.mjs +13 -0
  28. package/assets/skills/explainer-kit/scripts/lib/package-coverage.mjs +57 -403
  29. package/assets/skills/explainer-kit/scripts/lib/qa-result.mjs +168 -0
  30. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +90 -488
  31. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +28 -545
  32. package/assets/skills/explainer-kit/scripts/lib/run-package.mjs +120 -0
  33. package/assets/skills/explainer-kit/scripts/lib/sanitize.mjs +42 -0
  34. package/assets/skills/explainer-kit/scripts/record.mjs +335 -0
  35. package/assets/skills/explainer-kit/scripts/verify.mjs +648 -0
  36. package/assets/skills/oat-explainer-kit/SKILL.md +57 -117
  37. package/assets/skills/oat-explainer-kit/references/config-contract.md +20 -64
  38. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +85 -237
  39. package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +18 -10
  40. package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +1 -0
  41. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +256 -21
  42. package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +82 -3
  43. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +0 -162
  44. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +57 -123
  45. package/assets/skills/oat-project-autonomous/SKILL.md +14 -13
  46. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +165 -165
  47. package/assets/skills/oat-project-complete/SKILL.md +168 -349
  48. package/assets/skills/oat-project-complete/scripts/consume-persisted-recap-intent.mjs +125 -0
  49. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +0 -30
  50. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +4 -37
  51. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +17 -16
  52. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +9 -174
  53. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +1 -2
  54. package/assets/skills/oat-project-document/SKILL.md +1 -1
  55. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +165 -165
  56. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  57. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +44 -56
  58. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +165 -165
  59. package/assets/skills/oat-project-lite/SKILL.md +1 -1
  60. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +165 -165
  61. package/assets/skills/oat-project-plan/SKILL.md +5 -6
  62. package/assets/skills/oat-project-pr-final/SKILL.md +1 -1
  63. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +165 -165
  64. package/assets/skills/oat-project-quick-start/SKILL.md +1 -1
  65. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +165 -165
  66. package/assets/skills/oat-project-review-receive/SKILL.md +14 -1
  67. package/assets/skills/oat-project-summary/SKILL.md +35 -25
  68. package/assets/skills/oat-wave-execute/SKILL.md +11 -36
  69. package/assets/skills/oat-wave-program/SKILL.md +13 -37
  70. package/assets/skills/recon/SKILL.md +103 -40
  71. package/assets/skills/recon/references/packet-contract.md +150 -67
  72. package/assets/skills/recon/references/profiles.md +38 -16
  73. package/assets/skills/recon/references/worker-contract.md +39 -8
  74. package/assets/skills/recon/scripts/lib/contracts.mjs +703 -55
  75. package/assets/skills/recon/scripts/lib/routing.mjs +588 -0
  76. package/assets/skills/recon/scripts/lib/validated-run.mjs +2 -0
  77. package/assets/skills/recon/scripts/prepare-routing.mjs +88 -0
  78. package/assets/skills/recon/scripts/render-packet.mjs +69 -1
  79. package/assets/skills/recon/scripts/validate-packet.mjs +473 -56
  80. package/assets/skills/subagent-orchestration/SKILL.md +18 -9
  81. package/assets/skills/subagent-orchestration/references/model-selection-principles.md +17 -8
  82. package/dist/commands/config/index.d.ts.map +1 -1
  83. package/dist/commands/config/index.js +9 -113
  84. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  85. package/dist/commands/project/archive/archive-utils.js +32 -184
  86. package/dist/commands/project/archive/explainer-package-coverage.d.ts +3 -8
  87. package/dist/commands/project/archive/explainer-package-coverage.d.ts.map +1 -1
  88. package/dist/commands/project/archive/explainer-package-coverage.js +1 -1
  89. package/dist/config/oat-config.d.ts +0 -11
  90. package/dist/config/oat-config.d.ts.map +1 -1
  91. package/dist/config/oat-config.js +0 -34
  92. package/dist/config/resolve.d.ts.map +1 -1
  93. package/dist/config/resolve.js +0 -8
  94. package/dist/release/public-package-contract.d.ts.map +1 -1
  95. package/dist/release/public-package-contract.js +2 -10
  96. package/dist/validation/project-state.d.ts.map +1 -1
  97. package/dist/validation/project-state.js +42 -3
  98. package/package.json +2 -2
  99. package/assets/docs/contributing/explainer-kit-verification.md +0 -133
  100. package/assets/docs/workflows/skills/explainer-kit-providers.md +0 -155
  101. package/assets/skills/explainer-kit/briefs/deep-dive.md +0 -35
  102. package/assets/skills/explainer-kit/briefs/project-page.md +0 -38
  103. package/assets/skills/explainer-kit/briefs/supporting-diagram.md +0 -28
  104. package/assets/skills/explainer-kit/briefs/walkthrough-deck.md +0 -35
  105. package/assets/skills/explainer-kit/examples/project-explainer/content.md +0 -31
  106. package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +0 -22
  107. package/assets/skills/explainer-kit/examples/project-recap/content.md +0 -77
  108. package/assets/skills/explainer-kit/examples/project-recap/fact-base.json +0 -104
  109. package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +0 -44
  110. package/assets/skills/explainer-kit/examples/theme-bundle.json +0 -87
  111. package/assets/skills/explainer-kit/recipes/project-recap.v1.json +0 -93
  112. package/assets/skills/explainer-kit/references/contracts.md +0 -324
  113. package/assets/skills/explainer-kit/references/destination-contract.md +0 -210
  114. package/assets/skills/explainer-kit/references/extension-contract.md +0 -80
  115. package/assets/skills/explainer-kit/references/golden-conformance.md +0 -80
  116. package/assets/skills/explainer-kit/references/visual-review.md +0 -71
  117. package/assets/skills/explainer-kit/schemas/author-request.v2.schema.json +0 -212
  118. package/assets/skills/explainer-kit/schemas/author-request.v3.schema.json +0 -241
  119. package/assets/skills/explainer-kit/schemas/author-result.v2.schema.json +0 -52
  120. package/assets/skills/explainer-kit/schemas/build-record.schema.json +0 -98
  121. package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +0 -53
  122. package/assets/skills/explainer-kit/schemas/publish-receipt.v1.schema.json +0 -97
  123. package/assets/skills/explainer-kit/schemas/publish-receipt.v2.schema.json +0 -215
  124. package/assets/skills/explainer-kit/schemas/publish-request.v1.schema.json +0 -32
  125. package/assets/skills/explainer-kit/schemas/publish-request.v2.schema.json +0 -34
  126. package/assets/skills/explainer-kit/schemas/run-request.schema.json +0 -147
  127. package/assets/skills/explainer-kit/schemas/set-plan.v1.schema.json +0 -149
  128. package/assets/skills/explainer-kit/schemas/terminal-evidence.v1.schema.json +0 -81
  129. package/assets/skills/explainer-kit/schemas/visual-review-evidence.v1.schema.json +0 -66
  130. package/assets/skills/explainer-kit/schemas/visual-review-request.v1.schema.json +0 -117
  131. package/assets/skills/explainer-kit/schemas/visual-review-result.v1.schema.json +0 -80
  132. package/assets/skills/explainer-kit/scripts/lib/catalog.mjs +0 -349
  133. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +0 -418
  134. package/assets/skills/explainer-kit/scripts/lib/diagram.mjs +0 -514
  135. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +0 -643
  136. package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +0 -664
  137. package/assets/skills/explainer-kit/scripts/lib/internal-references.mjs +0 -538
  138. package/assets/skills/explainer-kit/scripts/lib/markdown.mjs +0 -414
  139. package/assets/skills/explainer-kit/scripts/lib/publication-policy.mjs +0 -54
  140. package/assets/skills/explainer-kit/scripts/lib/records.mjs +0 -954
  141. package/assets/skills/explainer-kit/scripts/lib/render.mjs +0 -703
  142. package/assets/skills/explainer-kit/scripts/lib/s3-roots.mjs +0 -353
  143. package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +0 -759
  144. package/assets/skills/explainer-kit/scripts/lib/set-plan.mjs +0 -209
  145. package/assets/skills/explainer-kit/scripts/lib/source-backlinks.mjs +0 -218
  146. package/assets/skills/explainer-kit/scripts/lib/terminal-evidence.mjs +0 -157
  147. package/assets/skills/explainer-kit/scripts/lib/visual-review.mjs +0 -400
  148. package/assets/skills/explainer-kit/scripts/publish.mjs +0 -76
  149. package/assets/skills/explainer-kit/scripts/record-durability.mjs +0 -64
  150. package/assets/skills/explainer-kit/scripts/render-qa.mjs +0 -461
  151. package/assets/skills/explainer-kit/scripts/run.mjs +0 -3038
  152. package/assets/skills/explainer-kit/scripts/validate.mjs +0 -59
  153. package/assets/skills/oat-explainer-kit/references/author-callback.md +0 -53
  154. package/assets/skills/oat-explainer-kit/references/migration.md +0 -144
  155. package/assets/skills/oat-explainer-kit/references/visual-review-callback.md +0 -83
  156. package/assets/skills/oat-explainer-kit/scripts/derive-destination.mjs +0 -91
  157. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +0 -531
  158. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +0 -371
  159. package/assets/skills/oat-explainer-kit/scripts/run.mjs +0 -905
  160. package/dist/commands/project/archive/explainer-source-backlinks.d.ts +0 -18
  161. package/dist/commands/project/archive/explainer-source-backlinks.d.ts.map +0 -1
  162. package/dist/commands/project/archive/explainer-source-backlinks.js +0 -27
  163. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts +0 -29
  164. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts.map +0 -1
  165. package/dist/commands/project/archive/explainer-terminal-evidence.js +0 -37
@@ -5,7 +5,7 @@ disable-model-invocation: true
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Bash, AskUserQuestion
7
7
  metadata:
8
- version: 1.7.10
8
+ version: 1.7.12
9
9
  ---
10
10
 
11
11
  # Complete Project
@@ -47,6 +47,23 @@ ACTIVE_PROJECT_PATH="$PROJECT_PATH"
47
47
 
48
48
  # Set SKILL_DIR to the absolute directory containing this loaded SKILL.md.
49
49
  COMPLETION_RECEIPT_SCRIPT="$SKILL_DIR/scripts/recover-completion-receipts.mjs"
50
+ RECAP_INTENT_CONSUMER="$SKILL_DIR/scripts/consume-persisted-recap-intent.mjs"
51
+ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
52
+ RECAP_TERMINAL_GUARD=""
53
+ for CANDIDATE in \
54
+ "$(dirname "$SKILL_DIR")/oat-explainer-kit" \
55
+ "${HOME}/.agents/skills/oat-explainer-kit" \
56
+ "$REPO_ROOT/.agents/skills/oat-explainer-kit"
57
+ do
58
+ if [[ -f "$CANDIDATE/SKILL.md" && -f "$CANDIDATE/scripts/check-terminal-outcome.mjs" ]]; then
59
+ RECAP_TERMINAL_GUARD="$CANDIDATE/scripts/check-terminal-outcome.mjs"
60
+ break
61
+ fi
62
+ done
63
+ test -f "$RECAP_TERMINAL_GUARD" || {
64
+ echo "oat-explainer-kit is not installed at the loaded, user, or project skill root." >&2
65
+ exit 1
66
+ }
50
67
  COMPLETION_RETRY_SCRIPT="$SKILL_DIR/scripts/resolve-completion-retry.mjs"
51
68
  COMPLETION_RETRY_FIELDS_SCRIPT="$SKILL_DIR/scripts/parse-completion-retry-fields.mjs"
52
69
  NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT="$SKILL_DIR/scripts/validate-nonarchive-lifecycle-receipt.mjs"
@@ -59,6 +76,10 @@ test -f "$COMPLETION_RECEIPT_SCRIPT" || {
59
76
  echo "oat: completion receipt recovery script is missing" >&2
60
77
  exit 1
61
78
  }
79
+ test -f "$RECAP_INTENT_CONSUMER" || {
80
+ echo "oat: persisted recap intent consumer is missing" >&2
81
+ exit 1
82
+ }
62
83
  test -f "$COMPLETION_RETRY_SCRIPT" || {
63
84
  echo "oat: completion retry routing script is missing" >&2
64
85
  exit 1
@@ -533,87 +554,119 @@ When `SHOULD_GENERATE_RETRO="false"`, do not dispatch the skill.
533
554
  Run this gate after the optional summary refresh and before any lifecycle
534
555
  mutation. Initialize `SELECTED_PROJECT_RECAP_RUN=""`.
535
556
 
536
- When `SHOULD_GENERATE_RECAP="true"`, inspect manifests under
537
- `{PROJECT_PATH}/explainers/` before generating. A fresh `project-recap` manifest for the current completed implementation is reused without invoking the adapter again. Fresh means the manifest identifies recipe `project-recap`, belongs to this project, has a terminal outcome, and its recorded source hashes match the current approved implementation inputs, including the refreshed summary when present.
538
-
539
- If no fresh recap exists, probe seam availability before invoking the adapter.
540
- Call `oat-explainer-kit/scripts/probe-recap-seams.mjs#probeRecapSeams` in
541
- `mode: unattended` with the exact seam inputs this step would pass. The probe is
542
- pure and covers all five required seams — author, fact critic, browser session,
543
- visual critic, and set planner — so a host missing only the set planner is
544
- detected here instead of at the adapter's `E_SET_PLANNER_REQUIRED`. When
545
- `OAT_AUTONOMOUS=1`, pass the result to autonomous intent resolution as
546
- `seamProbe`. The resolver accepts a `seamProbe` only for autonomous
547
- `projectRecap`, so an interactive completion keeps the decision recorded at the
548
- batched prompt and does not pass one.
549
-
550
- In autonomy, a probe result of `seams-unavailable` means no provider is
551
- configured for a required seam. Autonomous resolution then returns a recordable
552
- `skip` with source `capability_probe`: record it with the warning, leave
553
- `SELECTED_PROJECT_RECAP_RUN` empty, and complete without a recap. That
554
- probe-driven skip record supersedes the intent resolved and persisted earlier in
555
- this run for the remainder of the run: persist it through the same
556
- `oat-explainer-kit` intent-persistence helper with a freshly captured state hash,
557
- treat any `SHOULD_GENERATE_RECAP="true"` set from the earlier resolution as
558
- stale, and pass the skip — not the earlier `generate` — to the terminal-outcome
559
- guard as `--intent skip --skip-reason capability_probe`. Passing the superseded
560
- `generate` with no manifest raises `E_RECAP_OUTCOME` and blocks completion,
561
- which is the exact failure this gate exists to prevent. An interactive
562
- completion is unchanged: the decision recorded at the batched prompt governs, a
563
- recorded `generate` still attempts the recap, and a run that fails for a missing
564
- seam is still the `failed` outcome it is today. A probe result
565
- of `seams-invalid` means a seam is supplied but violates a resolution rule:
566
- report the configuration error and fail closed. Never convert a
567
- configured-but-invalid seam, or a run that failed after a passing probe, into a
568
- skip; that run stays `failed`.
569
-
570
- In autonomy, attempt the adapter run exactly once and only when the probe resolves every seam; an interactive `generate` still attempts the run regardless of the probe result, and a seam-less interactive attempt is still the `failed` outcome it is today. The autonomy gate and the interactive rule are two separate rules and are never read as one.
571
-
572
- When the gate above allows the attempt, invoke `scripts/run.mjs#runOatExplainer` exactly once with recipe `project-recap`, project invocation, the active project, and unattended lifecycle mode so approved OAT artifacts do not trigger a second content prompt. A returned `failed` outcome warns but does not block completion. An invocation that returns no terminal outcome blocks lifecycle mutation. Use a returned valid terminal `project-recap` manifest as the selected run; do not rerun to improve its outcome.
573
- Before that invocation, construct exactly one brief-aware, provider-neutral
574
- author seam as documented by
575
- `oat-explainer-kit/references/author-callback.md`. In-process callers pass
576
- `author`; JSON/CLI callers pass a validated `authorModulePath`. Supply it
577
- alongside the existing `critic` callback (or validated
578
- `criticModulePath`), and invoke the recap with `mode: unattended`.
579
-
580
- The author seam is the recap's quality mechanism, so derive its output from the
581
- request rather than from ambient context or a stock recap shape. Cover every
582
- `floor.requiredNarrative` section, ground each claim in the supplied `factBase`,
583
- and follow the inlined `brief` for structure — evidence tables for the
584
- implementation and validation sections, at least one high-level architecture
585
- diagram, and lists where material is enumerable. A recap whose warnings include
586
- `guideline-narrative-coverage-missing`, `guideline-structured-depth-missing`, or
587
- `guideline-architecture-diagram-missing` is thin: it still completes, but treat
588
- those warnings as the signal that the authored content did not use the evidence
589
- it was given.
590
-
591
- Set `SELECTED_PROJECT_RECAP_RUN` only to the final selected `project-recap` run. The value must be project-relative in the form `explainers/<run-slug>` so it can be passed safely to the archive CLI. An incomplete, stale, wrong-project, or `project-explainer` manifest is never selected as the final recap.
592
-
593
- Before any lifecycle mutation, invoke the shared
594
- `oat-explainer-kit/scripts/check-terminal-outcome.mjs` guard with the resolved
595
- intent and, for `generate`, the selected or attempted manifest. The only
596
- terminal generated outcomes are `built-durable`, `built-not-durable`,
597
- `built-needs-review`, and `failed`. Missing records and `incomplete` block
598
- completion; do not substitute a warning or infer an outcome from filesystem
599
- presence. A `skip` intent requires no manifest; pass its recorded source as
600
- `--skip-reason` so the receipt states why no recap exists.
601
-
602
- When recap intent resolves to `skip`, leave `SELECTED_PROJECT_RECAP_RUN` empty
603
- and complete without a recap. This covers both an interactive skip and a
604
- probe-driven `capability_probe` skip; neither prompts, and neither blocks
605
- completion. A terminal `failed` recap attempt is recorded as
606
- a warning rather than changing project completion status.
607
-
608
- `project-explainer` runs are active-project working artifacts, not durable post-completion reference products. Do not export, re-attest, or add archive-aware PR or summary reference links for a `project-explainer` run.
609
-
610
- For `IS_DURABLE_PROJECT="false"`, never export a tracked project recap and never construct or pass `--project-recap-run`. This is the local scope. A local-scope recap remains `built-not-durable` unless its manifest already contains independently verified publish evidence. Do not treat local filesystem presence as durability. Shared and synced recaps are exported and attested through the later durability stage.
557
+ First re-read the persisted `oat_project_recap` record from
558
+ `"$PROJECT_PATH/state.md"` through
559
+ `scripts/consume-persisted-recap-intent.mjs`. Pass the project path to this
560
+ single executable decision/effect boundary. It derives `state.md` and
561
+ `explainers/` itself, re-reads the persisted decision, and performs manifest
562
+ discovery only for `generate`. Its route and authoring permission are
563
+ authoritative even when an earlier in-memory resolution set
564
+ `SHOULD_GENERATE_RECAP`.
565
+
566
+ A persisted `skip`, including `skip/failed_attempt`, returns route `skip`
567
+ without touching `explainers/`, suppressing manifest discovery, bundle, and
568
+ authoring together. Leave `SELECTED_PROJECT_RECAP_RUN` empty and invoke the
569
+ terminal-outcome guard with `--intent skip` and the persisted source as
570
+ `--skip-reason`. For `failed_attempt`, use only the consumer's validated
571
+ `failedAttemptEvidence`; never rediscover or reconstruct a proof path from
572
+ memory.
573
+
574
+ ```bash
575
+ RECAP_CONSUMPTION=$(node "$RECAP_INTENT_CONSUMER" \
576
+ "$PROJECT_PATH") || exit 1
577
+ RECAP_CONSUMPTION_FIELDS=$(node -e '
578
+ const value = JSON.parse(process.argv[1]);
579
+ if (value.route !== value.decision) process.exit(1);
580
+ const evidence = value.failedAttemptEvidence ?? null;
581
+ if (value.route === "skip" && (value.manifestDiscoveryPerformed !== false ||
582
+ value.manifestCandidates.length !== 0 ||
583
+ value.authoringPermitted !== false)) process.exit(1);
584
+ if (value.route === "skip" && value.source === "failed_attempt" &&
585
+ (!evidence || !["manifest", "failure"].includes(evidence.kind) ||
586
+ typeof evidence.path !== "string")) process.exit(1);
587
+ if (value.route === "skip" && value.source !== "failed_attempt" &&
588
+ evidence !== null) process.exit(1);
589
+ if (value.route === "generate" &&
590
+ (value.manifestDiscoveryPerformed !== true ||
591
+ !Array.isArray(value.manifestCandidates) ||
592
+ value.authoringPermitted !== true ||
593
+ evidence !== null)) process.exit(1);
594
+ if (!["generate", "skip"].includes(value.route)) process.exit(1);
595
+ process.stdout.write(`${value.route}\t${value.source}\t` +
596
+ `${value.authoringPermitted}\t${JSON.stringify(value.manifestCandidates)}\t` +
597
+ JSON.stringify(evidence));
598
+ ' "$RECAP_CONSUMPTION") || exit 1
599
+ IFS=$'\t' read -r PERSISTED_RECAP_DECISION PERSISTED_RECAP_SOURCE \
600
+ RECAP_AUTHORING_PERMITTED RECAP_MANIFEST_CANDIDATES_JSON \
601
+ RECAP_FAILED_ATTEMPT_EVIDENCE_JSON \
602
+ <<< "$RECAP_CONSUMPTION_FIELDS"
603
+
604
+ RECAP_TERMINAL_EVIDENCE_ARGS=()
605
+ if [[ "$PERSISTED_RECAP_SOURCE" == "failed_attempt" ]]; then
606
+ while IFS= read -r -d '' RECAP_EVIDENCE_ARG; do
607
+ RECAP_TERMINAL_EVIDENCE_ARGS+=("$RECAP_EVIDENCE_ARG")
608
+ done < <(node -e '
609
+ const value = JSON.parse(process.argv[1]);
610
+ const flag = value.kind === "manifest" ? "--manifest" : "--failure";
611
+ process.stdout.write(`${flag}\0${value.path}\0`);
612
+ ' "$RECAP_FAILED_ATTEMPT_EVIDENCE_JSON")
613
+ fi
614
+ ```
615
+
616
+ For route `generate`, inspect only the manifest candidates returned in
617
+ `RECAP_MANIFEST_CANDIDATES_JSON`; do not perform a second filesystem discovery
618
+ outside the executable boundary. Reuse a fresh satisfied `project-recap`
619
+ package without invoking the adapter. Fresh means the manifest identifies
620
+ recipe `project-recap`, belongs to this project, has outcome `built` or
621
+ `built-needs-review`, passes the complete package guard, and its input hashes
622
+ match the current approved implementation inputs, including the refreshed
623
+ summary when present.
624
+
625
+ If no fresh package exists, require
626
+ `RECAP_AUTHORING_PERMITTED="true"` from that same boundary before invoking the
627
+ `oat-explainer-kit` adapter's § Generate with recipe `project-recap`, project
628
+ invocation, the active project, and `mode: unattended`. The executable boundary
629
+ does not fabricate host-agent authoring; it gates permission for the lifecycle
630
+ caller that performs the installed core check, resolves inputs, theme, and
631
+ output root, then runs `bundle` → host-agent authoring → `verify` → `record`.
632
+ Lifecycle generation never prompts. Use the first available browser rung; a
633
+ missing browser becomes `built-needs-review`, not a skip or block.
634
+
635
+ `built` and `built-needs-review` satisfy generation. Set
636
+ `SELECTED_PROJECT_RECAP_RUN` only to that final satisfied project-recap run, as
637
+ the project-relative path `explainers/<run-slug>`. A stale, wrong-project,
638
+ `project-explainer`, `failed`, or `incomplete` manifest is never selected.
639
+
640
+ On `failed` or `incomplete`, show the sanitized cause and require an explicit
641
+ retry or skip before lifecycle mutation. Under autonomy, retry once. If that
642
+ retry also fails, persist `skip/failed_attempt` with a fresh state hash and
643
+ `failed_attempt_evidence` naming that run's project-relative failed/incomplete
644
+ `manifest.json` or `failure.json`. Re-read it through the executable consumer
645
+ before continuing. Never silently skip a failed attempt.
646
+
647
+ Before any lifecycle mutation, invoke `"$RECAP_TERMINAL_GUARD"` with the
648
+ persisted intent. For `generate`, pass the selected package's canonical
649
+ `manifest.json`; for `skip`, pass `--project-root "$PROJECT_PATH"`, the
650
+ recorded source, and `"${RECAP_TERMINAL_EVIDENCE_ARGS[@]}"`. This passes only
651
+ the failed-attempt proof path already validated and canonicalized by the
652
+ executable consumer.
653
+ The outcome vocabulary is `built`, `built-needs-review`, `failed`, and
654
+ `incomplete`: only the first two satisfy generation. Missing packages do not
655
+ satisfy generation.
656
+
657
+ `project-explainer` runs are active-project working artifacts, not
658
+ post-completion reference products. Do not export or add archive-aware PR or
659
+ summary reference links for a `project-explainer` run.
660
+
661
+ For `IS_DURABLE_PROJECT="false"`, never export a tracked project recap and
662
+ never construct or pass `--project-recap-run`. This is the local scope. Do not
663
+ treat local filesystem presence as project durability. Shared and synced recaps
664
+ are exported by the later archive step.
611
665
 
612
666
  ### Step 3.65: Recover a Recognizable Completion Receipt Before Mutation
613
667
 
614
668
  Initialize `PROJECT_LINKS_PIN_COMMIT=""`, `PROJECT_REF_COMMIT=""`,
615
- `EVIDENCE_COMMIT=""`, `RECOVERED_EVIDENCE_COMMIT=""`,
616
- `EVIDENCE_PUSH_REQUIRED=""`, `PR_DESCRIPTION_RELATIVE_PATH=""`, and
669
+ `PR_DESCRIPTION_RELATIVE_PATH=""`, and
617
670
  `COMPLETION_RECEIPTS_RECOVERED="false"`. For a
618
671
  synced non-archive run, invoke the skill-owned retry router before the
619
672
  project-log probe, seal append, review moves, `complete-state`, active-pointer,
@@ -626,12 +679,6 @@ if [[ "$PROJECT_SCOPE" == "synced" && "$SHOULD_ARCHIVE" == "false" ]]; then
626
679
  --project-path "$ACTIVE_PROJECT_PATH"
627
680
  --retained-ref "$PROJECT_RETAINED_REF"
628
681
  )
629
- if [[ -n "$SELECTED_PROJECT_RECAP_RUN" ]]; then
630
- COMPLETION_RETRY_ARGS+=(
631
- --evidence-path "$SELECTED_PROJECT_RECAP_RUN/manifest.json"
632
- --evidence-path "$SELECTED_PROJECT_RECAP_RUN/build-record.json"
633
- )
634
- fi
635
682
  COMPLETION_RETRY_JSON=$(node "$COMPLETION_RETRY_SCRIPT" \
636
683
  "${COMPLETION_RETRY_ARGS[@]}") || exit 1
637
684
  COMPLETION_RETRY_FIELDS=$(node "$COMPLETION_RETRY_FIELDS_SCRIPT" \
@@ -640,11 +687,8 @@ if [[ "$PROJECT_SCOPE" == "synced" && "$SHOULD_ARCHIVE" == "false" ]]; then
640
687
  <<< "$COMPLETION_RETRY_FIELDS"
641
688
  if [[ "$COMPLETION_RETRY_ROUTE" == "recovery" ]]; then
642
689
  IFS=$'\t' read -r COMPLETION_RETRY_ROUTE PROJECT_LINKS_PIN_COMMIT \
643
- PROJECT_REF_COMMIT RECOVERED_EVIDENCE_COMMIT EVIDENCE_PUSH_REQUIRED \
644
- PR_DESCRIPTION_RELATIVE_PATH <<< "$COMPLETION_RETRY_FIELDS"
645
- if [[ "$RECOVERED_EVIDENCE_COMMIT" != "-" ]]; then
646
- EVIDENCE_COMMIT="$RECOVERED_EVIDENCE_COMMIT"
647
- fi
690
+ PROJECT_REF_COMMIT PR_DESCRIPTION_RELATIVE_PATH \
691
+ <<< "$COMPLETION_RETRY_FIELDS"
648
692
  PR_DESCRIPTION_PATH="$ACTIVE_PROJECT_PATH/$PR_DESCRIPTION_RELATIVE_PATH"
649
693
  COMPLETION_RECEIPTS_RECOVERED="true"
650
694
  elif [[ "$COMPLETION_RETRY_ROUTE" == "pin-source" ]]; then
@@ -917,8 +961,8 @@ the PR artifact → project-ref pin-source push → project archive → render
917
961
  `oat project links --durable-summary <path>` → update the open PR body. When
918
962
  archive is declined, it is: finalize → generate the PR artifact →
919
963
  project-ref pin-source push → render the final links → final artifact push →
920
- exact discovery-record commit → optional active-recap evidence commit and
921
- project push.
964
+ exact discovery-record commit. The recap already travels in the final project
965
+ reference push.
922
966
 
923
967
  The CLI command owns both the frontmatter completion fields and the canonical markdown body updates for `state.md`.
924
968
  It must set `oat_lifecycle: complete`, completion timestamps, `**Status:** Complete`, `**Last Updated:**`, the canonical `## Current Phase` body, normalized `## Progress`, and `## Next Milestone`.
@@ -1023,9 +1067,9 @@ artifact write. This receipt is the immutable pin source used when Step 8.6
1023
1067
  renders the final links. Keep it separate from the final non-archive artifact
1024
1068
  receipt:
1025
1069
 
1026
- Preserve `PROJECT_LINKS_PIN_COMMIT`, `PROJECT_REF_COMMIT`, `EVIDENCE_COMMIT`,
1027
- and `EVIDENCE_PUSH_REQUIRED` when the Step 3.65 router restored them. A
1028
- `pin-source` route skips this step entirely and resumes at Step 8.6. Do not
1070
+ Preserve `PROJECT_LINKS_PIN_COMMIT` and `PROJECT_REF_COMMIT` when the Step 3.65
1071
+ router restored them. A `pin-source` route skips this step entirely and resumes
1072
+ at Step 8.6. Do not
1029
1073
  initialize over a recovered value or run a second candidate-routing branch at
1030
1074
  this step. The pre-mutation router owns candidate detection, exact PR-artifact
1031
1075
  selection, pin-source retry validation, and `recoverCompletionReceipts`; its
@@ -1033,10 +1077,9 @@ read-only recovery must have validated the applicable receipt chain before
1033
1077
  returning a receipt:
1034
1078
 
1035
1079
  - a clean synced checkout and the retained local ref;
1036
- - the exact final-artifact and optional evidence subjects;
1037
- - exactly the PR-description path in the final-artifact commit and exactly the
1038
- two supplied recap record paths in an evidence commit;
1039
- - single-parent pin-source → final-artifact → optional evidence ordering, with
1080
+ - the exact final-artifact subject;
1081
+ - exactly the PR-description path in the final-artifact commit;
1082
+ - single-parent pin-source → final-artifact ordering, with
1040
1083
  the pin source subject equal to the preliminary push message below;
1041
1084
  - canonical `state.md` lifecycle fields in the pin-source tree, including
1042
1085
  `oat_lifecycle: complete` and equal valid UTC completion/update timestamps;
@@ -1044,63 +1087,17 @@ returning a receipt:
1044
1087
  canonical `oat-project-complete` completion seal; an absent log remains the
1045
1088
  supported inert project-log configuration from Step 3.7;
1046
1089
  - exactly one well-ordered links block pinned to the pin-source parent; and
1047
- - either equal local/remote final-artifact receipts, equal local/remote evidence
1048
- receipts, or the one allowed unpublished-evidence state where checkout HEAD
1049
- is the exact evidence child while both retained refs remain at its exact
1050
- final-artifact parent.
1090
+ - equal local and remote final-artifact receipts.
1051
1091
 
1052
1092
  Restore the returned `projectLinksPinCommit` as
1053
- `PROJECT_LINKS_PIN_COMMIT`, `projectRefCommit` as `PROJECT_REF_COMMIT`, and a
1054
- non-null `evidenceCommit` as `EVIDENCE_COMMIT`. Any candidate with a malformed
1093
+ `PROJECT_LINKS_PIN_COMMIT` and `projectRefCommit` as `PROJECT_REF_COMMIT`. Any
1094
+ candidate with a malformed
1055
1095
  subject, path set, parent, links block, retained ref, or local/remote relation
1056
1096
  fails closed. Do not fall through to a new pin-source publication after a
1057
1097
  partial or contradictory candidate. This retry recognition is valid whether
1058
1098
  the parent discovery record is still active or already complete.
1059
1099
 
1060
- Build the recovery arguments only for post-push revalidation of an unpublished
1061
- evidence receipt:
1062
-
1063
- ```bash
1064
- RECOVERY_ARGS=(
1065
- --project-path "$ACTIVE_PROJECT_PATH"
1066
- --retained-ref "$PROJECT_RETAINED_REF"
1067
- --pr-artifact "$PR_DESCRIPTION_RELATIVE_PATH"
1068
- )
1069
- if [[ -n "$SELECTED_PROJECT_RECAP_RUN" ]]; then
1070
- RECOVERY_ARGS+=(
1071
- --evidence-path "$SELECTED_PROJECT_RECAP_RUN/manifest.json"
1072
- --evidence-path "$SELECTED_PROJECT_RECAP_RUN/build-record.json"
1073
- )
1074
- fi
1075
-
1076
- parse_completion_receipts() {
1077
- node -e '
1078
- const value = JSON.parse(process.argv[1]);
1079
- const sha = /^[0-9a-f]{40}$/;
1080
- if (value.status !== "recovered" || !sha.test(value.projectLinksPinCommit) || !sha.test(value.projectRefCommit)) process.exit(1);
1081
- if (value.evidenceCommit !== null && !sha.test(value.evidenceCommit)) process.exit(1);
1082
- if (typeof value.evidencePushRequired !== "boolean") process.exit(1);
1083
- process.stdout.write([
1084
- value.projectLinksPinCommit,
1085
- value.projectRefCommit,
1086
- value.evidenceCommit ?? "-",
1087
- String(value.evidencePushRequired),
1088
- ].join("\t"));
1089
- ' "$1"
1090
- }
1091
-
1092
- ```
1093
-
1094
- Use this block only after the Step 3.65 router restored a candidate. Require
1095
- `EVIDENCE_PUSH_REQUIRED` to be `true` or `false`; no other output is accepted.
1096
-
1097
- When the recovery result reports `evidencePushRequired: true`, publish the
1098
- existing checkout HEAD with `oat project push "$PROJECT_PATH" --json` before
1099
- continuing. Require `status: "pushed"` or `status: "up-to-date"`, the same
1100
- retained ref, and a receipt SHA exactly equal to `EVIDENCE_COMMIT`. This push
1101
- must not create a commit, rerender the PR artifact, or rewrite any receipt.
1102
- Re-run the recovery surface after the push and require the exact same pin,
1103
- final-artifact, and evidence SHAs with `evidencePushRequired: false`.
1100
+ Parse synced push receipts with:
1104
1101
 
1105
1102
  ```bash
1106
1103
  parse_synced_push_receipt() {
@@ -1111,30 +1108,6 @@ if (!/^[0-9a-f]{40}$/.test(value.sha) || typeof value.ref !== "string") process.
1111
1108
  process.stdout.write(`${value.ref}\t${value.sha}`);
1112
1109
  ' "$1"
1113
1110
  }
1114
-
1115
- if [[ "$EVIDENCE_PUSH_REQUIRED" == "true" ]]; then
1116
- RECOVERED_EVIDENCE_PUSH_OUTPUT=$(oat project push \
1117
- "$PROJECT_PATH" --json) || exit 1
1118
- RECOVERED_EVIDENCE_PUSH_FIELDS=$( \
1119
- parse_synced_push_receipt "$RECOVERED_EVIDENCE_PUSH_OUTPUT"
1120
- ) || exit 1
1121
- IFS=$'\t' read -r RECOVERED_PUSH_REF RECOVERED_PUSH_SHA \
1122
- <<< "$RECOVERED_EVIDENCE_PUSH_FIELDS"
1123
- test "$RECOVERED_PUSH_REF" = "$PROJECT_RETAINED_REF" || exit 1
1124
- test "$RECOVERED_PUSH_SHA" = "$EVIDENCE_COMMIT" || exit 1
1125
- PUBLISHED_RECOVERY_JSON=$(node "$COMPLETION_RECEIPT_SCRIPT" \
1126
- "${RECOVERY_ARGS[@]}") || exit 1
1127
- PUBLISHED_RECOVERY_FIELDS=$( \
1128
- parse_completion_receipts "$PUBLISHED_RECOVERY_JSON"
1129
- ) || exit 1
1130
- IFS=$'\t' read -r PUBLISHED_PIN_COMMIT PUBLISHED_REF_COMMIT \
1131
- PUBLISHED_EVIDENCE_COMMIT PUBLISHED_EVIDENCE_PUSH_REQUIRED \
1132
- <<< "$PUBLISHED_RECOVERY_FIELDS"
1133
- test "$PUBLISHED_PIN_COMMIT" = "$PROJECT_LINKS_PIN_COMMIT" || exit 1
1134
- test "$PUBLISHED_REF_COMMIT" = "$PROJECT_REF_COMMIT" || exit 1
1135
- test "$PUBLISHED_EVIDENCE_COMMIT" = "$EVIDENCE_COMMIT" || exit 1
1136
- test "$PUBLISHED_EVIDENCE_PUSH_REQUIRED" = "false" || exit 1
1137
- fi
1138
1111
  ```
1139
1112
 
1140
1113
  When retry recognition did not set `PROJECT_REF_COMMIT`, publish the pin
@@ -1163,10 +1136,9 @@ write.
1163
1136
 
1164
1137
  Both configured and interactive archive-decline paths continue from this exact
1165
1138
  pin-source receipt into Step 8.6. The later final artifact receipt and exact
1166
- parent-branch record commit finish the non-archive transaction when no recap is
1167
- selected. With a selected recap, the evidence commit in Step 10.6 must remain
1168
- the immediate child of the final artifact receipt, never the preliminary pin
1169
- source.
1139
+ parent-branch record commit finish the non-archive transaction. A selected
1140
+ recap is already part of the project-ref content and requires no second
1141
+ completion commit.
1170
1142
 
1171
1143
  ### Step 8: Archive Project (Conditional)
1172
1144
 
@@ -1372,19 +1344,15 @@ byte-for-byte unchanged. The retained project ref remains the artifact
1372
1344
  authority after non-archive completion. Do not remove the checkout, delete the
1373
1345
  ref, create archive exports, or set `PROJECT_PATH` to an archive location.
1374
1346
 
1375
- When `SELECTED_PROJECT_RECAP_RUN is empty`, the final artifact push plus exact
1376
- record commit completes this transaction. When
1377
- `SELECTED_PROJECT_RECAP_RUN is non-empty`, Steps 10.5 and 10.6 additionally
1378
- attest the active recap within the project-ref history.
1347
+ The final artifact push plus exact record commit completes this transaction,
1348
+ whether or not `SELECTED_PROJECT_RECAP_RUN` is empty.
1379
1349
 
1380
1350
  On retry, accept an already-complete record only after its exact-path commit is
1381
1351
  verified and the final artifact push receipt still names the retained ref SHA.
1382
1352
  If the final artifact push succeeded but the record commit did not, reuse the
1383
1353
  validated `PROJECT_LINKS_PIN_COMMIT` and `PROJECT_REF_COMMIT` receipts and retry
1384
- only the record write/commit. If the record commit succeeded but recap evidence
1385
- did not, reuse both receipts and retry only recap finalization. Never create a
1386
- second lifecycle record commit, rerender the links against the final receipt,
1387
- or rewrite either history.
1354
+ only the record write/commit. Never create a second lifecycle record commit,
1355
+ rerender the links against the final receipt, or rewrite either history.
1388
1356
 
1389
1357
  ### Step 9: Regenerate Dashboard
1390
1358
 
@@ -1396,9 +1364,9 @@ oat state refresh
1396
1364
 
1397
1365
  ### Step 10: Commit + Push Bookkeeping (Required)
1398
1366
 
1399
- Completion is not done until lifecycle changes are committed. This commit also
1400
- anchors commit durability for a selected durable-project recap. Do not push yet
1401
- when recap attestation is pending.
1367
+ Completion is not done until lifecycle changes are committed and pushed. The
1368
+ archive export made in Step 8 is the durable recap copy; there is no later recap
1369
+ record commit.
1402
1370
 
1403
1371
  Expected changes may include:
1404
1372
 
@@ -1454,166 +1422,20 @@ Rules:
1454
1422
  cross-project receipts, and non-ancestor commits fail closed. Validate both
1455
1423
  recovered and freshly created lifecycle commit SHAs before continuing; a
1456
1424
  failed commit or hook must not reuse the prior `HEAD` as a receipt.
1457
- - The lifecycle bookkeeping commit is the artifact commit for final recap
1458
- durability. It must contain the final run's immutable paths.
1459
- - Snapshot unrelated working-tree changes before finalization so the shared
1460
- finalizer can verify they remain unchanged.
1461
-
1462
- ### Step 10.5: Re-attest Final Project Recap
1463
-
1464
- Skip when no final recap was selected, for local-scope projects, when the
1465
- selected recap is already durable solely through independently verified publish
1466
- evidence, or when Step 7.5 or the synced archive-resume executor restored an
1467
- exact `EVIDENCE_COMMIT`. In the recovered evidence case, the recovery primitive
1468
- has already verified the selected run's manifest and build record as the two
1469
- exact paths in that commit, with `LIFECYCLE_COMMIT` as its immediate parent.
1470
- Continue without re-attesting or rewriting either record.
1471
-
1472
- For an archived recap, consume the exact `projectRecapExport` values recorded
1473
- in Step 8. Plan finalization through
1474
- `oat-explainer-kit/scripts/finalize-tracked-run.mjs#planTrackedRunFinalization`
1475
- with:
1476
-
1477
- - `runRoot`: `projectRecapExport.exportRoot`;
1478
- - `manifestPath`:
1479
- `projectRecapExport.exportRoot/projectRecapExport.manifest.relativePath`;
1480
- - commitMode: `completion-bookkeeping`;
1481
- - relocatedFrom: `sourceRunRoot`; and
1482
- - context `artifactCommit`: the full `LIFECYCLE_COMMIT` SHA.
1483
-
1484
- For a durable project that was not archived, use the selected active run and
1485
- omit `relocatedFrom`, but keep the same `completion-bookkeeping` mode. Resolve
1486
- the finalizer repository root as `ACTIVE_PROJECT_PATH`, not the parent
1487
- checkout. Use `PROJECT_REF_COMMIT`, not the parent-branch `LIFECYCLE_COMMIT`,
1488
- as the active recap artifact commit. Its immutable paths must be present in
1489
- that exact project-ref commit. The parent record commit is separate durability
1490
- evidence for discovery and must never be substituted into the project-ref
1491
- history.
1492
-
1493
- When the finalization plan is `complete` with `built-needs-review` or `failed`,
1494
- preserve that exact outcome and skip both attestation and the evidence commit.
1495
- These evidence-only plans are already complete for lifecycle retention and
1496
- remain unpublishable. Call `verifyTrackedRunFinalization(...)` on the complete
1497
- plan; it must not promote either outcome to `built-durable`.
1498
-
1499
- For archive completion, the lifecycle bookkeeping commit is the artifact
1500
- commit. For non-archive synced completion, `PROJECT_REF_COMMIT` is the artifact
1501
- commit. Call the compatible
1502
- core's `recordDurability(...)` with the finalizer's planned request. Submit only immutable paths under `projectRecapExport.exportRoot` as commit evidence for an archived recap; `manifest.json` and `build-record.json` are mutable records and
1503
- must not appear in that evidence path list. The successful exported-path
1504
- attestation supersedes the prior active-path evidence. Verify the resulting
1505
- manifest records the old evidence in `supersedes` and reports the final
1506
- tracked export path.
1507
-
1508
- Never submit the gitignored archive path as commit evidence. Local archive
1509
- presence cannot make a recap durable.
1510
-
1511
- A failed exported recap attestation does not fail project completion. Preserve
1512
- the tracked export, report `built-not-durable`, retain actionable recovery
1513
- details, and continue to the evidence commit.
1514
-
1515
- ### Step 10.6: Commit Evidence + Push
1516
-
1517
- When Step 10.5 ran and neither Step 7.5 nor the synced archive-resume executor
1518
- restored `EVIDENCE_COMMIT`, create the evidence update. Commit only the exported `manifest.json` and `build-record.json` as the evidence update, including warning-bearing records from a failed attestation. On failure, commit the warning-bearing `manifest.json` and `build-record.json`. Run
1519
- `verifyTrackedRunFinalization(...)` with the artifact commit, immediate evidence
1520
- commit parent/order, exact evidence paths, attestation outcome, and unchanged
1521
- unrelated-change snapshots.
1522
-
1523
- Archive completion is exactly two commits when recap attestation runs:
1524
-
1525
- 1. lifecycle bookkeeping, including the tracked recap export; then
1526
- 2. final recap evidence records.
1527
-
1528
- Push once after both commits exist so they travel together. If no attestation
1529
- ran, push the lifecycle bookkeeping commit once. If verification detects
1530
- contamination or wrong commit order, do not push. If push fails, report the
1531
- failure and do not claim completion is fully recorded.
1532
-
1533
- The evidence update remains a direct, exact-path Git commit. Stage only the
1534
- reported exported `manifest.json` and `build-record.json` under tracked
1535
- `.oat/repo/reference/project-recaps/`:
1536
-
1537
- ```bash
1538
- UNRELATED_STAGED_PATCH_BEFORE=$(git diff --cached --binary)
1539
- git add -- "$EXPORTED_MANIFEST_PATH" "$EXPORTED_BUILD_RECORD_PATH"
1540
- git commit --only -m "chore(oat): attest final project recap" -- \
1541
- "$EXPORTED_MANIFEST_PATH" "$EXPORTED_BUILD_RECORD_PATH"
1542
- EVIDENCE_COMMIT=$(git rev-parse HEAD)
1543
- test "$(git rev-parse "$EVIDENCE_COMMIT^")" = "$LIFECYCLE_COMMIT"
1544
- test "$(git diff --cached --binary)" = "$UNRELATED_STAGED_PATCH_BEFORE"
1545
- EVIDENCE_PUSH_REQUIRED="true"
1546
- ```
1547
-
1548
- Verify the evidence commit contains exactly those two paths, the lifecycle
1549
- commit is its immediate parent, unrelated-change snapshots remain unchanged,
1550
- and then push once. The archive command does not own this evidence transition;
1551
- use the direct exact-path commit above.
1552
-
1553
- For a non-archive synced recap, stage and commit only the active run's reported
1554
- `manifest.json` and `build-record.json` from inside `ACTIVE_PROJECT_PATH`. The
1555
- non-archive recap evidence commit must be the immediate child of
1556
- `PROJECT_REF_COMMIT` in the project checkout. Verify exact commit containment
1557
- and the unchanged unrelated-state snapshot, then publish the evidence commit
1558
- with `oat project push`, retaining the custom ref and checkout. Require the
1559
- push receipt SHA to equal the evidence commit. Recovery reuses the existing
1560
- project-ref artifact commit and parent-branch record commit; it never moves
1561
- active recap files into archive-export paths.
1562
-
1563
- Use the same path-confined commit inside the synced checkout:
1564
-
1565
- ```bash
1566
- ACTIVE_MANIFEST_RELATIVE_PATH="$SELECTED_PROJECT_RECAP_RUN/manifest.json"
1567
- ACTIVE_BUILD_RECORD_RELATIVE_PATH="$SELECTED_PROJECT_RECAP_RUN/build-record.json"
1568
- UNRELATED_PROJECT_STAGE_BEFORE=$(git -C "$ACTIVE_PROJECT_PATH" diff --cached --binary)
1569
- git -C "$ACTIVE_PROJECT_PATH" add -- \
1570
- "$ACTIVE_MANIFEST_RELATIVE_PATH" "$ACTIVE_BUILD_RECORD_RELATIVE_PATH"
1571
- git -C "$ACTIVE_PROJECT_PATH" commit --only \
1572
- -m "chore(oat): attest final project recap" -- \
1573
- "$ACTIVE_MANIFEST_RELATIVE_PATH" "$ACTIVE_BUILD_RECORD_RELATIVE_PATH"
1574
- EVIDENCE_COMMIT=$(git -C "$ACTIVE_PROJECT_PATH" rev-parse HEAD)
1575
- test "$(git -C "$ACTIVE_PROJECT_PATH" rev-parse "$EVIDENCE_COMMIT^")" = \
1576
- "$PROJECT_REF_COMMIT"
1577
- test "$(git -C "$ACTIVE_PROJECT_PATH" diff --cached --binary)" = \
1578
- "$UNRELATED_PROJECT_STAGE_BEFORE"
1579
- ```
1580
-
1581
- When Step 7.5 restored `EVIDENCE_COMMIT` for a non-archive completion, do not
1582
- stage or commit recap records again. Require the retained remote ref to equal
1583
- that exact evidence SHA, keep its immediate parent equal to
1584
- `PROJECT_REF_COMMIT`, and preserve the recovered `PROJECT_LINKS_PIN_COMMIT`.
1585
- When the synced archive-resume executor restored `EVIDENCE_COMMIT`, likewise do
1586
- not re-attest, stage, or commit: it already required the evidence commit to
1587
- change exactly `EXPORTED_MANIFEST_PATH` and `EXPORTED_BUILD_RECORD_PATH`, with
1588
- `LIFECYCLE_COMMIT` as its immediate parent. Its `EVIDENCE_PUSH_REQUIRED`
1589
- receipt determines whether the one parent-branch push remains pending. All
1590
- unrelated staged-state snapshots must remain byte-for-byte unchanged.
1425
+ - The lifecycle bookkeeping commit must contain the tracked recap export when
1426
+ one was selected.
1427
+ - Snapshot unrelated working-tree changes and verify they remain unchanged.
1591
1428
 
1592
1429
  For every synced archive completion, including `SYNCED_ARCHIVE_RESUME="true"`,
1593
- push the parent branch exactly once after the lifecycle receipt and any recap
1594
- evidence commit are final. Verify the pushed upstream contains the exact final
1595
- bookkeeping commit before continuing to PR closeout or claiming completion:
1430
+ push the parent branch exactly once after the lifecycle receipt is final.
1431
+ Verify the pushed upstream contains that exact bookkeeping commit before
1432
+ continuing to PR closeout or claiming completion:
1596
1433
 
1597
1434
  ```bash
1598
1435
  if [[ "$PROJECT_SCOPE" == "synced" && "$SHOULD_ARCHIVE" == "true" ]]; then
1599
- BOOKKEEPING_PUSH_COMMIT="${EVIDENCE_COMMIT:-$LIFECYCLE_COMMIT}"
1436
+ BOOKKEEPING_PUSH_COMMIT="$LIFECYCLE_COMMIT"
1600
1437
  test -n "$BOOKKEEPING_PUSH_COMMIT" || exit 1
1601
- git merge-base --is-ancestor "$LIFECYCLE_COMMIT" \
1602
- "$BOOKKEEPING_PUSH_COMMIT" || exit 1
1603
- if [[ -n "$EVIDENCE_COMMIT" ]]; then
1604
- test "$(git rev-parse "$EVIDENCE_COMMIT^")" = \
1605
- "$LIFECYCLE_COMMIT" || exit 1
1606
- if [[ "$EVIDENCE_PUSH_REQUIRED" != "true" && \
1607
- "$EVIDENCE_PUSH_REQUIRED" != "false" ]]; then
1608
- exit 1
1609
- fi
1610
- case "$EVIDENCE_PUSH_REQUIRED" in
1611
- true) git push || exit 1 ;;
1612
- false) echo "Reusing published recap evidence receipt: $EVIDENCE_COMMIT" ;;
1613
- esac
1614
- else
1615
- git push || exit 1
1616
- fi
1438
+ git push || exit 1
1617
1439
  BOOKKEEPING_UPSTREAM=$(git rev-parse --abbrev-ref \
1618
1440
  --symbolic-full-name '@{u}') || exit 1
1619
1441
  BOOKKEEPING_UPSTREAM_COMMIT=$(git rev-parse \
@@ -1636,7 +1458,7 @@ Steps:
1636
1458
  1. Locate the PR description artifact at `{PROJECT_PATH}/pr/project-pr-*.md`.
1637
1459
  2. Write the stripped body to a temporary file (remove all lines from the opening `---` through the closing `---`, inclusive).
1638
1460
  3. Verify the temp file does not start with YAML frontmatter keys.
1639
- 4. Create the PR from the branch already pushed in Step 10.6:
1461
+ 4. Create the PR from the branch already pushed in Step 10:
1640
1462
 
1641
1463
  ```bash
1642
1464
  gh pr create --base main --title "{title}" --body-file "$TMP_BODY"
@@ -1656,7 +1478,7 @@ body to the existing PR. Archive completion uses the regenerated archive-aware
1656
1478
  body. Non-archive synced completion uses the exact PR artifact from
1657
1479
  `PROJECT_REF_COMMIT`, whose canonical links block is owned by
1658
1480
  `PROJECT_LINKS_PIN_COMMIT`; do not substitute the parent discovery-record
1659
- commit or the optional evidence child.
1481
+ commit.
1660
1482
 
1661
1483
  Skip this step when:
1662
1484
 
@@ -1716,7 +1538,7 @@ Failure handling:
1716
1538
  Step 12 clears the pointer after the receipt validates and the user updates
1717
1539
  the tracked PR by hand from the printed artifact path.
1718
1540
  - Never re-archive or re-commit on failure here — the lifecycle bookkeeping
1719
- and any recap evidence update in Step 10.6 already shipped.
1541
+ in Step 10 already shipped.
1720
1542
 
1721
1543
  ### Step 12: Confirm to User
1722
1544
 
@@ -1755,11 +1577,8 @@ Show user:
1755
1577
  - "Project **{PROJECT_NAME}** marked as complete."
1756
1578
  - If archived: "Archived location: **{PROJECT_PATH}**"
1757
1579
  - If S3 archive sync ran: include `ARCHIVE_S3_CONTEXT` when the archive command reported profile/region details. If only `ARCHIVE_S3_PATH` is available, include the S3 destination and note that profile/region context was not reported by the command. Never echo raw credentials (`AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, etc.).
1758
- - Include both lifecycle bookkeeping and recap evidence commit hashes when
1759
- attestation ran, plus the single push result.
1760
- - Report the final recap outcome and tracked reference root. A failed
1761
- attestation is a warning with `built-not-durable`, not a project-completion
1762
- failure.
1580
+ - Include the lifecycle bookkeeping commit hash and the single push result.
1581
+ - Report the final recap outcome and tracked reference root.
1763
1582
  - Report every absorbed-project retirement finding from the Step 3.7 sweep with
1764
1583
  its disposition. This is the required destination whenever the sweep could not
1765
1584
  append them to the project log — an absent log, or a resume whose log is