@deftai/directive-core 0.104.0 → 0.106.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 (287) hide show
  1. package/dist/authz/classify.js +1108 -67
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/named-cause.d.ts +1 -1
  5. package/dist/check/named-cause.js +34 -4
  6. package/dist/codebase/default-extractor.d.ts +5 -0
  7. package/dist/codebase/default-extractor.js +7 -15
  8. package/dist/deposit/copy-tree.js +60 -0
  9. package/dist/deposit/python-free.js +26 -18
  10. package/dist/doctor/checks.d.ts +8 -0
  11. package/dist/doctor/checks.js +37 -25
  12. package/dist/doctor/doctor-state.d.ts +4 -0
  13. package/dist/doctor/doctor-state.js +7 -1
  14. package/dist/doctor/main.js +9 -19
  15. package/dist/doctor/types.d.ts +9 -0
  16. package/dist/forward-coverage/diff-coverage.d.ts +39 -0
  17. package/dist/forward-coverage/diff-coverage.js +112 -0
  18. package/dist/forward-coverage/diff-lines.d.ts +19 -0
  19. package/dist/forward-coverage/diff-lines.js +173 -0
  20. package/dist/forward-coverage/evaluate.d.ts +24 -9
  21. package/dist/forward-coverage/evaluate.js +125 -19
  22. package/dist/fs/contained-write.d.ts +115 -1
  23. package/dist/fs/contained-write.js +241 -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 +1 -0
  31. package/dist/index.js +2 -0
  32. package/dist/init-deposit/agent-hooks.d.ts +1 -1
  33. package/dist/init-deposit/agent-hooks.js +18 -16
  34. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  35. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  36. package/dist/init-deposit/gitignore.js +9 -0
  37. package/dist/init-deposit/hygiene.d.ts +47 -11
  38. package/dist/init-deposit/hygiene.js +172 -37
  39. package/dist/init-deposit/legacy-detect.js +6 -2
  40. package/dist/init-deposit/refresh.d.ts +21 -1
  41. package/dist/init-deposit/refresh.js +106 -9
  42. package/dist/init-deposit/scaffold.js +28 -279
  43. package/dist/init-deposit/slash-deposit.js +13 -7
  44. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  45. package/dist/init-deposit/xbrief-projections.js +24 -11
  46. package/dist/intake/clause-derivation.d.ts +47 -1
  47. package/dist/intake/clause-derivation.js +238 -9
  48. package/dist/intake/issue-ingest.d.ts +3 -1
  49. package/dist/intake/issue-ingest.js +35 -6
  50. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  51. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  52. package/dist/lifecycle-visible/evaluate.d.ts +98 -0
  53. package/dist/lifecycle-visible/evaluate.js +710 -0
  54. package/dist/lifecycle-visible/index.d.ts +2 -0
  55. package/dist/lifecycle-visible/index.js +2 -0
  56. package/dist/literal-acceptance/capture.d.ts +10 -0
  57. package/dist/literal-acceptance/capture.js +226 -77
  58. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  59. package/dist/literal-acceptance/evaluate.js +70 -2
  60. package/dist/literal-acceptance/index.d.ts +3 -3
  61. package/dist/literal-acceptance/index.js +3 -3
  62. package/dist/literal-acceptance/safety.d.ts +41 -0
  63. package/dist/literal-acceptance/safety.js +126 -2
  64. package/dist/literal-acceptance/types.d.ts +8 -0
  65. package/dist/orchestration/judgment-policy.d.ts +13 -0
  66. package/dist/orchestration/judgment-policy.js +15 -0
  67. package/dist/orchestration/probe-session.js +13 -8
  68. package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
  69. package/dist/orchestration/verify-judgment-gates.js +43 -11
  70. package/dist/orphan-active/evaluate.d.ts +7 -1
  71. package/dist/orphan-active/evaluate.js +102 -23
  72. package/dist/platform/platform-capabilities.js +2 -3
  73. package/dist/policy/base-branch.d.ts +37 -0
  74. package/dist/policy/base-branch.js +114 -0
  75. package/dist/policy/branch-sync.d.ts +80 -0
  76. package/dist/policy/branch-sync.js +211 -0
  77. package/dist/policy/ceremony-dial-escalation.js +1 -0
  78. package/dist/policy/ceremony-dial.js +11 -21
  79. package/dist/policy/delivery-branch.d.ts +5 -3
  80. package/dist/policy/delivery-branch.js +7 -3
  81. package/dist/policy/file-size-thresholds.d.ts +24 -0
  82. package/dist/policy/file-size-thresholds.js +23 -0
  83. package/dist/policy/forge-outage-retry.d.ts +47 -0
  84. package/dist/policy/forge-outage-retry.js +157 -0
  85. package/dist/policy/host-hooks.d.ts +20 -0
  86. package/dist/policy/host-hooks.js +121 -2
  87. package/dist/policy/index.d.ts +7 -0
  88. package/dist/policy/index.js +66 -7
  89. package/dist/policy/org-force-on-migration.js +2 -1
  90. package/dist/policy/plan-extensions.d.ts +1 -1
  91. package/dist/policy/plan-extensions.js +2 -0
  92. package/dist/policy/product-signal.js +6 -7
  93. package/dist/policy/project-invariants.d.ts +50 -0
  94. package/dist/policy/project-invariants.js +205 -0
  95. package/dist/policy/require-human-merge.js +8 -6
  96. package/dist/policy/resolve.d.ts +7 -2
  97. package/dist/policy/resolve.js +25 -8
  98. package/dist/policy/sync-default.d.ts +129 -0
  99. package/dist/policy/sync-default.js +452 -0
  100. package/dist/policy/sync-max-files.d.ts +93 -0
  101. package/dist/policy/sync-max-files.js +192 -0
  102. package/dist/policy/value-feedback.js +7 -8
  103. package/dist/pr-monitor/absent-required.d.ts +11 -0
  104. package/dist/pr-monitor/absent-required.js +61 -0
  105. package/dist/pr-monitor/constants.d.ts +7 -0
  106. package/dist/pr-monitor/constants.js +7 -0
  107. package/dist/pr-monitor/index.d.ts +2 -1
  108. package/dist/pr-monitor/index.js +2 -1
  109. package/dist/pr-monitor/main.js +4 -0
  110. package/dist/pr-monitor/monitor.js +24 -1
  111. package/dist/pr-wait-mergeable/classify.js +6 -0
  112. package/dist/preflight/evaluate.d.ts +4 -0
  113. package/dist/preflight/evaluate.js +35 -1
  114. package/dist/preflight/index.d.ts +4 -0
  115. package/dist/preflight/index.js +2 -0
  116. package/dist/preflight/intended-placement.d.ts +62 -0
  117. package/dist/preflight/intended-placement.js +275 -0
  118. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  119. package/dist/preflight/project-invariants-gate.js +82 -0
  120. package/dist/preflight-cache/evaluate.d.ts +12 -0
  121. package/dist/preflight-cache/evaluate.js +15 -1
  122. package/dist/preflight-cache/index.d.ts +1 -1
  123. package/dist/preflight-cache/index.js +1 -1
  124. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  125. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  126. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  127. package/dist/product-first-done-gate/acceptance.js +79 -8
  128. package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
  129. package/dist/product-first-done-gate/empty-resolution.js +12 -1
  130. package/dist/product-first-done-gate/evaluate.d.ts +16 -0
  131. package/dist/product-first-done-gate/evaluate.js +298 -34
  132. package/dist/product-first-done-gate/index.d.ts +2 -0
  133. package/dist/product-first-done-gate/index.js +1 -0
  134. package/dist/release/build-dist.d.ts +101 -0
  135. package/dist/release/build-dist.js +428 -46
  136. package/dist/release/closed-verb-gate.d.ts +12 -0
  137. package/dist/release/closed-verb-gate.js +51 -0
  138. package/dist/release/index.d.ts +1 -0
  139. package/dist/release/index.js +1 -0
  140. package/dist/release/pipeline.js +7 -0
  141. package/dist/release/types.d.ts +12 -0
  142. package/dist/render/constants.d.ts +2 -1
  143. package/dist/render/constants.js +2 -1
  144. package/dist/render/framework-commands.js +4 -0
  145. package/dist/render/spec-validate.js +23 -12
  146. package/dist/run-summary/emit.d.ts +16 -10
  147. package/dist/run-summary/emit.js +26 -15
  148. package/dist/run-summary/index.d.ts +3 -2
  149. package/dist/run-summary/index.js +2 -1
  150. package/dist/run-summary/session-id.d.ts +21 -0
  151. package/dist/run-summary/session-id.js +92 -0
  152. package/dist/run-summary/types.d.ts +33 -4
  153. package/dist/run-summary/types.js +1 -0
  154. package/dist/scope/acceptance-evidence.d.ts +19 -7
  155. package/dist/scope/acceptance-evidence.js +38 -11
  156. package/dist/scope/delivery-evidence.d.ts +3 -3
  157. package/dist/scope/delivery-evidence.js +22 -27
  158. package/dist/scope/index.d.ts +1 -0
  159. package/dist/scope/index.js +1 -0
  160. package/dist/scope/main.js +15 -5
  161. package/dist/scope/parent-lineage.js +7 -6
  162. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  163. package/dist/scope/project-invariant-coverage.js +322 -0
  164. package/dist/scope/promote-from-issue.js +5 -5
  165. package/dist/scope/transition.js +1 -1
  166. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  167. package/dist/scope-provenance/compare-intent.js +233 -0
  168. package/dist/scope-provenance/digest.d.ts +18 -1
  169. package/dist/scope-provenance/digest.js +16 -11
  170. package/dist/scope-provenance/evaluate.d.ts +5 -1
  171. package/dist/scope-provenance/evaluate.js +67 -7
  172. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  173. package/dist/scope-provenance/extract-intent.js +262 -0
  174. package/dist/scope-provenance/index.d.ts +7 -1
  175. package/dist/scope-provenance/index.js +7 -1
  176. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  177. package/dist/scope-provenance/intent-digest.js +33 -0
  178. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  179. package/dist/scope-provenance/intent-evaluate.js +149 -0
  180. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  181. package/dist/scope-provenance/json-tokenizer.js +225 -0
  182. package/dist/scope-provenance/known-machine.d.ts +38 -0
  183. package/dist/scope-provenance/known-machine.js +157 -0
  184. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  185. package/dist/scope-provenance/mint-artifacts.js +425 -0
  186. package/dist/session/ac-pass-banking.d.ts +9 -36
  187. package/dist/session/ac-pass-banking.js +33 -79
  188. package/dist/session/ac-pass-reuse.d.ts +53 -0
  189. package/dist/session/ac-pass-reuse.js +95 -0
  190. package/dist/session/git.js +19 -4
  191. package/dist/session/index.d.ts +4 -0
  192. package/dist/session/index.js +4 -0
  193. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  194. package/dist/session/occupancy-stress-worker.js +36 -0
  195. package/dist/session/occupancy.d.ts +97 -0
  196. package/dist/session/occupancy.js +422 -0
  197. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  198. package/dist/session/process-cost.d.ts +32 -10
  199. package/dist/session/process-cost.js +189 -1
  200. package/dist/session/product-state-hash.d.ts +26 -0
  201. package/dist/session/product-state-hash.js +700 -0
  202. package/dist/session/ritual-entrypoint.js +16 -1
  203. package/dist/session/session-ready.d.ts +2 -0
  204. package/dist/session/session-ready.js +52 -30
  205. package/dist/session/session-start.d.ts +13 -0
  206. package/dist/session/session-start.js +103 -9
  207. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  208. package/dist/session/verify-ac-session-cache.js +126 -0
  209. package/dist/session/verify-session-ritual.d.ts +28 -0
  210. package/dist/session/verify-session-ritual.js +97 -5
  211. package/dist/slash/openclaw-deposit.js +13 -9
  212. package/dist/slice/constants.d.ts +2 -2
  213. package/dist/slice/constants.js +2 -2
  214. package/dist/slice/existing.js +9 -3
  215. package/dist/slice/lock.d.ts +16 -1
  216. package/dist/slice/lock.js +137 -11
  217. package/dist/story-ready/evaluate.d.ts +2 -0
  218. package/dist/story-ready/evaluate.js +13 -0
  219. package/dist/swarm/complete-cohort.d.ts +3 -0
  220. package/dist/swarm/complete-cohort.js +59 -11
  221. package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
  222. package/dist/swarm/finalize-cohort-cli.js +165 -35
  223. package/dist/swarm/finalize-cohort.d.ts +1 -0
  224. package/dist/swarm/finalize-cohort.js +47 -4
  225. package/dist/swarm/launch.d.ts +22 -0
  226. package/dist/swarm/launch.js +155 -0
  227. package/dist/swarm/routing-set-cli.d.ts +11 -1
  228. package/dist/swarm/routing-set-cli.js +15 -3
  229. package/dist/swarm/routing-verify.d.ts +13 -1
  230. package/dist/swarm/routing-verify.js +60 -21
  231. package/dist/swarm/routing.d.ts +14 -0
  232. package/dist/swarm/routing.js +53 -3
  233. package/dist/telemetry-coverage/fake-trial.js +10 -0
  234. package/dist/telemetry-coverage/kinds.js +2 -0
  235. package/dist/triage/actions/index.js +4 -1
  236. package/dist/triage/bootstrap/index.js +6 -6
  237. package/dist/triage/help/registry-data.d.ts +1 -1
  238. package/dist/triage/help/registry-data.js +1 -1
  239. package/dist/triage/welcome/writers.d.ts +1 -1
  240. package/dist/triage/welcome/writers.js +10 -5
  241. package/dist/ts-check-lane/index.d.ts +3 -0
  242. package/dist/ts-check-lane/index.js +2 -0
  243. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  244. package/dist/ts-check-lane/progress-reporter.js +38 -0
  245. package/dist/ts-check-lane/progress.d.ts +32 -0
  246. package/dist/ts-check-lane/progress.js +57 -0
  247. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  248. package/dist/ts-check-lane/run-lane.js +8 -6
  249. package/dist/validate-content/validate-links.d.ts +8 -0
  250. package/dist/validate-content/validate-links.js +9 -15
  251. package/dist/value/feedback-file.js +12 -2
  252. package/dist/value/readback.d.ts +4 -1
  253. package/dist/value/readback.js +51 -12
  254. package/dist/vbrief-build/index.d.ts +1 -0
  255. package/dist/vbrief-build/index.js +1 -0
  256. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  257. package/dist/vbrief-build/project-invariants-io.js +41 -0
  258. package/dist/vbrief-reconcile/graph.js +18 -1
  259. package/dist/vbrief-reconcile/index.d.ts +1 -1
  260. package/dist/vbrief-reconcile/index.js +1 -1
  261. package/dist/vbrief-reconcile/types.d.ts +13 -0
  262. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  263. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  264. package/dist/vbrief-validate/index.d.ts +1 -1
  265. package/dist/vbrief-validate/index.js +1 -1
  266. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  267. package/dist/vbrief-validate/plan-hooks.js +68 -0
  268. package/dist/vbrief-validate/schema.d.ts +4 -0
  269. package/dist/vbrief-validate/schema.js +1 -1
  270. package/dist/verify-ac/evaluate.d.ts +7 -1
  271. package/dist/verify-ac/evaluate.js +34 -26
  272. package/dist/verify-ac/flag.d.ts +4 -0
  273. package/dist/verify-ac/flag.js +16 -0
  274. package/dist/verify-ac/index.d.ts +2 -2
  275. package/dist/verify-ac/index.js +2 -2
  276. package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
  277. package/dist/verify-env/agent-hook-readiness.js +12 -8
  278. package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
  279. package/dist/verify-env/agent-hooks-live-probe.js +26 -5
  280. package/dist/verify-env/agent-hooks.js +3 -4
  281. package/dist/verify-source/contained-writes.js +2 -0
  282. package/dist/verify-source/verify-stubs.d.ts +15 -1
  283. package/dist/verify-source/verify-stubs.js +20 -16
  284. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  285. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  286. package/dist/xbrief-migrate/migrate-project.js +2 -5
  287. package/package.json +7 -3
