@open-agent-toolkit/cli 0.2.73 → 0.2.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +3 -56
  3. package/assets/docs/cli-utilities/tool-packs.md +4 -4
  4. package/assets/docs/contributing/code.md +2 -2
  5. package/assets/docs/contributing/index.md +0 -1
  6. package/assets/docs/reference/cli-reference.md +1 -1
  7. package/assets/docs/reference/troubleshooting.md +17 -40
  8. package/assets/docs/workflows/projects/artifacts.md +16 -34
  9. package/assets/docs/workflows/projects/lifecycle.md +20 -19
  10. package/assets/docs/workflows/skills/explainer-kit.md +180 -440
  11. package/assets/docs/workflows/skills/index.md +1 -2
  12. package/assets/public-package-versions.json +4 -4
  13. package/assets/skills/explainer-kit/SKILL.md +96 -171
  14. package/assets/skills/explainer-kit/recipes/engineer-tour.json +1 -22
  15. package/assets/skills/explainer-kit/recipes/program-recap.json +1 -29
  16. package/assets/skills/explainer-kit/recipes/project-explainer.json +1 -22
  17. package/assets/skills/explainer-kit/recipes/project-recap.v2.json +1 -43
  18. package/assets/skills/explainer-kit/references/fact-base-contract.md +76 -101
  19. package/assets/skills/explainer-kit/references/recap-authoring.md +99 -0
  20. package/assets/skills/explainer-kit/schemas/manifest.schema.json +13 -135
  21. package/assets/skills/explainer-kit/scripts/bundle.mjs +712 -0
  22. package/assets/skills/explainer-kit/scripts/lib/claim-subject.mjs +40 -0
  23. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +113 -1504
  24. package/assets/skills/explainer-kit/scripts/lib/failure.mjs +13 -0
  25. package/assets/skills/explainer-kit/scripts/lib/package-coverage.mjs +57 -403
  26. package/assets/skills/explainer-kit/scripts/lib/qa-result.mjs +168 -0
  27. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +90 -488
  28. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +28 -545
  29. package/assets/skills/explainer-kit/scripts/lib/run-package.mjs +120 -0
  30. package/assets/skills/explainer-kit/scripts/lib/sanitize.mjs +42 -0
  31. package/assets/skills/explainer-kit/scripts/record.mjs +335 -0
  32. package/assets/skills/explainer-kit/scripts/verify.mjs +648 -0
  33. package/assets/skills/oat-explainer-kit/SKILL.md +57 -117
  34. package/assets/skills/oat-explainer-kit/references/config-contract.md +20 -64
  35. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +85 -237
  36. package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +18 -10
  37. package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +1 -0
  38. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +256 -21
  39. package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +82 -3
  40. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +0 -162
  41. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +57 -123
  42. package/assets/skills/oat-project-autonomous/SKILL.md +14 -13
  43. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +165 -165
  44. package/assets/skills/oat-project-complete/SKILL.md +168 -349
  45. package/assets/skills/oat-project-complete/scripts/consume-persisted-recap-intent.mjs +125 -0
  46. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +0 -30
  47. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +4 -37
  48. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +17 -16
  49. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +9 -174
  50. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +1 -2
  51. package/assets/skills/oat-project-document/SKILL.md +1 -1
  52. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +165 -165
  53. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  54. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +44 -56
  55. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +165 -165
  56. package/assets/skills/oat-project-lite/SKILL.md +1 -1
  57. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +165 -165
  58. package/assets/skills/oat-project-plan/SKILL.md +5 -6
  59. package/assets/skills/oat-project-pr-final/SKILL.md +1 -1
  60. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +165 -165
  61. package/assets/skills/oat-project-quick-start/SKILL.md +1 -1
  62. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +165 -165
  63. package/assets/skills/oat-project-summary/SKILL.md +35 -25
  64. package/assets/skills/oat-wave-execute/SKILL.md +11 -36
  65. package/assets/skills/oat-wave-program/SKILL.md +13 -37
  66. package/dist/commands/config/index.d.ts.map +1 -1
  67. package/dist/commands/config/index.js +9 -113
  68. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  69. package/dist/commands/project/archive/archive-utils.js +32 -184
  70. package/dist/commands/project/archive/explainer-package-coverage.d.ts +3 -8
  71. package/dist/commands/project/archive/explainer-package-coverage.d.ts.map +1 -1
  72. package/dist/commands/project/archive/explainer-package-coverage.js +1 -1
  73. package/dist/config/oat-config.d.ts +0 -11
  74. package/dist/config/oat-config.d.ts.map +1 -1
  75. package/dist/config/oat-config.js +0 -34
  76. package/dist/config/resolve.d.ts.map +1 -1
  77. package/dist/config/resolve.js +0 -8
  78. package/dist/release/public-package-contract.d.ts.map +1 -1
  79. package/dist/release/public-package-contract.js +2 -10
  80. package/dist/validation/project-state.d.ts.map +1 -1
  81. package/dist/validation/project-state.js +42 -3
  82. package/package.json +2 -2
  83. package/assets/docs/contributing/explainer-kit-verification.md +0 -133
  84. package/assets/docs/workflows/skills/explainer-kit-providers.md +0 -155
  85. package/assets/skills/explainer-kit/briefs/deep-dive.md +0 -35
  86. package/assets/skills/explainer-kit/briefs/project-page.md +0 -38
  87. package/assets/skills/explainer-kit/briefs/supporting-diagram.md +0 -28
  88. package/assets/skills/explainer-kit/briefs/walkthrough-deck.md +0 -35
  89. package/assets/skills/explainer-kit/examples/project-explainer/content.md +0 -31
  90. package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +0 -22
  91. package/assets/skills/explainer-kit/examples/project-recap/content.md +0 -77
  92. package/assets/skills/explainer-kit/examples/project-recap/fact-base.json +0 -104
  93. package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +0 -44
  94. package/assets/skills/explainer-kit/examples/theme-bundle.json +0 -87
  95. package/assets/skills/explainer-kit/recipes/project-recap.v1.json +0 -93
  96. package/assets/skills/explainer-kit/references/contracts.md +0 -324
  97. package/assets/skills/explainer-kit/references/destination-contract.md +0 -210
  98. package/assets/skills/explainer-kit/references/extension-contract.md +0 -80
  99. package/assets/skills/explainer-kit/references/golden-conformance.md +0 -80
  100. package/assets/skills/explainer-kit/references/visual-review.md +0 -71
  101. package/assets/skills/explainer-kit/schemas/author-request.v2.schema.json +0 -212
  102. package/assets/skills/explainer-kit/schemas/author-request.v3.schema.json +0 -241
  103. package/assets/skills/explainer-kit/schemas/author-result.v2.schema.json +0 -52
  104. package/assets/skills/explainer-kit/schemas/build-record.schema.json +0 -98
  105. package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +0 -53
  106. package/assets/skills/explainer-kit/schemas/publish-receipt.v1.schema.json +0 -97
  107. package/assets/skills/explainer-kit/schemas/publish-receipt.v2.schema.json +0 -215
  108. package/assets/skills/explainer-kit/schemas/publish-request.v1.schema.json +0 -32
  109. package/assets/skills/explainer-kit/schemas/publish-request.v2.schema.json +0 -34
  110. package/assets/skills/explainer-kit/schemas/run-request.schema.json +0 -147
  111. package/assets/skills/explainer-kit/schemas/set-plan.v1.schema.json +0 -149
  112. package/assets/skills/explainer-kit/schemas/terminal-evidence.v1.schema.json +0 -81
  113. package/assets/skills/explainer-kit/schemas/visual-review-evidence.v1.schema.json +0 -66
  114. package/assets/skills/explainer-kit/schemas/visual-review-request.v1.schema.json +0 -117
  115. package/assets/skills/explainer-kit/schemas/visual-review-result.v1.schema.json +0 -80
  116. package/assets/skills/explainer-kit/scripts/lib/catalog.mjs +0 -349
  117. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +0 -418
  118. package/assets/skills/explainer-kit/scripts/lib/diagram.mjs +0 -514
  119. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +0 -643
  120. package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +0 -664
  121. package/assets/skills/explainer-kit/scripts/lib/internal-references.mjs +0 -538
  122. package/assets/skills/explainer-kit/scripts/lib/markdown.mjs +0 -414
  123. package/assets/skills/explainer-kit/scripts/lib/publication-policy.mjs +0 -54
  124. package/assets/skills/explainer-kit/scripts/lib/records.mjs +0 -954
  125. package/assets/skills/explainer-kit/scripts/lib/render.mjs +0 -703
  126. package/assets/skills/explainer-kit/scripts/lib/s3-roots.mjs +0 -353
  127. package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +0 -759
  128. package/assets/skills/explainer-kit/scripts/lib/set-plan.mjs +0 -209
  129. package/assets/skills/explainer-kit/scripts/lib/source-backlinks.mjs +0 -218
  130. package/assets/skills/explainer-kit/scripts/lib/terminal-evidence.mjs +0 -157
  131. package/assets/skills/explainer-kit/scripts/lib/visual-review.mjs +0 -400
  132. package/assets/skills/explainer-kit/scripts/publish.mjs +0 -76
  133. package/assets/skills/explainer-kit/scripts/record-durability.mjs +0 -64
  134. package/assets/skills/explainer-kit/scripts/render-qa.mjs +0 -461
  135. package/assets/skills/explainer-kit/scripts/run.mjs +0 -3038
  136. package/assets/skills/explainer-kit/scripts/validate.mjs +0 -59
  137. package/assets/skills/oat-explainer-kit/references/author-callback.md +0 -53
  138. package/assets/skills/oat-explainer-kit/references/migration.md +0 -144
  139. package/assets/skills/oat-explainer-kit/references/visual-review-callback.md +0 -83
  140. package/assets/skills/oat-explainer-kit/scripts/derive-destination.mjs +0 -91
  141. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +0 -531
  142. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +0 -371
  143. package/assets/skills/oat-explainer-kit/scripts/run.mjs +0 -905
  144. package/dist/commands/project/archive/explainer-source-backlinks.d.ts +0 -18
  145. package/dist/commands/project/archive/explainer-source-backlinks.d.ts.map +0 -1
  146. package/dist/commands/project/archive/explainer-source-backlinks.js +0 -27
  147. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts +0 -29
  148. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts.map +0 -1
  149. package/dist/commands/project/archive/explainer-terminal-evidence.js +0 -37
