@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
@@ -3,6 +3,7 @@ import { validateCoverageDebt } from "../policy/coverage-debt.js";
3
3
  import { validateHostHooks } from "../policy/host-hooks.js";
4
4
  import { validateHostSlashCommands } from "../policy/host-slash-commands.js";
5
5
  import { readPlanPolicy } from "../policy/plan-extensions.js";
6
+ import { parseProjectInvariants } from "../policy/project-invariants.js";
6
7
  import { validateRuntimeAuthority } from "../policy/runtime-authority.js";
7
8
  import { validateStalenessTickler } from "../policy/staleness-tickler.js";
8
9
  import { validateOpenClawProductCommands } from "../slash/openclaw-deposit.js";
@@ -93,6 +94,61 @@ export function validateSessionRitualStalenessHoursOnPlan(plan, filepath) {
93
94
  }
94
95
  return out;
95
96
  }
97
+ function validateForgeOutageRetryMinutes(value) {
98
+ if (value === null || value === undefined) {
99
+ return [];
100
+ }
101
+ if (typeof value !== "number" || !Number.isInteger(value)) {
102
+ const repr = typeof value === "string"
103
+ ? pyStrRepr(value)
104
+ : typeof value === "boolean"
105
+ ? value
106
+ ? "True"
107
+ : "False"
108
+ : String(value);
109
+ return [
110
+ "plan.policy.forgeOutageRetryMinutes must be an integer; got " +
111
+ `${pythonTypeName(value)} (${repr})`,
112
+ ];
113
+ }
114
+ if (value < 5) {
115
+ return [`plan.policy.forgeOutageRetryMinutes must be >= 5; got ${value}`];
116
+ }
117
+ return [];
118
+ }
119
+ /** vbrief_validate hook for ``projectInvariants`` (#3425). */
120
+ export function validateProjectInvariantsOnPlan(plan, filepath) {
121
+ if (typeof plan !== "object" || plan === null || Array.isArray(plan)) {
122
+ return [];
123
+ }
124
+ const policy = readPlanPolicy(plan);
125
+ if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
126
+ return [];
127
+ }
128
+ if (!("projectInvariants" in policy)) {
129
+ return [];
130
+ }
131
+ const { errors } = parseProjectInvariants(policy.projectInvariants);
132
+ return errors.map((err) => `${filepath}: ${err} (#3425)`);
133
+ }
134
+ /** vbrief_validate hook for ``forgeOutageRetryMinutes`` (#3422). */
135
+ export function validateForgeOutageRetryMinutesOnPlan(plan, filepath) {
136
+ if (typeof plan !== "object" || plan === null || Array.isArray(plan)) {
137
+ return [];
138
+ }
139
+ const policy = readPlanPolicy(plan);
140
+ if (typeof policy !== "object" || policy === null || Array.isArray(policy)) {
141
+ return [];
142
+ }
143
+ if (!("forgeOutageRetryMinutes" in policy)) {
144
+ return [];
145
+ }
146
+ const out = [];
147
+ for (const err of validateForgeOutageRetryMinutes(policy.forgeOutageRetryMinutes)) {
148
+ out.push(`${filepath}: ${err} (#3422)`);
149
+ }
150
+ return out;
151
+ }
96
152
  /** vbrief_validate hook: validate ``plan.policy.triageRankingLabels`` (#1128). */