@@ -175,7 +175,7 @@ export function verifyDeliveryAncestry(projectRoot, mergeCommit, deliveryBranch,
175
175
  return {
176
176
  ok: false,
177
177
  error: `merge commit ${mergeCommit} is not an ancestor of refreshed remote delivery ref ` +
178
- `${refresh.remoteRef} (${remoteTip}). Intermediate/integration-only merges are not delivery evidence (#3041).`,
178
+ `${refresh.remoteRef} (${remoteTip}).`,
179
179
  remoteTip,
180
180
  };
181
181
  }
@@ -199,14 +199,21 @@ function buildProvenance(input) {
199
199
  uatVerified: e.uatVerified ?? null,
200
200
  };
201
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
+ }
202
209
  /**
203
- * Gate delivered completion for a code-bearing scope (#3041).
210
+ * Gate delivered completion for a code-bearing scope (#3041 / #3380).
204
211
  *
205
212
  * Returns ok=true with provenance when:
206
213
  * - scope is not code-bearing (provenance may be null or non-code note), OR
207
214
  * - explicit non-delivery disposition is provided, OR
208
- * - durable delivery evidence validates (PR base == deliveryBranch, merge commit
209
- * 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).
210
217
  */
211
218
  export function evaluateDeliveryGate(options) {
212
219
  const runGit = options.runGit ?? defaultGitRunner;
@@ -267,10 +274,8 @@ export function evaluateDeliveryGate(options) {
267
274
  return {
268
275
  ok: false,
269
276
  message: `Delivery evidence required for code-bearing scope completion (#3041). ` +
270
- `Provide merge/PR delivery proof (merge commit ancestor of remote ` +
271
- `'${deliveryBranch}') or an explicit --non-delivery disposition ` +
272
- `(${NON_DELIVERY_DISPOSITIONS.join("|")}). ` +
273
- `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)}`,
274
279
  provenance: null,
275
280
  codeBearing: true,
276
281
  };
@@ -294,27 +299,11 @@ export function evaluateDeliveryGate(options) {
294
299
  };
295
300
  }
296
301
  }