@@ -1,5 +1,3 @@
1
- import { RECAP_PROBE_CODES, RECAP_SEAM_IDS } from './probe-recap-seams.mjs';
2
-
3
1
  const PRODUCTS = new Set(['projectExplainer', 'projectRecap']);
4
2
  const MODES = new Set(['interactive', 'autonomous']);
5
3
  const PREFERENCES = new Set(['always', 'ask', 'never']);
@@ -9,6 +7,7 @@ const SOURCES = new Set([
9
7
  'kickoff_prompt',
10
8
  'autonomous_policy',
11
9
  'capability_probe',
10
+ 'failed_attempt',
12
11
  ]);
13
12
  const ALLOWED_PAIRS = Object.freeze({
14
13
  projectExplainer: new Set([
@@ -21,10 +20,18 @@ const ALLOWED_PAIRS = Object.freeze({
21
20
  'skip:interactive',
22
21
  'generate:autonomous_policy',
23
22
  'skip:capability_probe',
23
+ 'skip:failed_attempt',
24
24
  ]),
25
25
  });
26
26
  const ISO_TIMESTAMP_PATTERN =
27
27
  /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
28
+ const INTENT_RECORD_KEYS = new Set([
29
+ 'decision',
30
+ 'source',
31
+ 'decided_at',
32
+ 'failed_attempt_evidence',
33
+ ]);
34
+ const RUN_SLUG_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
28
35
 
29
36
  export function resolveIntent({
30
37
  product,
@@ -33,7 +40,6 @@ export function resolveIntent({
33
40
  preference,
34
41
  kickoffRequest = false,
35
42
  answer,
36
- seamProbe,
37
43
  now = new Date().toISOString(),
38
44
  }) {
39
45
  assertProduct(product);
@@ -48,20 +54,6 @@ export function resolveIntent({
48
54
  if (typeof kickoffRequest !== 'boolean') {
49
55
  throw new TypeError('kickoffRequest must be a boolean.');
50
56
  }
51
- if (seamProbe !== undefined) {
52
- assertSeamProbe(seamProbe);
53
- if (product !== 'projectRecap') {
54
- throw new Error(
55
- 'Seam probe results apply only to projectRecap resolution.',
56
- );
57
- }
58
- if (mode !== 'autonomous') {
59
- throw new Error(
60
- 'Seam probe results apply only to autonomous projectRecap resolution.',
61
- );
62
- }
63
- }
64
-
65
57
  if (mode === 'autonomous') {
66
58
  if (answer !== undefined) {
67
59
  throw new Error('Autonomous lifecycle intent cannot use an answer.');
@@ -71,7 +63,6 @@ export function resolveIntent({
71
63
  state,
72
64
  preference,
73
65
  kickoffRequest,
74
- seamProbe,
75
66
  now,
76
67
  });
77
68
  }
@@ -130,12 +121,9 @@ export function validateIntentRecord(product, record) {
130
121
  throw new TypeError(`${product} intent must be a decision record.`);
131
122
  }
132
123
  const keys = Object.keys(record);
133
- if (
134
- keys.length !== 3 ||
135
- keys.some((key) => !['decision', 'source', 'decided_at'].includes(key))
136
- ) {
124
+ if (keys.some((key) => !INTENT_RECORD_KEYS.has(key))) {
137
125
  throw new Error(
138
- `${product} intent must contain only decision, source, and decided_at.`,
126
+ `${product} intent contains an unsupported lifecycle decision field.`,
139
127
  );
140
128
  }
141
129
  if (!DECISIONS.has(record.decision)) {
@@ -150,9 +138,54 @@ export function validateIntentRecord(product, record) {
150
138
  );
151
139
  }
152
140
  assertTimestamp(record.decided_at);
141
+ const isFailedAttempt =
142
+ product === 'projectRecap' &&
143
+ record.decision === 'skip' &&
144
+ record.source === 'failed_attempt';
145
+ if (isFailedAttempt) {
146
+ validateFailedAttemptEvidenceLocator(record.failed_attempt_evidence);
147
+ } else if (Object.hasOwn(record, 'failed_attempt_evidence')) {
148
+ throw new Error(
149
+ 'failed_attempt_evidence is allowed only for projectRecap skip/failed_attempt.',
150
+ );
151
+ }
153
152
  return record;
154
153
  }
155
154
 
155
+ export function validateWritableIntentRecord(product, record) {
156
+ validateIntentRecord(product, record);
157
+ if (
158
+ product === 'projectRecap' &&
159
+ record.decision === 'skip' &&
160
+ record.source === 'capability_probe'
161
+ ) {
162
+ throw new Error(
163
+ 'projectRecap skip/capability_probe is a read-only legacy intent.',
164
+ );
165
+ }
166
+ return record;
167
+ }
168
+
169
+ export function validateFailedAttemptEvidenceLocator(value) {
170
+ if (typeof value !== 'string') {
171
+ throw new Error(
172
+ 'projectRecap skip/failed_attempt requires failed_attempt_evidence.',
173
+ );
174
+ }
175
+ const parts = value.split('/');
176
+ if (
177
+ parts.length !== 3 ||
178
+ parts[0] !== 'explainers' ||
179
+ !RUN_SLUG_PATTERN.test(parts[1]) ||
180
+ !['manifest.json', 'failure.json'].includes(parts[2])
181
+ ) {
182
+ throw new Error(
183
+ 'failed_attempt_evidence must be explainers/<run-slug>/manifest.json or explainers/<run-slug>/failure.json.',
184
+ );
185
+ }
186
+ return value;
187
+ }
188
+
156
189
  export function explainerModeForIntent(intent) {
157
190
  if (
158
191
  !intent ||
@@ -172,30 +205,10 @@ function resolveAutonomous({
172
205
  state,
173
206
  preference,
174
207
  kickoffRequest,
175
- seamProbe,
176
208
  now,
177
209
  }) {
178
210
  if (product === 'projectRecap') {
179
211
  const warnings = [];
180
- if (seamProbe !== undefined && seamProbe.ok !== true) {
181
- if (seamProbe.code !== 'seams-unavailable') {
182
- const error = new Error(
183
- `Project recap seams are configured but invalid, so the recap fails closed rather than resolving a capability skip: ${seamProbe.message ?? seamProbe.code}`,
184
- );
185
- error.code = 'E_RECAP_SEAMS_INVALID';
186
- throw error;
187
- }
188
- warnings.push(
189
- `Autonomous project recap skipped: no provider is configured for ${formatSeams(seamProbe.missing)}.`,
190
- );
191
- return result(
192
- product,
193
- 'skip',
194
- 'capability_probe',
195
- createRecord(product, 'skip', 'capability_probe', now),
196
- warnings,
197
- );
198
- }
199
212
  if (state?.decision === 'skip') {
200
213
  warnings.push(
201
214
  'Autonomous project recap policy overrode a lower-precedence skip decision.',
@@ -228,7 +241,7 @@ function resolveAutonomous({
228
241
 
229
242
  function createRecord(product, decision, source, now) {
230
243
  const record = { decision, source, decided_at: now };
231
- validateIntentRecord(product, record);
244
+ validateWritableIntentRecord(product, record);
232
245
  return record;
233
246
  }
234
247
 
@@ -249,85 +262,6 @@ function result(
249
262
  };
250
263
  }
251
264
 
252
- /**
253
- * A seam probe result is a decision input, so a malformed one must fail rather
254
- * than silently degrade into either a skip or a forced generate.
255
- */
256
- function assertSeamProbe(seamProbe) {
257
- if (
258
- !seamProbe ||
259
- typeof seamProbe !== 'object' ||
260
- Array.isArray(seamProbe) ||
261
- typeof seamProbe.ok !== 'boolean' ||
262
- !RECAP_PROBE_CODES.includes(seamProbe.code)
263
- ) {
264
- throw new TypeError(
265
- 'seamProbe must be a probeRecapSeams result with ok and a known code.',
266
- );
267
- }
268
- // A recap that runs from this decision runs unattended, so an interactive
269
- // probe is the wrong evidence: it checks only the author and critic and would
270
- // report a host with no set planner as fully available.
271
- if (seamProbe.mode !== 'unattended') {
272
- throw new TypeError(
273
- 'seamProbe must come from an unattended probe of the recap seams.',
274
- );
275
- }
276
- if (
277
- !Array.isArray(seamProbe.missing) ||
278
- !Array.isArray(seamProbe.invalid) ||
279
- !Array.isArray(seamProbe.resolved)
280
- ) {
281
- throw new TypeError(
282
- 'seamProbe must partition the canonical recap seams into missing, invalid, and resolved.',
283
- );
284
- }
285
- // Enforce the partition this message promises: every canonical seam appears
286
- // in exactly one bucket. Without the disjointness and coverage checks, a
287
- // forged result can claim a seam is both missing and resolved (yielding a
288
- // capability skip the probe would never emit), or pad `resolved` with
289
- // duplicates of one seam to fake full availability and force a generate.
290
- const claimed = [
291
- ...seamProbe.missing,
292
- ...seamProbe.invalid.map((entry) => entry?.seam),
293
- ...seamProbe.resolved,
294
- ];
295
- const distinct = new Set(claimed);
296
- if (
297
- distinct.size !== claimed.length ||
298
- distinct.size !== RECAP_SEAM_IDS.length ||
299
- !RECAP_SEAM_IDS.every((seam) => distinct.has(seam))
300
- ) {
301
- throw new TypeError(
302
- 'seamProbe must partition the canonical recap seams into missing, invalid, and resolved.',
303
- );
304
- }
305
- // The result is a discriminated union, so each code must carry exactly the
306
- // evidence it claims. A half-populated object must never reach the skip
307
- // branch and forge a capability skip out of an invalid seam.
308
- const consistent =
309
- seamProbe.code === 'seams-ok'
310
- ? seamProbe.ok === true &&
311
- seamProbe.missing.length === 0 &&
312
- seamProbe.invalid.length === 0 &&
313
- seamProbe.resolved.length === RECAP_SEAM_IDS.length
314
- : seamProbe.ok === false &&
315
- (seamProbe.code === 'seams-unavailable'
316
- ? seamProbe.missing.length > 0 && seamProbe.invalid.length === 0
317
- : seamProbe.invalid.length > 0);
318
- if (!consistent) {
319
- throw new TypeError(
320
- 'An unsatisfied seamProbe must list the seams its code claims.',
321
- );
322
- }
323
- }
324
-
325
- function formatSeams(seams) {
326
- if (!Array.isArray(seams) || seams.length === 0) return 'a required seam';
327
- if (seams.length === 1) return seams[0];
328
- return `${seams.slice(0, -1).join(', ')} and ${seams.at(-1)}`;
329
- }
330
-
331
265
  function assertProduct(product) {
332
266
  if (!PRODUCTS.has(product)) {
333
267
  throw new Error(`Unsupported lifecycle product: ${String(product)}`);
@@ -6,7 +6,7 @@ disable-model-invocation: true
6
6
  user-invocable: true
7
7
  allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, Task
8
8
  metadata:
9
- version: 1.0.14
9
+ version: 1.0.15
10
10
  ---
11
11
 
12
12
  # Autonomous OAT Project
@@ -264,18 +264,19 @@ existing project is resolved, use the `oat-explainer-kit` lifecycle intent
264
264
  resolver and persistence helper against that project's `state.md`.
265
265
 
266
266
  Resolve and persist `projectRecap` as `generate` with source `autonomous_policy` after project creation or resolution.
267
- Reassert this forced recap intent on resume; a stale lower-precedence skip is overridden, warned, and recorded.
268
- The autonomous mode policy has precedence over project state and workflow
269
- preference, so `never` does not suppress the recap.
270
-
271
- Kickoff persists the forced `generate` intent without probing seams, because the
272
- host that runs the recap is the one that matters and closeout is where it runs.
273
- The closeout recap gate probes seam availability and may resolve a recordable
274
- `skip` with source `capability_probe` on a host where a required seam is
275
- unavailable. That later capability skip is the only thing that overrides this
276
- forced intent, it is decided before any run rather than from a failed one, and
277
- it never blocks unattended completion. Do not reassert `generate` over a
278
- recorded `capability_probe` skip within the same closeout.
267
+ Reassert this forced recap intent on resume unless closeout already persisted
268
+ `skip/failed_attempt`. The autonomous mode policy has precedence over workflow
269
+ preference, so `never` does not suppress the initial recap attempt.
270
+
271
+ Kickoff persists the forced `generate` intent. At closeout, invoke
272
+ `oat-explainer-kit` § Generate with recipe `project-recap`. If the terminal
273
+ outcome is `failed` or `incomplete`, make one retry. If that retry also fails,
274
+ persist `skip/failed_attempt` with `failed_attempt_evidence` naming that run's
275
+ project-relative failed or incomplete `manifest.json`, or its `failure.json`
276
+ when recording did not occur, and continue unattended closeout. On resume, use
277
+ the completion consumer's containment-checked proof and honor that persisted
278
+ skip without another bundle or authoring pass; do not reassert `generate` over
279
+ it.
279
280
 
280
281
  Resolve and persist `projectExplainer` as `generate` with source `kickoff_prompt` only when the kickoff request explicitly asks for a project explainer.
281
282
  A general autonomous goal, project creation, or normal planning does not count as an explainer request.