@deftai/directive-core 0.103.0 → 0.105.0

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 (255) hide show
  1. package/dist/authz/classify.js +682 -35
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/gate-lists.d.ts +3 -2
  5. package/dist/check/gate-lists.js +5 -2
  6. package/dist/check/index.d.ts +1 -0
  7. package/dist/check/index.js +1 -0
  8. package/dist/check/named-cause.d.ts +1 -1
  9. package/dist/check/named-cause.js +33 -3
  10. package/dist/check/session-completed-ac.d.ts +39 -0
  11. package/dist/check/session-completed-ac.js +198 -0
  12. package/dist/codebase/default-extractor.d.ts +5 -0
  13. package/dist/codebase/default-extractor.js +7 -15
  14. package/dist/deposit/copy-tree.js +60 -0
  15. package/dist/deposit/python-free.js +26 -18
  16. package/dist/doctor/checks.d.ts +8 -0
  17. package/dist/doctor/checks.js +37 -25
  18. package/dist/doctor/doctor-state.d.ts +4 -0
  19. package/dist/doctor/doctor-state.js +7 -1
  20. package/dist/doctor/main.js +9 -14
  21. package/dist/doctor/types.d.ts +9 -0
  22. package/dist/fs/contained-write.d.ts +115 -1
  23. package/dist/fs/contained-write.js +242 -5
  24. package/dist/fs/mutation-ledger.d.ts +54 -0
  25. package/dist/fs/mutation-ledger.js +133 -0
  26. package/dist/fs/non-product-dirs.d.ts +79 -0
  27. package/dist/fs/non-product-dirs.js +96 -0
  28. package/dist/hooks/dispatcher.d.ts +3 -1
  29. package/dist/hooks/dispatcher.js +14 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +3 -0
  32. package/dist/init-deposit/agent-hooks.js +17 -15
  33. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  34. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  35. package/dist/init-deposit/gitignore.js +9 -0
  36. package/dist/init-deposit/hygiene.d.ts +47 -11
  37. package/dist/init-deposit/hygiene.js +172 -37
  38. package/dist/init-deposit/legacy-detect.js +6 -2
  39. package/dist/init-deposit/refresh.d.ts +21 -1
  40. package/dist/init-deposit/refresh.js +106 -9
  41. package/dist/init-deposit/scaffold.js +28 -279
  42. package/dist/init-deposit/slash-deposit.js +13 -7
  43. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  44. package/dist/init-deposit/xbrief-projections.js +24 -11
  45. package/dist/intake/clause-derivation.d.ts +74 -0
  46. package/dist/intake/clause-derivation.js +409 -0
  47. package/dist/intake/index.d.ts +1 -0
  48. package/dist/intake/index.js +1 -0
  49. package/dist/intake/issue-ingest.d.ts +3 -1
  50. package/dist/intake/issue-ingest.js +36 -43
  51. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  52. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  53. package/dist/literal-acceptance/capture.d.ts +10 -0
  54. package/dist/literal-acceptance/capture.js +224 -75
  55. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  56. package/dist/literal-acceptance/evaluate.js +70 -2
  57. package/dist/literal-acceptance/index.d.ts +3 -3
  58. package/dist/literal-acceptance/index.js +3 -3
  59. package/dist/literal-acceptance/safety.d.ts +41 -0
  60. package/dist/literal-acceptance/safety.js +126 -2
  61. package/dist/literal-acceptance/types.d.ts +8 -0
  62. package/dist/orphan-active/evaluate.d.ts +7 -1
  63. package/dist/orphan-active/evaluate.js +102 -23
  64. package/dist/platform/platform-capabilities.js +2 -3
  65. package/dist/policy/base-branch.d.ts +37 -0
  66. package/dist/policy/base-branch.js +114 -0
  67. package/dist/policy/branch-sync.d.ts +80 -0
  68. package/dist/policy/branch-sync.js +211 -0
  69. package/dist/policy/ceremony-dial-escalation.js +1 -0
  70. package/dist/policy/ceremony-dial.js +4 -14
  71. package/dist/policy/delivery-branch.d.ts +5 -3
  72. package/dist/policy/delivery-branch.js +7 -3
  73. package/dist/policy/file-size-thresholds.d.ts +24 -0
  74. package/dist/policy/file-size-thresholds.js +23 -0
  75. package/dist/policy/forge-outage-retry.d.ts +47 -0
  76. package/dist/policy/forge-outage-retry.js +157 -0
  77. package/dist/policy/index.d.ts +7 -0
  78. package/dist/policy/index.js +66 -7
  79. package/dist/policy/project-invariants.d.ts +50 -0
  80. package/dist/policy/project-invariants.js +205 -0
  81. package/dist/policy/sync-default.d.ts +129 -0
  82. package/dist/policy/sync-default.js +452 -0
  83. package/dist/policy/sync-max-files.d.ts +93 -0
  84. package/dist/policy/sync-max-files.js +192 -0
  85. package/dist/pr-monitor/absent-required.d.ts +11 -0
  86. package/dist/pr-monitor/absent-required.js +61 -0
  87. package/dist/pr-monitor/constants.d.ts +7 -0
  88. package/dist/pr-monitor/constants.js +7 -0
  89. package/dist/pr-monitor/index.d.ts +2 -1
  90. package/dist/pr-monitor/index.js +2 -1
  91. package/dist/pr-monitor/main.js +4 -0
  92. package/dist/pr-monitor/monitor.js +24 -1
  93. package/dist/pr-wait-mergeable/classify.js +6 -0
  94. package/dist/preflight/evaluate.d.ts +9 -0
  95. package/dist/preflight/evaluate.js +49 -1
  96. package/dist/preflight/index.d.ts +5 -1
  97. package/dist/preflight/index.js +2 -0
  98. package/dist/preflight/intended-placement.d.ts +62 -0
  99. package/dist/preflight/intended-placement.js +275 -0
  100. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  101. package/dist/preflight/project-invariants-gate.js +82 -0
  102. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  103. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  104. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  105. package/dist/product-first-done-gate/acceptance.js +79 -8
  106. package/dist/product-first-done-gate/empty-resolution.d.ts +5 -2
  107. package/dist/product-first-done-gate/empty-resolution.js +13 -2
  108. package/dist/product-first-done-gate/evaluate.d.ts +29 -0
  109. package/dist/product-first-done-gate/evaluate.js +307 -33
  110. package/dist/product-first-done-gate/index.d.ts +3 -1
  111. package/dist/product-first-done-gate/index.js +2 -1
  112. package/dist/release/build-dist.d.ts +101 -0
  113. package/dist/release/build-dist.js +428 -46
  114. package/dist/run-summary/emit.d.ts +50 -4
  115. package/dist/run-summary/emit.js +262 -26
  116. package/dist/run-summary/index.d.ts +3 -2
  117. package/dist/run-summary/index.js +2 -1
  118. package/dist/run-summary/session-id.d.ts +21 -0
  119. package/dist/run-summary/session-id.js +92 -0
  120. package/dist/run-summary/share.d.ts +1 -1
  121. package/dist/run-summary/share.js +2 -2
  122. package/dist/run-summary/types.d.ts +38 -6
  123. package/dist/run-summary/types.js +1 -0
  124. package/dist/scope/acceptance-activate-gate.d.ts +1 -1
  125. package/dist/scope/acceptance-activate-gate.js +4 -4
  126. package/dist/scope/acceptance-evidence.d.ts +27 -0
  127. package/dist/scope/acceptance-evidence.js +66 -0
  128. package/dist/scope/capacity-stamp.d.ts +2 -0
  129. package/dist/scope/capacity-stamp.js +4 -0
  130. package/dist/scope/delivery-evidence.d.ts +9 -3
  131. package/dist/scope/delivery-evidence.js +39 -27
  132. package/dist/scope/index.d.ts +1 -0
  133. package/dist/scope/index.js +1 -0
  134. package/dist/scope/parent-lineage.js +7 -6
  135. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  136. package/dist/scope/project-invariant-coverage.js +322 -0
  137. package/dist/scope/transition.js +66 -4
  138. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  139. package/dist/scope-provenance/compare-intent.js +233 -0
  140. package/dist/scope-provenance/digest.d.ts +18 -1
  141. package/dist/scope-provenance/digest.js +16 -11
  142. package/dist/scope-provenance/evaluate.d.ts +5 -1
  143. package/dist/scope-provenance/evaluate.js +64 -4
  144. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  145. package/dist/scope-provenance/extract-intent.js +262 -0
  146. package/dist/scope-provenance/index.d.ts +7 -1
  147. package/dist/scope-provenance/index.js +7 -1
  148. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  149. package/dist/scope-provenance/intent-digest.js +33 -0
  150. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  151. package/dist/scope-provenance/intent-evaluate.js +149 -0
  152. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  153. package/dist/scope-provenance/json-tokenizer.js +225 -0
  154. package/dist/scope-provenance/known-machine.d.ts +38 -0
  155. package/dist/scope-provenance/known-machine.js +157 -0
  156. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  157. package/dist/scope-provenance/mint-artifacts.js +425 -0
  158. package/dist/session/ac-pass-banking.d.ts +4 -36
  159. package/dist/session/ac-pass-banking.js +30 -77
  160. package/dist/session/ac-pass-reuse.d.ts +53 -0
  161. package/dist/session/ac-pass-reuse.js +95 -0
  162. package/dist/session/ceremony-dial-evidence.d.ts +42 -0
  163. package/dist/session/ceremony-dial-evidence.js +194 -0
  164. package/dist/session/git.js +19 -4
  165. package/dist/session/index.d.ts +5 -0
  166. package/dist/session/index.js +5 -0
  167. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  168. package/dist/session/occupancy-stress-worker.js +36 -0
  169. package/dist/session/occupancy.d.ts +97 -0
  170. package/dist/session/occupancy.js +422 -0
  171. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  172. package/dist/session/product-state-hash.d.ts +26 -0
  173. package/dist/session/product-state-hash.js +683 -0
  174. package/dist/session/session-ready.d.ts +2 -0
  175. package/dist/session/session-ready.js +52 -30
  176. package/dist/session/session-start.d.ts +7 -0
  177. package/dist/session/session-start.js +88 -5
  178. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  179. package/dist/session/verify-ac-session-cache.js +126 -0
  180. package/dist/session/verify-session-ritual.d.ts +5 -0
  181. package/dist/session/verify-session-ritual.js +9 -0
  182. package/dist/slash/openclaw-deposit.js +13 -9
  183. package/dist/slice/constants.d.ts +2 -2
  184. package/dist/slice/constants.js +2 -2
  185. package/dist/slice/existing.js +21 -4
  186. package/dist/slice/lock.d.ts +16 -1
  187. package/dist/slice/lock.js +137 -11
  188. package/dist/slice/record.d.ts +8 -5
  189. package/dist/slice/record.js +21 -13
  190. package/dist/story-ready/evaluate.d.ts +2 -0
  191. package/dist/story-ready/evaluate.js +13 -0
  192. package/dist/swarm/complete-cohort.d.ts +3 -0
  193. package/dist/swarm/complete-cohort.js +59 -11
  194. package/dist/swarm/finalize-cohort.js +33 -2
  195. package/dist/swarm/launch.d.ts +22 -0
  196. package/dist/swarm/launch.js +155 -0
  197. package/dist/swarm/routing-set-cli.d.ts +11 -1
  198. package/dist/swarm/routing-set-cli.js +13 -3
  199. package/dist/swarm/routing-verify.d.ts +12 -0
  200. package/dist/swarm/routing-verify.js +59 -20
  201. package/dist/swarm/routing.d.ts +14 -0
  202. package/dist/swarm/routing.js +53 -3
  203. package/dist/telemetry-coverage/evaluate.d.ts +42 -0
  204. package/dist/telemetry-coverage/evaluate.js +148 -0
  205. package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
  206. package/dist/telemetry-coverage/fake-trial.js +204 -0
  207. package/dist/telemetry-coverage/index.d.ts +5 -0
  208. package/dist/telemetry-coverage/index.js +5 -0
  209. package/dist/telemetry-coverage/kinds.d.ts +19 -0
  210. package/dist/telemetry-coverage/kinds.js +54 -0
  211. package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
  212. package/dist/telemetry-coverage/scan-callers.js +168 -0
  213. package/dist/triage/actions/index.js +4 -1
  214. package/dist/ts-check-lane/index.d.ts +3 -0
  215. package/dist/ts-check-lane/index.js +2 -0
  216. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  217. package/dist/ts-check-lane/progress-reporter.js +38 -0
  218. package/dist/ts-check-lane/progress.d.ts +32 -0
  219. package/dist/ts-check-lane/progress.js +57 -0
  220. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  221. package/dist/ts-check-lane/run-lane.js +8 -6
  222. package/dist/validate-content/validate-links.d.ts +8 -0
  223. package/dist/validate-content/validate-links.js +9 -15
  224. package/dist/value/feedback-file.js +12 -2
  225. package/dist/vbrief-build/index.d.ts +1 -0
  226. package/dist/vbrief-build/index.js +1 -0
  227. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  228. package/dist/vbrief-build/project-invariants-io.js +41 -0
  229. package/dist/vbrief-reconcile/graph.js +18 -1
  230. package/dist/vbrief-reconcile/index.d.ts +3 -1
  231. package/dist/vbrief-reconcile/index.js +2 -1
  232. package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
  233. package/dist/vbrief-reconcile/origin-freshness.js +221 -0
  234. package/dist/vbrief-reconcile/types.d.ts +13 -0
  235. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  236. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  237. package/dist/vbrief-validate/index.d.ts +1 -1
  238. package/dist/vbrief-validate/index.js +1 -1
  239. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  240. package/dist/vbrief-validate/plan-hooks.js +68 -0
  241. package/dist/verify-ac/evaluate.d.ts +7 -1
  242. package/dist/verify-ac/evaluate.js +34 -26
  243. package/dist/verify-ac/flag.d.ts +4 -0
  244. package/dist/verify-ac/flag.js +16 -0
  245. package/dist/verify-ac/index.d.ts +2 -2
  246. package/dist/verify-ac/index.js +2 -2
  247. package/dist/verify-source/contained-writes.js +2 -0
  248. package/dist/verify-source/index.d.ts +1 -0
  249. package/dist/verify-source/index.js +1 -0
  250. package/dist/verify-source/verify-stubs.d.ts +15 -1
  251. package/dist/verify-source/verify-stubs.js +20 -16
  252. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  253. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  254. package/dist/xbrief-migrate/migrate-project.js +2 -5
  255. package/package.json +3 -3
