@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
@@ -5,12 +5,14 @@
5
5
  * most one warning when an *explicit* DEFT_RUN_SUMMARY_PATH write fails.
6
6
  * Symlink destinations are refused (no-follow / containment) — fail-open.
7
7
  */
8
- import { mkdirSync, realpathSync } from "node:fs";
8
+ import { randomBytes } from "node:crypto";
9
+ import { existsSync, mkdirSync, readFileSync, realpathSync, unlinkSync } from "node:fs";
9
10
  import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
10
11
  import { readCorePackageVersion } from "../engine-version.js";
11
- import { containedWrite } from "../fs/contained-write.js";
12
+ import { ContainedWriteError, ContainedWriteErrorCode, containedWrite, } from "../fs/contained-write.js";
12
13
  import { assertWriteTargetSafe } from "../fs/projection-containment.js";
13
14
  import { resolveRunSummaryDestination } from "./path.js";
15
+ import { resolveRunSummarySessionId } from "./session-id.js";
14
16
  import { ENV_TOTAL_TOOL_TURNS, RUN_SUMMARY_SCHEMA_VERSION, RUN_SUMMARY_STDOUT_PREFIX, RUN_SUMMARY_WRITE_WARNING, } from "./types.js";
15
17
  function sortKeysDeep(value) {
16
18
  if (Array.isArray(value)) {
@@ -80,13 +82,176 @@ function writeRunSummaryLine(projectRoot, targetPath, textLine, mode) {
80
82
  assertRealpathStillContained(parentAbs, targetAbs);
81
83
  }
82
84
  /**
83
- * Stateful emitter: one instance per session tracks seq and write-warning once.
85
+ * Count non-empty lines in an existing append-only JSONL. Missing/unreadable
86
+ * files seed at 0 (fail-open). Used so a fresh CLI process continues seq
87
+ * from the destination file instead of resetting to 1 (#3350).
88
+ */
89
+ function countExistingJsonlLines(path) {
90
+ try {
91
+ if (!existsSync(path)) {
92
+ return 0;
93
+ }
94
+ const text = readFileSync(path, "utf8");
95
+ if (text.length === 0) {
96
+ return 0;
97
+ }
98
+ let count = 0;
99
+ for (const line of text.split(/\r?\n/)) {
100
+ if (line.trim().length > 0) {
101
+ count += 1;
102
+ }
103
+ }
104
+ return count;
105
+ }
106
+ catch {
107
+ return 0;
108
+ }
109
+ }
110
+ function seedSeqFromDestination(destination) {
111
+ if (destination.kind !== "file") {
112
+ return 0;
113
+ }
114
+ return countExistingJsonlLines(destination.path);
115
+ }
116
+ const SEQ_LOCK_WAIT_MS = 2_000;
117
+ const SEQ_LOCK_SPIN_MS = 15;
118
+ function isErrno(err, code) {
119
+ return Boolean(err && typeof err === "object" && "code" in err && err.code === code);
120
+ }
121
+ function isPidAlive(pid) {
122
+ try {
123
+ process.kill(pid, 0);
124
+ return true;
125
+ }
126
+ catch (err) {
127
+ // EPERM: process exists but we cannot signal it — treat as live.
128
+ return isErrno(err, "EPERM");
129
+ }
130
+ }
131
+ function parseSeqLockOwner(raw) {
132
+ try {
133
+ const parsed = JSON.parse(raw);
134
+ if (parsed === null || typeof parsed !== "object") {
135
+ return null;
136
+ }
137
+ const pid = parsed.pid;
138
+ const nonce = parsed.nonce;
139
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
140
+ return null;
141
+ }
142
+ if (typeof nonce !== "string" || nonce.length === 0) {
143
+ return null;
144
+ }
145
+ return { pid, nonce };
146
+ }
147
+ catch {
148
+ return null;
149
+ }
150
+ }
151
+ function newSeqLockOwner() {
152
+ return { pid: process.pid, nonce: randomBytes(8).toString("hex") };
153
+ }
154
+ function serializeSeqLockOwner(owner) {
155
+ return `${JSON.stringify({ pid: owner.pid, nonce: owner.nonce })}\n`;
156
+ }
157
+ /**
158
+ * Reclaim `.seq.lock` only when the owner process is dead or the token is
159
+ * missing/unreadable/corrupt (unknown owner). Live holders are never stolen
160
+ * by mtime (#3361).
161
+ */
162
+ export function tryReclaimSeqLock(lockPath) {
163
+ try {
164
+ const owner = parseSeqLockOwner(readFileSync(lockPath, "utf8"));
165
+ if (owner !== null && isPidAlive(owner.pid)) {
166
+ return false;
167
+ }
168
+ unlinkSync(lockPath);
169
+ return true;
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
175
+ /**
176
+ * Unlink `.seq.lock` only when the on-disk token still matches this holder
177
+ * (ownership-blind release must not delete a successor's lock).
178
+ */
179
+ export function releaseSeqLockIfOwner(lockPath, owner) {
180
+ try {
181
+ const current = parseSeqLockOwner(readFileSync(lockPath, "utf8"));
182
+ if (current === null || current.pid !== owner.pid || current.nonce !== owner.nonce) {
183
+ return false;
184
+ }
185
+ unlinkSync(lockPath);
186
+ return true;
187
+ }
188
+ catch {
189
+ return false;
190
+ }
191
+ }
192
+ /**
193
+ * Cross-process exclusive lock so count-then-append is one critical section
194
+ * (#3350 / #3361). Fail-open: if the lock cannot be acquired within the wait
195
+ * window, emit still proceeds with a best-effort recount. Reclaim is allowed
196
+ * only when the owner process is dead or the token is unknown — never by
197
+ * mtime of a live holder.
198
+ */
199
+ function acquireSeqLock(targetPath) {
200
+ const noop = () => {
201
+ /* fail-open: no lock held */
202
+ };
203
+ try {
204
+ const targetAbs = resolve(targetPath);
205
+ const parent = dirname(targetAbs);
206
+ mkdirSync(parent, { recursive: true });
207
+ const lockPath = `${targetAbs}.seq.lock`;
208
+ const deadline = Date.now() + SEQ_LOCK_WAIT_MS;
209
+ while (true) {
210
+ const owner = newSeqLockOwner();
211
+ try {
212
+ containedWrite({
213
+ root: parent,
214
+ target: lockPath,
215
+ data: serializeSeqLockOwner(owner),
216
+ mode: "create",
217
+ });
218
+ return () => {
219
+ releaseSeqLockIfOwner(lockPath, owner);
220
+ };
221
+ }
222
+ catch (err) {
223
+ if (err instanceof ContainedWriteError && err.code === ContainedWriteErrorCode.EXISTS) {
224
+ if (tryReclaimSeqLock(lockPath)) {
225
+ continue;
226
+ }
227
+ if (Date.now() < deadline) {
228
+ const spinEnd = Date.now() + SEQ_LOCK_SPIN_MS;
229
+ while (Date.now() < spinEnd) {
230
+ /* brief spin */
231
+ }
232
+ continue;
233
+ }
234
+ }
235
+ return noop;
236
+ }
237
+ }
238
+ }
239
+ catch {
240
+ return noop;
241
+ }
242
+ }
243
+ /**
244
+ * Stateful emitter: one instance tracks seq and write-warning once.
245
+ * File destinations seed seq from the current JSONL line count so multiple
246
+ * CLI processes appending to one DEFT_RUN_SUMMARY_PATH share 1..N (#3350).
247
+ * Stdout destinations stay per-process (each constructor starts at 0).
84
248
  */
85
249
  export class RunSummaryEmitter {
86
250
  seq = 0;
87
251
  warned = false;
88
252
  projectRoot;
89
253
  sessionId;
254
+ component;
90
255
  frameworkVersion;
91
256
  now;
92
257
  destination;
@@ -95,7 +260,12 @@ export class RunSummaryEmitter {
95
260
  writeStderr;
96
261
  constructor(options) {
97
262
  this.projectRoot = options.projectRoot;
98
- this.sessionId = options.sessionId;
263
+ this.sessionId = resolveRunSummarySessionId({
264
+ projectRoot: options.projectRoot,
265
+ explicit: options.sessionId,
266
+ env: options.env,
267
+ });
268
+ this.component = options.component?.trim() || undefined;
99
269
  this.frameworkVersion = options.frameworkVersion ?? readCorePackageVersion();
100
270
  this.now = options.now ?? (() => new Date());
101
271
  this.env = options.env ?? process.env;
@@ -105,43 +275,52 @@ export class RunSummaryEmitter {
105
275
  env: this.env,
106
276
  gitignoreCovers: options.gitignoreCovers,
107
277
  });
278
+ this.seq = seedSeqFromDestination(this.destination);
108
279
  this.writeStdout = options.writeStdout ?? ((line) => process.stdout.write(`${line}\n`));
109
280
  this.writeStderr = options.writeStderr ?? ((line) => process.stderr.write(`${line}\n`));
110
281
  }
111
282
  getDestination() {
112
283
  return this.destination;
113
284
  }
285
+ buildLine(event, payload) {
286
+ const denominator = readPayloadToolTurnDenominator(payload) ?? readEnvToolTurnDenominator(this.env);
287
+ return {
288
+ schema_version: RUN_SUMMARY_SCHEMA_VERSION,
289
+ session_id: this.sessionId,
290
+ framework_version: this.frameworkVersion,
291
+ seq: this.seq,
292
+ ts: this.now().toISOString(),
293
+ event,
294
+ payload,
295
+ ...(this.component !== undefined ? { component: this.component } : {}),
296
+ ...(denominator !== undefined ? { total_tool_turns: denominator } : {}),
297
+ };
298
+ }
114
299
  emit(event, payload) {
115
300
  try {
116
301
  if (this.destination.kind === "silent") {
117
302
  return { emitted: false, destination: this.destination, line: null, warning: false };
118
303
  }
119
- this.seq += 1;
120
- const denominator = readPayloadToolTurnDenominator(payload) ?? readEnvToolTurnDenominator(this.env);
121
- const line = {
122
- schema_version: RUN_SUMMARY_SCHEMA_VERSION,
123
- session_id: this.sessionId,
124
- framework_version: this.frameworkVersion,
125
- seq: this.seq,
126
- ts: this.now().toISOString(),
127
- event,
128
- payload,
129
- ...(denominator !== undefined ? { total_tool_turns: denominator } : {}),
130
- };
131
- const text = lineToJson(line);
132
304
  if (this.destination.kind === "stdout") {
133
- this.writeStdout(`${RUN_SUMMARY_STDOUT_PREFIX}${text}`);
305
+ this.seq += 1;
306
+ const line = this.buildLine(event, payload);
307
+ this.writeStdout(`${RUN_SUMMARY_STDOUT_PREFIX}${lineToJson(line)}`);
134
308
  return { emitted: true, destination: this.destination, line, warning: false };
135
309
  }
136
- // file destination — no-follow containment (#3282 Greptile P1 security)
310
+ // file destination — lock count-then-append so concurrent CLI processes
311
+ // cannot share the same next seq (#3350 Greptile P1).
137
312
  const { path, truncateOnSessionStart, explicit } = this.destination;
313
+ const release = acquireSeqLock(path);
138
314
  try {
139
- const mode = event === "session_start" && truncateOnSessionStart ? "replace" : "append";
140
- writeRunSummaryLine(this.projectRoot, path, text, mode);
315
+ const replace = event === "session_start" && truncateOnSessionStart;
316
+ this.seq = replace ? 1 : countExistingJsonlLines(path) + 1;
317
+ const line = this.buildLine(event, payload);
318
+ writeRunSummaryLine(this.projectRoot, path, lineToJson(line), replace ? "replace" : "append");
141
319
  return { emitted: true, destination: this.destination, line, warning: false };
142
320
  }
143
321
  catch {
144
322
  // Symlink / containment refusal and I/O both fail-open.
323
+ const line = this.buildLine(event, payload);
145
324
  if (explicit && !this.warned) {
146
325
  this.warned = true;
147
326
  this.writeStderr(RUN_SUMMARY_WRITE_WARNING);
@@ -149,6 +328,9 @@ export class RunSummaryEmitter {
149
328
  }
150
329
  return { emitted: false, destination: this.destination, line, warning: false };
151
330
  }
331
+ finally {
332
+ release();
333
+ }
152
334
  }
153
335
  catch {
154
336
  return { emitted: false, destination: this.destination, line: null, warning: false };
@@ -178,6 +360,9 @@ export class RunSummaryEmitter {
178
360
  emitAcceptanceStamp(payload) {
179
361
  return this.emit("acceptance_stamp", payload);
180
362
  }
363
+ emitAcPassBank(payload) {
364
+ return this.emit("ac_pass_bank", payload);
365
+ }
181
366
  /** Emit the harness-supplied denominator when DEFT_TOTAL_TOOL_TURNS is set. */
182
367
  emitKnownToolTurnDenominator() {
183
368
  const n = readEnvToolTurnDenominator(this.env);
@@ -186,6 +371,18 @@ export class RunSummaryEmitter {
186
371
  }
187
372
  return this.emitToolTurnDenominator({ total_tool_turns: n });
188
373
  }
374
+ /**
375
+ * Emit a session denominator only when a host/harness value is known (#3399).
376
+ * `emitKnownToolTurnDenominator` stays silent unless DEFT_TOTAL_TOOL_TURNS is
377
+ * set; this caller also records DEFT_MAX_TURNS / host maxTurns.
378
+ */
379
+ emitSessionToolTurnDenominator(hostMaxTurns) {
380
+ const resolved = resolveSessionToolTurnDenominator(this.env, hostMaxTurns);
381
+ if (resolved === undefined) {
382
+ return { emitted: false, destination: this.destination, line: null, warning: false };
383
+ }
384
+ return this.emitToolTurnDenominator(resolved);
385
+ }
189
386
  }
190
387
  function readPayloadToolTurnDenominator(payload) {
191
388
  if (!("total_tool_turns" in payload)) {
@@ -196,19 +393,58 @@ function readPayloadToolTurnDenominator(payload) {
196
393
  }
197
394
  /** Parse harness-supplied DEFT_TOTAL_TOOL_TURNS (integer > 0). Invalid/unset → omit. */
198
395
  export function readEnvToolTurnDenominator(env) {
199
- const raw = env[ENV_TOTAL_TOOL_TURNS];
396
+ return readPositiveIntegerEnv(env, ENV_TOTAL_TOOL_TURNS);
397
+ }
398
+ /** Canonical host planned-turn budget recorded at session:start (#3356). */
399
+ export const ENV_MAX_TURNS_DENOMINATOR = "DEFT_MAX_TURNS";
400
+ function isPositiveIntegerDenominator(value) {
401
+ return (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value) && value > 0);
402
+ }
403
+ /**
404
+ * Host descriptors (#3266) accept any finite number >= 0. Keep a positive
405
+ * planned-turn budget as-is so share uses the host value, not a floored proxy.
406
+ */
407
+ function coercePositiveHostDenominator(value) {
408
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
409
+ return undefined;
410
+ }
411
+ return value;
412
+ }
413
+ function readPositiveIntegerEnv(env, key) {
414
+ const raw = env[key];
200
415
  if (raw === undefined || raw.trim().length === 0) {
201
416
  return undefined;
202
417
  }
203
418
  const n = Number(raw.trim());
204
- if (!Number.isInteger(n) || !Number.isFinite(n) || n <= 0) {
205
- return undefined;
419
+ return isPositiveIntegerDenominator(n) ? n : undefined;
420
+ }
421
+ /**
422
+ * Resolve the session tool/turn denominator (#3399).
423
+ *
424
+ * Prefer harness actuals (`DEFT_TOTAL_TOOL_TURNS`), then a host planned-turn
425
+ * budget (`DEFT_MAX_TURNS` or `hostMaxTurns`). Unset → undefined (no event).
426
+ * Share is unevaluable without a host/harness value.
427
+ */
428
+ export function resolveSessionToolTurnDenominator(env, hostMaxTurns) {
429
+ const known = readEnvToolTurnDenominator(env);
430
+ if (known !== undefined) {
431
+ return { total_tool_turns: known, denominator_source: "harness_actual" };
432
+ }
433
+ const planned = readPositiveIntegerEnv(env, ENV_MAX_TURNS_DENOMINATOR);
434
+ if (planned !== undefined) {
435
+ return { total_tool_turns: planned, denominator_source: "host_planned" };
436
+ }
437
+ const host = coercePositiveHostDenominator(hostMaxTurns);
438
+ if (host !== undefined) {
439
+ return { total_tool_turns: host, denominator_source: "host_planned" };
206
440
  }
207
- return n;
441
+ return undefined;
208
442
  }
209
443
  /**
210
444
  * One-shot helper for call sites that do not hold an emitter (e.g. dial escalate).
211
- * Still fail-open; creates a fresh seq=1 emitter unless `seqSeed` is passed via reuse.
445
+ * Still fail-open. File destinations seed seq from the existing JSONL line
446
+ * count so successive one-shot calls into the same path continue 1..N (#3350).
447
+ * Stdout destinations stay per-process (each call starts at seq=1).
212
448
  */
213
449
  export function emitRunSummaryEvent(options) {
214
450
  const emitter = new RunSummaryEmitter(options);
@@ -1,5 +1,6 @@
1
- export { type EmitRunSummaryResult, emitRunSummaryEvent, RunSummaryEmitter, type RunSummaryEmitterOptions, } from "./emit.js";
1
+ export { type EmitRunSummaryResult, ENV_MAX_TURNS_DENOMINATOR, emitRunSummaryEvent, type ResolvedSessionToolTurnDenominator, RunSummaryEmitter, type RunSummaryEmitterOptions, resolveSessionToolTurnDenominator, } from "./emit.js";
2
2
  export { gitignoreCoversRunSummary, type ResolveRunSummaryDestinationOptions, resolveRunSummaryDestination, } from "./path.js";
3
+ export { type ResolveRunSummarySessionIdInput, resolveRunSummarySessionId, } from "./session-id.js";
3
4
  export { computeRitualGateShare, parseRunSummaryJsonl, type RitualGateShare, readToolTurnDenominator, } from "./share.js";
4
- export { type AcceptanceClauseOutcomeRow, type AcceptanceRunSummaryOutcome, type AcceptanceRunSummaryPayload, type AcceptanceStampRunSummaryPayload, type CheckGateOutcome, type CheckInvocationRunSummaryPayload, DEFAULT_RUN_SUMMARY_BASENAME, type DialEscalationEvaluationOutcome, type DialEscalationEvaluationRunSummaryPayload, type DialTransitionRunSummaryPayload, ENV_RUN_SUMMARY_PATH, ENV_TOTAL_TOOL_TURNS, RUN_SUMMARY_EVENT_KINDS, RUN_SUMMARY_SCHEMA_VERSION, RUN_SUMMARY_STDOUT_PREFIX, RUN_SUMMARY_WRITE_WARNING, type RunSummaryBaseFields, type RunSummaryDestination, type RunSummaryEventKind, type RunSummaryLine, type RunSummaryPayload, type SessionStartRunSummaryPayload, type ToolTurnDenominatorRunSummaryPayload, type VerificationOutcome, type VerificationRunSummaryPayload, } from "./types.js";
5
+ export { type AcceptanceClauseOutcomeRow, type AcceptanceRunSummaryOutcome, type AcceptanceRunSummaryPayload, type AcceptanceStampRunSummaryPayload, type AcPassBankRunSummaryPayload, type CheckGateOutcome, type CheckInvocationRunSummaryPayload, DEFAULT_RUN_SUMMARY_BASENAME, type DialEscalationEvaluationOutcome, type DialEscalationEvaluationRunSummaryPayload, type DialTransitionRunSummaryPayload, ENV_RUN_SUMMARY_PATH, ENV_TOTAL_TOOL_TURNS, RUN_SUMMARY_EVENT_KINDS, RUN_SUMMARY_SCHEMA_VERSION, RUN_SUMMARY_STDOUT_PREFIX, RUN_SUMMARY_WRITE_WARNING, type RunSummaryBaseFields, type RunSummaryDestination, type RunSummaryEventKind, type RunSummaryLine, type RunSummaryPayload, type SessionStartRunSummaryPayload, type ToolTurnDenominatorRunSummaryPayload, type ToolTurnDenominatorSource, type VerificationOutcome, type VerificationRunSummaryPayload, } from "./types.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,6 @@
1
- export { emitRunSummaryEvent, RunSummaryEmitter, } from "./emit.js";
1
+ export { ENV_MAX_TURNS_DENOMINATOR, emitRunSummaryEvent, RunSummaryEmitter, resolveSessionToolTurnDenominator, } from "./emit.js";
2
2
  export { gitignoreCoversRunSummary, resolveRunSummaryDestination, } from "./path.js";
3
+ export { resolveRunSummarySessionId, } from "./session-id.js";
3
4
  export { computeRitualGateShare, parseRunSummaryJsonl, readToolTurnDenominator, } from "./share.js";
4
5
  export { DEFAULT_RUN_SUMMARY_BASENAME, ENV_RUN_SUMMARY_PATH, ENV_TOTAL_TOOL_TURNS, RUN_SUMMARY_EVENT_KINDS, RUN_SUMMARY_SCHEMA_VERSION, RUN_SUMMARY_STDOUT_PREFIX, RUN_SUMMARY_WRITE_WARNING, } from "./types.js";
5
6
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared workspace session identity for run-summary emitters (#3399).
3
+ *
4
+ * Ritual-state holds the workspace session id written by session:start.
5
+ * #3350 persisted seq by counting JSONL lines; it is not the identity store.
6
+ */
7
+ export interface ResolveRunSummarySessionIdInput {
8
+ readonly projectRoot: string;
9
+ readonly explicit?: string | null;
10
+ readonly env?: NodeJS.ProcessEnv;
11
+ readonly mint?: () => string;
12
+ }
13
+ /**
14
+ * Resolve one workspace session id for a run-summary line.
15
+ *
16
+ * Order: explicit option → DEFT_SESSION_ID → ritual-state session_id →
17
+ * last session_id already in the destination JSONL → mint only when no
18
+ * workspace session exists yet.
19
+ */
20
+ export declare function resolveRunSummarySessionId(input: ResolveRunSummarySessionIdInput): string;
21
+ //# sourceMappingURL=session-id.d.ts.map
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared workspace session identity for run-summary emitters (#3399).
3
+ *
4
+ * Ritual-state holds the workspace session id written by session:start.
5
+ * #3350 persisted seq by counting JSONL lines; it is not the identity store.
6
+ */
7
+ import { randomUUID } from "node:crypto";
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { resolve } from "node:path";
10
+ import { readRitualState } from "../session/ritual-sentinel.js";
11
+ import { resolveRunSummaryDestination } from "./path.js";
12
+ import { parseRunSummaryJsonl } from "./share.js";
13
+ const mintedByProjectRoot = new Map();
14
+ function trimNonEmpty(value) {
15
+ if (typeof value !== "string") {
16
+ return undefined;
17
+ }
18
+ const trimmed = value.trim();
19
+ return trimmed.length > 0 ? trimmed : undefined;
20
+ }
21
+ function lastSessionIdFromJsonl(path) {
22
+ try {
23
+ if (!existsSync(path)) {
24
+ return undefined;
25
+ }
26
+ const lines = parseRunSummaryJsonl(readFileSync(path, "utf8"));
27
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
28
+ const id = trimNonEmpty(lines[i]?.session_id);
29
+ if (id !== undefined) {
30
+ return id;
31
+ }
32
+ }
33
+ return undefined;
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ }
39
+ function ritualSessionId(projectRoot) {
40
+ try {
41
+ const [state] = readRitualState(projectRoot);
42
+ return trimNonEmpty(state?.sessionId);
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ /**
49
+ * Resolve one workspace session id for a run-summary line.
50
+ *
51
+ * Order: explicit option → DEFT_SESSION_ID → ritual-state session_id →
52
+ * last session_id already in the destination JSONL → mint only when no
53
+ * workspace session exists yet.
54
+ */
55
+ export function resolveRunSummarySessionId(input) {
56
+ const explicit = trimNonEmpty(input.explicit);
57
+ if (explicit !== undefined) {
58
+ return explicit;
59
+ }
60
+ const env = input.env ?? process.env;
61
+ const fromEnv = trimNonEmpty(env.DEFT_SESSION_ID);
62
+ if (fromEnv !== undefined) {
63
+ return fromEnv;
64
+ }
65
+ const fromRitual = ritualSessionId(input.projectRoot);
66
+ if (fromRitual !== undefined) {
67
+ return fromRitual;
68
+ }
69
+ const dest = resolveRunSummaryDestination(input.projectRoot, { env });
70
+ if (dest.kind === "file") {
71
+ const fromJsonl = lastSessionIdFromJsonl(dest.path);
72
+ if (fromJsonl !== undefined) {
73
+ return fromJsonl;
74
+ }
75
+ }
76
+ const rootKey = resolve(input.projectRoot);
77
+ if (input.mint !== undefined) {
78
+ const minted = trimNonEmpty(input.mint());
79
+ if (minted !== undefined) {
80
+ mintedByProjectRoot.set(rootKey, minted);
81
+ return minted;
82
+ }
83
+ }
84
+ const cached = mintedByProjectRoot.get(rootKey);
85
+ if (cached !== undefined) {
86
+ return cached;
87
+ }
88
+ const minted = randomUUID();
89
+ mintedByProjectRoot.set(rootKey, minted);
90
+ return minted;
91
+ }
92
+ //# sourceMappingURL=session-id.js.map
@@ -11,7 +11,7 @@ export interface RitualGateShare {
11
11
  readonly totalToolTurns: number | null;
12
12
  readonly share: number | null;
13
13
  }
14
- /** True when n is a finite integer usable as a share denominator. */
14
+ /** True when n is a finite positive number usable as a share denominator. */
15
15
  export declare function isValidToolTurnDenominator(value: unknown): value is number;
16
16
  /** Read total_tool_turns from a line (top-level field or payload). */
17
17
  export declare function readToolTurnDenominator(line: unknown): number | undefined;
@@ -11,9 +11,9 @@ function asRecord(value) {
11
11
  }
12
12
  return value;
13
13
  }
14
- /** True when n is a finite integer usable as a share denominator. */
14
+ /** True when n is a finite positive number usable as a share denominator. */
15
15
  export function isValidToolTurnDenominator(value) {
16
- return (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value) && value > 0);
16
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
17
17
  }
18
18
  /** Read total_tool_turns from a line (top-level field or payload). */
19
19
  export function readToolTurnDenominator(line) {
@@ -15,16 +15,28 @@ export declare const DEFAULT_RUN_SUMMARY_BASENAME = ".deft-run-summary.json";
15
15
  export declare const RUN_SUMMARY_STDOUT_PREFIX = "DEFT-TLM:";
16
16
  /** One warning when an explicitly requested write fails. */
17
17
  export declare const RUN_SUMMARY_WRITE_WARNING = "[deft run-summary] failed to write DEFT_RUN_SUMMARY_PATH telemetry (fail-open; exit codes unchanged)";
18
- export declare const RUN_SUMMARY_EVENT_KINDS: readonly ["session_start", "dial_transition", "dial_escalation_evaluation", "check_invocation", "tool_turn_denominator", "verification", "acceptance", "acceptance_stamp"];
18
+ export declare const RUN_SUMMARY_EVENT_KINDS: readonly ["session_start", "dial_transition", "dial_escalation_evaluation", "check_invocation", "tool_turn_denominator", "verification", "acceptance", "acceptance_stamp", "ac_pass_bank"];
19
19
  export type RunSummaryEventKind = (typeof RUN_SUMMARY_EVENT_KINDS)[number];
20
20
  export interface RunSummaryBaseFields {
21
21
  readonly schema_version: typeof RUN_SUMMARY_SCHEMA_VERSION;
22
22
  readonly session_id: string;
23
23
  readonly framework_version: string;
24
- /** Monotonic per-emitter sequence (1-based). */
24
+ /**
25
+ * Monotonic 1-based sequence for this destination (#3350).
26
+ * File destinations continue from the existing JSONL line count so multiple
27
+ * CLI processes appending to one DEFT_RUN_SUMMARY_PATH share 1..N. Concurrent
28
+ * file writers serialize count-then-append via a sibling lock; reclaim is
29
+ * allowed only when the lock owner process is dead or the token is unknown
30
+ * (#3361). Stdout destinations stay per-process (each process starts at 1).
31
+ */
25
32
  readonly seq: number;
26
33
  readonly ts: string;
27
34
  readonly event: RunSummaryEventKind;
35
+ /**
36
+ * Optional emitter label (verify-ac, clause-derivation, …). Not a closed
37
+ * union — new callers add a string without a schema bump (#3399).
38
+ */
39
+ readonly component?: string;
28
40
  /**
29
41
  * Session total tool/turn count (#3320). Present so ritual+gate share is
30
42
  * computable from the summary alone. Absence means the #3286 trigger is unevaluable.
@@ -81,14 +93,32 @@ export interface CheckInvocationRunSummaryPayload {
81
93
  readonly none_stated?: boolean;
82
94
  readonly clause_outcomes?: readonly AcceptanceClauseOutcomeRow[];
83
95
  }
84
- /** Total tool/turn count for the session (#3320). */
96
+ /** How a tool_turn_denominator value was obtained (#3399). */
97
+ export type ToolTurnDenominatorSource = "harness_actual" | "host_planned";
98
+ /** Total tool/turn count for the session (#3320 / #3399). */
85
99
  export interface ToolTurnDenominatorRunSummaryPayload {
86
100
  readonly total_tool_turns: number;
101
+ readonly denominator_source?: ToolTurnDenominatorSource;
102
+ }
103
+ /** Bank checkpoint JSONL payload. Disk ledger stays camelCase (#3387). */
104
+ export interface AcPassBankRunSummaryPayload {
105
+ readonly scope_id: string;
106
+ readonly banked_at: string;
107
+ readonly next_action?: string;
108
+ readonly had_surplus?: boolean;
109
+ readonly surplus_threshold?: number;
110
+ readonly remaining_fraction?: number | null;
111
+ readonly remaining_turns?: number | null;
112
+ readonly remaining_budget?: number | null;
113
+ readonly max_turns?: number | null;
114
+ readonly max_budget?: number | null;
115
+ readonly head_sha?: string | null;
116
+ readonly path?: string;
87
117
  }
88
118
  /** Product-oracle attempt (#3322). Same emitter as #3319 / #3320. */
89
119
  export type VerificationOutcome = "pass" | "fail";
90
- /** verify:ac resolution telemetry (#3334). Distinct from verification pass/fail. */
91
- export type AcceptanceRunSummaryOutcome = "verified-pass" | "empty-pass" | "soft_empty" | "fail";
120
+ /** verify:ac resolution telemetry (#3334 / #3355). Distinct from verification pass/fail. */
121
+ export type AcceptanceRunSummaryOutcome = "verified-pass" | "empty-pass" | "soft_empty" | "fail" | "config-error" | "soft-missing" | "rejected-noop";
92
122
  export interface AcceptanceRunSummaryPayload {
93
123
  readonly resolved_command_count: number;
94
124
  readonly outcome: AcceptanceRunSummaryOutcome;
@@ -96,6 +126,8 @@ export interface AcceptanceRunSummaryPayload {
96
126
  readonly none_stated?: boolean;
97
127
  readonly clause_count?: number;
98
128
  readonly clause_outcomes?: readonly AcceptanceClauseOutcomeRow[];
129
+ /** bank | cache | executed — how verify:ac obtained this result (#3387). */
130
+ readonly served_from?: "bank" | "cache" | "executed";
99
131
  }
100
132
  /** Intake-time stamp: which rung locked, whether commands were stated, counts (#3323). */
101
133
  export interface AcceptanceStampRunSummaryPayload {
@@ -115,7 +147,7 @@ export interface VerificationRunSummaryPayload {
115
147
  */
116
148
  readonly independent_rederivation?: boolean;
117
149
  }
118
- export type RunSummaryPayload = SessionStartRunSummaryPayload | DialTransitionRunSummaryPayload | DialEscalationEvaluationRunSummaryPayload | CheckInvocationRunSummaryPayload | ToolTurnDenominatorRunSummaryPayload | VerificationRunSummaryPayload | AcceptanceRunSummaryPayload | AcceptanceStampRunSummaryPayload;
150
+ export type RunSummaryPayload = SessionStartRunSummaryPayload | DialTransitionRunSummaryPayload | DialEscalationEvaluationRunSummaryPayload | CheckInvocationRunSummaryPayload | ToolTurnDenominatorRunSummaryPayload | VerificationRunSummaryPayload | AcceptanceRunSummaryPayload | AcceptanceStampRunSummaryPayload | AcPassBankRunSummaryPayload;
119
151
  export type RunSummaryLine = RunSummaryBaseFields & {
120
152
  readonly payload: RunSummaryPayload;
121
153
  };
@@ -24,5 +24,6 @@ export const RUN_SUMMARY_EVENT_KINDS = [
24
24
  "verification",
25
25
  "acceptance",
26
26
  "acceptance_stamp",
27
+ "ac_pass_bank",
27
28
  ];
28
29
  //# sourceMappingURL=types.js.map
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Agents author Test / AcceptanceCriteria / Verification prose in narratives
5
5
  * and then skip the executable plan.acceptance block. Activation fails closed
6
- * with one remediation: stamp the acceptance block.
6
+ * with one remediation: stamp plan.acceptance via clause derivation.
7
7
  */
8
8
  export interface AcceptanceActivateHit {
9
9
  readonly key: string;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Agents author Test / AcceptanceCriteria / Verification prose in narratives
5
5
  * and then skip the executable plan.acceptance block. Activation fails closed
6
- * with one remediation: stamp the acceptance block.
6
+ * with one remediation: stamp plan.acceptance via clause derivation.
7
7
  */
8
8
  import { validatePlanAcceptance } from "../product-first-done-gate/acceptance.js";
9
9
  function asRecord(value) {
@@ -51,7 +51,7 @@ export function evaluateAcceptanceActivateGate(plan) {
51
51
  ok: false,
52
52
  message: `Refusing activate: plan.acceptance is present but invalid (#3334): ` +
53
53
  `${schemaErrors.join("; ")}. Stamp a valid plan.acceptance block ` +
54
- `(author commands or none_stated via intake capture / task issue:ingest).`,
54
+ `via clause derivation (scope:activate / scope:promote runs #3323).`,
55
55
  hits,
56
56
  };
57
57
  }
@@ -61,8 +61,8 @@ export function evaluateAcceptanceActivateGate(plan) {
61
61
  return {
62
62
  ok: false,
63
63
  message: `Refusing activate: narratives contain acceptance-shaped keys (${keys}) ` +
64
- `but plan.acceptance is absent (#3334). Stamp plan.acceptance ` +
65
- `(author commands or none_stated via intake capture / task issue:ingest) — ` +
64
+ `but plan.acceptance is absent (#3334). Stamp plan.acceptance via clause derivation ` +
65
+ `(scope:activate / scope:promote runs #3323, or task issue:ingest) — ` +
66
66
  `the criteria are in the wrong, non-executable field.`,
67
67
  hits,
68
68
  };