@open-agent-toolkit/cli 0.2.41 → 0.2.45
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/agents/oat-phase-implementer.md +11 -1
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/configuration.md +11 -1
- package/assets/docs/quickstart.md +9 -0
- package/assets/docs/reference/cli-reference.md +56 -1
- package/assets/docs/reference/file-locations.md +18 -1
- package/assets/docs/reference/oat-directory-structure.md +20 -4
- package/assets/docs/workflows/projects/artifacts.md +27 -1
- package/assets/docs/workflows/projects/implementation-execution.md +22 -0
- package/assets/docs/workflows/projects/index.md +6 -0
- package/assets/docs/workflows/projects/lifecycle.md +19 -5
- package/assets/docs/workflows/projects/picking-up-projects.md +75 -0
- package/assets/docs/workflows/projects/pr-flow.md +22 -1
- package/assets/docs/workflows/projects/reviewing-oat-prs.md +60 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-brainstorm/SKILL.md +135 -32
- package/assets/skills/oat-brainstorm/references/destinations.md +9 -6
- package/assets/skills/oat-cursor-cloud-projects/SKILL.md +11 -1
- package/assets/skills/oat-doctor/SKILL.md +8 -1
- package/assets/skills/oat-project-autonomous/SKILL.md +45 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +8 -8
- package/assets/skills/oat-project-capture/SKILL.md +29 -9
- package/assets/skills/oat-project-complete/SKILL.md +610 -38
- package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +265 -0
- package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +764 -0
- package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +134 -0
- package/assets/skills/oat-project-complete/scripts/validate-nonarchive-lifecycle-receipt.mjs +160 -0
- package/assets/skills/oat-project-design/SKILL.md +33 -9
- package/assets/skills/oat-project-discover/SKILL.md +16 -3
- package/assets/skills/oat-project-document/SKILL.md +10 -4
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +8 -8
- package/assets/skills/oat-project-implement/SKILL.md +14 -3
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +18 -6
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +8 -8
- package/assets/skills/oat-project-implement/references/phase-execution.md +9 -3
- package/assets/skills/oat-project-implement/references/plan-and-resume.md +3 -0
- package/assets/skills/oat-project-import-plan/SKILL.md +15 -9
- package/assets/skills/oat-project-new/SKILL.md +7 -5
- package/assets/skills/oat-project-next/SKILL.md +32 -10
- package/assets/skills/oat-project-plan/SKILL.md +18 -3
- package/assets/skills/oat-project-pr-final/SKILL.md +23 -2
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +8 -8
- package/assets/skills/oat-project-pr-progress/SKILL.md +23 -2
- package/assets/skills/oat-project-progress/SKILL.md +23 -9
- package/assets/skills/oat-project-promote-spec-driven/SKILL.md +20 -2
- package/assets/skills/oat-project-quick-start/SKILL.md +48 -18
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +8 -8
- package/assets/skills/oat-project-reconcile/SKILL.md +14 -10
- package/assets/skills/oat-project-retro/SKILL.md +3 -3
- package/assets/skills/oat-project-retro/references/apply-procedure.md +102 -6
- package/assets/skills/oat-project-retro-file/SKILL.md +57 -6
- package/assets/skills/oat-project-review-provide/SKILL.md +45 -4
- package/assets/skills/oat-project-review-receive/SKILL.md +16 -7
- package/assets/skills/oat-project-review-receive-remote/SKILL.md +9 -3
- package/assets/skills/oat-project-revise/SKILL.md +12 -3
- package/assets/skills/oat-project-spec/SKILL.md +16 -3
- package/assets/skills/oat-project-summary/SKILL.md +113 -13
- package/assets/skills/oat-wave-execute/SKILL.md +34 -2
- package/assets/skills/oat-worktree-bootstrap/SKILL.md +13 -1
- package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +13 -1
- 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 +30 -2
- package/dist/commands/doctor/index.d.ts +2 -0
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +27 -3
- package/dist/commands/doctor/synced-projects.d.ts +12 -0
- package/dist/commands/doctor/synced-projects.d.ts.map +1 -0
- package/dist/commands/doctor/synced-projects.js +208 -0
- package/dist/commands/init/gitattributes.d.ts +4 -0
- package/dist/commands/init/gitattributes.d.ts.map +1 -0
- package/dist/commands/init/gitattributes.js +12 -0
- package/dist/commands/init/gitignore.d.ts +8 -1
- package/dist/commands/init/gitignore.d.ts.map +1 -1
- package/dist/commands/init/gitignore.js +146 -41
- package/dist/commands/init/index.d.ts +2 -0
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -0
- package/dist/commands/init/managed-block.d.ts +10 -0
- package/dist/commands/init/managed-block.d.ts.map +1 -0
- package/dist/commands/init/managed-block.js +40 -0
- package/dist/commands/init/tools/workflows/install-workflows.js +1 -1
- package/dist/commands/local/index.d.ts.map +1 -1
- package/dist/commands/local/index.js +5 -1
- package/dist/commands/local/sync.d.ts +4 -0
- package/dist/commands/local/sync.d.ts.map +1 -1
- package/dist/commands/local/sync.js +123 -2
- package/dist/commands/pjm/adoption.d.ts +2 -0
- package/dist/commands/pjm/adoption.d.ts.map +1 -1
- package/dist/commands/pjm/adoption.js +1 -1
- package/dist/commands/project/archive/archive-utils.d.ts +24 -0
- package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
- package/dist/commands/project/archive/archive-utils.js +349 -22
- package/dist/commands/project/archive/index.d.ts.map +1 -1
- package/dist/commands/project/archive/index.js +1 -0
- package/dist/commands/project/archive/push-runner.d.ts +5 -1
- package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
- package/dist/commands/project/archive/push-runner.js +33 -4
- package/dist/commands/project/complete-state/index.d.ts.map +1 -1
- package/dist/commands/project/complete-state/index.js +3 -1
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +12 -0
- package/dist/commands/project/links/compute.d.ts +9 -0
- package/dist/commands/project/links/compute.d.ts.map +1 -0
- package/dist/commands/project/links/compute.js +27 -0
- package/dist/commands/project/links/index.d.ts +17 -0
- package/dist/commands/project/links/index.d.ts.map +1 -0
- package/dist/commands/project/links/index.js +72 -0
- package/dist/commands/project/links/refresh.d.ts +26 -0
- package/dist/commands/project/links/refresh.d.ts.map +1 -0
- package/dist/commands/project/links/refresh.js +92 -0
- package/dist/commands/project/links/render.d.ts +24 -0
- package/dist/commands/project/links/render.d.ts.map +1 -0
- package/dist/commands/project/links/render.js +68 -0
- package/dist/commands/project/list.d.ts +5 -0
- package/dist/commands/project/list.d.ts.map +1 -1
- package/dist/commands/project/list.js +182 -9
- package/dist/commands/project/migrate/index.d.ts +22 -0
- package/dist/commands/project/migrate/index.d.ts.map +1 -0
- package/dist/commands/project/migrate/index.js +79 -0
- package/dist/commands/project/new/index.d.ts +2 -0
- package/dist/commands/project/new/index.d.ts.map +1 -1
- package/dist/commands/project/new/index.js +14 -2
- package/dist/commands/project/new/scaffold.d.ts +22 -1
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +287 -69
- package/dist/commands/project/open/index.d.ts +16 -0
- package/dist/commands/project/open/index.d.ts.map +1 -1
- package/dist/commands/project/open/index.js +151 -19
- package/dist/commands/project/pause/index.d.ts +8 -0
- package/dist/commands/project/pause/index.d.ts.map +1 -1
- package/dist/commands/project/pause/index.js +129 -19
- package/dist/commands/project/prune/index.d.ts +21 -0
- package/dist/commands/project/prune/index.d.ts.map +1 -0
- package/dist/commands/project/prune/index.js +95 -0
- package/dist/commands/project/pull/index.d.ts +28 -0
- package/dist/commands/project/pull/index.d.ts.map +1 -0
- package/dist/commands/project/pull/index.js +157 -0
- package/dist/commands/project/push/index.d.ts +22 -0
- package/dist/commands/project/push/index.d.ts.map +1 -0
- package/dist/commands/project/push/index.js +100 -0
- package/dist/commands/project/scope/index.d.ts +17 -0
- package/dist/commands/project/scope/index.d.ts.map +1 -0
- package/dist/commands/project/scope/index.js +107 -0
- package/dist/commands/project/split/run.d.ts +4 -0
- package/dist/commands/project/split/run.d.ts.map +1 -1
- package/dist/commands/project/split/run.js +48 -10
- package/dist/commands/project/sync/git.d.ts +18 -0
- package/dist/commands/project/sync/git.d.ts.map +1 -0
- package/dist/commands/project/sync/git.js +60 -0
- package/dist/commands/project/sync/record.d.ts +22 -0
- package/dist/commands/project/sync/record.d.ts.map +1 -0
- package/dist/commands/project/sync/record.js +133 -0
- package/dist/commands/project/sync/ref-sync.d.ts +120 -0
- package/dist/commands/project/sync/ref-sync.d.ts.map +1 -0
- package/dist/commands/project/sync/ref-sync.js +962 -0
- package/dist/commands/project/sync/resolve-target.d.ts +27 -0
- package/dist/commands/project/sync/resolve-target.d.ts.map +1 -0
- package/dist/commands/project/sync/resolve-target.js +159 -0
- package/dist/commands/shared/oat-paths.d.ts +4 -1
- package/dist/commands/shared/oat-paths.d.ts.map +1 -1
- package/dist/commands/shared/oat-paths.js +2 -2
- package/dist/commands/shared/project-scope.d.ts +23 -0
- package/dist/commands/shared/project-scope.d.ts.map +1 -0
- package/dist/commands/shared/project-scope.js +106 -0
- package/dist/commands/tools/migrate/index.js +1 -1
- package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-inventory.js +11 -0
- package/dist/commands/tools/shared/pack-lifecycle.js +1 -1
- package/dist/commands/tools/shared/pack-reconcile.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-reconcile.js +4 -1
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +20 -10
- package/dist/commands/tools/update/update-tools.d.ts +2 -0
- package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
- package/dist/config/oat-config.d.ts +6 -3
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +41 -7
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +2 -1
- package/dist/fs/io.d.ts +2 -1
- package/dist/fs/io.d.ts.map +1 -1
- package/dist/fs/io.js +5 -2
- package/dist/projects/split/finalize.d.ts.map +1 -1
- package/dist/projects/split/finalize.js +55 -2
- package/dist/projects/split/resume.d.ts +3 -0
- package/dist/projects/split/resume.d.ts.map +1 -1
- package/dist/projects/split/resume.js +34 -7
- package/dist/projects/split/seed-children.d.ts.map +1 -1
- package/dist/projects/split/seed-children.js +6 -0
- package/dist/projects/split/write-parent.d.ts +7 -0
- package/dist/projects/split/write-parent.d.ts.map +1 -1
- package/dist/projects/split/write-parent.js +7 -4
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +1 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +434 -0
- package/package.json +4 -4
- package/dist/__tests__/skills/split-flow-fixtures.d.ts +0 -50
- package/dist/__tests__/skills/split-flow-fixtures.d.ts.map +0 -1
- package/dist/__tests__/skills/split-flow-fixtures.js +0 -161
- package/dist/commands/__tests__/helpers.d.ts +0 -12
- package/dist/commands/__tests__/helpers.d.ts.map +0 -1
- package/dist/commands/__tests__/helpers.js +0 -36
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-complete
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.7.5
|
|
4
4
|
description: Use when all implementation work is finished and the project is ready to close. Marks the OAT project lifecycle as complete.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -42,14 +42,42 @@ if [[ -z "$PROJECT_PATH" ]]; then
|
|
|
42
42
|
fi
|
|
43
43
|
|
|
44
44
|
PROJECT_NAME=$(basename "$PROJECT_PATH")
|
|
45
|
+
ACTIVE_PROJECT_PATH="$PROJECT_PATH"
|
|
46
|
+
|
|
47
|
+
# Set SKILL_DIR to the absolute directory containing this loaded SKILL.md.
|
|
48
|
+
COMPLETION_RECEIPT_SCRIPT="$SKILL_DIR/scripts/recover-completion-receipts.mjs"
|
|
49
|
+
COMPLETION_RETRY_SCRIPT="$SKILL_DIR/scripts/resolve-completion-retry.mjs"
|
|
50
|
+
COMPLETION_RETRY_FIELDS_SCRIPT="$SKILL_DIR/scripts/parse-completion-retry-fields.mjs"
|
|
51
|
+
NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT="$SKILL_DIR/scripts/validate-nonarchive-lifecycle-receipt.mjs"
|
|
52
|
+
test -f "$COMPLETION_RECEIPT_SCRIPT" || {
|
|
53
|
+
echo "oat: completion receipt recovery script is missing" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
}
|
|
56
|
+
test -f "$COMPLETION_RETRY_SCRIPT" || {
|
|
57
|
+
echo "oat: completion retry routing script is missing" >&2
|
|
58
|
+
exit 1
|
|
59
|
+
}
|
|
60
|
+
test -f "$COMPLETION_RETRY_FIELDS_SCRIPT" || {
|
|
61
|
+
echo "oat: completion retry field decoder is missing" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
}
|
|
64
|
+
test -f "$NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" || {
|
|
65
|
+
echo "Missing non-archive lifecycle receipt validator: $NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" >&2
|
|
66
|
+
exit 1
|
|
67
|
+
}
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
69
|
+
PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing completion" >&2; exit 1; }
|
|
70
|
+
if [[ "$PROJECT_SCOPE" == "synced" ]]; then
|
|
71
|
+
oat project pull "$PROJECT_PATH" || { echo "oat: project pull failed for $PROJECT_PATH; resolve the reported state before continuing" >&2; exit 1; }
|
|
72
|
+
fi
|
|
73
|
+
PROJECT_RETAINED_REF=""
|
|
74
|
+
if [[ "$PROJECT_SCOPE" == "synced" ]]; then
|
|
75
|
+
PROJECT_RETAINED_REF="refs/oat/projects/${PROJECT_NAME}"
|
|
76
|
+
fi
|
|
77
|
+
IS_DURABLE_PROJECT="false"
|
|
78
|
+
if [[ "$PROJECT_SCOPE" == "shared" || "$PROJECT_SCOPE" == "synced" ]]; then
|
|
79
|
+
IS_DURABLE_PROJECT="true"
|
|
80
|
+
fi
|
|
53
81
|
```
|
|
54
82
|
|
|
55
83
|
### Step 2: Upfront User Questions (Batched)
|
|
@@ -94,16 +122,102 @@ PR_ON_COMPLETE=$(oat config get workflow.createPrOnComplete 2>/dev/null || true)
|
|
|
94
122
|
PROJECT_RECAP_CONFIG=$(oat config get workflow.explainers.projectRecap --json 2>/dev/null || true)
|
|
95
123
|
```
|
|
96
124
|
|
|
97
|
-
- **If `
|
|
98
|
-
|
|
99
|
-
|
|
125
|
+
- **If `IS_DURABLE_PROJECT` is `false`:** Omit the archive question regardless of
|
|
126
|
+
`ARCHIVE_PREF`. The resolver below selects `local-default`; do not assign
|
|
127
|
+
`SHOULD_ARCHIVE` directly.
|
|
128
|
+
- **If `IS_DURABLE_PROJECT` is `true` and `ARCHIVE_PREF` is `true`:** Skip the
|
|
129
|
+
archive question. Print
|
|
130
|
+
`Archive on complete: enabled (from workflow.archiveOnComplete).`
|
|
131
|
+
- **If `IS_DURABLE_PROJECT` is `true` and `ARCHIVE_PREF` is `false`:** Skip the
|
|
132
|
+
archive question. Print
|
|
133
|
+
`Archive on complete: disabled (from workflow.archiveOnComplete).`
|
|
134
|
+
- **If `IS_DURABLE_PROJECT` is `true` and `ARCHIVE_PREF` is unset:** Include
|
|
135
|
+
the archive question in the batched prompt as normal (backward compatible).
|
|
100
136
|
- **If `PR_ON_COMPLETE` is `true` AND no tracked open PR exists:** Set `SHOULD_OPEN_PR="true"`. Skip the Open PR question. Print `PR on complete: enabled (from workflow.createPrOnComplete).`
|
|
101
137
|
- **If `PR_ON_COMPLETE` is `false`:** Set `SHOULD_OPEN_PR="false"`. Skip the Open PR question. Print `PR on complete: disabled (from workflow.createPrOnComplete).`
|
|
102
138
|
- **If `PR_ON_COMPLETE` is unset:** Include the Open PR question in the batched prompt as normal (backward compatible).
|
|
103
139
|
- The existing tracked-PR skip still applies: if `oat_pr_status` is `open`, do not ask the Open PR question and do not honor `PR_ON_COMPLETE=true` — the PR already exists.
|
|
104
140
|
|
|
141
|
+
Select archive prompt participation before assembling the batched prompt:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# archive-prompt-selection:start
|
|
145
|
+
ARCHIVE_QUESTION_REQUIRED="false"
|
|
146
|
+
if [[ "$IS_DURABLE_PROJECT" == "true" ]]; then
|
|
147
|
+
if [[ "$ARCHIVE_PREF" == "true" ]]; then
|
|
148
|
+
echo "Archive on complete: enabled (from workflow.archiveOnComplete)."
|
|
149
|
+
elif [[ "$ARCHIVE_PREF" == "false" ]]; then
|
|
150
|
+
echo "Archive on complete: disabled (from workflow.archiveOnComplete)."
|
|
151
|
+
else
|
|
152
|
+
ARCHIVE_QUESTION_REQUIRED="true"
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
# archive-prompt-selection:end
|
|
156
|
+
```
|
|
157
|
+
|
|
105
158
|
The "Ready to mark complete?" confirmation is always asked — it is a meaningful "are you sure" moment, not a preference.
|
|
106
159
|
|
|
160
|
+
The configured-decline case is `workflow.archiveOnComplete=false`. When the
|
|
161
|
+
preference is unset and the user declines the batched archive question, the
|
|
162
|
+
interactive archive answer is `false`. Both cases select the same explicit
|
|
163
|
+
non-archive transaction below; declining archive never means skipping synced
|
|
164
|
+
record durability.
|
|
165
|
+
|
|
166
|
+
Route every source through
|
|
167
|
+
`scripts/recover-completion-receipts.mjs#resolveCompletionArchiveDecision`
|
|
168
|
+
before assigning `SHOULD_ARCHIVE`. For a local project, pass the explicit
|
|
169
|
+
`localNonArchive=true` decision without asking the archive question. For a
|
|
170
|
+
durable project, pass `configuredPreference` only when
|
|
171
|
+
`workflow.archiveOnComplete` is set; otherwise pass the accepted batched
|
|
172
|
+
`interactiveAnswer`. Require the result's `source` to be `local-default`,
|
|
173
|
+
`configured`, or `interactive` as appropriate and use its `shouldArchive`
|
|
174
|
+
boolean. An absent, conflicting, or non-boolean decision fails closed instead
|
|
175
|
+
of silently selecting a lifecycle path. The executable completion transaction
|
|
176
|
+
tests must use this same resolver; scenario labels alone are not decision
|
|
177
|
+
coverage.
|
|
178
|
+
|
|
179
|
+
After the configured preference or accepted interactive answer is available,
|
|
180
|
+
invoke the resolver rather than assigning `SHOULD_ARCHIVE` directly:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# archive-decision-resolution:start
|
|
184
|
+
ARCHIVE_DECISION_ARGS=()
|
|
185
|
+
EXPECTED_ARCHIVE_DECISION_SOURCE=""
|
|
186
|
+
if [[ "$IS_DURABLE_PROJECT" == "false" ]]; then
|
|
187
|
+
ARCHIVE_DECISION_ARGS+=(--local-nonarchive true)
|
|
188
|
+
EXPECTED_ARCHIVE_DECISION_SOURCE="local-default"
|
|
189
|
+
elif [[ "$ARCHIVE_PREF" == "true" || "$ARCHIVE_PREF" == "false" ]]; then
|
|
190
|
+
ARCHIVE_DECISION_ARGS+=(--archive-preference "$ARCHIVE_PREF")
|
|
191
|
+
EXPECTED_ARCHIVE_DECISION_SOURCE="configured"
|
|
192
|
+
else
|
|
193
|
+
test "$ARCHIVE_INTERACTIVE_ANSWER" = "true" \
|
|
194
|
+
|| test "$ARCHIVE_INTERACTIVE_ANSWER" = "false" \
|
|
195
|
+
|| exit 1
|
|
196
|
+
ARCHIVE_DECISION_ARGS+=(--interactive-archive "$ARCHIVE_INTERACTIVE_ANSWER")
|
|
197
|
+
EXPECTED_ARCHIVE_DECISION_SOURCE="interactive"
|
|
198
|
+
fi
|
|
199
|
+
ARCHIVE_DECISION_JSON=$(node "$COMPLETION_RECEIPT_SCRIPT" \
|
|
200
|
+
"${ARCHIVE_DECISION_ARGS[@]}") || exit 1
|
|
201
|
+
ARCHIVE_DECISION_FIELDS=$(node -e '
|
|
202
|
+
const value = JSON.parse(process.argv[1]);
|
|
203
|
+
if (typeof value.shouldArchive !== "boolean" || !["local-default", "configured", "interactive"].includes(value.source)) process.exit(1);
|
|
204
|
+
process.stdout.write(`${value.shouldArchive}\t${value.source}`);
|
|
205
|
+
' "$ARCHIVE_DECISION_JSON") || exit 1
|
|
206
|
+
IFS=$'\t' read -r SHOULD_ARCHIVE ARCHIVE_DECISION_SOURCE \
|
|
207
|
+
<<< "$ARCHIVE_DECISION_FIELDS"
|
|
208
|
+
test "$ARCHIVE_DECISION_SOURCE" = "$EXPECTED_ARCHIVE_DECISION_SOURCE" || exit 1
|
|
209
|
+
if [[ "$ARCHIVE_DECISION_SOURCE" == "local-default" ]]; then
|
|
210
|
+
test "$SHOULD_ARCHIVE" = "false" || exit 1
|
|
211
|
+
fi
|
|
212
|
+
# archive-decision-resolution:end
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Require `ARCHIVE_DECISION_SOURCE` to match the source selected above. Local
|
|
216
|
+
completion always resolves to explicit non-archive without asking the archive
|
|
217
|
+
question. Store an unconfigured durable-project batched answer as
|
|
218
|
+
`ARCHIVE_INTERACTIVE_ANSWER` until this resolver returns; only then assign
|
|
219
|
+
`SHOULD_ARCHIVE`.
|
|
220
|
+
|
|
107
221
|
Resolve `projectRecap` intent before presenting the batched completion prompt.
|
|
108
222
|
Use the `oat-explainer-kit` lifecycle intent resolver in interactive mode with
|
|
109
223
|
the current `oat_project_recap` value from the same `state.md` read and the
|
|
@@ -142,7 +256,8 @@ implementation ran:
|
|
|
142
256
|
**Questions to ask (in a single prompt):**
|
|
143
257
|
|
|
144
258
|
1. **Confirm completion:** "Ready to mark **{PROJECT_NAME}** as complete?"
|
|
145
|
-
2. **Archive** (only if `
|
|
259
|
+
2. **Archive** (only if `ARCHIVE_QUESTION_REQUIRED` is `true`):
|
|
260
|
+
"Archive the project after completion?"
|
|
146
261
|
3. **Generate or refresh summary** (only if summary status is `missing` or `stale`): present the status explicitly:
|
|
147
262
|
- Missing example: "A summary has not been generated yet. Would you like me to generate it now as part of completion?"
|
|
148
263
|
- Stale example: "The project summary is out of date. Would you like me to refresh it now as part of completion?"
|
|
@@ -166,9 +281,11 @@ Ready to complete project **{PROJECT_NAME}**?
|
|
|
166
281
|
|
|
167
282
|
If the user declines the completion confirmation, exit gracefully.
|
|
168
283
|
|
|
169
|
-
After the user accepts the completion confirmation, store
|
|
170
|
-
`
|
|
171
|
-
|
|
284
|
+
After the user accepts the completion confirmation, store a prompted archive
|
|
285
|
+
answer as `ARCHIVE_INTERACTIVE_ANSWER`; assign `SHOULD_ARCHIVE` only through
|
|
286
|
+
the decision resolver above. Store the remaining answers as
|
|
287
|
+
`SHOULD_GENERATE_SUMMARY`, `SHOULD_GENERATE_RETRO`, `SHOULD_GENERATE_RECAP`,
|
|
288
|
+
and `SHOULD_OPEN_PR` for use in later steps. Set
|
|
172
289
|
`SHOULD_GENERATE_RETRO="false"` when the retro already exists or this completion
|
|
173
290
|
run is non-interactive. Persist a prompted recap answer only after that
|
|
174
291
|
confirmation is accepted.
|
|
@@ -352,7 +469,69 @@ a warning rather than changing project completion status.
|
|
|
352
469
|
|
|
353
470
|
`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.
|
|
354
471
|
|
|
355
|
-
For `
|
|
472
|
+
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.
|
|
473
|
+
|
|
474
|
+
### Step 3.65: Recover a Recognizable Completion Receipt Before Mutation
|
|
475
|
+
|
|
476
|
+
Initialize `PROJECT_LINKS_PIN_COMMIT=""`, `PROJECT_REF_COMMIT=""`,
|
|
477
|
+
`EVIDENCE_COMMIT=""`, `RECOVERED_EVIDENCE_COMMIT=""`,
|
|
478
|
+
`EVIDENCE_PUSH_REQUIRED=""`, `PR_DESCRIPTION_RELATIVE_PATH=""`, and
|
|
479
|
+
`COMPLETION_RECEIPTS_RECOVERED="false"`. For a
|
|
480
|
+
synced non-archive run, invoke the skill-owned retry router before the
|
|
481
|
+
project-log probe, seal append, review moves, `complete-state`, active-pointer,
|
|
482
|
+
or PR-artifact mutation. This is the one executable routing surface; do not
|
|
483
|
+
recreate candidate detection and recovery as separate shell branches:
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
if [[ "$PROJECT_SCOPE" == "synced" && "$SHOULD_ARCHIVE" == "false" ]]; then
|
|
487
|
+
COMPLETION_RETRY_ARGS=(
|
|
488
|
+
--project-path "$ACTIVE_PROJECT_PATH"
|
|
489
|
+
--retained-ref "$PROJECT_RETAINED_REF"
|
|
490
|
+
)
|
|
491
|
+
if [[ -n "$SELECTED_PROJECT_RECAP_RUN" ]]; then
|
|
492
|
+
COMPLETION_RETRY_ARGS+=(
|
|
493
|
+
--evidence-path "$SELECTED_PROJECT_RECAP_RUN/manifest.json"
|
|
494
|
+
--evidence-path "$SELECTED_PROJECT_RECAP_RUN/build-record.json"
|
|
495
|
+
)
|
|
496
|
+
fi
|
|
497
|
+
COMPLETION_RETRY_JSON=$(node "$COMPLETION_RETRY_SCRIPT" \
|
|
498
|
+
"${COMPLETION_RETRY_ARGS[@]}") || exit 1
|
|
499
|
+
COMPLETION_RETRY_FIELDS=$(node "$COMPLETION_RETRY_FIELDS_SCRIPT" \
|
|
500
|
+
"$COMPLETION_RETRY_JSON") || exit 1
|
|
501
|
+
IFS=$'\t' read -r COMPLETION_RETRY_ROUTE _ \
|
|
502
|
+
<<< "$COMPLETION_RETRY_FIELDS"
|
|
503
|
+
if [[ "$COMPLETION_RETRY_ROUTE" == "recovery" ]]; then
|
|
504
|
+
IFS=$'\t' read -r COMPLETION_RETRY_ROUTE PROJECT_LINKS_PIN_COMMIT \
|
|
505
|
+
PROJECT_REF_COMMIT RECOVERED_EVIDENCE_COMMIT EVIDENCE_PUSH_REQUIRED \
|
|
506
|
+
PR_DESCRIPTION_RELATIVE_PATH <<< "$COMPLETION_RETRY_FIELDS"
|
|
507
|
+
if [[ "$RECOVERED_EVIDENCE_COMMIT" != "-" ]]; then
|
|
508
|
+
EVIDENCE_COMMIT="$RECOVERED_EVIDENCE_COMMIT"
|
|
509
|
+
fi
|
|
510
|
+
PR_DESCRIPTION_PATH="$ACTIVE_PROJECT_PATH/$PR_DESCRIPTION_RELATIVE_PATH"
|
|
511
|
+
COMPLETION_RECEIPTS_RECOVERED="true"
|
|
512
|
+
elif [[ "$COMPLETION_RETRY_ROUTE" == "pin-source" ]]; then
|
|
513
|
+
IFS=$'\t' read -r COMPLETION_RETRY_ROUTE PROJECT_LINKS_PIN_COMMIT \
|
|
514
|
+
PR_DESCRIPTION_RELATIVE_PATH <<< "$COMPLETION_RETRY_FIELDS"
|
|
515
|
+
PR_DESCRIPTION_PATH="$ACTIVE_PROJECT_PATH/$PR_DESCRIPTION_RELATIVE_PATH"
|
|
516
|
+
COMPLETION_RECEIPTS_RECOVERED="true"
|
|
517
|
+
elif [[ "$COMPLETION_RETRY_ROUTE" != "normal" || \
|
|
518
|
+
"$COMPLETION_RETRY_FIELDS" != "normal" ]]; then
|
|
519
|
+
exit 1
|
|
520
|
+
fi
|
|
521
|
+
fi
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
A recognized candidate must be clean and validate completely; dirty,
|
|
525
|
+
malformed, mixed, or contradictory candidates exit before the router returns.
|
|
526
|
+
When the result is `route: "normal"`, follow the ordinary flow without
|
|
527
|
+
changing its existing dirty-worktree guarantees. When it is
|
|
528
|
+
`route: "recovery"`, the executable has already restored the final receipts.
|
|
529
|
+
Jump directly to Step 7.5 and skip every mutation in Steps 3.7 through 7. When
|
|
530
|
+
it is `route: "pin-source"`, the executable has validated the already-published
|
|
531
|
+
pin-source tree and PR artifact; preserve `PROJECT_LINKS_PIN_COMMIT`, jump
|
|
532
|
+
directly to Step 8.6, and skip Steps 3.7 through 7, including a duplicate
|
|
533
|
+
pin-source push. The executable transaction matrix must use this same router
|
|
534
|
+
for all configured and interactive interruption rows.
|
|
356
535
|
|
|
357
536
|
### Step 3.7: Project Log Completion Gate
|
|
358
537
|
|
|
@@ -439,13 +618,26 @@ Delegate the canonical `state.md` completion mutation to the CLI:
|
|
|
439
618
|
|
|
440
619
|
```bash
|
|
441
620
|
COMPLETE_STATE_ARGS=("$PROJECT_PATH")
|
|
442
|
-
if [[ "$SHOULD_ARCHIVE" == "true" && "$
|
|
621
|
+
if [[ "$SHOULD_ARCHIVE" == "true" && "$IS_DURABLE_PROJECT" == "true" ]]; then
|
|
443
622
|
COMPLETE_STATE_ARGS+=("--archived")
|
|
444
623
|
fi
|
|
445
624
|
|
|
446
625
|
oat project complete-state "${COMPLETE_STATE_ARGS[@]}"
|
|
447
626
|
```
|
|
448
627
|
|
|
628
|
+
For `synced`, keep this finalized lifecycle state in the project checkout until
|
|
629
|
+
Step 7.5 publishes it together with every later pre-archive artifact write. Do
|
|
630
|
+
not push here: Step 7 may still create or replace the PR-description artifact,
|
|
631
|
+
and the retained project ref must include that late artifact.
|
|
632
|
+
|
|
633
|
+
When archive is selected, the synced completion order is: finalize → generate
|
|
634
|
+
the PR artifact → project-ref pin-source push → project archive → render
|
|
635
|
+
`oat project links --durable-summary <path>` → update the open PR body. When
|
|
636
|
+
archive is declined, it is: finalize → generate the PR artifact →
|
|
637
|
+
project-ref pin-source push → render the final links → final artifact push →
|
|
638
|
+
exact discovery-record commit → optional active-recap evidence commit and
|
|
639
|
+
project push.
|
|
640
|
+
|
|
449
641
|
The CLI command owns both the frontmatter completion fields and the canonical markdown body updates for `state.md`.
|
|
450
642
|
It must set `oat_lifecycle: complete`, completion timestamps, `**Status:** Complete`, `**Last Updated:**`, the canonical `## Current Phase` body, normalized `## Progress`, and `## Next Milestone`.
|
|
451
643
|
|
|
@@ -481,6 +673,15 @@ fi
|
|
|
481
673
|
|
|
482
674
|
5. **Write PR description artifact** — write to `{PROJECT_PATH}/pr/project-pr-YYYY-MM-DD.md` following the template and policies from `oat-project-pr-final` Step 4 (frontmatter policy, reference links policy, local path exclusion).
|
|
483
675
|
|
|
676
|
+
When no PR description artifact exists, write it before the final synced
|
|
677
|
+
project-ref publication, regardless of archive or recap selection.
|
|
678
|
+
|
|
679
|
+
Retain the one selected or written artifact as `PR_DESCRIPTION_PATH`. Resolve
|
|
680
|
+
`PR_DESCRIPTION_RELATIVE_PATH` from `ACTIVE_PROJECT_PATH`, require it to be a
|
|
681
|
+
normalized project-relative path, and reject zero, multiple, symlinked, or
|
|
682
|
+
outside-project candidates. Step 7.5 passes that exact relative path to the
|
|
683
|
+
receipt recovery surface.
|
|
684
|
+
|
|
484
685
|
If a PR description artifact already exists at `{PROJECT_PATH}/pr/project-pr-*.md`:
|
|
485
686
|
|
|
486
687
|
- When `SHOULD_ARCHIVE` is `true`, regenerate it (overwrite). The existing artifact was authored by `oat-project-pr-final` before any archive intent existed and links to artifact paths that will be local-only after Step 8. Regenerating ensures Step 11 / Step 11.5 push a body whose links still resolve on the remote.
|
|
@@ -509,9 +710,161 @@ When archiving, the project artifacts at `{PROJECT_PATH}/{plan,implementation,di
|
|
|
509
710
|
|
|
510
711
|
Anti-pattern: do not "rescue" a dropped artifact by linking to its archived path under `.oat/projects/archived/<name>/...`. That path is gitignored on every checkout and never reaches the remote.
|
|
511
712
|
|
|
713
|
+
#### Step 7.5: Publish Synced Project Pin Source
|
|
714
|
+
|
|
715
|
+
For `synced`, publish only after Step 7 has finished every pre-archive project
|
|
716
|
+
artifact write. This receipt is the immutable pin source used when Step 8.6
|
|
717
|
+
renders the final links. Keep it separate from the final non-archive artifact
|
|
718
|
+
receipt:
|
|
719
|
+
|
|
720
|
+
Preserve `PROJECT_LINKS_PIN_COMMIT`, `PROJECT_REF_COMMIT`, `EVIDENCE_COMMIT`,
|
|
721
|
+
and `EVIDENCE_PUSH_REQUIRED` when the Step 3.65 router restored them. A
|
|
722
|
+
`pin-source` route skips this step entirely and resumes at Step 8.6. Do not
|
|
723
|
+
initialize over a recovered value or run a second candidate-routing branch at
|
|
724
|
+
this step. The pre-mutation router owns candidate detection, exact PR-artifact
|
|
725
|
+
selection, pin-source retry validation, and `recoverCompletionReceipts`; its
|
|
726
|
+
read-only recovery must have validated the applicable receipt chain before
|
|
727
|
+
returning a receipt:
|
|
728
|
+
|
|
729
|
+
- a clean synced checkout and the retained local ref;
|
|
730
|
+
- the exact final-artifact and optional evidence subjects;
|
|
731
|
+
- exactly the PR-description path in the final-artifact commit and exactly the
|
|
732
|
+
two supplied recap record paths in an evidence commit;
|
|
733
|
+
- single-parent pin-source → final-artifact → optional evidence ordering, with
|
|
734
|
+
the pin source subject equal to the preliminary push message below;
|
|
735
|
+
- canonical `state.md` lifecycle fields in the pin-source tree, including
|
|
736
|
+
`oat_lifecycle: complete` and equal valid UTC completion/update timestamps;
|
|
737
|
+
- when the pin source contains `project-log.md`, its final entry is the
|
|
738
|
+
canonical `oat-project-complete` completion seal; an absent log remains the
|
|
739
|
+
supported inert project-log configuration from Step 3.7;
|
|
740
|
+
- exactly one well-ordered links block pinned to the pin-source parent; and
|
|
741
|
+
- either equal local/remote final-artifact receipts, equal local/remote evidence
|
|
742
|
+
receipts, or the one allowed unpublished-evidence state where checkout HEAD
|
|
743
|
+
is the exact evidence child while both retained refs remain at its exact
|
|
744
|
+
final-artifact parent.
|
|
745
|
+
|
|
746
|
+
Restore the returned `projectLinksPinCommit` as
|
|
747
|
+
`PROJECT_LINKS_PIN_COMMIT`, `projectRefCommit` as `PROJECT_REF_COMMIT`, and a
|
|
748
|
+
non-null `evidenceCommit` as `EVIDENCE_COMMIT`. Any candidate with a malformed
|
|
749
|
+
subject, path set, parent, links block, retained ref, or local/remote relation
|
|
750
|
+
fails closed. Do not fall through to a new pin-source publication after a
|
|
751
|
+
partial or contradictory candidate. This retry recognition is valid whether
|
|
752
|
+
the parent discovery record is still active or already complete.
|
|
753
|
+
|
|
754
|
+
Build the recovery arguments only for post-push revalidation of an unpublished
|
|
755
|
+
evidence receipt:
|
|
756
|
+
|
|
757
|
+
```bash
|
|
758
|
+
RECOVERY_ARGS=(
|
|
759
|
+
--project-path "$ACTIVE_PROJECT_PATH"
|
|
760
|
+
--retained-ref "$PROJECT_RETAINED_REF"
|
|
761
|
+
--pr-artifact "$PR_DESCRIPTION_RELATIVE_PATH"
|
|
762
|
+
)
|
|
763
|
+
if [[ -n "$SELECTED_PROJECT_RECAP_RUN" ]]; then
|
|
764
|
+
RECOVERY_ARGS+=(
|
|
765
|
+
--evidence-path "$SELECTED_PROJECT_RECAP_RUN/manifest.json"
|
|
766
|
+
--evidence-path "$SELECTED_PROJECT_RECAP_RUN/build-record.json"
|
|
767
|
+
)
|
|
768
|
+
fi
|
|
769
|
+
|
|
770
|
+
parse_completion_receipts() {
|
|
771
|
+
node -e '
|
|
772
|
+
const value = JSON.parse(process.argv[1]);
|
|
773
|
+
const sha = /^[0-9a-f]{40}$/;
|
|
774
|
+
if (value.status !== "recovered" || !sha.test(value.projectLinksPinCommit) || !sha.test(value.projectRefCommit)) process.exit(1);
|
|
775
|
+
if (value.evidenceCommit !== null && !sha.test(value.evidenceCommit)) process.exit(1);
|
|
776
|
+
if (typeof value.evidencePushRequired !== "boolean") process.exit(1);
|
|
777
|
+
process.stdout.write([
|
|
778
|
+
value.projectLinksPinCommit,
|
|
779
|
+
value.projectRefCommit,
|
|
780
|
+
value.evidenceCommit ?? "-",
|
|
781
|
+
String(value.evidencePushRequired),
|
|
782
|
+
].join("\t"));
|
|
783
|
+
' "$1"
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
Use this block only after the Step 3.65 router restored a candidate. Require
|
|
789
|
+
`EVIDENCE_PUSH_REQUIRED` to be `true` or `false`; no other output is accepted.
|
|
790
|
+
|
|
791
|
+
When the recovery result reports `evidencePushRequired: true`, publish the
|
|
792
|
+
existing checkout HEAD with `oat project push "$PROJECT_PATH" --json` before
|
|
793
|
+
continuing. Require `status: "pushed"` or `status: "up-to-date"`, the same
|
|
794
|
+
retained ref, and a receipt SHA exactly equal to `EVIDENCE_COMMIT`. This push
|
|
795
|
+
must not create a commit, rerender the PR artifact, or rewrite any receipt.
|
|
796
|
+
Re-run the recovery surface after the push and require the exact same pin,
|
|
797
|
+
final-artifact, and evidence SHAs with `evidencePushRequired: false`.
|
|
798
|
+
|
|
799
|
+
```bash
|
|
800
|
+
parse_synced_push_receipt() {
|
|
801
|
+
node -e '
|
|
802
|
+
const value = JSON.parse(process.argv[1]);
|
|
803
|
+
if (!["pushed", "up-to-date"].includes(value.status)) process.exit(1);
|
|
804
|
+
if (!/^[0-9a-f]{40}$/.test(value.sha) || typeof value.ref !== "string") process.exit(1);
|
|
805
|
+
process.stdout.write(`${value.ref}\t${value.sha}`);
|
|
806
|
+
' "$1"
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if [[ "$EVIDENCE_PUSH_REQUIRED" == "true" ]]; then
|
|
810
|
+
RECOVERED_EVIDENCE_PUSH_OUTPUT=$(oat project push \
|
|
811
|
+
"$PROJECT_PATH" --json) || exit 1
|
|
812
|
+
RECOVERED_EVIDENCE_PUSH_FIELDS=$( \
|
|
813
|
+
parse_synced_push_receipt "$RECOVERED_EVIDENCE_PUSH_OUTPUT"
|
|
814
|
+
) || exit 1
|
|
815
|
+
IFS=$'\t' read -r RECOVERED_PUSH_REF RECOVERED_PUSH_SHA \
|
|
816
|
+
<<< "$RECOVERED_EVIDENCE_PUSH_FIELDS"
|
|
817
|
+
test "$RECOVERED_PUSH_REF" = "$PROJECT_RETAINED_REF" || exit 1
|
|
818
|
+
test "$RECOVERED_PUSH_SHA" = "$EVIDENCE_COMMIT" || exit 1
|
|
819
|
+
PUBLISHED_RECOVERY_JSON=$(node "$COMPLETION_RECEIPT_SCRIPT" \
|
|
820
|
+
"${RECOVERY_ARGS[@]}") || exit 1
|
|
821
|
+
PUBLISHED_RECOVERY_FIELDS=$( \
|
|
822
|
+
parse_completion_receipts "$PUBLISHED_RECOVERY_JSON"
|
|
823
|
+
) || exit 1
|
|
824
|
+
IFS=$'\t' read -r PUBLISHED_PIN_COMMIT PUBLISHED_REF_COMMIT \
|
|
825
|
+
PUBLISHED_EVIDENCE_COMMIT PUBLISHED_EVIDENCE_PUSH_REQUIRED \
|
|
826
|
+
<<< "$PUBLISHED_RECOVERY_FIELDS"
|
|
827
|
+
test "$PUBLISHED_PIN_COMMIT" = "$PROJECT_LINKS_PIN_COMMIT" || exit 1
|
|
828
|
+
test "$PUBLISHED_REF_COMMIT" = "$PROJECT_REF_COMMIT" || exit 1
|
|
829
|
+
test "$PUBLISHED_EVIDENCE_COMMIT" = "$EVIDENCE_COMMIT" || exit 1
|
|
830
|
+
test "$PUBLISHED_EVIDENCE_PUSH_REQUIRED" = "false" || exit 1
|
|
831
|
+
fi
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
When retry recognition did not set `PROJECT_REF_COMMIT`, publish the pin
|
|
835
|
+
source:
|
|
836
|
+
|
|
837
|
+
```bash
|
|
838
|
+
if [[ "$PROJECT_SCOPE" == "synced" && -z "$PROJECT_REF_COMMIT" ]]; then
|
|
839
|
+
PROJECT_PUSH_OUTPUT=$(oat project push "$PROJECT_PATH" \
|
|
840
|
+
--message "chore(oat): finalize project lifecycle" --json) || exit 1
|
|
841
|
+
PROJECT_PUSH_FIELDS=$( \
|
|
842
|
+
parse_synced_push_receipt "$PROJECT_PUSH_OUTPUT"
|
|
843
|
+
) || exit 1
|
|
844
|
+
IFS=$'\t' read -r PROJECT_RETAINED_REF PROJECT_LINKS_PIN_COMMIT \
|
|
845
|
+
<<< "$PROJECT_PUSH_FIELDS"
|
|
846
|
+
printf '%s\n' "$PROJECT_PUSH_OUTPUT"
|
|
847
|
+
fi
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
Require the structured push result to report `status: "pushed"` or
|
|
851
|
+
`status: "up-to-date"`, the retained project ref, and a full `sha`. Capture the
|
|
852
|
+
exact structured receipt SHA as `PROJECT_LINKS_PIN_COMMIT`. Never infer this
|
|
853
|
+
receipt from the parent branch, a stale local ref, or an earlier push. Verify
|
|
854
|
+
the receipt commit contains the newly created PR-description artifact when
|
|
855
|
+
Step 7 started without one, as well as every other pre-archive project artifact
|
|
856
|
+
write.
|
|
857
|
+
|
|
858
|
+
Both configured and interactive archive-decline paths continue from this exact
|
|
859
|
+
pin-source receipt into Step 8.6. The later final artifact receipt and exact
|
|
860
|
+
parent-branch record commit finish the non-archive transaction when no recap is
|
|
861
|
+
selected. With a selected recap, the evidence commit in Step 10.6 must remain
|
|
862
|
+
the immediate child of the final artifact receipt, never the preliminary pin
|
|
863
|
+
source.
|
|
864
|
+
|
|
512
865
|
### Step 8: Archive Project (Conditional)
|
|
513
866
|
|
|
514
|
-
**Skip if `SHOULD_ARCHIVE` is false or `
|
|
867
|
+
**Skip if `SHOULD_ARCHIVE` is false or `IS_DURABLE_PROJECT` is false.**
|
|
515
868
|
|
|
516
869
|
This conditional skips archive movement only; it does not skip the Step 3.7
|
|
517
870
|
seal append for an existing project log.
|
|
@@ -520,6 +873,9 @@ Archive happens after PR description generation (so artifacts are readable at tr
|
|
|
520
873
|
|
|
521
874
|
The archive-side effects in this step are CLI-owned. Do not reimplement local archive movement, summary export, S3 sync, AWS credential handling, or worktree durability checks in the skill.
|
|
522
875
|
|
|
876
|
+
Archive refuses a dirty or unpushed synced checkout. The correction is
|
|
877
|
+
`oat project push "$PROJECT_PATH"`; never discard or bypass pending artifacts.
|
|
878
|
+
|
|
523
879
|
```bash
|
|
524
880
|
ARCHIVE_OUTPUT=""
|
|
525
881
|
ARCHIVE_ARGS=("$PROJECT_PATH")
|
|
@@ -538,8 +894,14 @@ printf '%s\n' "$ARCHIVE_OUTPUT"
|
|
|
538
894
|
|
|
539
895
|
Parse `ARCHIVE_OUTPUT` as the `oat project archive --json` report. Require
|
|
540
896
|
`status: "ok"`, `mode: "apply"`, and a non-empty `archivePath`; use its
|
|
541
|
-
`s3Path`, `summaryExportFile`, and `warnings` fields for later reporting. Set
|
|
542
|
-
`ARCHIVE_PATH` from `archivePath`,
|
|
897
|
+
`s3Path`, `summaryExportFile`, `lifecycleCommit`, and `warnings` fields for later reporting. Set
|
|
898
|
+
`ARCHIVE_PATH` from `archivePath`, set `SUMMARY_EXPORT_FILE` from
|
|
899
|
+
`summaryExportFile` (empty when null), then set `PROJECT_PATH="$ARCHIVE_PATH"`.
|
|
900
|
+
|
|
901
|
+
For a synced project, require a full `lifecycleCommit` SHA in the archive
|
|
902
|
+
report and set `LIFECYCLE_COMMIT` to it. This is the parent-branch record and
|
|
903
|
+
summary-export commit owned by archive; do not replace it with
|
|
904
|
+
`git rev-parse HEAD` and do not create another lifecycle commit.
|
|
543
905
|
|
|
544
906
|
When `SELECTED_PROJECT_RECAP_RUN` is non-empty, also require the report's
|
|
545
907
|
`projectRecapExport.sourceRunRoot`, `projectRecapExport.exportRoot`, and
|
|
@@ -557,7 +919,7 @@ authoritative. A missing, malformed, mismatched, outside-root, or gitignored
|
|
|
557
919
|
export report is an archive failure; stop before lifecycle bookkeeping.
|
|
558
920
|
Never use the gitignored archive as evidence or a link target.
|
|
559
921
|
|
|
560
|
-
SELECTED_PROJECT_RECAP_RUN must be project-relative. Never add `--project-recap-run` when `SELECTED_PROJECT_RECAP_RUN` is empty. The empty case remains the existing archive behavior. Because this step runs only for
|
|
922
|
+
SELECTED_PROJECT_RECAP_RUN must be project-relative. Never add `--project-recap-run` when `SELECTED_PROJECT_RECAP_RUN` is empty. The empty case remains the existing archive behavior. Because this step runs only for durable projects, local-scope projects never pass a recap archive argument.
|
|
561
923
|
|
|
562
924
|
The no-recap invocation remains `oat project archive "$PROJECT_PATH"` with
|
|
563
925
|
`--json` added only to select the machine-readable report.
|
|
@@ -577,6 +939,113 @@ Omit either link when its containing artifact does not exist.
|
|
|
577
939
|
|
|
578
940
|
Use the current head branch for the blob URL while the PR is open. Never link to `.oat/projects/archived/`; it is gitignored and will return 404 remotely.
|
|
579
941
|
|
|
942
|
+
The final synced links block is rendered independently in Step 8.6. Do not
|
|
943
|
+
make pinned project links conditional on a recap export.
|
|
944
|
+
|
|
945
|
+
#### Step 8.6: Render Final Synced Project Links
|
|
946
|
+
|
|
947
|
+
Run this for every synced completion after the final project ref or archive SHA
|
|
948
|
+
is known. It is required even when no project recap was selected and
|
|
949
|
+
`summaryExportFile` is null.
|
|
950
|
+
|
|
951
|
+
Locate the PR-description artifact under the current `PROJECT_PATH` (which is
|
|
952
|
+
the archive path after Step 8). Render the canonical pinned block:
|
|
953
|
+
|
|
954
|
+
```bash
|
|
955
|
+
FINAL_LINK_ARGS=("$PROJECT_NAME" --format markdown)
|
|
956
|
+
if [[ -n "${SUMMARY_EXPORT_FILE:-}" ]]; then
|
|
957
|
+
test -f "$SUMMARY_EXPORT_FILE" || exit 1
|
|
958
|
+
git ls-files --error-unmatch -- "$SUMMARY_EXPORT_FILE" >/dev/null || exit 1
|
|
959
|
+
git check-ignore --quiet -- "$SUMMARY_EXPORT_FILE" && exit 1
|
|
960
|
+
SUMMARY_EXPORT_RELATIVE=$(git ls-files --full-name -- "$SUMMARY_EXPORT_FILE") || exit 1
|
|
961
|
+
[[ -n "$SUMMARY_EXPORT_RELATIVE" ]] || exit 1
|
|
962
|
+
FINAL_LINK_ARGS+=(--durable-summary "$SUMMARY_EXPORT_RELATIVE")
|
|
963
|
+
fi
|
|
964
|
+
FINAL_PROJECT_LINKS=$(oat project links "${FINAL_LINK_ARGS[@]}") || exit 1
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
Insert `FINAL_PROJECT_LINKS` when the body has no
|
|
968
|
+
`<!-- oat:project-links:start -->` block, or replace exactly the existing
|
|
969
|
+
delimited block through `<!-- oat:project-links:end -->`. Do not duplicate the
|
|
970
|
+
markers. The base invocation remains
|
|
971
|
+
`oat project links "$PROJECT_NAME" --format markdown`; add
|
|
972
|
+
`--durable-summary` only for the verified tracked export above.
|
|
973
|
+
|
|
974
|
+
For `PROJECT_SCOPE="synced"` with `SHOULD_ARCHIVE="false"`, render this block
|
|
975
|
+
in the active PR-description artifact before the push whose receipt becomes
|
|
976
|
+
`PROJECT_REF_COMMIT`. Skip the rewrite only when Step 7.5 recognized and
|
|
977
|
+
validated an already-finalized retry receipt. Otherwise publish the rendered
|
|
978
|
+
artifact with a distinct final push:
|
|
979
|
+
|
|
980
|
+
```bash
|
|
981
|
+
if [[ "$PROJECT_SCOPE" == "synced" && "$SHOULD_ARCHIVE" == "false" && \
|
|
982
|
+
-z "$PROJECT_REF_COMMIT" ]]; then
|
|
983
|
+
FINAL_PROJECT_PUSH_ARGS=("$PROJECT_PATH" \
|
|
984
|
+
--message "chore(oat): publish final project links" --json)
|
|
985
|
+
FINAL_PROJECT_PUSH_OUTPUT=$(oat project push \
|
|
986
|
+
"${FINAL_PROJECT_PUSH_ARGS[@]}") || exit 1
|
|
987
|
+
FINAL_PROJECT_PUSH_FIELDS=$( \
|
|
988
|
+
parse_synced_push_receipt "$FINAL_PROJECT_PUSH_OUTPUT"
|
|
989
|
+
) || exit 1
|
|
990
|
+
IFS=$'\t' read -r FINAL_PROJECT_PUSH_REF PROJECT_REF_COMMIT \
|
|
991
|
+
<<< "$FINAL_PROJECT_PUSH_FIELDS"
|
|
992
|
+
test "$FINAL_PROJECT_PUSH_REF" = "$PROJECT_RETAINED_REF" || exit 1
|
|
993
|
+
printf '%s\n' "$FINAL_PROJECT_PUSH_OUTPUT"
|
|
994
|
+
fi
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Require the structured result to report `status: "pushed"` or
|
|
998
|
+
`status: "up-to-date"`, the same retained project ref, and a full `sha`. Capture
|
|
999
|
+
that exact SHA as `PROJECT_REF_COMMIT`. Verify the checkout is clean, the
|
|
1000
|
+
retained remote ref equals the receipt, and the receipt contains the final
|
|
1001
|
+
PR-description artifact with exactly one links block pinned to
|
|
1002
|
+
`PROJECT_LINKS_PIN_COMMIT`. When the final render produced a commit, require
|
|
1003
|
+
its immediate parent to equal `PROJECT_LINKS_PIN_COMMIT` and require the commit
|
|
1004
|
+
to contain exactly the PR-description artifact. Never substitute the
|
|
1005
|
+
preliminary receipt for `PROJECT_REF_COMMIT` after the artifact changed.
|
|
1006
|
+
|
|
1007
|
+
Both PR paths consume this final body: when
|
|
1008
|
+
`WAS_PR_OPEN_AT_START="false"`, Step 11 creates the new PR with it; when
|
|
1009
|
+
`WAS_PR_OPEN_AT_START="true"`, Step 11.5 updates the already-open PR with it.
|
|
1010
|
+
Neither path depends on `projectRecapExport` or a configured
|
|
1011
|
+
`archive.summaryExportPath`.
|
|
1012
|
+
|
|
1013
|
+
#### Step 8.7: Non-Archive Synced Completion Transaction
|
|
1014
|
+
|
|
1015
|
+
Run this only when `PROJECT_SCOPE="synced"` and `SHOULD_ARCHIVE="false"`.
|
|
1016
|
+
The configured and interactive decline paths converge here after the finalized
|
|
1017
|
+
project tree has been pushed and `PROJECT_REF_COMMIT` has been captured.
|
|
1018
|
+
|
|
1019
|
+
Set `SYNCED_RECORD_PATH="${ACTIVE_PROJECT_PATH}.json"`; require it to be the
|
|
1020
|
+
canonical direct-child discovery record under the configured synced root and
|
|
1021
|
+
require its parsed `slug` and `ref` to match `PROJECT_NAME` and the project
|
|
1022
|
+
target. Mark the discovery record `complete` with `completedAt` using a
|
|
1023
|
+
structured JSON write that preserves the schema's other fields and the
|
|
1024
|
+
formatter-stable trailing newline. Refuse symlinks, malformed records, and any
|
|
1025
|
+
path outside that exact boundary before writing.
|
|
1026
|
+
|
|
1027
|
+
Snapshot unrelated staged state before this write. Step 10 must commit only
|
|
1028
|
+
`SYNCED_RECORD_PATH` on the parent branch with
|
|
1029
|
+
`chore(oat): complete synced project ${PROJECT_NAME}`, then verify the commit
|
|
1030
|
+
contains exactly that path and verify the unrelated staged snapshot is
|
|
1031
|
+
byte-for-byte unchanged. The retained project ref remains the artifact
|
|
1032
|
+
authority after non-archive completion. Do not remove the checkout, delete the
|
|
1033
|
+
ref, create archive exports, or set `PROJECT_PATH` to an archive location.
|
|
1034
|
+
|
|
1035
|
+
When `SELECTED_PROJECT_RECAP_RUN is empty`, the final artifact push plus exact
|
|
1036
|
+
record commit completes this transaction. When
|
|
1037
|
+
`SELECTED_PROJECT_RECAP_RUN is non-empty`, Steps 10.5 and 10.6 additionally
|
|
1038
|
+
attest the active recap within the project-ref history.
|
|
1039
|
+
|
|
1040
|
+
On retry, accept an already-complete record only after its exact-path commit is
|
|
1041
|
+
verified and the final artifact push receipt still names the retained ref SHA.
|
|
1042
|
+
If the final artifact push succeeded but the record commit did not, reuse the
|
|
1043
|
+
validated `PROJECT_LINKS_PIN_COMMIT` and `PROJECT_REF_COMMIT` receipts and retry
|
|
1044
|
+
only the record write/commit. If the record commit succeeded but recap evidence
|
|
1045
|
+
did not, reuse both receipts and retry only recap finalization. Never create a
|
|
1046
|
+
second lifecycle record commit, rerender the links against the final receipt,
|
|
1047
|
+
or rewrite either history.
|
|
1048
|
+
|
|
580
1049
|
### Step 9: Regenerate Dashboard
|
|
581
1050
|
|
|
582
1051
|
Regenerate the repo state dashboard so the completion status is reflected before committing.
|
|
@@ -588,7 +1057,7 @@ oat state refresh
|
|
|
588
1057
|
### Step 10: Commit + Push Bookkeeping (Required)
|
|
589
1058
|
|
|
590
1059
|
Completion is not done until lifecycle changes are committed. This commit also
|
|
591
|
-
anchors commit durability for a selected
|
|
1060
|
+
anchors commit durability for a selected durable-project recap. Do not push yet
|
|
592
1061
|
when recap attestation is pending.
|
|
593
1062
|
|
|
594
1063
|
Expected changes may include:
|
|
@@ -599,17 +1068,36 @@ Expected changes may include:
|
|
|
599
1068
|
- `{PROJECT_PATH}/pr/project-pr-*.md` (PR description artifact)
|
|
600
1069
|
- `.oat/state.md` is regenerated locally in Step 9 but should not be staged; it is generated dashboard state and normally gitignored.
|
|
601
1070
|
- `.oat/config.local.json` (if `activeProject` cleared)
|
|
602
|
-
- Shared-project deletions
|
|
1071
|
+
- Shared-project deletions or synced-project record updates (if archived)
|
|
603
1072
|
- The complete tracked recap export and tracked summary export reported by
|
|
604
1073
|
archive (if present)
|
|
605
1074
|
|
|
606
1075
|
Run:
|
|
607
1076
|
|
|
608
1077
|
```bash
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
1078
|
+
if [[ "$PROJECT_SCOPE" == "synced" ]]; then
|
|
1079
|
+
if [[ "$SHOULD_ARCHIVE" == "true" ]]; then
|
|
1080
|
+
test -n "$LIFECYCLE_COMMIT"
|
|
1081
|
+
else
|
|
1082
|
+
git add -- "$SYNCED_RECORD_PATH"
|
|
1083
|
+
if git diff --cached --quiet -- "$SYNCED_RECORD_PATH"; then
|
|
1084
|
+
LIFECYCLE_COMMIT=$(git log -1 --format=%H -- "$SYNCED_RECORD_PATH")
|
|
1085
|
+
node "$NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" \
|
|
1086
|
+
"$SYNCED_RECORD_PATH" "$LIFECYCLE_COMMIT" "$PROJECT_NAME" || exit 1
|
|
1087
|
+
else
|
|
1088
|
+
git commit --only "$SYNCED_RECORD_PATH" \
|
|
1089
|
+
-m "chore(oat): complete synced project ${PROJECT_NAME}" &&
|
|
1090
|
+
LIFECYCLE_COMMIT=$(git rev-parse HEAD) &&
|
|
1091
|
+
node "$NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" \
|
|
1092
|
+
"$SYNCED_RECORD_PATH" "$LIFECYCLE_COMMIT" "$PROJECT_NAME" || exit 1
|
|
1093
|
+
fi
|
|
1094
|
+
fi
|
|
1095
|
+
else
|
|
1096
|
+
git status --short
|
|
1097
|
+
git add -- <exact completion and lifecycle paths>
|
|
1098
|
+
git commit -m "chore(oat): complete project lifecycle for ${PROJECT_NAME}"
|
|
1099
|
+
LIFECYCLE_COMMIT=$(git rev-parse HEAD)
|
|
1100
|
+
fi
|
|
613
1101
|
```
|
|
614
1102
|
|
|
615
1103
|
Rules:
|
|
@@ -618,6 +1106,13 @@ Rules:
|
|
|
618
1106
|
completion/bookkeeping files. Never use a repository-wide `git add -A` when
|
|
619
1107
|
unrelated changes exist.
|
|
620
1108
|
- If there is nothing to commit, state that explicitly and verify whether the completion bookkeeping was already committed in a prior commit.
|
|
1109
|
+
- A non-archive synced lifecycle receipt is valid only when it is an ancestor
|
|
1110
|
+
of current parent-branch `HEAD`, changes exactly `SYNCED_RECORD_PATH`, and
|
|
1111
|
+
contains the current byte-identical complete record for `PROJECT_NAME` with
|
|
1112
|
+
the canonical synced ref. Missing records, unrelated paths, stale content,
|
|
1113
|
+
cross-project receipts, and non-ancestor commits fail closed. Validate both
|
|
1114
|
+
recovered and freshly created lifecycle commit SHAs before continuing; a
|
|
1115
|
+
failed commit or hook must not reuse the prior `HEAD` as a receipt.
|
|
621
1116
|
- The lifecycle bookkeeping commit is the artifact commit for final recap
|
|
622
1117
|
durability. It must contain the final run's immutable paths.
|
|
623
1118
|
- Snapshot unrelated working-tree changes before finalization so the shared
|
|
@@ -625,9 +1120,11 @@ Rules:
|
|
|
625
1120
|
|
|
626
1121
|
### Step 10.5: Re-attest Final Project Recap
|
|
627
1122
|
|
|
628
|
-
Skip when no final recap was selected, for local-scope projects,
|
|
1123
|
+
Skip when no final recap was selected, for local-scope projects, when the
|
|
629
1124
|
selected recap is already durable solely through independently verified publish
|
|
630
|
-
evidence.
|
|
1125
|
+
evidence, or when Step 7.5 restored an exact `EVIDENCE_COMMIT`. In the recovered
|
|
1126
|
+
evidence case, verify the selected run's manifest and build record are the two
|
|
1127
|
+
exact paths in that commit and continue without re-attesting or rewriting them.
|
|
631
1128
|
|
|
632
1129
|
For an archived recap, consume the exact `projectRecapExport` values recorded
|
|
633
1130
|
in Step 8. Plan finalization through
|
|
@@ -641,8 +1138,14 @@ with:
|
|
|
641
1138
|
- relocatedFrom: `sourceRunRoot`; and
|
|
642
1139
|
- context `artifactCommit`: the full `LIFECYCLE_COMMIT` SHA.
|
|
643
1140
|
|
|
644
|
-
For a
|
|
645
|
-
omit `relocatedFrom`, but keep the same `completion-bookkeeping` mode.
|
|
1141
|
+
For a durable project that was not archived, use the selected active run and
|
|
1142
|
+
omit `relocatedFrom`, but keep the same `completion-bookkeeping` mode. Resolve
|
|
1143
|
+
the finalizer repository root as `ACTIVE_PROJECT_PATH`, not the parent
|
|
1144
|
+
checkout. Use `PROJECT_REF_COMMIT`, not the parent-branch `LIFECYCLE_COMMIT`,
|
|
1145
|
+
as the active recap artifact commit. Its immutable paths must be present in
|
|
1146
|
+
that exact project-ref commit. The parent record commit is separate durability
|
|
1147
|
+
evidence for discovery and must never be substituted into the project-ref
|
|
1148
|
+
history.
|
|
646
1149
|
|
|
647
1150
|
When the finalization plan is `complete` with `built-needs-review` or `failed`,
|
|
648
1151
|
preserve that exact outcome and skip both attestation and the evidence commit.
|
|
@@ -650,7 +1153,9 @@ These evidence-only plans are already complete for lifecycle retention and
|
|
|
650
1153
|
remain unpublishable. Call `verifyTrackedRunFinalization(...)` on the complete
|
|
651
1154
|
plan; it must not promote either outcome to `built-durable`.
|
|
652
1155
|
|
|
653
|
-
|
|
1156
|
+
For archive completion, the lifecycle bookkeeping commit is the artifact
|
|
1157
|
+
commit. For non-archive synced completion, `PROJECT_REF_COMMIT` is the artifact
|
|
1158
|
+
commit. Call the compatible
|
|
654
1159
|
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
|
|
655
1160
|
must not appear in that evidence path list. The successful exported-path
|
|
656
1161
|
attestation supersedes the prior active-path evidence. Verify the resulting
|
|
@@ -666,7 +1171,7 @@ details, and continue to the evidence commit.
|
|
|
666
1171
|
|
|
667
1172
|
### Step 10.6: Commit Evidence + Push
|
|
668
1173
|
|
|
669
|
-
When Step 10.5 ran
|
|
1174
|
+
When Step 10.5 ran and Step 7.5 did not restore `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
|
|
670
1175
|
`verifyTrackedRunFinalization(...)` with the artifact commit, immediate evidence
|
|
671
1176
|
commit parent/order, exact evidence paths, attestation outcome, and unchanged
|
|
672
1177
|
unrelated-change snapshots.
|
|
@@ -681,6 +1186,60 @@ ran, push the lifecycle bookkeeping commit once. If verification detects
|
|
|
681
1186
|
contamination or wrong commit order, do not push. If push fails, report the
|
|
682
1187
|
failure and do not claim completion is fully recorded.
|
|
683
1188
|
|
|
1189
|
+
The evidence update remains a direct, exact-path Git commit. Stage only the
|
|
1190
|
+
reported exported `manifest.json` and `build-record.json` under tracked
|
|
1191
|
+
`.oat/repo/reference/project-recaps/`:
|
|
1192
|
+
|
|
1193
|
+
```bash
|
|
1194
|
+
UNRELATED_STAGED_PATCH_BEFORE=$(git diff --cached --binary)
|
|
1195
|
+
git add -- "$EXPORTED_MANIFEST_PATH" "$EXPORTED_BUILD_RECORD_PATH"
|
|
1196
|
+
git commit --only -m "chore(oat): attest final project recap" -- \
|
|
1197
|
+
"$EXPORTED_MANIFEST_PATH" "$EXPORTED_BUILD_RECORD_PATH"
|
|
1198
|
+
EVIDENCE_COMMIT=$(git rev-parse HEAD)
|
|
1199
|
+
test "$(git rev-parse "$EVIDENCE_COMMIT^")" = "$LIFECYCLE_COMMIT"
|
|
1200
|
+
test "$(git diff --cached --binary)" = "$UNRELATED_STAGED_PATCH_BEFORE"
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
Verify the evidence commit contains exactly those two paths, the lifecycle
|
|
1204
|
+
commit is its immediate parent, unrelated-change snapshots remain unchanged,
|
|
1205
|
+
and then push once. The archive command does not own this evidence transition;
|
|
1206
|
+
use the direct exact-path commit above.
|
|
1207
|
+
|
|
1208
|
+
For a non-archive synced recap, stage and commit only the active run's reported
|
|
1209
|
+
`manifest.json` and `build-record.json` from inside `ACTIVE_PROJECT_PATH`. The
|
|
1210
|
+
non-archive recap evidence commit must be the immediate child of
|
|
1211
|
+
`PROJECT_REF_COMMIT` in the project checkout. Verify exact commit containment
|
|
1212
|
+
and the unchanged unrelated-state snapshot, then publish the evidence commit
|
|
1213
|
+
with `oat project push`, retaining the custom ref and checkout. Require the
|
|
1214
|
+
push receipt SHA to equal the evidence commit. Recovery reuses the existing
|
|
1215
|
+
project-ref artifact commit and parent-branch record commit; it never moves
|
|
1216
|
+
active recap files into archive-export paths.
|
|
1217
|
+
|
|
1218
|
+
Use the same path-confined commit inside the synced checkout:
|
|
1219
|
+
|
|
1220
|
+
```bash
|
|
1221
|
+
ACTIVE_MANIFEST_RELATIVE_PATH="$SELECTED_PROJECT_RECAP_RUN/manifest.json"
|
|
1222
|
+
ACTIVE_BUILD_RECORD_RELATIVE_PATH="$SELECTED_PROJECT_RECAP_RUN/build-record.json"
|
|
1223
|
+
UNRELATED_PROJECT_STAGE_BEFORE=$(git -C "$ACTIVE_PROJECT_PATH" diff --cached --binary)
|
|
1224
|
+
git -C "$ACTIVE_PROJECT_PATH" add -- \
|
|
1225
|
+
"$ACTIVE_MANIFEST_RELATIVE_PATH" "$ACTIVE_BUILD_RECORD_RELATIVE_PATH"
|
|
1226
|
+
git -C "$ACTIVE_PROJECT_PATH" commit --only \
|
|
1227
|
+
-m "chore(oat): attest final project recap" -- \
|
|
1228
|
+
"$ACTIVE_MANIFEST_RELATIVE_PATH" "$ACTIVE_BUILD_RECORD_RELATIVE_PATH"
|
|
1229
|
+
EVIDENCE_COMMIT=$(git -C "$ACTIVE_PROJECT_PATH" rev-parse HEAD)
|
|
1230
|
+
test "$(git -C "$ACTIVE_PROJECT_PATH" rev-parse "$EVIDENCE_COMMIT^")" = \
|
|
1231
|
+
"$PROJECT_REF_COMMIT"
|
|
1232
|
+
test "$(git -C "$ACTIVE_PROJECT_PATH" diff --cached --binary)" = \
|
|
1233
|
+
"$UNRELATED_PROJECT_STAGE_BEFORE"
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
When Step 7.5 restored `EVIDENCE_COMMIT`, do not stage or commit recap records
|
|
1237
|
+
again. Require the retained remote ref to equal that exact evidence SHA, keep
|
|
1238
|
+
its immediate parent equal to `PROJECT_REF_COMMIT`, and preserve the recovered
|
|
1239
|
+
`PROJECT_LINKS_PIN_COMMIT`. The parent discovery-record commit remains confined
|
|
1240
|
+
to its one canonical path, and all unrelated staged-state snapshots must remain
|
|
1241
|
+
byte-for-byte unchanged.
|
|
1242
|
+
|
|
684
1243
|
### Step 11: Open PR in GitHub (Conditional)
|
|
685
1244
|
|
|
686
1245
|
**Skip if `SHOULD_OPEN_PR` is false.**
|
|
@@ -705,19 +1264,32 @@ Do not assume `gh` is installed; if missing, instruct manual PR creation using t
|
|
|
705
1264
|
|
|
706
1265
|
### Step 11.5: Sync Open-PR Description on GitHub (Conditional)
|
|
707
1266
|
|
|
708
|
-
**Run only when `WAS_PR_OPEN_AT_START="true"`
|
|
1267
|
+
**Run only when `WAS_PR_OPEN_AT_START="true"` and either
|
|
1268
|
+
`SHOULD_ARCHIVE="true"` or `PROJECT_SCOPE="synced"`.**
|
|
709
1269
|
|
|
710
|
-
When the PR was already open at the start
|
|
1270
|
+
When the PR was already open at the start, push the final validated completion
|
|
1271
|
+
body to the existing PR. Archive completion uses the regenerated archive-aware
|
|
1272
|
+
body. Non-archive synced completion uses the exact PR artifact from
|
|
1273
|
+
`PROJECT_REF_COMMIT`, whose canonical links block is owned by
|
|
1274
|
+
`PROJECT_LINKS_PIN_COMMIT`; do not substitute the parent discovery-record
|
|
1275
|
+
commit or the optional evidence child.
|
|
711
1276
|
|
|
712
1277
|
Skip this step when:
|
|
713
1278
|
|
|
714
1279
|
- The PR was not yet open at the start (`WAS_PR_OPEN_AT_START="false"`) — Step 11 already created the PR with the archive-aware body.
|
|
715
|
-
- No archive happened
|
|
716
|
-
|
|
1280
|
+
- No archive happened and the project is not synced — no final retained-ref
|
|
1281
|
+
body was published.
|
|
1282
|
+
- `IS_DURABLE_PROJECT="false"` — local projects are not archived in this skill, so no link breakage.
|
|
717
1283
|
|
|
718
1284
|
Steps:
|
|
719
1285
|
|
|
720
|
-
1. Locate the PR description artifact
|
|
1286
|
+
1. Locate the exact PR description artifact. After archive, use
|
|
1287
|
+
`{ARCHIVE_PATH}/pr/project-pr-*.md`. For non-archive synced completion, use
|
|
1288
|
+
`PR_DESCRIPTION_PATH`, require the retained remote ref to contain
|
|
1289
|
+
`PROJECT_REF_COMMIT`, and require
|
|
1290
|
+
`git show "$PROJECT_REF_COMMIT:$PR_DESCRIPTION_RELATIVE_PATH"` to equal the
|
|
1291
|
+
body on disk with exactly one links block pinned to
|
|
1292
|
+
`PROJECT_LINKS_PIN_COMMIT`.
|
|
721
1293
|
2. Strip YAML frontmatter (everything from the opening `---` through and including the closing `---`) and write the result to a temporary file. Verify the temp file does not start with YAML frontmatter keys.
|
|
722
1294
|
3. Resolve the open PR. Prefer the tracked URL captured in Step 2:
|
|
723
1295
|
|