@@ -13,6 +13,8 @@
13
13
  * ITEM_CORE is not expanded with bare keys; verify:vbrief-conformance rejects them.
14
14
  */
15
15
  import type { GrantOrigin } from "../authz/types.js";
16
+ import { type AcceptancePredicate } from "../product-first-done-gate/acceptance-resolver.js";
17
+ import { type EvaluateVerifyAcOptions } from "../product-first-done-gate/evaluate.js";
16
18
  /** Canonical namespaced key for typed acceptance evidence (#3305 / #1620). */
17
19
  export declare const ACCEPTANCE_EVIDENCE_KEY: "x-directive/evidence";
18
20
  /** Canonical namespaced key for human-origin disposition (#3305 / #1620). */
@@ -55,6 +57,10 @@ export interface AcceptanceEvidenceGateResult {
55
57
  readonly ok: boolean;
56
58
  readonly message: string;
57
59
  readonly reports: readonly CriterionAcceptanceReport[];
60
+ /** How the #3357 walk obtained AC (#3387). */
61
+ readonly servedFrom?: "bank" | "cache" | "executed";
62
+ /** Which acceptance check decided the walk (#3497). Undefined when no walk ran. */
63
+ readonly predicate?: AcceptancePredicate;
58
64
  }
59
65
  export declare function isAcceptanceEvidenceKind(value: unknown): value is AcceptanceEvidenceKind;