97
153
  export function validateTriageRankingLabelsOnPlan(plan, filepath) {
98
154
  if (typeof plan !== "object" || plan === null || Array.isArray(plan)) {
@@ -283,6 +339,18 @@ export function runProjectDefinitionHooks(plan, filepath) {
283
339
  catch {
284
340
  /* hook must not break validation */
285
341
  }
342
+ try {
343
+ errors.push(...validateForgeOutageRetryMinutesOnPlan(plan, filepath));
344
+ }
345
+ catch {
346
+ /* hook must not break validation */
347
+ }
348
+ try {
349
+ errors.push(...validateProjectInvariantsOnPlan(plan, filepath));
350
+ }
351
+ catch {
352
+ /* hook must not break validation */
353
+ }
286
354
  try {
287
355
  errors.push(...validateStalenessTicklerOnPlan(plan, filepath));
288
356
  }
@@ -27,6 +27,11 @@ export interface OracleIntegrityResultFields {
27
27
  readonly code: number;
28
28
  readonly message: string;
29
29
  }
30
+ /**
31
+ * Walk-level method fingerprint: command list + cwd hash (#3397 / #3322).
32
+ * Same shape for fail and pass so an honest product fix does not flag.
33
+ */
34
+ export declare function methodFingerprintForWalk(commands: readonly string[], cwd: string): string;
30
35
  /** Stable prefix for product-oracle check ids emitted by verify:ac (#3322 / #3337). */
31
36
  export declare const VERIFY_AC_CHECK_ID_PREFIX = "verify:ac";
32
37
  /**
@@ -40,7 +45,8 @@ export declare function verifyAcCheckId(scopeKey?: string | null): string;
40
45
  /** Test seam: isolate stdout-dest buffer across cases. */
41
46
  export declare function resetInProcessVerificationBuffer(): void;
42
47
  /**
43
- * Record each executed acceptance command as a verification event (#3322).
48
+ * Record one walk-level verification event for the executed command set (#3322 / #3397).
49
+ * Fail and pass use the same method_fingerprint shape (command list + cwd hash).
44
50
  * Fail-open: missing dest / write errors never change the AC result.
45
51
  * Stdout dest also appends to the same-process buffer so evaluate can
46
52
  * inspect this invocation without re-reading a file.
@@ -7,14 +7,25 @@
7
7
  * attempts just emitted by this verify:ac — it does not treat non-file
8
8
  * dest as no evidence.
9
9
  */
10
- import { randomUUID } from "node:crypto";
10
+ import { createHash } from "node:crypto";
11
11
  import { existsSync, readFileSync } from "node:fs";
12
12
  import { resolve } from "node:path";
13
13
  import { parseRunSummaryJsonl, RunSummaryEmitter, resolveRunSummaryDestination, } from "../run-summary/index.js";
14
14
  import { flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
15
15
  function formatUnresolved(flag) {
16
+ const delta = typeof flag.resolved_command_count_delta === "number"
17
+ ? ` command_count_delta=${flag.resolved_command_count_delta}`
18
+ : "";
16
19
  return (`check_id=${flag.check_id} fail method=${flag.failed_method} ` +
17
- `then pass method=${flag.passed_method} without independent re-derivation`);
20
+ `then pass method=${flag.passed_method} without independent re-derivation${delta}`);
21
+ }
22
+ /**
23
+ * Walk-level method fingerprint: command list + cwd hash (#3397 / #3322).
24
+ * Same shape for fail and pass so an honest product fix does not flag.
25
+ */
26
+ export function methodFingerprintForWalk(commands, cwd) {
27
+ const cwdHash = createHash("sha256").update(cwd, "utf8").digest("hex");
28
+ return `${commands.join("\0")}\0${cwdHash}`;
18
29
  }
19
30
  /** Stable prefix for product-oracle check ids emitted by verify:ac (#3322 / #3337). */
20
31
  export const VERIFY_AC_CHECK_ID_PREFIX = "verify:ac";
@@ -36,11 +47,9 @@ export function verifyAcCheckId(scopeKey) {
36
47
  }
37
48
  /** Same-process verification JSONL when dest is stdout (`-`). */
38
49
  const inProcessVerificationLines = [];
39
- let inProcessStdoutSessionId;
40
50
  /** Test seam: isolate stdout-dest buffer across cases. */
41
51
  export function resetInProcessVerificationBuffer() {
42
52
  inProcessVerificationLines.length = 0;
43
- inProcessStdoutSessionId = undefined;
44
53
  }
45
54
  function inProcessVerificationText() {
46
55
  if (inProcessVerificationLines.length === 0) {
@@ -49,7 +58,8 @@ function inProcessVerificationText() {
49
58
  return inProcessVerificationLines.join("\n");
50
59
  }
51
60
  /**
52
- * Record each executed acceptance command as a verification event (#3322).
61
+ * Record one walk-level verification event for the executed command set (#3322 / #3397).
62
+ * Fail and pass use the same method_fingerprint shape (command list + cwd hash).
53
63
  * Fail-open: missing dest / write errors never change the AC result.
54
64
  * Stdout dest also appends to the same-process buffer so evaluate can
55
65
  * inspect this invocation without re-reading a file.
@@ -63,18 +73,7 @@ export function emitVerifyAcAttempts(options) {
63
73
  const env = options.env ?? process.env;
64
74
  const projectRoot = resolve(options.projectRoot);
65
75
  const dest = resolveRunSummaryDestination(projectRoot, { env });
66
- const explicitSession = options.sessionId?.trim() ||
67
- (typeof env.DEFT_SESSION_ID === "string" ? env.DEFT_SESSION_ID.trim() : "");
68
- let sessionId = explicitSession;
69
- if (!sessionId) {
70
- if (dest.kind === "stdout") {
71
- inProcessStdoutSessionId ??= randomUUID();
72
- sessionId = inProcessStdoutSessionId;
73
- }
74
- else {
75
- sessionId = randomUUID();
76
- }
77
- }
76
+ const sessionId = options.sessionId;
78
77
  const explicitCheck = typeof options.checkId === "string" && options.checkId.trim().length > 0
79
78
  ? options.checkId.trim()
80
79
  : null;
@@ -83,17 +82,26 @@ export function emitVerifyAcAttempts(options) {
83
82
  projectRoot,
84
83
  sessionId,
85
84
  env,
85
+ component: "verify-ac",
86
86
  writeStdout: options.writeStdout,
87
87
  });
88
- for (const run of options.runs) {
89
- const emitted = emitter.emitVerification({
90
- check_id: checkId,
91
- method_fingerprint: `${run.command}\0${run.cwd}`,
92
- outcome: run.ok ? "pass" : "fail",
93
- });
94
- if (dest.kind === "stdout" && emitted.line !== null) {
95
- inProcessVerificationLines.push(JSON.stringify(emitted.line));
96
- }
88
+ // One walk-level event: the method is the command set, not each command.
89
+ // Per-command emit was blind to a shrinking list that kept the first command (#3397).
90
+ const commands = options.runs.map((run) => run.command);
91
+ const firstCwd = options.runs[0]?.cwd ?? "";
92
+ // Hash the cwd key (joined only when cwds differ) so cwd paths never enter
93
+ // the fingerprint; commandCountFromFingerprint can still count commands.
94
+ const cwdKey = options.runs.every((run) => run.cwd === firstCwd)
95
+ ? firstCwd
96
+ : options.runs.map((run) => run.cwd).join("\0");
97
+ const outcome = options.runs.every((run) => run.ok) ? "pass" : "fail";
98
+ const emitted = emitter.emitVerification({
99
+ check_id: checkId,
100
+ method_fingerprint: methodFingerprintForWalk(commands, cwdKey),
101
+ outcome,
102
+ });
103
+ if (dest.kind === "stdout" && emitted.line !== null) {
104
+ inProcessVerificationLines.push(JSON.stringify(emitted.line));
97
105
  }
98
106
  }
99
107
  catch {
@@ -20,7 +20,11 @@ export interface FlaggedMethodChangePass {
20
20
  readonly failed_method: string;
21
21
  readonly passed_method: string;
22
22
  readonly independent_rederivation: boolean;
23
+ /** Pass count minus fail count when both fingerprints carry a command list (#3397). */
24
+ readonly resolved_command_count_delta?: number;
23
25
  }
26
+ /** Command count encoded in a walk fingerprint (`cmd\0cmd\0cwd-or-hash`). */
27
+ export declare function commandCountFromFingerprint(fingerprint: string): number;
24
28
  /** Extract well-formed verification attempts in stream order. */
25
29
  export declare function readVerificationAttempts(lines: readonly RunSummaryLine[]): VerificationAttempt[];
26
30
  /**
@@ -6,6 +6,19 @@
6
6
  * In-place comparison repair then pass is unresolved.
7
7
  */
8
8
  import { parseRunSummaryJsonl } from "../run-summary/index.js";
9
+ /** Command count encoded in a walk fingerprint (`cmd\0cmd\0cwd-or-hash`). */
10
+ export function commandCountFromFingerprint(fingerprint) {
11
+ const parts = fingerprint.split("\0");
12
+ if (parts.length <= 1) {
13
+ return 1;
14
+ }
15
+ const last = parts[parts.length - 1] ?? "";
16
+ const lastIsCwdOrHash = /^[0-9a-f]{8,64}$/i.test(last) ||
17
+ last.includes("/") ||
18
+ last.includes("\\") ||
19
+ last.includes(":");
20
+ return lastIsCwdOrHash ? Math.max(1, parts.length - 1) : parts.length;
21
+ }
9
22
  function asRecord(value) {
10
23
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
11
24
  return null;
@@ -74,11 +87,14 @@ export function flagPassAfterFailWithMethodChange(attempts) {
74
87
  }
75
88
  const other = [...prior].find((method) => method !== attempt.method_fingerprint);
76
89
  if (other !== undefined) {
90
+ const delta = commandCountFromFingerprint(attempt.method_fingerprint) -
91
+ commandCountFromFingerprint(other);
77
92
  flagged.push({
78
93
  check_id: attempt.check_id,
79
94
  failed_method: other,
80
95
  passed_method: attempt.method_fingerprint,
81
96
  independent_rederivation: attempt.independent_rederivation,
97
+ ...(delta !== 0 ? { resolved_command_count_delta: delta } : {}),
82
98
  });
83
99
  }
84
100
  if (attempt.independent_rederivation || other === undefined) {
@@ -5,6 +5,6 @@
5
5
  * by editing the comparison. Deterministic surface is the flagged event.
6
6
  */
7
7
  export { type AcceptanceClause, type AcceptanceClauseReading, type ClauseOutcome, type ClauseWalkReport, type ClauseWalkResult, deriveAcceptanceClauses, formatClauseWalkMessage, isScratchArtifactPath, readAcceptanceClauses, serializeAcceptanceClauses, stampDerivedClausesOnAcceptance, walkAcceptanceClauses, } from "./clauses.js";
8
- export { type EvaluateProductOracleIntegrityOptions, emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, type OracleIntegrityResultFields, type ProductOracleIntegrityVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
- export { type FlaggedMethodChangePass, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, type VerificationAttempt, } from "./flag.js";
8
+ export { type EvaluateProductOracleIntegrityOptions, emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, methodFingerprintForWalk, type OracleIntegrityResultFields, type ProductOracleIntegrityVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
+ export { commandCountFromFingerprint, type FlaggedMethodChangePass, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, type VerificationAttempt, } from "./flag.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -5,6 +5,6 @@
5
5
  * by editing the comparison. Deterministic surface is the flagged event.
6
6
  */
7
7
  export { deriveAcceptanceClauses, formatClauseWalkMessage, isScratchArtifactPath, readAcceptanceClauses, serializeAcceptanceClauses, stampDerivedClausesOnAcceptance, walkAcceptanceClauses, } from "./clauses.js";
8
- export { emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
- export { flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
8
+ export { emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, methodFingerprintForWalk, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
+ export { commandCountFromFingerprint, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
10
10
  //# sourceMappingURL=index.js.map
@@ -46,6 +46,8 @@ export const CONTAINED_WRITES_ALLOWLIST = [
46
46
  // Implementation modules for containment + contained write.
47
47
  "packages/core/src/fs/contained-write.ts",
48
48
  "packages/core/src/fs/projection-containment.ts",
49
+ // #3424: read-only O_NOFOLLOW fd pin in intended-placement inspect (not a write sink).
50
+ "packages/core/src/preflight/intended-placement.ts",
49
51
  // Deposit tree copy / contain primitives (low-level install sinks).
50
52
  "packages/core/src/deposit/copy-tree.ts",
51
53
  "packages/core/src/deposit/contain.ts",
@@ -1,3 +1,4 @@
1
+ export * from "../telemetry-coverage/index.js";
1
2
  export * from "./biome-config.js";
2
3
  export * from "./code-structure-validate.js";
3
4
  export * from "./contained-writes.js";
@@ -1,3 +1,4 @@
1
+ export * from "../telemetry-coverage/index.js";
1
2
  export * from "./biome-config.js";
2
3
  export * from "./code-structure-validate.js";
3
4
  export * from "./contained-writes.js";
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Shared "not product source" core (#3487) plus the directories only the stub
3
+ * scan treats as non-product: fixtures/tests, vendored trees, the history
4
+ * archive, and operator scripts.
5
+ */
1
6
  export declare const EXCLUDE_DIRS: Set<string>;
2
7
  export declare const EXTENSIONS: Set<string>;
3
8
  export interface StubFinding {
@@ -6,7 +11,16 @@ export interface StubFinding {
6
11
  readonly label: string;
7
12
  readonly text: string;
8
13
  }
9
- /** Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`. */
14
+ /**
15
+ * Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`, pruning
16
+ * `EXCLUDE_DIRS` before recursing.
17
+ *
18
+ * Pruning is load-bearing, not an optimisation of a filter applied later: on a
19
+ * host with a populated `.deft-scratch/` the unpruned walk enumerates every
20
+ * swarm worktree (millions of entries) only to discard them per-file. #2953
21
+ * added `.deft-scratch` / `swarm-worktrees` to `EXCLUDE_DIRS` for exactly this
22
+ * reason but left the walk descending into them (#3481).
23
+ */
10
24
  export declare function sortedRglob(root: string): string[];
11
25
  export declare function scanFileForStubs(relPath: string, fullPath: string): StubFinding[];
12
26
  export interface VerifyStubsResult {
@@ -1,20 +1,12 @@
1
1
  import { readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
- export const EXCLUDE_DIRS = new Set([
4
- "tests",
5
- "vendor",
6
- ".git",
7
- "backup",
8
- "history",
9
- "node_modules",
10
- ".venv",
11
- "__pycache__",
12
- "dist",
13
- "scripts",
14
- // Swarm / agent worktrees are not product source (#2953, #1656).
15
- ".deft-scratch",
16
- "swarm-worktrees",
17
- ]);
3
+ import { NON_PRODUCT_DIRS } from "../fs/non-product-dirs.js";
4
+ /**
5
+ * Shared "not product source" core (#3487) plus the directories only the stub
6
+ * scan treats as non-product: fixtures/tests, vendored trees, the history
7
+ * archive, and operator scripts.
8
+ */
9
+ export const EXCLUDE_DIRS = new Set([...NON_PRODUCT_DIRS, "tests", "vendor", "history", "scripts"]);
18
10
  export const EXTENSIONS = new Set([".py", ".go", ".sh"]);
19
11
  function isWordChar(ch) {
20
12
  if (ch.length === 0) {
@@ -73,7 +65,16 @@ function hasReturnNull(text) {
73
65
  }
74
66
  return false;
75
67
  }
76
- /** Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`. */
68
+ /**
69
+ * Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`, pruning
70
+ * `EXCLUDE_DIRS` before recursing.
71
+ *
72
+ * Pruning is load-bearing, not an optimisation of a filter applied later: on a
73
+ * host with a populated `.deft-scratch/` the unpruned walk enumerates every
74
+ * swarm worktree (millions of entries) only to discard them per-file. #2953
75
+ * added `.deft-scratch` / `swarm-worktrees` to `EXCLUDE_DIRS` for exactly this
76
+ * reason but left the walk descending into them (#3481).
77
+ */
77
78
  export function sortedRglob(root) {
78
79
  const out = [];
79
80
  function walk(dir, relPrefix) {
@@ -95,6 +96,9 @@ export function sortedRglob(root) {
95
96
  continue;
96
97
  }
97
98
  if (st.isDirectory()) {
99
+ if (EXCLUDE_DIRS.has(name)) {
100
+ continue;
101
+ }
98
102
  walk(full, rel);
99
103
  }
100
104
  else {
@@ -3,18 +3,17 @@ export declare const COVERAGE_TMP_CHUNK_RE: RegExp;
3
3
  export declare function isCoverageTmpChunkPath(filePath: string): boolean;
4
4
  export declare function ensureCoverageTmpDir(coverageTmpDir?: string): void;
5
5
  /**
6
- * Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
7
- * (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
8
- * directory can disappear between clean() and writeFile under release-scale
6
+ * Vitest 4.x includes the upstream mkdir (vitest-dev/vitest#10117). On Windows the
7
+ * directory can still disappear between clean() and writeFile under release-scale
9
8
  * load; mkdir immediately before chunk writes closes that race without
10
- * soft-failing real threshold failures (#2634).
9
+ * soft-failing real threshold failures (#2634 / #3480).
11
10
  */
12
11
  export declare function installCoverageTmpWriteGuard(): () => void;
13
12
  /**
14
13
  * Win32 globalSetup for coverage runs (#2580, hardened #2634).
15
14
  *
16
- * Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
17
- * directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
15
+ * Keepalive mkdir plus a writeFile guard remain until a full win32 coverage
16
+ * run proves vitest 4's #10117 mkdir is enough on its own (#3480).
18
17
  */
19
18
  export default function setup(): () => void;
20
19
  //# sourceMappingURL=win32-coverage-tmp-setup.d.ts.map
@@ -10,11 +10,10 @@ export function ensureCoverageTmpDir(coverageTmpDir = defaultCoverageTmp) {
10
10
  mkdirSync(coverageTmpDir, { recursive: true });
11
11
  }
12
12
  /**
13
- * Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
14
- * (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
15
- * directory can disappear between clean() and writeFile under release-scale
13
+ * Vitest 4.x includes the upstream mkdir (vitest-dev/vitest#10117). On Windows the
14
+ * directory can still disappear between clean() and writeFile under release-scale
16
15
  * load; mkdir immediately before chunk writes closes that race without
17
- * soft-failing real threshold failures (#2634).
16
+ * soft-failing real threshold failures (#2634 / #3480).
18
17
  */
19
18
  export function installCoverageTmpWriteGuard() {
20
19
  const originalWriteFile = fsPromises.writeFile.bind(fsPromises);
@@ -33,8 +32,8 @@ export function installCoverageTmpWriteGuard() {
33
32
  /**
34
33
  * Win32 globalSetup for coverage runs (#2580, hardened #2634).
35
34
  *
36
- * Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
37
- * directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
35
+ * Keepalive mkdir plus a writeFile guard remain until a full win32 coverage
36
+ * run proves vitest 4's #10117 mkdir is enough on its own (#3480).
38
37
  */
39
38
  export default function setup() {
40
39
  if (process.platform !== "win32")
@@ -1,6 +1,6 @@
1
1
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join, relative, resolve } from "node:path";
3
- import { containedWrite } from "../fs/contained-write.js";
3
+ import { containedRemove, containedWrite } from "../fs/contained-write.js";
4
4
  import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
5
5
  import { checkGitClean } from "../migrate-preflight/index.js";
6
6
  import { applyAgentsRefresh } from "../platform/agents-md.js";
@@ -36,10 +36,7 @@ export function shouldOmitLegacyMigrationFile(relativePath) {
36
36
  */
37
37
  export function removeStaleMigratedFrameworkNarrative(projectRoot) {
38
38
  const stale = join(projectRoot, MIGRATED_ARTIFACT_DIR, OBSOLETE_FRAMEWORK_NARRATIVE_FILENAME);
39
- if (!existsSync(stale))
40
- return false;
41
- rmSync(stale, { force: true });
42
- return true;
39
+ return containedRemove({ root: projectRoot, target: stale }).removed;
43
40
  }
44
41
  function mapRelativePath(relativePath) {
45
42
  return relativePath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-core",
3
- "version": "0.103.0",
3
+ "version": "0.105.0",
4
4
  "description": "TypeScript engine core for the Directive framework.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -382,8 +382,8 @@
382
382
  "provenance": true
383
383
  },
384
384
  "dependencies": {
385
- "@deftai/directive-content": "^0.103.0",
386
- "@deftai/directive-types": "^0.103.0",
385
+ "@deftai/directive-content": "^0.105.0",
386
+ "@deftai/directive-types": "^0.105.0",
387
387
  "archiver": "^8.0.0"
388
388
  },
389
389
  "scripts": {