@open-agent-toolkit/cli 0.2.62 → 0.2.64
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.
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/config-and-local-state.md +1 -0
- package/assets/docs/cli-utilities/configuration.md +10 -8
- package/assets/docs/cli-utilities/project-log.md +16 -0
- package/assets/docs/cli-utilities/tool-packs.md +83 -0
- package/assets/docs/cli-utilities/workflow-gates.md +124 -16
- package/assets/docs/contributing/skills.md +42 -7
- package/assets/docs/provider-sync/commands.md +3 -0
- package/assets/docs/provider-sync/instruction-sync.md +107 -0
- package/assets/docs/provider-sync/manifest-and-drift.md +105 -0
- package/assets/docs/reference/cli-reference.md +16 -6
- package/assets/docs/reference/oat-directory-structure.md +32 -31
- package/assets/docs/workflows/projects/lifecycle.md +45 -0
- package/assets/docs/workflows/projects/picking-up-projects.md +14 -0
- package/assets/docs/workflows/skills/explainer-kit.md +10 -4
- package/assets/docs/workflows/skills/repo-improve.md +15 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/create-agnostic-skill/SKILL.md +9 -7
- package/assets/skills/create-agnostic-skill/references/skill-template.md +9 -7
- package/assets/skills/oat-explainer-kit/SKILL.md +14 -1
- package/assets/skills/oat-explainer-kit/references/config-contract.md +12 -0
- package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +57 -10
- package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +28 -5
- package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +371 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +123 -1
- package/assets/skills/oat-project-autonomous/SKILL.md +10 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +122 -121
- package/assets/skills/oat-project-complete/SKILL.md +134 -4
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +38 -6
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-next/SKILL.md +62 -19
- package/assets/skills/oat-project-plan/SKILL.md +31 -5
- package/assets/skills/oat-project-pr-final/SKILL.md +281 -6
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-progress/SKILL.md +12 -3
- package/assets/skills/oat-project-quick-start/SKILL.md +264 -4
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-summary/SKILL.md +34 -23
- package/assets/skills/oat-repo-improve/SKILL.md +40 -5
- package/assets/skills/oat-repo-improve/references/plan-template.md +84 -7
- package/dist/agents/canonical/resolve.d.ts.map +1 -1
- package/dist/agents/canonical/resolve.js +25 -4
- package/dist/commands/config/index.d.ts +1 -0
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +401 -18
- package/dist/commands/doctor/index.d.ts +7 -0
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +10 -2
- package/dist/commands/gate/index.d.ts +3 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +699 -211
- package/dist/commands/init/tools/index.d.ts.map +1 -1
- package/dist/commands/init/tools/index.js +68 -36
- package/dist/commands/init/tools/shared/skill-script-references.d.ts +126 -0
- package/dist/commands/init/tools/shared/skill-script-references.d.ts.map +1 -0
- package/dist/commands/init/tools/shared/skill-script-references.js +311 -0
- package/dist/commands/instructions/instructions.types.d.ts +63 -0
- package/dist/commands/instructions/instructions.types.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.d.ts +51 -2
- package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.js +201 -4
- package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
- package/dist/commands/instructions/sync/sync.js +12 -1
- package/dist/commands/instructions/validate/validate.d.ts.map +1 -1
- package/dist/commands/instructions/validate/validate.js +12 -1
- package/dist/commands/project/log/append.d.ts +195 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +1034 -11
- package/dist/commands/shared/frontmatter.d.ts +51 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +118 -6
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +5 -3
- package/dist/commands/sync/index.d.ts +14 -0
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +21 -0
- package/dist/commands/tools/info/index.d.ts.map +1 -1
- package/dist/commands/tools/info/index.js +14 -1
- package/dist/commands/tools/info/info-tool.d.ts +12 -0
- package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
- package/dist/commands/tools/info/info-tool.js +54 -6
- package/dist/commands/tools/info/skill-views.d.ts +86 -0
- package/dist/commands/tools/info/skill-views.d.ts.map +1 -0
- package/dist/commands/tools/info/skill-views.js +383 -0
- package/dist/commands/tools/install/index.d.ts.map +1 -1
- package/dist/commands/tools/install/index.js +3 -25
- package/dist/commands/tools/list/list-tools.d.ts +2 -0
- package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
- package/dist/commands/tools/list/list-tools.js +23 -4
- package/dist/commands/tools/remove/index.d.ts.map +1 -1
- package/dist/commands/tools/remove/index.js +35 -42
- package/dist/commands/tools/remove/remove-tools.d.ts +3 -2
- package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
- package/dist/commands/tools/remove/remove-tools.js +14 -4
- package/dist/commands/tools/shared/auto-sync.d.ts +12 -1
- package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
- package/dist/commands/tools/shared/auto-sync.js +20 -4
- package/dist/commands/tools/shared/format-pack-inventory.d.ts +12 -1
- package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
- package/dist/commands/tools/shared/format-pack-inventory.js +48 -6
- package/dist/commands/tools/shared/in-process-sync.d.ts +11 -0
- package/dist/commands/tools/shared/in-process-sync.d.ts.map +1 -0
- package/dist/commands/tools/shared/in-process-sync.js +79 -0
- package/dist/commands/tools/shared/pack-evidence.d.ts +78 -2
- package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-evidence.js +96 -2
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +11 -0
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-lifecycle-outcome.js +24 -3
- package/dist/commands/tools/shared/pack-provider-evidence.d.ts +73 -0
- package/dist/commands/tools/shared/pack-provider-evidence.d.ts.map +1 -0
- package/dist/commands/tools/shared/pack-provider-evidence.js +161 -0
- package/dist/commands/tools/shared/provider-context.d.ts +88 -0
- package/dist/commands/tools/shared/provider-context.d.ts.map +1 -0
- package/dist/commands/tools/shared/provider-context.js +77 -0
- package/dist/commands/tools/shared/provider-reachability.d.ts +93 -0
- package/dist/commands/tools/shared/provider-reachability.d.ts.map +1 -0
- package/dist/commands/tools/shared/provider-reachability.js +358 -0
- package/dist/commands/tools/shared/sync-evidence.d.ts +57 -0
- package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -0
- package/dist/commands/tools/shared/sync-evidence.js +147 -0
- package/dist/commands/tools/update/index.d.ts +0 -4
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +22 -40
- package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
- package/dist/commands/tools/update/update-tools.js +23 -8
- package/dist/config/json.d.ts +36 -0
- package/dist/config/json.d.ts.map +1 -1
- package/dist/config/json.js +135 -3
- package/dist/config/oat-config.d.ts +41 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +111 -0
- package/dist/drift/index.d.ts +2 -0
- package/dist/drift/index.d.ts.map +1 -1
- package/dist/drift/index.js +1 -0
- package/dist/drift/skill-view-diagnostic.d.ts +197 -0
- package/dist/drift/skill-view-diagnostic.d.ts.map +1 -0
- package/dist/drift/skill-view-diagnostic.js +343 -0
- package/dist/validation/skills.d.ts +1 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +181 -19
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-next
|
|
3
|
-
version: 1.1.
|
|
3
|
+
version: 1.1.1
|
|
4
4
|
description: Use when continuing work on the active OAT project. Reads project state, determines the next lifecycle action, and invokes the appropriate skill automatically.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -125,15 +125,16 @@ projects, and synced records whose detached checkout is absent.
|
|
|
125
125
|
|
|
126
126
|
Read `"$PROJECT_PATH/state.md"` frontmatter and extract:
|
|
127
127
|
|
|
128
|
-
| Field | Used For
|
|
129
|
-
| ------------------------- |
|
|
130
|
-
| `oat_phase` | Current lifecycle position (discovery, spec, design, plan, implement)
|
|
131
|
-
| `oat_phase_status` | Phase completion state (in_progress, complete, pr_open)
|
|
132
|
-
| `oat_workflow_mode` | Routing table selection (spec-driven, quick, import, lite). Default: `spec-driven`
|
|
133
|
-
| `oat_hill_checkpoints` | Which phases require HiLL approval
|
|
134
|
-
| `oat_hill_completed` | Which HiLL gates have been passed
|
|
135
|
-
| `oat_blockers` | Informational warnings (not routing gates)
|
|
136
|
-
| `oat_implement_exit_gate` | Whether the implementation exit gate is allowed and fresh
|
|
128
|
+
| Field | Used For |
|
|
129
|
+
| ------------------------- | -------------------------------------------------------------------------------------------- |
|
|
130
|
+
| `oat_phase` | Current lifecycle position (discovery, spec, design, plan, implement) |
|
|
131
|
+
| `oat_phase_status` | Phase completion state (in_progress, complete, pr_open) |
|
|
132
|
+
| `oat_workflow_mode` | Routing table selection (spec-driven, quick, import, lite). Default: `spec-driven` |
|
|
133
|
+
| `oat_hill_checkpoints` | Which phases require HiLL approval |
|
|
134
|
+
| `oat_hill_completed` | Which HiLL gates have been passed |
|
|
135
|
+
| `oat_blockers` | Informational warnings (not routing gates) |
|
|
136
|
+
| `oat_implement_exit_gate` | Whether the implementation exit gate is allowed and fresh |
|
|
137
|
+
| `oat_lifecycle` | Terminal status (active, paused, complete). `complete` is the terminal signal Step 5.2 reads |
|
|
137
138
|
|
|
138
139
|
**If state.md is missing or unreadable:** Report error and suggest running the relevant phase skill directly. STOP.
|
|
139
140
|
|
|
@@ -165,12 +166,22 @@ Apply the following tiers in order:
|
|
|
165
166
|
|
|
166
167
|
- `oat_status == "complete"` AND `oat_ready_for` is not null
|
|
167
168
|
- → Use `oat_ready_for` as the target skill
|
|
169
|
+
- Exception: in quick mode at the `plan` phase, the Quick Mode table's
|
|
170
|
+
`Quick Plan Readiness` column decides the target. A tier-1 quick plan that
|
|
171
|
+
fails readiness returns to the quick workflow, and `oat_ready_for` is not
|
|
172
|
+
followed on its own.
|
|
168
173
|
|
|
169
174
|
**Tier 1b (Complete without target):**
|
|
170
175
|
|
|
171
176
|
- `oat_status == "complete"` AND `oat_ready_for` is null
|
|
172
177
|
- → Route to the NEXT phase's skill (the artifact is complete, so advance)
|
|
173
178
|
- This handles cases where a phase skill completed the artifact but didn't set `oat_ready_for`.
|
|
179
|
+
- Exception: in quick mode at the `plan` phase, a tier-1b artifact is evaluated
|
|
180
|
+
against **quick plan readiness** like every other plan-phase classification.
|
|
181
|
+
Tier 1b means `oat_ready_for` is null, so readiness always fails, so it
|
|
182
|
+
returns to the quick workflow instead of advancing to the next phase's skill.
|
|
183
|
+
This state is reachable when the Step 3.7 frontmatter write is interrupted or
|
|
184
|
+
after a hand edit, and it must not reach implementation unchecked.
|
|
174
185
|
|
|
175
186
|
**Tier 2 (Substantive content):**
|
|
176
187
|
|
|
@@ -238,15 +249,36 @@ Otherwise, look up the target skill from the routing table for the current `oat_
|
|
|
238
249
|
|
|
239
250
|
**Quick Mode:**
|
|
240
251
|
|
|
241
|
-
| Current Phase | Phase Status | Boundary Tier | Target Skill |
|
|
242
|
-
| ------------- | ------------ | ------------- | -------------------------- |
|
|
243
|
-
| discovery | in_progress | tier 3 | `oat-project-discover` |
|
|
244
|
-
| discovery | in_progress | tier 2 | `oat-project-plan` |
|
|
245
|
-
| discovery | complete | tier 1 | `oat-project-plan` |
|
|
246
|
-
| plan | in_progress | tier 3 | `oat-project-quick-start` |
|
|
247
|
-
| plan | in_progress | tier 2 | `oat-project-
|
|
248
|
-
| plan |
|
|
249
|
-
|
|
|
252
|
+
| Current Phase | Phase Status | Boundary Tier | Quick Plan Readiness | Target Skill |
|
|
253
|
+
| ------------- | ------------ | ------------- | -------------------- | -------------------------- |
|
|
254
|
+
| discovery | in_progress | tier 3 | — | `oat-project-discover` |
|
|
255
|
+
| discovery | in_progress | tier 2 | — | `oat-project-plan` |
|
|
256
|
+
| discovery | complete | tier 1 | — | `oat-project-plan` |
|
|
257
|
+
| plan | in_progress | tier 3 | not ready | `oat-project-quick-start` |
|
|
258
|
+
| plan | in_progress | tier 2 | not ready | `oat-project-quick-start` |
|
|
259
|
+
| plan | in_progress | tier 1 | not ready | `oat-project-quick-start` |
|
|
260
|
+
| plan | in_progress | tier 1 | ready | `oat-project-implement` \* |
|
|
261
|
+
| plan | complete | tier 1 | not ready | `oat-project-quick-start` |
|
|
262
|
+
| plan | complete | tier 1 | ready | `oat-project-implement` \* |
|
|
263
|
+
| plan | any | tier 1b | not ready (always) | `oat-project-quick-start` |
|
|
264
|
+
| implement | in_progress | — | — | `oat-project-implement` \* |
|
|
265
|
+
|
|
266
|
+
The `Quick Plan Readiness` column applies to the `plan` phase only, and only
|
|
267
|
+
after the boundary tier has already been classified by Step 2, so tier semantics
|
|
268
|
+
are unchanged: it discriminates the two `plan` outcomes that would otherwise
|
|
269
|
+
share one tier. A tier-2 or tier-1 quick plan is no longer assumed ready, and a
|
|
270
|
+
tier-1 plan whose readiness fails is returned to the quick workflow rather than
|
|
271
|
+
advanced. Both recorded phase statuses carry a tier-1 pair of rows, so a plan
|
|
272
|
+
artifact that has already advanced past the `state.md` phase status still
|
|
273
|
+
matches a route instead of falling through the table. Tier 1b carries one row
|
|
274
|
+
under either phase status because a null `oat_ready_for` can never satisfy
|
|
275
|
+
readiness. Readiness is the named **quick plan readiness** predicate: load
|
|
276
|
+
`oat-project-quick-start/SKILL.md` and apply it as written to
|
|
277
|
+
`{PROJECT_PATH}/plan.md` instead of restating its conditions here, and never
|
|
278
|
+
infer readiness from the presence of substantive tasks. A `not ready` result
|
|
279
|
+
resumes the quick workflow in place: load `oat-project-quick-start/SKILL.md` and
|
|
280
|
+
follow its Step 0.5 resume branch. Spec-driven planning is not the recovery path
|
|
281
|
+
for a quick project.
|
|
250
282
|
|
|
251
283
|
**Import Mode:**
|
|
252
284
|
|
|
@@ -392,6 +424,17 @@ or a summary exists. A completed snapshot falls through to the normal router.
|
|
|
392
424
|
|
|
393
425
|
**5.2: Incomplete revision tasks**
|
|
394
426
|
|
|
427
|
+
Read `oat_lifecycle` from `state.md` before grepping anything. When
|
|
428
|
+
`oat_lifecycle` is `complete`, revision phases are historical: skip this check
|
|
429
|
+
and fall through to 5.3, and do not route to `oat-project-implement` even when
|
|
430
|
+
`p-revN` tasks are still marked incomplete. Lifecycle is the only terminal
|
|
431
|
+
signal here — neither a null current task nor a `complete` or `pr_open`
|
|
432
|
+
`oat_phase_status` is terminal, because an active project reaches both while it
|
|
433
|
+
still owns pending revision work. The guard is workflow-mode independent: it
|
|
434
|
+
applies identically to `spec-driven`, `quick`, `import`, and `lite` projects.
|
|
435
|
+
|
|
436
|
+
For every other `oat_lifecycle` value the check below is unchanged.
|
|
437
|
+
|
|
395
438
|
Grep plan.md for `p-revN` phases. If any `p-revN` tasks exist with status != completed in implementation.md:
|
|
396
439
|
→ Route to `oat-project-implement`
|
|
397
440
|
→ Announce: "Revision tasks pending — continuing implementation"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-plan
|
|
3
|
-
version: 1.4.
|
|
3
|
+
version: 1.4.10
|
|
4
4
|
description: Use when design.md is complete and executable implementation tasks are needed. Breaks design into bite-sized TDD tasks in canonical plan.md format.
|
|
5
5
|
oat_gateable: true
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -21,7 +21,7 @@ directly.
|
|
|
21
21
|
Read `oat_workflow_mode` from `{PROJECT_PATH}/state.md` (default: `spec-driven`):
|
|
22
22
|
|
|
23
23
|
- **`spec-driven`**: Complete design document required (`design.md` with `oat_status: complete`). If missing, **Stop.** Tell the user: "Run the `oat-project-design` skill first, then return to planning." Otherwise proceed with planning.
|
|
24
|
-
- **`quick`**: **Stop.**
|
|
24
|
+
- **`quick`**: **Stop.** Spec-driven planning does not apply here: the quick workflow authors `plan.md` itself and owns it through its own review disposition. Step 1 routes the project by the named **quick plan readiness** predicate instead of assuming the plan is finished.
|
|
25
25
|
- **`import`**: **Stop.** If a normalized `plan.md` exists, tell the user: "Imported plan is ready. Run `oat-project-implement` to begin execution." If no `plan.md` exists, tell the user: "Run `oat-project-import-plan` to import and normalize the external plan first."
|
|
26
26
|
- **`lite`**: **Stop.** Tell the user: "Lite planning is owned by `oat-project-lite`; run it to author or resume the combined plan contract."
|
|
27
27
|
|
|
@@ -113,13 +113,39 @@ PROJECTS_ROOT="${PROJECTS_ROOT%/}"
|
|
|
113
113
|
WORKFLOW_MODE=$(oat project status --field project.workflowMode 2>/dev/null || echo null)
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
**Mode: `quick`** — **STOP.**
|
|
116
|
+
**Mode: `quick`** — **STOP.** Spec-driven planning does not apply: the quick
|
|
117
|
+
workflow owns `plan.md` from discovery through the review disposition it records
|
|
118
|
+
at its Step 3.7, so this skill never authors, finishes, or reviews a quick plan.
|
|
119
|
+
It still has to say where the project continues, and a quick plan that is not
|
|
120
|
+
implementation-ready must not be handed to implementation. Decide the
|
|
121
|
+
continuation with the named **quick plan readiness** predicate: load
|
|
122
|
+
`oat-project-quick-start/SKILL.md` and apply that predicate as written to
|
|
123
|
+
`"$PROJECT_PATH/plan.md"`, rather than restating or re-deriving its conditions
|
|
124
|
+
here.
|
|
125
|
+
|
|
126
|
+
**Not implementation-ready** (the predicate fails; substantive tasks alone never
|
|
127
|
+
satisfy it). Print:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
⚠️ This project uses quick mode and its plan is not implementation-ready.
|
|
131
|
+
Spec-driven planning does not apply — the quick workflow finishes its own
|
|
132
|
+
plan in place, without re-scaffolding the project.
|
|
133
|
+
|
|
134
|
+
Continue with: oat-project-quick-start
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Then load `oat-project-quick-start/SKILL.md` and follow its Step 0.5 resume
|
|
138
|
+
branch. Exit skill.
|
|
139
|
+
|
|
140
|
+
**Implementation-ready** (every predicate condition holds). Print:
|
|
117
141
|
|
|
118
142
|
```
|
|
119
|
-
⚠️ This project uses quick mode
|
|
120
|
-
|
|
143
|
+
⚠️ This project uses quick mode and its plan is implementation-ready.
|
|
144
|
+
|
|
145
|
+
Continue with: oat-project-implement
|
|
121
146
|
```
|
|
122
147
|
|
|
148
|
+
Then load `oat-project-implement/SKILL.md` and follow it to begin execution.
|
|
123
149
|
Exit skill.
|
|
124
150
|
|
|
125
151
|
**Mode: `lite`** — **STOP.** Print:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-pr-final
|
|
3
|
-
version: 1.6.
|
|
3
|
+
version: 1.6.3
|
|
4
4
|
description: Use when the user requests or confirms opening the final PR for an active OAT project — e.g. "open the final PR", "ship it", "run oat-project-pr-final", or confirms a previously offered final-PR step. Do NOT auto-invoke when phases are marked complete. Generates the final lifecycle PR description from artifacts and creates the PR.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -131,17 +131,30 @@ Before generating the final PR, detect any leftover active review artifacts in t
|
|
|
131
131
|
find "$PROJECT_PATH/reviews" -maxdepth 1 -type f -name "*.md" 2>/dev/null
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
**Archive eligibility is its own predicate.** An artifact is archive-eligible only when the `## Reviews` event that binds it — matched by `Scope` + `Type` + `Artifact` filename — has Status `passed` or `fixes_completed`. Those are the two processed statuses in `oat-project-review-receive`; `fixes_completed` still awaits re-review, and archiving it keeps the artifact discoverable without treating that re-review as done. A `pending`, `received`, or `fixes_added` event is still being consumed: leave its artifact in the top level of `reviews/` and report it. Leave a top-level artifact that no ledger event binds in place and report it too.
|
|
135
|
+
|
|
136
|
+
Archive eligibility is not the Step 2 final-review gate. Step 2 still requires the latest `final`/`code` event to be `passed`, so an archived `fixes_completed` final row still stops autonomous finalization at `PRFINAL-03`.
|
|
137
|
+
|
|
138
|
+
For each archive-eligible artifact:
|
|
135
139
|
|
|
136
140
|
1. Create `"$PROJECT_PATH/reviews/archived"` if needed.
|
|
137
|
-
2.
|
|
138
|
-
3.
|
|
139
|
-
|
|
141
|
+
2. Resolve the destination filename before anything is rewritten or moved: keep `{filename}.md` when `reviews/archived/{filename}.md` is free; otherwise `{stem}-$(date -u +%Y-%m-%dT%H%M%SZ).md`, then a `-2`, `-3`, … index while that name is also taken. Never overwrite an existing archive destination. This is the same collision-free identity rule as `oat-project-review-receive` Step 1, per DR-260706.
|
|
142
|
+
3. Rewrite references from `reviews/{filename}.md` to `reviews/archived/{destination}` in exactly these files:
|
|
143
|
+
- `"$PROJECT_PATH/plan.md"`
|
|
144
|
+
- `"$PROJECT_PATH/implementation.md"`
|
|
145
|
+
- `"$PROJECT_PATH/state.md"`
|
|
146
|
+
|
|
147
|
+
In `plan.md`, select the ledger event by `Scope` + `Type` + `Artifact` filename and rewrite only that event's Artifact cell. Duplicate scope/type rows keep their own identity; never rewrite a sibling row that merely shares the scope and type.
|
|
148
|
+
|
|
149
|
+
4. Move the review artifact to `reviews/archived/{destination}` only after those references are rewritten.
|
|
150
|
+
5. Report the archived paths before continuing.
|
|
140
151
|
|
|
141
152
|
Rules:
|
|
142
153
|
|
|
143
154
|
- Only archive top-level active review artifacts. Leave `reviews/archived/` untouched.
|
|
144
155
|
- Keep archive destinations inside the project so worktree runs do not depend on the shared-project archive flow.
|
|
156
|
+
- Step 0.5 is idempotent. A re-run re-derives eligibility from the ledger: an event whose Artifact cell already points inside `reviews/archived/` and whose top-level file is gone is already archived, so skip it — never rewrite its cell a second time and never write a second archived copy. Re-running over the same artifact set therefore neither duplicates nor clobbers an archived artifact.
|
|
157
|
+
- If a rewritten reference names an archived destination that does not exist while the source artifact is still in the top level, a previous run stopped between the rewrite and the move: complete the move to that exact destination rather than deriving a second name.
|
|
145
158
|
|
|
146
159
|
### Step 1: Validate Required Artifacts (Mode-Aware)
|
|
147
160
|
|
|
@@ -396,6 +409,267 @@ Only include links to artifacts that actually exist in the project. Omit any tha
|
|
|
396
409
|
|
|
397
410
|
After writing the PR artifact, push and create the PR automatically.
|
|
398
411
|
|
|
412
|
+
**Ledger-path guard (both PR paths).** Before either `gh pr create` path runs, validate every artifact path in the project's `## Reviews` ledger. Parse each row's Artifact cell rather than grepping the section as free text, and skip a `-` placeholder. The ledger is the table rows of `## Reviews`: the scan starts at the first exact `## Reviews` heading and ends at the next level-two heading — a `###` subsection inside that section is still scanned, exactly as Step 2 reads the ledger — and a blockquoted line or a fenced block inside the section is a note or an event example, never an event. Columns are split on `|`, so an escaped `\|` anywhere in a ledger header or ledger row stops rather than shifting the Artifact column onto a neighbouring cell: no ledger value needs a literal pipe, and reading one cell while naming another is exactly the silent skip this gate exists to prevent. Every other cell must normalize — `..` segments and symlinks resolved physically — to a regular file inside `$PROJECT_PATH`. The ledger is the table inside `## Reviews` whose header carries `Scope`, `Type`, and `Artifact` columns, matched after emphasis is stripped and in whatever order the header declares; a section that holds table rows but no such header, or an unclosed fenced block, stops rather than validating nothing. Processed review artifacts live in the gitignored `reviews/archived/`, so when that directory does not exist in this checkout at all — a fresh clone, a remote workspace, or a lane worktree — an absent path inside it is a local-only artifact: report it and continue. Once `reviews/archived/` exists, a file missing from it is a dangling row, usually an archive interrupted between the reference rewrite and the move, and it stops like any other absent path. That excuse covers a location that was never materialized, so it requires the path to be absent outright: a regular file, a dangling symlink, or any other non-directory at `reviews/archived` is an anomaly, not a fresh checkout, and it stops rather than excusing the row. Every other absent path fails, in every project scope — git ignores whole project directories for `local`, `synced`, and `archived` projects, so ignore state says nothing about whether a row resolves. A missing file in a tracked location, a directory, a path that escapes the project, a non-directory at `reviews/archived`, an unreadable ledger, a plan with no `## Reviews` section, an escaped pipe in a ledger header or row, a row the parser cannot read, or a ledger the guard could not check row for row stops this skill at gate `PRFINAL-05`, naming the offending row by scope, type, and artifact filename. Every stop fails closed. Both the synced flow below and the non-synced flow run after this block, so no PR is created from a ledger whose artifact paths do not resolve.
|
|
413
|
+
|
|
414
|
+
````bash
|
|
415
|
+
LEDGER_PROJECT_ROOT=$(cd -P "$PROJECT_PATH" 2>/dev/null && pwd -P) || {
|
|
416
|
+
echo "PRFINAL-05: project path does not resolve: $PROJECT_PATH" >&2
|
|
417
|
+
exit 1
|
|
418
|
+
}
|
|
419
|
+
if [ ! -r "$PROJECT_PATH/plan.md" ]; then
|
|
420
|
+
echo "PRFINAL-05: cannot read the review ledger: $PROJECT_PATH/plan.md" >&2
|
|
421
|
+
exit 1
|
|
422
|
+
fi
|
|
423
|
+
LEDGER_ARCHIVE_DIR="$LEDGER_PROJECT_ROOT/reviews/archived"
|
|
424
|
+
# Classify the archive location before excusing an absent artifact under it.
|
|
425
|
+
# `[ ! -d ]` is also true for a regular file and for a dangling symlink, so
|
|
426
|
+
# keying the "never materialized" excuse on it re-opens the dangling row this
|
|
427
|
+
# gate exists to catch. Absent means absent: `-e` alone still misses a dangling
|
|
428
|
+
# symlink, which is why `-L` is tested too.
|
|
429
|
+
classify_absent_ledger_artifact() {
|
|
430
|
+
LEDGER_ABSENT_CLASS=missing
|
|
431
|
+
case "$1" in
|
|
432
|
+
"$LEDGER_ARCHIVE_DIR"/*) ;;
|
|
433
|
+
*) return 0 ;;
|
|
434
|
+
esac
|
|
435
|
+
if [ -d "$LEDGER_ARCHIVE_DIR" ]; then
|
|
436
|
+
return 0
|
|
437
|
+
fi
|
|
438
|
+
if [ -e "$LEDGER_ARCHIVE_DIR" ] || [ -L "$LEDGER_ARCHIVE_DIR" ]; then
|
|
439
|
+
LEDGER_ABSENT_CLASS=not-a-directory
|
|
440
|
+
return 0
|
|
441
|
+
fi
|
|
442
|
+
LEDGER_ABSENT_CLASS=local-only
|
|
443
|
+
}
|
|
444
|
+
LEDGER_ROWS=$(awk -F'|' '
|
|
445
|
+
!in_fence && /^[[:space:]]*(```|~~~)/ {
|
|
446
|
+
marker = $0
|
|
447
|
+
sub(/^[[:space:]]*/, "", marker)
|
|
448
|
+
fence_char = substr(marker, 1, 1)
|
|
449
|
+
fence_length = 0
|
|
450
|
+
while (substr(marker, fence_length + 1, 1) == fence_char) fence_length++
|
|
451
|
+
in_fence = 1
|
|
452
|
+
next
|
|
453
|
+
}
|
|
454
|
+
in_fence {
|
|
455
|
+
marker = $0
|
|
456
|
+
sub(/^[[:space:]]*/, "", marker)
|
|
457
|
+
close_length = 0
|
|
458
|
+
while (substr(marker, close_length + 1, 1) == fence_char) close_length++
|
|
459
|
+
if (close_length >= fence_length && substr(marker, close_length + 1) ~ /^[[:space:]]*$/) in_fence = 0
|
|
460
|
+
next
|
|
461
|
+
}
|
|
462
|
+
/^## Reviews[[:space:]]*$/ { in_reviews = 1; at_table_start = 1; next }
|
|
463
|
+
!in_reviews { next }
|
|
464
|
+
/^##[[:space:]]/ { exit }
|
|
465
|
+
/^#+[[:space:]]/ { at_table_start = 1; in_ledger_table = 0; next }
|
|
466
|
+
/^[[:space:]]*>/ { next }
|
|
467
|
+
/^[[:space:]]*$/ { at_table_start = 1; in_ledger_table = 0; next }
|
|
468
|
+
$0 !~ /^[[:space:]]*\|/ {
|
|
469
|
+
if ($0 ~ /\|/) {
|
|
470
|
+
print "PRFINAL-05: unsupported review-ledger row (a row must start with |): " $0 > "/dev/stderr"
|
|
471
|
+
exit 3
|
|
472
|
+
}
|
|
473
|
+
next
|
|
474
|
+
}
|
|
475
|
+
{
|
|
476
|
+
escaped_pipe_row = $0
|
|
477
|
+
for (i = 1; i <= NF; i++) {
|
|
478
|
+
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $i)
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
at_table_start {
|
|
482
|
+
if (index(escaped_pipe_row, "\\|") > 0) {
|
|
483
|
+
print "PRFINAL-05: review-ledger table header contains an escaped |; its columns cannot be identified: " escaped_pipe_row > "/dev/stderr"
|
|
484
|
+
exit 3
|
|
485
|
+
}
|
|
486
|
+
at_table_start = 0
|
|
487
|
+
saw_table = 1
|
|
488
|
+
scope_column = 0
|
|
489
|
+
type_column = 0
|
|
490
|
+
artifact_column = 0
|
|
491
|
+
last_cell = ($NF == "") ? NF - 1 : NF
|
|
492
|
+
for (i = 2; i <= last_cell; i++) {
|
|
493
|
+
header_cell = tolower($i)
|
|
494
|
+
gsub(/[*_`]/, "", header_cell)
|
|
495
|
+
gsub(/^[[:space:]]+|[[:space:]]+$/, "", header_cell)
|
|
496
|
+
if (header_cell == "scope") scope_column = i
|
|
497
|
+
if (header_cell == "type") type_column = i
|
|
498
|
+
if (header_cell == "artifact") artifact_column = i
|
|
499
|
+
}
|
|
500
|
+
in_ledger_table = (scope_column > 0 && type_column > 0 && artifact_column > 0)
|
|
501
|
+
if (in_ledger_table) {
|
|
502
|
+
recognized_ledger = 1
|
|
503
|
+
} else if (scope_column > 0 && type_column > 0) {
|
|
504
|
+
print "PRFINAL-05: review-ledger table has no Artifact column; its rows cannot be validated" > "/dev/stderr"
|
|
505
|
+
exit 3
|
|
506
|
+
}
|
|
507
|
+
next
|
|
508
|
+
}
|
|
509
|
+
!in_ledger_table { next }
|
|
510
|
+
index(escaped_pipe_row, "\\|") > 0 {
|
|
511
|
+
print "PRFINAL-05: unsupported review-ledger row (an escaped | cannot be assigned to a column): " escaped_pipe_row > "/dev/stderr"
|
|
512
|
+
exit 3
|
|
513
|
+
}
|
|
514
|
+
{
|
|
515
|
+
last_cell = ($NF == "") ? NF - 1 : NF
|
|
516
|
+
is_separator = (last_cell >= 2)
|
|
517
|
+
for (i = 2; i <= last_cell; i++) {
|
|
518
|
+
if ($i !~ /^:?-+:?$/) is_separator = 0
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
is_separator { next }
|
|
522
|
+
{
|
|
523
|
+
artifact_value = $artifact_column
|
|
524
|
+
unwrapping = 1
|
|
525
|
+
while (unwrapping) {
|
|
526
|
+
unwrapping = 0
|
|
527
|
+
if (length(artifact_value) > 2 && artifact_value ~ /^`.*`$/) {
|
|
528
|
+
artifact_value = substr(artifact_value, 2, length(artifact_value) - 2)
|
|
529
|
+
unwrapping = 1
|
|
530
|
+
} else if (length(artifact_value) > 4 && artifact_value ~ /^\*\*.*\*\*$/) {
|
|
531
|
+
artifact_value = substr(artifact_value, 3, length(artifact_value) - 4)
|
|
532
|
+
unwrapping = 1
|
|
533
|
+
} else if (length(artifact_value) > 2 && artifact_value ~ /^\*.*\*$/) {
|
|
534
|
+
artifact_value = substr(artifact_value, 2, length(artifact_value) - 2)
|
|
535
|
+
unwrapping = 1
|
|
536
|
+
} else if (length(artifact_value) > 2 && artifact_value ~ /^_.*_$/) {
|
|
537
|
+
artifact_value = substr(artifact_value, 2, length(artifact_value) - 2)
|
|
538
|
+
unwrapping = 1
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
print $scope_column "\t" $type_column "\t" artifact_value
|
|
542
|
+
}
|
|
543
|
+
END {
|
|
544
|
+
if (in_fence) {
|
|
545
|
+
print "PRFINAL-05: unclosed fenced block; the review ledger was never scanned" > "/dev/stderr"
|
|
546
|
+
exit 3
|
|
547
|
+
}
|
|
548
|
+
if (!in_reviews) {
|
|
549
|
+
print "PRFINAL-05: no ## Reviews section; the review ledger was never scanned" > "/dev/stderr"
|
|
550
|
+
exit 3
|
|
551
|
+
}
|
|
552
|
+
if (saw_table && !recognized_ledger) {
|
|
553
|
+
print "PRFINAL-05: unrecognized review-ledger header; no table in ## Reviews carries Scope, Type, and Artifact columns" > "/dev/stderr"
|
|
554
|
+
exit 3
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
' "$PROJECT_PATH/plan.md") || {
|
|
558
|
+
echo "PRFINAL-05: cannot parse the review ledger: $PROJECT_PATH/plan.md" >&2
|
|
559
|
+
exit 1
|
|
560
|
+
}
|
|
561
|
+
LEDGER_ROW_COUNT=$(printf '%s\n' "$LEDGER_ROWS" | grep -c '[^[:space:]]') || LEDGER_ROW_COUNT=0
|
|
562
|
+
LEDGER_ROWS_SEEN=0
|
|
563
|
+
LEDGER_PATH_FAILURES=0
|
|
564
|
+
while IFS="$(printf '\t')" read -r ROW_SCOPE ROW_TYPE ROW_ARTIFACT; do
|
|
565
|
+
[ -n "$ROW_SCOPE$ROW_TYPE$ROW_ARTIFACT" ] || continue
|
|
566
|
+
LEDGER_ROWS_SEEN=$((LEDGER_ROWS_SEEN + 1))
|
|
567
|
+
if [ "$ROW_ARTIFACT" = "-" ]; then continue; fi
|
|
568
|
+
ROW_REASON=""
|
|
569
|
+
if [ -z "$ROW_ARTIFACT" ]; then
|
|
570
|
+
ROW_REASON="artifact cell is empty"
|
|
571
|
+
else
|
|
572
|
+
ROW_TARGET="$PROJECT_PATH/$ROW_ARTIFACT"
|
|
573
|
+
ROW_DIR=$(cd -P "$(dirname "$ROW_TARGET")" 2>/dev/null && pwd -P) || ROW_DIR=""
|
|
574
|
+
ROW_RESOLVED=""
|
|
575
|
+
if [ -n "$ROW_DIR" ]; then
|
|
576
|
+
ROW_RESOLVED="$ROW_DIR/$(basename "$ROW_TARGET")"
|
|
577
|
+
ROW_HOPS=0
|
|
578
|
+
while [ -L "$ROW_RESOLVED" ] && [ "$ROW_HOPS" -lt 16 ]; do
|
|
579
|
+
ROW_LINK=$(readlink "$ROW_RESOLVED")
|
|
580
|
+
ROW_DIR=$(cd -P "$(dirname "$ROW_RESOLVED")" 2>/dev/null && cd -P "$(dirname "$ROW_LINK")" 2>/dev/null && pwd -P) || ROW_DIR=""
|
|
581
|
+
if [ -z "$ROW_DIR" ]; then
|
|
582
|
+
ROW_RESOLVED=""
|
|
583
|
+
break
|
|
584
|
+
fi
|
|
585
|
+
ROW_RESOLVED="$ROW_DIR/$(basename "$ROW_LINK")"
|
|
586
|
+
ROW_HOPS=$((ROW_HOPS + 1))
|
|
587
|
+
done
|
|
588
|
+
fi
|
|
589
|
+
ROW_MATERIALIZED=1
|
|
590
|
+
if [ -z "$ROW_RESOLVED" ]; then
|
|
591
|
+
ROW_MATERIALIZED=0
|
|
592
|
+
ROW_RESOLVED=$(printf '%s\n' "$LEDGER_PROJECT_ROOT/$ROW_ARTIFACT" | awk -F'/' '{
|
|
593
|
+
depth = 0
|
|
594
|
+
for (i = 1; i <= NF; i++) {
|
|
595
|
+
if ($i == "" || $i == ".") continue
|
|
596
|
+
if ($i == "..") { if (depth > 0) depth--; continue }
|
|
597
|
+
segment[++depth] = $i
|
|
598
|
+
}
|
|
599
|
+
normalized = ""
|
|
600
|
+
for (i = 1; i <= depth; i++) normalized = normalized "/" segment[i]
|
|
601
|
+
print (normalized == "" ? "/" : normalized)
|
|
602
|
+
}')
|
|
603
|
+
fi
|
|
604
|
+
ROW_CONTAINED=0
|
|
605
|
+
case "$ROW_RESOLVED" in
|
|
606
|
+
"$LEDGER_PROJECT_ROOT"/*) ROW_CONTAINED=1 ;;
|
|
607
|
+
esac
|
|
608
|
+
if [ "$ROW_CONTAINED" -eq 1 ] && [ "$ROW_MATERIALIZED" -eq 0 ]; then
|
|
609
|
+
ROW_ANCESTOR="$ROW_RESOLVED"
|
|
610
|
+
while [ ! -e "$ROW_ANCESTOR" ] && [ "$ROW_ANCESTOR" != "/" ]; do
|
|
611
|
+
ROW_ANCESTOR=$(dirname "$ROW_ANCESTOR")
|
|
612
|
+
done
|
|
613
|
+
if [ ! -d "$ROW_ANCESTOR" ]; then
|
|
614
|
+
ROW_ANCESTOR=$(dirname "$ROW_ANCESTOR")
|
|
615
|
+
fi
|
|
616
|
+
ROW_ANCESTOR_REAL=$(cd -P "$ROW_ANCESTOR" 2>/dev/null && pwd -P) || ROW_ANCESTOR_REAL=""
|
|
617
|
+
case "$ROW_ANCESTOR_REAL" in
|
|
618
|
+
"$LEDGER_PROJECT_ROOT" | "$LEDGER_PROJECT_ROOT"/*) ;;
|
|
619
|
+
*) ROW_CONTAINED=0 ;;
|
|
620
|
+
esac
|
|
621
|
+
fi
|
|
622
|
+
if [ "$ROW_CONTAINED" -eq 0 ]; then
|
|
623
|
+
ROW_REASON="artifact resolves outside the project: $ROW_RESOLVED"
|
|
624
|
+
elif [ "$ROW_MATERIALIZED" -eq 0 ]; then
|
|
625
|
+
classify_absent_ledger_artifact "$ROW_RESOLVED"
|
|
626
|
+
case "$LEDGER_ABSENT_CLASS" in
|
|
627
|
+
local-only)
|
|
628
|
+
echo "oat: local-only review artifact; reviews/archived/ was never materialized in this checkout | scope=$ROW_SCOPE type=$ROW_TYPE artifact=$ROW_ARTIFACT"
|
|
629
|
+
;;
|
|
630
|
+
not-a-directory)
|
|
631
|
+
ROW_REASON="reviews/archived exists but is not a directory"
|
|
632
|
+
;;
|
|
633
|
+
*)
|
|
634
|
+
ROW_REASON="artifact file does not exist"
|
|
635
|
+
;;
|
|
636
|
+
esac
|
|
637
|
+
elif [ -L "$ROW_RESOLVED" ]; then
|
|
638
|
+
ROW_REASON="artifact symlink chain does not resolve within 16 hops"
|
|
639
|
+
elif [ -d "$ROW_RESOLVED" ]; then
|
|
640
|
+
ROW_REASON="artifact path is a directory"
|
|
641
|
+
elif [ ! -e "$ROW_RESOLVED" ]; then
|
|
642
|
+
classify_absent_ledger_artifact "$ROW_RESOLVED"
|
|
643
|
+
case "$LEDGER_ABSENT_CLASS" in
|
|
644
|
+
local-only)
|
|
645
|
+
echo "oat: local-only review artifact; reviews/archived/ was never materialized in this checkout | scope=$ROW_SCOPE type=$ROW_TYPE artifact=$ROW_ARTIFACT"
|
|
646
|
+
;;
|
|
647
|
+
not-a-directory)
|
|
648
|
+
ROW_REASON="reviews/archived exists but is not a directory"
|
|
649
|
+
;;
|
|
650
|
+
*)
|
|
651
|
+
ROW_REASON="artifact file does not exist"
|
|
652
|
+
;;
|
|
653
|
+
esac
|
|
654
|
+
elif [ ! -f "$ROW_RESOLVED" ]; then
|
|
655
|
+
ROW_REASON="artifact is not a regular file"
|
|
656
|
+
fi
|
|
657
|
+
fi
|
|
658
|
+
[ -n "$ROW_REASON" ] || continue
|
|
659
|
+
echo "PRFINAL-05: unresolved review-ledger artifact | scope=$ROW_SCOPE type=$ROW_TYPE artifact=$ROW_ARTIFACT | $ROW_REASON" >&2
|
|
660
|
+
LEDGER_PATH_FAILURES=$((LEDGER_PATH_FAILURES + 1))
|
|
661
|
+
done <<LEDGER
|
|
662
|
+
$LEDGER_ROWS
|
|
663
|
+
LEDGER
|
|
664
|
+
if [ "$LEDGER_ROWS_SEEN" -ne "$LEDGER_ROW_COUNT" ]; then
|
|
665
|
+
echo "PRFINAL-05: validated $LEDGER_ROWS_SEEN of $LEDGER_ROW_COUNT review-ledger rows; the ledger was not fully checked" >&2
|
|
666
|
+
exit 1
|
|
667
|
+
fi
|
|
668
|
+
[ "$LEDGER_PATH_FAILURES" -eq 0 ] || exit 1
|
|
669
|
+
````
|
|
670
|
+
|
|
671
|
+
On `PRFINAL-05`, stop and repair the offending ledger row — usually a `reviews/` path whose artifact Step 0.5 moved into `reviews/archived/` — then re-run. Never create the PR with an unresolved ledger path.
|
|
672
|
+
|
|
399
673
|
For a synced project, use this ordered flow; do not reorder it:
|
|
400
674
|
|
|
401
675
|
1. Finish or refresh `summary.md` and the PR artifact.
|
|
@@ -482,7 +756,8 @@ If `state.md` is missing, skip with a warning.
|
|
|
482
756
|
|
|
483
757
|
## Success Criteria
|
|
484
758
|
|
|
485
|
-
- Residual
|
|
759
|
+
- Residual review artifacts whose ledger event is `passed` or `fixes_completed` are archived before final PR generation continues, with their ledger event rewritten; other rows keep their active path
|
|
760
|
+
- Every `## Reviews` artifact path resolves to a regular file inside the project before `gh pr create` runs
|
|
486
761
|
- Final PR description artifact written to `{PROJECT_PATH}/pr/`
|
|
487
762
|
- Final review status checked and referenced
|
|
488
763
|
- User has clear next step to open PR (manual or gh)
|