60
66
  export declare function isAcceptanceDispositionKind(value: unknown): value is AcceptanceDispositionKind;
@@ -98,6 +104,27 @@ export declare function stampNamespacedEvidence(item: Record<string, unknown>, r
98
104
  * cannot carry both acceptance fields after a replace (#3305 Greptile P2).
99
105
  */
100
106
  export declare function stampNamespacedDisposition(item: Record<string, unknown>, record: AcceptanceDispositionRecord): void;
107
+ /**
108
+ * Standing contract for scope:complete's acceptance precondition (#3357 / #3497).
109
+ *
110
+ * It no longer asserts a predicate ("empty or failing") — the actual predicate is
111
+ * named per refusal by the shared resolver. It also no longer tells operators to
112
+ * stamp by running verify:ac: verify:ac is the verifier and never writes the brief
113
+ * (a verifier that authors the acceptance it then checks is not a gate). Stamping
114
+ * happens at intake / promote via clause derivation (#3323).
115
+ */
116
+ export declare const SCOPE_COMPLETE_ACCEPTANCE_REMEDIATION: string;
117
+ /**
118
+ * Hard precondition for scope:complete (#3357 / #3267 / #3284).
119
+ *
120
+ * Runs the same verify:ac walk check uses, through the one shared option profile and
121
+ * the one shared verdict resolver (#3497) — so scope:complete can no longer report a
122
+ * different story than verify:ac about the same artifact. Disposition on plan items
123
+ * does not skip it. Briefs with no stamped plan.acceptance and no executable commands
124
+ * keep the legacy #3267 "nothing to run" pass so existing evidence-only fixtures stay
125
+ * valid.
126
+ */
127
+ export declare function evaluateScopeCompleteAcceptanceWalk(plan: Record<string, unknown>, options?: EvaluateVerifyAcOptions): AcceptanceEvidenceGateResult;
101
128
  /**
102
129
  * Fail closed when any non-terminal plan item lacks suitable evidence or a human-origin disposition.
103
130
  */
@@ -13,6 +13,8 @@
13
13
  * ITEM_CORE is not expanded with bare keys; verify:vbrief-conformance rejects them.
14
14
  */
15
15
  import { isHumanOrigin } from "../authz/origin.js";
16
+ import { formatAcceptanceVerdict, resolveAcceptanceGateProfile, resolveAcceptanceVerdict, } from "../product-first-done-gate/acceptance-resolver.js";
17
+ import { evaluateVerifyAcFromPlan, } from "../product-first-done-gate/evaluate.js";
16
18
  /** Canonical namespaced key for typed acceptance evidence (#3305 / #1620). */
17
19
  export const ACCEPTANCE_EVIDENCE_KEY = "x-directive/evidence";
18
20
  /** Canonical namespaced key for human-origin disposition (#3305 / #1620). */
@@ -369,6 +371,70 @@ function walkItems(items, pathPrefix, reports) {
369
371
  walkItems(obj.items, `${path}.items`, reports);
370
372
  });
371
373
  }