297
- if (prBase !== null && prBase !== deliveryBranch) {
298
- const provenance = buildProvenance({
299
- evidence,
300
- deliveryBranch,
301
- disposition: "merged_to_integration",
302
- handoffState: "merged_to_integration",
303
- nowIso: options.nowIso,
304
- verifier,
305
- });
306
- return {
307
- ok: false,
308
- message: `PR base '${prBase}' is not the configured delivery branch '${deliveryBranch}'. ` +
309
- `A merge into an intermediate/feature/integration branch is not delivery evidence (#3041).`,
310
- provenance,
311
- codeBearing: true,
312
- };
313
- }
314
302
  if (mergeCommit === null) {
315
303
  return {
316
304
  ok: false,
317
- 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),
318
307
  provenance: null,
319
308
  codeBearing: true,
320
309
  };
@@ -339,9 +328,15 @@ export function evaluateDeliveryGate(options) {
339
328
  const ancestry = verifyDeliveryAncestry(options.projectRoot, mergeCommit, deliveryBranch, runGit);
340
329
  if (!ancestry.ok) {
341
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}`;
342
337
  return {
343
338
  ok: false,
344
- message: ancestry.error ?? "delivery ancestry check failed",
339
+ message,
345
340
  provenance: buildProvenance({
346
341
  evidence,
347
342
  deliveryBranch,
@@ -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";
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
3
  import { maybeRunStalenessTickler } from "../staleness-tickler/run.js";
4
+ import { interceptHelp } from "../triage/help/index.js";
4
5
  import { reconcileUmbrellas, renderUmbrellasReport } from "../vbrief-reconcile/umbrellas.js";
5
6
  import { canonicalLogPath, readAll } from "./audit-log.js";
6
7
  import { batchPromote } from "./batch-promote.js";
@@ -13,12 +14,11 @@ import { promoteFromIssue } from "./promote-from-issue.js";
13
14
  import { promotePath } from "./promote-path.js";
14
15
  import { runTransition } from "./transition.js";
15
16
  import { findByDecisionId, isAlreadyUndone, REVERSIBLE_ACTIONS, undoBatch, undoOne, } from "./undo.js";
16
- const LIFECYCLE_USAGE_STDERR = "usage: scope_lifecycle.py [-h] [--project-root PROJECT_ROOT] [--force] [--batch]\n" +
17
- " [--from-issue N] [--repo OWNER/NAME] [--strict] [--force-no-cache]\n" +
17
+ const LIFECYCLE_USAGE_STDERR = "usage: deft scope:<action> [file] [--batch] [--from-issue N] [--repo OWNER/NAME]\n" +
18
+ " [--force] [--project-root PATH] [--strict] [--force-no-cache]\n" +
18
19
  " [--path PATH]\n" +
19
- " {activate,block,cancel,complete,fail,promote,restore,unblock}\n" +
20
- " [file ...]\n" +
21
- "scope_lifecycle.py: error: the following arguments are required: action, file\n" +
20
+ " actions: activate, block, cancel, complete, fail, promote, restore, unblock\n" +
21
+ "The verb already encodes the action (e.g. deft scope:promote <file>). Do not pass the action again.\n" +
22
22
  "(promote --batch may omit file and promotes all proposed/ scopes; #3011)\n" +
23
23
  "(promote --from-issue=N may omit file; #1136)\n";
24
24
  function parseLifecycleArgv(argv) {
@@ -50,6 +50,8 @@ function parseLifecycleArgv(argv) {
50
50
  if (arg === undefined) {
51
51
  return { args: null, error: "usage" };
52
52
  }
53
+ if (arg === "--")
54
+ continue;
53
55
  if (arg === "--force") {
54
56
  force = true;
55
57
  }
@@ -236,6 +238,14 @@ function parseLifecycleArgv(argv) {
236
238
  }
237
239
  /** Main entry for scope_lifecycle.py parity. */
238
240
  export function lifecycleMain(argv) {
241
+ if (argv.includes("--help") || argv.includes("-h")) {
242
+ const helpRc = interceptHelp("scope_lifecycle", argv);
243
+ if (helpRc !== null) {
244
+ return helpRc;
245
+ }
246
+ process.stdout.write(LIFECYCLE_USAGE_STDERR);
247
+ return 0;
248
+ }
239
249
  const parsed = parseLifecycleArgv(argv);
240
250
  if (parsed.args === null) {
241
251
  if (parsed.error === "usage") {
@@ -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
@@ -0,0 +1,322 @@
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 { matchPath, normalizePath } from "../orchestration/pathspec.js";
9
+ import { parseBehavioralDeltas, parseCoverageMap } from "./coverage-map.js";
10
+ export const PROJECT_INVARIANT_DISPOSITIONS = [
11
+ "covered",
12
+ "deferred",
13
+ "behavioral_delta",
14
+ "not_applicable",
15
+ ];
16
+ function asRecord(value) {
17
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
18
+ return value;
19
+ }
20
+ return null;
21
+ }
22
+ function isNonEmptyString(value) {
23
+ return typeof value === "string" && value.trim().length > 0;
24
+ }
25
+ /**
26
+ * Classify a path/glob without regular expressions (CodeQL js/polynomial-redos).
27
+ * Unstarred paths are directory prefixes (file_scope semantics).
28
+ */
29
+ export function classifyGlob(glob) {
30
+ let p = normalizePath(glob).trim();
31
+ if (p.endsWith("/"))
32
+ p = p.slice(0, -1);
33
+ if (p === "**") {
34
+ return { prefix: "", depth: "subtree", leadingDoubleStar: true };
35
+ }
36
+ if (p.startsWith("**/")) {
37
+ let rest = p.slice(3);
38
+ if (rest.endsWith("/*"))
39
+ rest = rest.slice(0, -2);
40
+ const inner = rest.indexOf("/**");
41
+ if (inner >= 0)
42
+ rest = rest.slice(0, inner);
43
+ return { prefix: rest, depth: "subtree", leadingDoubleStar: true };
44
+ }
45
+ const starStar = p.indexOf("/**");
46
+ if (starStar >= 0) {
47
+ return { prefix: p.slice(0, starStar), depth: "subtree", leadingDoubleStar: false };
48
+ }
49
+ if (p.endsWith("/*")) {
50
+ return { prefix: p.slice(0, -2), depth: "one", leadingDoubleStar: false };
51
+ }
52
+ if (p.includes("*") || p.includes("?")) {
53
+ const slashStar = p.indexOf("/*");
54
+ if (slashStar >= 0) {
55
+ return { prefix: p.slice(0, slashStar), depth: "subtree", leadingDoubleStar: false };
56
+ }
57
+ return { prefix: p, depth: "subtree", leadingDoubleStar: false };
58
+ }
59
+ return { prefix: p, depth: "subtree", leadingDoubleStar: false };
60
+ }
61
+ /** Strip glob tails so prefix comparison stays path-shaped. */
62
+ export function normalizeGlobAsPath(glob) {
63
+ return classifyGlob(glob).prefix;
64
+ }
65
+ function remainderUnder(child, parent) {
66
+ if (child === parent)
67
+ return "";
68
+ const stem = parent.length === 0 ? "" : `${parent}/`;
69
+ if (parent.length === 0)
70
+ return child;
71
+ if (!child.startsWith(stem))
72
+ return null;
73
+ return child.slice(stem.length);
74
+ }
75
+ function depthAllows(depth, remainder) {
76
+ if (depth === "subtree")
77
+ return true;
78
+ if (depth === "exact")
79
+ return remainder.length === 0;
80
+ return remainder.length > 0 && !remainder.includes("/");
81
+ }
82
+ /**
83
+ * True when two path/glob strings can name a shared tree.
84
+ * `/*` is one segment; `/**` / unstarred file_scope paths are subtrees.
85
+ */
86
+ export function pathGlobsIntersect(left, right) {
87
+ const a = normalizePath(left).trim();
88
+ const b = normalizePath(right).trim();
89
+ if (a.length === 0 || b.length === 0)
90
+ return false;
91
+ if (a === b)
92
+ return true;
93
+ if (matchPath(a, b) || matchPath(b, a))
94
+ return true;
95
+ const ca = classifyGlob(a);
96
+ const cb = classifyGlob(b);
97
+ if (ca.prefix.length === 0 && cb.prefix.length === 0)
98
+ return true;
99
+ const aUnderB = remainderUnder(ca.prefix, cb.prefix);
100
+ if (aUnderB !== null && depthAllows(cb.depth, aUnderB))
101
+ return true;
102
+ const bUnderA = remainderUnder(cb.prefix, ca.prefix);
103
+ if (bUnderA !== null && depthAllows(ca.depth, bUnderA))
104
+ return true;
105
+ if (ca.leadingDoubleStar && suffixMatch(cb.prefix, ca.prefix))
106
+ return true;
107
+ if (cb.leadingDoubleStar && suffixMatch(ca.prefix, cb.prefix))
108
+ return true;
109
+ return false;
110
+ }
111
+ function suffixMatch(path, suffix) {
112
+ if (suffix.length === 0 || path.length === 0)
113
+ return false;
114
+ return path === suffix || path.endsWith(`/${suffix}`);
115
+ }
116
+ function surfacePaths(invariant, modulePathGlobs) {
117
+ const paths = [...invariant.contractSurface.paths];
118
+ const unresolvedModuleIds = [];
119
+ for (const moduleId of invariant.contractSurface.moduleIds) {
120
+ const mapped = modulePathGlobs[moduleId];
121
+ if (mapped === undefined || mapped.length === 0) {
122
+ unresolvedModuleIds.push(moduleId);
123
+ continue;
124
+ }
125
+ paths.push(...mapped);
126
+ }
127
+ return { paths, unresolvedModuleIds };
128
+ }
129
+ function anyPathOverlap(left, right) {
130
+ for (const a of left) {
131
+ for (const b of right) {
132
+ if (pathGlobsIntersect(a, b))
133
+ return true;
134
+ }
135
+ }
136
+ return false;
137
+ }
138
+ /**
139
+ * Invariants whose contract surface intersects `fileScope`.
140
+ * Empty file_scope → empty intersection (no disposition required).
141
+ * Unresolved module ids (no pathGlobs mapping) are treated as applicable.
142
+ */
143
+ export function applicableProjectInvariants(invariants, fileScope, modulePathGlobs = {}) {
144
+ const scope = fileScope.map((s) => s.trim()).filter((s) => s.length > 0);
145
+ if (scope.length === 0)
146
+ return [];
147
+ const out = [];
148
+ for (const invariant of invariants) {
149
+ const { paths, unresolvedModuleIds } = surfacePaths(invariant, modulePathGlobs);
150
+ if (unresolvedModuleIds.length > 0) {
151
+ out.push({ id: invariant.id, reason: "unresolved-module" });
152
+ continue;
153
+ }
154
+ if (anyPathOverlap(paths, scope)) {
155
+ const viaModule = invariant.contractSurface.moduleIds.length > 0 && paths.length > 0;
156
+ out.push({
157
+ id: invariant.id,
158
+ reason: viaModule && invariant.contractSurface.paths.length === 0 ? "module" : "path",
159
+ });
160
+ }
161
+ }
162
+ return out;
163
+ }
164
+ function peelNotApplicable(raw) {
165
+ const notApplicable = [];
166
+ const errors = [];
167
+ if (raw === null || raw === undefined) {
168
+ return { remainder: raw, notApplicable, errors };
169
+ }
170
+ const takeReason = (body) => {
171
+ const nested = asRecord(body.provenance);
172
+ const reason = nested?.reason ?? body.reason;
173
+ return isNonEmptyString(reason) ? reason.trim() : null;
174
+ };
175
+ if (Array.isArray(raw)) {
176
+ const remainder = [];
177
+ for (let i = 0; i < raw.length; i += 1) {
178
+ const item = raw[i];
179
+ const loc = `coverage_map[${i}]`;
180
+ const rec = asRecord(item);
181
+ if (rec === null) {
182
+ remainder.push(item);
183
+ continue;
184
+ }
185
+ const disposition = rec.disposition;
186
+ if (typeof disposition === "string" &&
187
+ disposition.trim().toLowerCase() === "not_applicable") {
188
+ const id = rec.parent_requirement_id ?? rec.parentRequirementId ?? rec.id;
189
+ if (!isNonEmptyString(id)) {
190
+ errors.push(`${loc}: parent_requirement_id is required`);
191
+ continue;
192
+ }
193
+ const reason = takeReason(rec);
194
+ if (reason === null) {
195
+ errors.push(`${loc}: disposition not_applicable requires reason`);
196
+ }
197
+ notApplicable.push({ id: id.trim(), reason, loc });
198
+ continue;
199
+ }
200
+ remainder.push(item);
201
+ }
202
+ return { remainder, notApplicable, errors };
203
+ }
204
+ const map = asRecord(raw);
205
+ if (map === null) {
206
+ return { remainder: raw, notApplicable, errors };
207
+ }
208
+ const remainder = {};
209
+ for (const [key, value] of Object.entries(map)) {
210
+ const loc = `coverage_map[${key}]`;
211
+ const rec = asRecord(value);
212
+ if (rec === null) {
213
+ remainder[key] = value;
214
+ continue;
215
+ }
216
+ const disposition = rec.disposition;
217
+ if (typeof disposition === "string" && disposition.trim().toLowerCase() === "not_applicable") {
218
+ const id = rec.parent_requirement_id ?? rec.parentRequirementId ?? key;
219
+ if (!isNonEmptyString(id)) {
220
+ errors.push(`${loc}: parent_requirement_id is required`);
221
+ continue;
222
+ }
223
+ const reason = takeReason(rec);
224
+ if (reason === null) {
225
+ errors.push(`${loc}: disposition not_applicable requires reason`);
226
+ }
227
+ notApplicable.push({ id: String(id).trim(), reason, loc });
228
+ continue;
229
+ }
230
+ remainder[key] = value;
231
+ }
232
+ return { remainder, notApplicable, errors };
233
+ }
234
+ function extractCoverageRaw(draft) {
235
+ const rec = asRecord(draft);
236
+ if (rec === null)
237
+ return undefined;
238
+ if (rec.coverage_map !== undefined || rec.coverageMap !== undefined) {
239
+ return rec.coverage_map ?? rec.coverageMap;
240
+ }
241
+ const plan = asRecord(rec.plan);
242
+ if (plan === null)
243
+ return undefined;
244
+ if (plan.coverage_map !== undefined || plan.coverageMap !== undefined) {
245
+ return plan.coverage_map ?? plan.coverageMap;
246
+ }
247
+ const metadata = asRecord(plan.metadata);
248
+ if (metadata === null)
249
+ return undefined;
250
+ return metadata.coverage_map ?? metadata.coverageMap;
251
+ }
252
+ function extractDeltasRaw(draft) {
253
+ const rec = asRecord(draft);
254
+ if (rec === null)
255
+ return undefined;
256
+ if (rec.behavioral_deltas !== undefined || rec.behavioralDeltas !== undefined) {
257
+ return rec.behavioral_deltas ?? rec.behavioralDeltas;
258
+ }
259
+ const plan = asRecord(rec.plan);
260
+ if (plan === null)
261
+ return undefined;
262
+ return plan.behavioral_deltas ?? plan.behavioralDeltas;
263
+ }
264
+ /**
265
+ * Completeness of coverage_map dispositions for applicable project invariant IDs.
266
+ * Extra coverage_map keys (e.g. parent requirement IDs) are ignored.
267
+ * Empty applicable set is a no-op success.
268
+ */
269
+ export function validateProjectInvariantCoverage(opts) {
270
+ const applicableIds = [...new Set(opts.applicableIds.map((id) => id.trim()).filter(Boolean))];
271
+ const errors = [];
272
+ const coverageRaw = extractCoverageRaw(opts.draft);
273
+ const peeled = peelNotApplicable(coverageRaw);
274
+ errors.push(...peeled.errors);
275
+ const { entries, errors: mapErrors } = parseCoverageMap(peeled.remainder);
276
+ errors.push(...mapErrors);
277
+ const { byId: deltasById, errors: deltaErrors } = parseBehavioralDeltas(extractDeltasRaw(opts.draft));
278
+ errors.push(...deltaErrors);
279
+ const applicableSet = new Set(applicableIds);
280
+ const byId = new Map();
281
+ for (const entry of entries) {
282
+ if (!applicableSet.has(entry.parent_requirement_id)) {
283
+ continue;
284
+ }
285
+ if (entry.disposition === "split") {
286
+ errors.push(`coverage_map[${entry.parent_requirement_id}]: disposition split is excluded at project level`);
287
+ continue;
288
+ }
289
+ if (byId.has(entry.parent_requirement_id)) {
290
+ errors.push(`coverage_map[${entry.parent_requirement_id}]: duplicate coverage entries ` +
291
+ `(one disposition per project invariant ID)`);
292
+ continue;
293
+ }
294
+ byId.set(entry.parent_requirement_id, entry);
295
+ if (entry.disposition === "behavioral_delta") {
296
+ const deltaId = entry.delta_id;
297
+ if (isNonEmptyString(deltaId) && !deltasById.has(deltaId)) {
298
+ errors.push(`coverage_map[${entry.parent_requirement_id}]: behavioral_delta delta_id '${deltaId}' ` +
299
+ `has no linked record in behavioral_deltas`);
300
+ }
301
+ }
302
+ }
303
+ const addressed = new Set();
304
+ for (const na of peeled.notApplicable) {
305
+ addressed.add(na.id);
306
+ }
307
+ for (const id of byId.keys()) {
308
+ addressed.add(id);
309
+ }
310
+ const missingIds = applicableIds.filter((id) => !addressed.has(id));
311
+ if (missingIds.length > 0) {
312
+ errors.push(`uncovered applicable project invariant IDs: ${missingIds.join(", ")} ` +
313
+ `(declare coverage_map[<id>].disposition as ${PROJECT_INVARIANT_DISPOSITIONS.join("|")})`);
314
+ }
315
+ return {
316
+ ok: errors.length === 0,
317
+ applicableIds,
318
+ missingIds,
319
+ errors,
320
+ };
321
+ }
322
+ //# sourceMappingURL=project-invariant-coverage.js.map
@@ -195,7 +195,7 @@ export function promoteFromIssue(options) {
195
195
  return {
196
196
  ok: false,
197
197
  message: `No triage-cache decision for #${n} (${repoSafe}). ` +
198
- `Accept first: task triage:accept -- --issue ${n} --repo ${repoSafe} ` +
198
+ `Accept first: deft triage:accept --issue ${n} --repo ${repoSafe} ` +
199
199
  `(or omit --strict to soft-warn and proceed; --force-no-cache skips the gate).`,
200
200
  exitCode: 1,
201
201
  warnings,
@@ -212,7 +212,7 @@ export function promoteFromIssue(options) {
212
212
  ok: false,
213
213
  message: `Refusing promote for #${n} (${repoSafe}): latest triage decision is '${sanitizeMsg(latest.decision)}' ` +
214
214
  `(decision_id=${latest.decision_id}). ` +
215
- `Accept first: task triage:accept -- --issue ${n} --repo ${repoSafe} ` +
215
+ `Accept first: deft triage:accept --issue ${n} --repo ${repoSafe} ` +
216
216
  `or override with --force-no-cache.`,
217
217
  exitCode: 1,
218
218
  warnings,
@@ -315,8 +315,8 @@ export function promoteFromIssue(options) {
315
315
  return {
316
316
  ok: false,
317
317
  message: `No proposed/ scope artifact found for issue #${n} (${repoSafe}). ` +
318
- `Ingest first (task triage:accept -- --issue ${n} --repo ${repoSafe}) ` +
319
- `or pass an explicit path: task scope:promote -- <path>.`,
318
+ `Ingest first (deft triage:accept --issue ${n} --repo ${repoSafe}) ` +
319
+ `or pass an explicit path: deft scope:promote <path>.`,
320
320
  exitCode: 1,
321
321
  warnings,
322
322
  repo,
@@ -330,7 +330,7 @@ export function promoteFromIssue(options) {
330
330
  return {
331
331
  ok: false,
332
332
  message: `Multiple proposed/ artifacts match issue #${n}; refuse to guess.\n${list}\n` +
333
- `Promote one path explicitly: task scope:promote -- <path> ` +
333
+ `Promote one path explicitly: deft scope:promote <path> ` +
334
334
  `or re-run with --path <one-of-the-above>.`,
335
335
  exitCode: 1,
336
336
  warnings,
@@ -154,7 +154,7 @@ export function runTransition(action, filePath, now = new Date(), options = {})
154
154
  projectRoot,
155
155
  emitStamp: false,
156
156
  });
157
- if (derivation.applied) {
157
+ if (derivation.notice.length > 0) {
158
158
  derivationNotice = derivation.notice;
159
159
  }
160
160
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Public compare entry for extracted intent (#3376 R2 / R5 / #3385 F1–F2).
3
+ *
4
+ * Scalars are byte-equal after canonicalize. Decisions and references[] are
5
+ * guarded-append. Unclassified key only when unknown AND absent from base.
6
+ */
7
+ import { type IntentPreimage } from "./extract-intent.js";
8
+ export type IntentCompareKind = "intent-drift" | "unclassified-key" | "reference-mutation" | "decisions-mutation" | "repo-not-approved" | "ref-type-not-appendable" | "decision-pointer-missing";
9
+ export interface IntentCompareFinding {
10
+ readonly kind: IntentCompareKind;
11
+ readonly path: string;
12
+ readonly detail: string;
13
+ }
14
+ export interface IntentCompareResult {
15
+ readonly ok: boolean;
16
+ readonly findings: readonly IntentCompareFinding[];
17
+ }
18
+ export interface CompareIntentOptions {
19
+ readonly changedFiles?: readonly string[];
20
+ readonly decisionExists?: (relPath: string) => boolean;
21
+ }
22
+ /**
23
+ * Compare a live extraction to the base-committed preimage.
24
+ * One entry point covers scalar equality and guarded append (R2 / R5).
25
+ */
26
+ export declare function compareExtractedIntent(base: IntentPreimage, live: IntentPreimage, options?: CompareIntentOptions): IntentCompareResult;
27
+ //# sourceMappingURL=compare-intent.d.ts.map