374
+ /**
375
+ * Standing contract for scope:complete's acceptance precondition (#3357 / #3497).
376
+ *
377
+ * It no longer asserts a predicate ("empty or failing") — the actual predicate is
378
+ * named per refusal by the shared resolver. It also no longer tells operators to
379
+ * stamp by running verify:ac: verify:ac is the verifier and never writes the brief
380
+ * (a verifier that authors the acceptance it then checks is not a gate). Stamping
381
+ * happens at intake / promote via clause derivation (#3323).
382
+ */
383
+ export const SCOPE_COMPLETE_ACCEPTANCE_REMEDIATION = "scope:complete requires executable plan.acceptance that runs green; stamp commands on " +
384
+ "plan.acceptance.commands (or plan.metadata.swarm.verify_commands) — task verify:ac verifies, " +
385
+ "it does not stamp — then re-run task verify:ac -- <completing-xbrief> " +
386
+ "(disposition is not a substitute) (#3357/#3497)";
387
+ /**
388
+ * Hard precondition for scope:complete (#3357 / #3267 / #3284).
389
+ *
390
+ * Runs the same verify:ac walk check uses, through the one shared option profile and
391
+ * the one shared verdict resolver (#3497) — so scope:complete can no longer report a
392
+ * different story than verify:ac about the same artifact. Disposition on plan items
393
+ * does not skip it. Briefs with no stamped plan.acceptance and no executable commands
394
+ * keep the legacy #3267 "nothing to run" pass so existing evidence-only fixtures stay
395
+ * valid.
396
+ */
397
+ export function evaluateScopeCompleteAcceptanceWalk(plan, options = {}) {
398
+ const stamped = plan.acceptance !== undefined;
399
+ const profile = resolveAcceptanceGateProfile("complete");
400
+ const walk = evaluateVerifyAcFromPlan(plan, {
401
+ ...options,
402
+ checkIntegrated: profile.checkIntegrated,
403
+ captureFromNarratives: options.captureFromNarratives ?? profile.captureFromNarratives,
404
+ reuseMode: options.reuseMode ?? profile.reuseMode,
405
+ });
406
+ const rejectedCount = walk.rejected?.length ?? 0;
407
+ const hadWork = walk.runs.length > 0 || walk.commands.length > 0 || rejectedCount > 0;
408
+ const servedFrom = walk.servedFrom ?? "executed";
409
+ if (!stamped && !hadWork) {
410
+ return {
411
+ ok: true,
412
+ message: "Acceptance walk not required (no stamped plan.acceptance) (#3357)",
413
+ reports: [],
414
+ servedFrom: "executed",
415
+ };
416
+ }
417
+ const verdict = resolveAcceptanceVerdict(walk);
418
+ if (walk.ok) {
419
+ return {
420
+ ok: true,
421
+ message: walk.message,
422
+ reports: [],
423
+ servedFrom,
424
+ predicate: verdict.predicate,
425
+ };
426
+ }
427
+ return {
428
+ ok: false,
429
+ // Name the check that refused and the value it read BEFORE the standing
430
+ // contract, so the first line the operator sees is the actual cause (#3497).
431
+ message: `scope:complete refused acceptance — ${formatAcceptanceVerdict(verdict)}\n` +
432
+ `${SCOPE_COMPLETE_ACCEPTANCE_REMEDIATION}\n${walk.message}`,
433
+ reports: [],
434
+ servedFrom,
435
+ predicate: verdict.predicate,
436
+ };
437
+ }
372
438
  /**
373
439
  * Fail closed when any non-terminal plan item lacks suitable evidence or a human-origin disposition.
374
440
  */
@@ -19,6 +19,8 @@ export interface StampCompletionOptions {
19
19
  * tests so the fallback path is exercised without a network call.
20
20
  */
21
21
  readonly liveLabelReader?: LabelReader;
22
+ /** Session that ran scope:complete; check uses this to target xbrief/completed (#3357). */
23
+ readonly completedSessionId?: string | null;
22
24
  }
23
25
  /** Stamp completedAt + label-matched capacityBucket onto a completing vBRIEF (#1419, #2237). */
24
26
  export declare function stampCompletionMetadata(plan: Record<string, unknown>, projectRoot: string, timestamp: string, options?: StampCompletionOptions): void;
@@ -86,6 +86,10 @@ export function stampCompletionMetadata(plan, projectRoot, timestamp, options =
86
86
  }
87
87
  const meta = metadata;
88
88
  meta.completedAt = timestamp;
89
+ const sessionId = options.completedSessionId?.trim() ?? "";
90
+ if (sessionId.length > 0) {
91
+ meta.completedSessionId = sessionId;
92
+ }
89
93
  const existing = meta.capacityBucket;
90
94
  if (typeof existing === "string" && existing.trim().length > 0) {
91
95
  return;
@@ -32,6 +32,8 @@ export interface CompletionProvenance {
32
32
  readonly deployed: boolean | null;
33
33
  /** Always null unless explicitly supplied — never inferred from Git (#3041). */
34
34
  readonly uatVerified: boolean | null;
35
+ /** Session that completed the brief; used by check to target xbrief/completed (#3357). */
36
+ readonly completedSessionId?: string | null;
35
37
  }
36
38
  export interface DeliveryEvidenceInput {
37
39
  readonly repository?: string | null;
@@ -67,6 +69,10 @@ export interface DeliveryGateResult {
67
69
  readonly provenance: CompletionProvenance | null;
68
70
  readonly codeBearing: boolean;
69
71
  }
72
+ /**
73
+ * Session id for a completing brief (#3357). Prefer DEFT_SESSION_ID, then ritual-state.
74
+ */
75
+ export declare function resolveCompletionSessionId(projectRoot: string, env?: NodeJS.ProcessEnv): string | null;
70
76
  export declare function isNonDeliveryDisposition(value: unknown): value is NonDeliveryDisposition;
71
77
  /** True when the brief is treated as code-bearing for the delivery gate (#3041). */
72
78
  export declare function isCodeBearingScope(plan: Record<string, unknown>): boolean;
@@ -93,13 +99,13 @@ export declare function verifyDeliveryAncestry(projectRoot: string, mergeCommit:
93
99
  remoteTip: string | null;
94
100
  };
95
101
  /**
96
- * Gate delivered completion for a code-bearing scope (#3041).
102
+ * Gate delivered completion for a code-bearing scope (#3041 / #3380).
97
103
  *
98
104
  * Returns ok=true with provenance when:
99
105
  * - scope is not code-bearing (provenance may be null or non-code note), OR
100
106
  * - explicit non-delivery disposition is provided, OR
101
- * - durable delivery evidence validates (PR base == deliveryBranch, merge commit
102
- * ancestor of refreshed remote delivery ref).
107
+ * - merge commit is an ancestor of the refreshed remote delivery ref (prBase is
108
+ * provenance only; it need not equal deliveryBranch).
103
109
  */
104
110
  export declare function evaluateDeliveryGate(options: DeliveryGateOptions): DeliveryGateResult;
105
111
  /** Stamp completion provenance onto plan.metadata (mutates plan). */
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { resolveDeliveryBranch } from "../policy/delivery-branch.js";
11
11
  import { defaultGitRunner, gitIsAncestor } from "../session/git.js";
12
+ import { readRitualState } from "../session/ritual-sentinel.js";
12
13
  /** Handoff states that Git delivery can assert (deploy/UAT never inferred). */
13
14
  export const HANDOFF_STATES = [
14
15
  "implemented",
@@ -29,6 +30,18 @@ function asRecord(value) {
29
30
  }
30
31
  return null;
31
32
  }
33
+ /**
34
+ * Session id for a completing brief (#3357). Prefer DEFT_SESSION_ID, then ritual-state.
35
+ */
36
+ export function resolveCompletionSessionId(projectRoot, env = process.env) {
37
+ const fromEnv = typeof env.DEFT_SESSION_ID === "string" ? env.DEFT_SESSION_ID.trim() : "";
38
+ if (fromEnv.length > 0) {
39
+ return fromEnv;
40
+ }
41
+ const [state] = readRitualState(projectRoot);
42
+ const id = state?.sessionId.trim() ?? "";
43
+ return id.length > 0 ? id : null;
44
+ }
32
45
  export function isNonDeliveryDisposition(value) {
33
46
  return (typeof value === "string" && NON_DELIVERY_DISPOSITIONS.includes(value));
34
47
  }
@@ -162,7 +175,7 @@ export function verifyDeliveryAncestry(projectRoot, mergeCommit, deliveryBranch,
162
175
  return {
163
176
  ok: false,
164
177
  error: `merge commit ${mergeCommit} is not an ancestor of refreshed remote delivery ref ` +
165
- `${refresh.remoteRef} (${remoteTip}). Intermediate/integration-only merges are not delivery evidence (#3041).`,
178
+ `${refresh.remoteRef} (${remoteTip}).`,
166
179
  remoteTip,
167
180
  };
168
181
  }
@@ -186,14 +199,21 @@ function buildProvenance(input) {
186
199
  uatVerified: e.uatVerified ?? null,
187
200
  };
188
201
  }
202
+ function deliveryEvidenceRemediation(deliveryBranch) {
203
+ return (`Pass scope:complete -- --merge-commit <sha> (and --pr <n> if you have one). ` +
204
+ `When develop is the real delivery target, type plan.policy.deliveryBranch ` +
205
+ `(task policy:show --field=deliveryBranch). ` +
206
+ `When ${deliveryBranch} is delivery, wait until the merge commit is an ancestor of ` +
207
+ `origin/${deliveryBranch}, then complete. Do not use --non-delivery for work that shipped.`);
208
+ }
189
209
  /**
190
- * Gate delivered completion for a code-bearing scope (#3041).
210
+ * Gate delivered completion for a code-bearing scope (#3041 / #3380).
191
211
  *
192
212
  * Returns ok=true with provenance when:
193
213
  * - scope is not code-bearing (provenance may be null or non-code note), OR
194
214
  * - explicit non-delivery disposition is provided, OR
195
- * - durable delivery evidence validates (PR base == deliveryBranch, merge commit
196
- * ancestor of refreshed remote delivery ref).
215
+ * - merge commit is an ancestor of the refreshed remote delivery ref (prBase is
216
+ * provenance only; it need not equal deliveryBranch).
197
217
  */
198
218
  export function evaluateDeliveryGate(options) {
199
219
  const runGit = options.runGit ?? defaultGitRunner;
@@ -254,10 +274,8 @@ export function evaluateDeliveryGate(options) {
254
274
  return {
255
275
  ok: false,
256
276
  message: `Delivery evidence required for code-bearing scope completion (#3041). ` +
257
- `Provide merge/PR delivery proof (merge commit ancestor of remote ` +
258
- `'${deliveryBranch}') or an explicit --non-delivery disposition ` +
259
- `(${NON_DELIVERY_DISPOSITIONS.join("|")}). ` +
260
- `Merged-to-integration alone is not delivery.`,
277
+ `A merge commit that is an ancestor of refreshed origin/${deliveryBranch} is delivery; ` +
278
+ `PR base is provenance only. ${deliveryEvidenceRemediation(deliveryBranch)}`,
261
279
  provenance: null,
262
280
  codeBearing: true,
263
281
  };
@@ -281,27 +299,11 @@ export function evaluateDeliveryGate(options) {
281
299
  };
282
300
  }
283
301
  }
284
- if (prBase !== null && prBase !== deliveryBranch) {
285
- const provenance = buildProvenance({
286
- evidence,
287
- deliveryBranch,
288
- disposition: "merged_to_integration",
289
- handoffState: "merged_to_integration",
290
- nowIso: options.nowIso,
291
- verifier,
292
- });
293
- return {
294
- ok: false,
295
- message: `PR base '${prBase}' is not the configured delivery branch '${deliveryBranch}'. ` +
296
- `A merge into an intermediate/feature/integration branch is not delivery evidence (#3041).`,
297
- provenance,
298
- codeBearing: true,
299
- };
300
- }
301
302
  if (mergeCommit === null) {
302
303
  return {
303
304
  ok: false,
304
- message: "Delivery evidence missing merge_commit_sha; cannot prove ancestry on delivery branch (#3041).",
305
+ message: "Delivery evidence missing merge_commit_sha; cannot prove ancestry on delivery branch (#3041). " +
306
+ deliveryEvidenceRemediation(deliveryBranch),
305
307
  provenance: null,
306
308
  codeBearing: true,
307
309
  };
@@ -326,9 +328,15 @@ export function evaluateDeliveryGate(options) {
326
328
  const ancestry = verifyDeliveryAncestry(options.projectRoot, mergeCommit, deliveryBranch, runGit);
327
329
  if (!ancestry.ok) {
328
330
  const integrationOnly = prBase !== null && prBase !== deliveryBranch;
331
+ const ancestryMsg = ancestry.error ?? "delivery ancestry check failed";
332
+ const rem = deliveryEvidenceRemediation(deliveryBranch);
333
+ const message = integrationOnly
334
+ ? `${ancestryMsg} PR base '${prBase}' is provenance only; ` +
335
+ `the merge is not yet on origin/${deliveryBranch}. ${rem}`
336
+ : `${ancestryMsg} ${rem}`;
329
337
  return {
330
338
  ok: false,
331
- message: ancestry.error ?? "delivery ancestry check failed",
339
+ message,
332
340
  provenance: buildProvenance({
333
341
  evidence,
334
342
  deliveryBranch,
@@ -380,6 +388,10 @@ export function stampDeliveryProvenance(plan, provenance) {
380
388
  // Deploy/UAT are explicit-only; default null so readers never infer from Git.
381
389
  deployed: provenance.deployed,
382
390
  uatVerified: provenance.uatVerified,
391
+ ...(typeof provenance.completedSessionId === "string" &&
392
+ provenance.completedSessionId.trim().length > 0
393
+ ? { completedSessionId: provenance.completedSessionId.trim() }
394
+ : {}),
383
395
  };
384
396
  meta.deliveryDisposition = provenance.disposition;
385
397
  meta.handoffState = provenance.handoffState;
@@ -12,6 +12,7 @@ export * from "./main.js";
12
12
  export * from "./open-umbrella-warning.js";
13
13
  export * from "./parent-lineage.js";
14
14
  export * from "./project-context.js";
15
+ export * from "./project-invariant-coverage.js";
15
16
  export * from "./promote-from-issue.js";
16
17
  export * from "./promote-path.js";
17
18
  export * from "./transition.js";
@@ -12,6 +12,7 @@ export * from "./main.js";
12
12
  export * from "./open-umbrella-warning.js";
13
13
  export * from "./parent-lineage.js";
14
14
  export * from "./project-context.js";
15
+ export * from "./project-invariant-coverage.js";
15
16
  export * from "./promote-from-issue.js";
16
17
  export * from "./promote-path.js";
17
18
  export * from "./transition.js";
@@ -98,20 +98,21 @@ export function extractChildCoverageDraft(child) {
98
98
  candidates.push({ source: "plan", obj: plan });
99
99
  candidates.push({ source: "root", obj: root });
100
100
  for (const c of candidates) {
101
+ const nestedCoverage = asRecord(c.obj.coverage);
101
102
  const hasMap = "coverage_map" in c.obj ||
102
103
  "coverageMap" in c.obj ||
103
- asRecord(c.obj.coverage)?.coverage_map !== undefined;
104
+ nestedCoverage?.coverage_map !== undefined ||
105
+ nestedCoverage?.coverageMap !== undefined;
104
106
  if (!hasMap)
105
107
  continue;
106
- const coverageNested = asRecord(c.obj.coverage);
107
108
  const coverage_map = c.obj.coverage_map ??
108
109
  c.obj.coverageMap ??
109
- coverageNested?.coverage_map ??
110
- coverageNested?.coverageMap;
110
+ nestedCoverage?.coverage_map ??
111
+ nestedCoverage?.coverageMap;
111
112
  const behavioral_deltas = c.obj.behavioral_deltas ??
112
113
  c.obj.behavioralDeltas ??
113
- coverageNested?.behavioral_deltas ??
114
- coverageNested?.behavioralDeltas;
114
+ nestedCoverage?.behavioral_deltas ??
115
+ nestedCoverage?.behavioralDeltas;
115
116
  return {
116
117
  draft: {
117
118
  coverage_map,
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Project-invariant coverage + applicability (#3425 Story A).
3
+ *
4
+ * Reuses the #3238 coverage_map parser and side-field rules. `split` is
5
+ * excluded at project level. Optional `not_applicable` requires a reason.
6
+ * Applicability is a pure intersection of contract surface × file_scope.
7
+ */
8
+ import type { ProjectInvariant } from "../policy/project-invariants.js";
9
+ export declare const PROJECT_INVARIANT_DISPOSITIONS: readonly ["covered", "deferred", "behavioral_delta", "not_applicable"];
10
+ export type ProjectInvariantDisposition = (typeof PROJECT_INVARIANT_DISPOSITIONS)[number];
11
+ export interface ApplicableInvariant {
12
+ readonly id: string;
13
+ readonly reason: "path" | "module" | "unresolved-module";
14
+ }
15
+ export interface ProjectInvariantCoverageResult {
16
+ readonly ok: boolean;
17
+ readonly applicableIds: readonly string[];
18
+ readonly missingIds: readonly string[];
19
+ readonly errors: readonly string[];
20
+ }
21
+ export type GlobDepth = "exact" | "one" | "subtree";
22
+ export interface ClassifiedGlob {
23
+ readonly prefix: string;
24
+ readonly depth: GlobDepth;
25
+ readonly leadingDoubleStar: boolean;
26
+ }
27
+ /**
28
+ * Classify a path/glob without regular expressions (CodeQL js/polynomial-redos).
29
+ * Unstarred paths are directory prefixes (file_scope semantics).
30
+ */
31
+ export declare function classifyGlob(glob: string): ClassifiedGlob;
32
+ /** Strip glob tails so prefix comparison stays path-shaped. */
33
+ export declare function normalizeGlobAsPath(glob: string): string;
34
+ /**
35
+ * True when two path/glob strings can name a shared tree.
36
+ * `/*` is one segment; `/**` / unstarred file_scope paths are subtrees.
37
+ */
38
+ export declare function pathGlobsIntersect(left: string, right: string): boolean;
39
+ /**
40
+ * Invariants whose contract surface intersects `fileScope`.
41
+ * Empty file_scope → empty intersection (no disposition required).
42
+ * Unresolved module ids (no pathGlobs mapping) are treated as applicable.
43
+ */
44
+ export declare function applicableProjectInvariants(invariants: readonly ProjectInvariant[], fileScope: readonly string[], modulePathGlobs?: Readonly<Record<string, readonly string[]>>): ApplicableInvariant[];
45
+ /**
46
+ * Completeness of coverage_map dispositions for applicable project invariant IDs.
47
+ * Extra coverage_map keys (e.g. parent requirement IDs) are ignored.
48
+ * Empty applicable set is a no-op success.
49
+ */
50
+ export declare function validateProjectInvariantCoverage(opts: {
51
+ applicableIds: readonly string[];
52
+ draft: unknown;
53
+ }): ProjectInvariantCoverageResult;
54
+ //# sourceMappingURL=project-invariant-coverage.d.ts.map