@deftai/directive-core 0.103.0 → 0.105.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/authz/classify.js +682 -35
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/gate-lists.d.ts +3 -2
  5. package/dist/check/gate-lists.js +5 -2
  6. package/dist/check/index.d.ts +1 -0
  7. package/dist/check/index.js +1 -0
  8. package/dist/check/named-cause.d.ts +1 -1
  9. package/dist/check/named-cause.js +33 -3
  10. package/dist/check/session-completed-ac.d.ts +39 -0
  11. package/dist/check/session-completed-ac.js +198 -0
  12. package/dist/codebase/default-extractor.d.ts +5 -0
  13. package/dist/codebase/default-extractor.js +7 -15
  14. package/dist/deposit/copy-tree.js +60 -0
  15. package/dist/deposit/python-free.js +26 -18
  16. package/dist/doctor/checks.d.ts +8 -0
  17. package/dist/doctor/checks.js +37 -25
  18. package/dist/doctor/doctor-state.d.ts +4 -0
  19. package/dist/doctor/doctor-state.js +7 -1
  20. package/dist/doctor/main.js +9 -14
  21. package/dist/doctor/types.d.ts +9 -0
  22. package/dist/fs/contained-write.d.ts +115 -1
  23. package/dist/fs/contained-write.js +242 -5
  24. package/dist/fs/mutation-ledger.d.ts +54 -0
  25. package/dist/fs/mutation-ledger.js +133 -0
  26. package/dist/fs/non-product-dirs.d.ts +79 -0
  27. package/dist/fs/non-product-dirs.js +96 -0
  28. package/dist/hooks/dispatcher.d.ts +3 -1
  29. package/dist/hooks/dispatcher.js +14 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +3 -0
  32. package/dist/init-deposit/agent-hooks.js +17 -15
  33. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  34. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  35. package/dist/init-deposit/gitignore.js +9 -0
  36. package/dist/init-deposit/hygiene.d.ts +47 -11
  37. package/dist/init-deposit/hygiene.js +172 -37
  38. package/dist/init-deposit/legacy-detect.js +6 -2
  39. package/dist/init-deposit/refresh.d.ts +21 -1
  40. package/dist/init-deposit/refresh.js +106 -9
  41. package/dist/init-deposit/scaffold.js +28 -279
  42. package/dist/init-deposit/slash-deposit.js +13 -7
  43. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  44. package/dist/init-deposit/xbrief-projections.js +24 -11
  45. package/dist/intake/clause-derivation.d.ts +74 -0
  46. package/dist/intake/clause-derivation.js +409 -0
  47. package/dist/intake/index.d.ts +1 -0
  48. package/dist/intake/index.js +1 -0
  49. package/dist/intake/issue-ingest.d.ts +3 -1
  50. package/dist/intake/issue-ingest.js +36 -43
  51. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  52. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  53. package/dist/literal-acceptance/capture.d.ts +10 -0
  54. package/dist/literal-acceptance/capture.js +224 -75
  55. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  56. package/dist/literal-acceptance/evaluate.js +70 -2
  57. package/dist/literal-acceptance/index.d.ts +3 -3
  58. package/dist/literal-acceptance/index.js +3 -3
  59. package/dist/literal-acceptance/safety.d.ts +41 -0
  60. package/dist/literal-acceptance/safety.js +126 -2
  61. package/dist/literal-acceptance/types.d.ts +8 -0
  62. package/dist/orphan-active/evaluate.d.ts +7 -1
  63. package/dist/orphan-active/evaluate.js +102 -23
  64. package/dist/platform/platform-capabilities.js +2 -3
  65. package/dist/policy/base-branch.d.ts +37 -0
  66. package/dist/policy/base-branch.js +114 -0
  67. package/dist/policy/branch-sync.d.ts +80 -0
  68. package/dist/policy/branch-sync.js +211 -0
  69. package/dist/policy/ceremony-dial-escalation.js +1 -0
  70. package/dist/policy/ceremony-dial.js +4 -14
  71. package/dist/policy/delivery-branch.d.ts +5 -3
  72. package/dist/policy/delivery-branch.js +7 -3
  73. package/dist/policy/file-size-thresholds.d.ts +24 -0
  74. package/dist/policy/file-size-thresholds.js +23 -0
  75. package/dist/policy/forge-outage-retry.d.ts +47 -0
  76. package/dist/policy/forge-outage-retry.js +157 -0
  77. package/dist/policy/index.d.ts +7 -0
  78. package/dist/policy/index.js +66 -7
  79. package/dist/policy/project-invariants.d.ts +50 -0
  80. package/dist/policy/project-invariants.js +205 -0
  81. package/dist/policy/sync-default.d.ts +129 -0
  82. package/dist/policy/sync-default.js +452 -0
  83. package/dist/policy/sync-max-files.d.ts +93 -0
  84. package/dist/policy/sync-max-files.js +192 -0
  85. package/dist/pr-monitor/absent-required.d.ts +11 -0
  86. package/dist/pr-monitor/absent-required.js +61 -0
  87. package/dist/pr-monitor/constants.d.ts +7 -0
  88. package/dist/pr-monitor/constants.js +7 -0
  89. package/dist/pr-monitor/index.d.ts +2 -1
  90. package/dist/pr-monitor/index.js +2 -1
  91. package/dist/pr-monitor/main.js +4 -0
  92. package/dist/pr-monitor/monitor.js +24 -1
  93. package/dist/pr-wait-mergeable/classify.js +6 -0
  94. package/dist/preflight/evaluate.d.ts +9 -0
  95. package/dist/preflight/evaluate.js +49 -1
  96. package/dist/preflight/index.d.ts +5 -1
  97. package/dist/preflight/index.js +2 -0
  98. package/dist/preflight/intended-placement.d.ts +62 -0
  99. package/dist/preflight/intended-placement.js +275 -0
  100. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  101. package/dist/preflight/project-invariants-gate.js +82 -0
  102. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  103. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  104. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  105. package/dist/product-first-done-gate/acceptance.js +79 -8
  106. package/dist/product-first-done-gate/empty-resolution.d.ts +5 -2
  107. package/dist/product-first-done-gate/empty-resolution.js +13 -2
  108. package/dist/product-first-done-gate/evaluate.d.ts +29 -0
  109. package/dist/product-first-done-gate/evaluate.js +307 -33
  110. package/dist/product-first-done-gate/index.d.ts +3 -1
  111. package/dist/product-first-done-gate/index.js +2 -1
  112. package/dist/release/build-dist.d.ts +101 -0
  113. package/dist/release/build-dist.js +428 -46
  114. package/dist/run-summary/emit.d.ts +50 -4
  115. package/dist/run-summary/emit.js +262 -26
  116. package/dist/run-summary/index.d.ts +3 -2
  117. package/dist/run-summary/index.js +2 -1
  118. package/dist/run-summary/session-id.d.ts +21 -0
  119. package/dist/run-summary/session-id.js +92 -0
  120. package/dist/run-summary/share.d.ts +1 -1
  121. package/dist/run-summary/share.js +2 -2
  122. package/dist/run-summary/types.d.ts +38 -6
  123. package/dist/run-summary/types.js +1 -0
  124. package/dist/scope/acceptance-activate-gate.d.ts +1 -1
  125. package/dist/scope/acceptance-activate-gate.js +4 -4
  126. package/dist/scope/acceptance-evidence.d.ts +27 -0
  127. package/dist/scope/acceptance-evidence.js +66 -0
  128. package/dist/scope/capacity-stamp.d.ts +2 -0
  129. package/dist/scope/capacity-stamp.js +4 -0
  130. package/dist/scope/delivery-evidence.d.ts +9 -3
  131. package/dist/scope/delivery-evidence.js +39 -27
  132. package/dist/scope/index.d.ts +1 -0
  133. package/dist/scope/index.js +1 -0
  134. package/dist/scope/parent-lineage.js +7 -6
  135. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  136. package/dist/scope/project-invariant-coverage.js +322 -0
  137. package/dist/scope/transition.js +66 -4
  138. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  139. package/dist/scope-provenance/compare-intent.js +233 -0
  140. package/dist/scope-provenance/digest.d.ts +18 -1
  141. package/dist/scope-provenance/digest.js +16 -11
  142. package/dist/scope-provenance/evaluate.d.ts +5 -1
  143. package/dist/scope-provenance/evaluate.js +64 -4
  144. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  145. package/dist/scope-provenance/extract-intent.js +262 -0
  146. package/dist/scope-provenance/index.d.ts +7 -1
  147. package/dist/scope-provenance/index.js +7 -1
  148. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  149. package/dist/scope-provenance/intent-digest.js +33 -0
  150. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  151. package/dist/scope-provenance/intent-evaluate.js +149 -0
  152. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  153. package/dist/scope-provenance/json-tokenizer.js +225 -0
  154. package/dist/scope-provenance/known-machine.d.ts +38 -0
  155. package/dist/scope-provenance/known-machine.js +157 -0
  156. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  157. package/dist/scope-provenance/mint-artifacts.js +425 -0
  158. package/dist/session/ac-pass-banking.d.ts +4 -36
  159. package/dist/session/ac-pass-banking.js +30 -77
  160. package/dist/session/ac-pass-reuse.d.ts +53 -0
  161. package/dist/session/ac-pass-reuse.js +95 -0
  162. package/dist/session/ceremony-dial-evidence.d.ts +42 -0
  163. package/dist/session/ceremony-dial-evidence.js +194 -0
  164. package/dist/session/git.js +19 -4
  165. package/dist/session/index.d.ts +5 -0
  166. package/dist/session/index.js +5 -0
  167. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  168. package/dist/session/occupancy-stress-worker.js +36 -0
  169. package/dist/session/occupancy.d.ts +97 -0
  170. package/dist/session/occupancy.js +422 -0
  171. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  172. package/dist/session/product-state-hash.d.ts +26 -0
  173. package/dist/session/product-state-hash.js +683 -0
  174. package/dist/session/session-ready.d.ts +2 -0
  175. package/dist/session/session-ready.js +52 -30
  176. package/dist/session/session-start.d.ts +7 -0
  177. package/dist/session/session-start.js +88 -5
  178. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  179. package/dist/session/verify-ac-session-cache.js +126 -0
  180. package/dist/session/verify-session-ritual.d.ts +5 -0
  181. package/dist/session/verify-session-ritual.js +9 -0
  182. package/dist/slash/openclaw-deposit.js +13 -9
  183. package/dist/slice/constants.d.ts +2 -2
  184. package/dist/slice/constants.js +2 -2
  185. package/dist/slice/existing.js +21 -4
  186. package/dist/slice/lock.d.ts +16 -1
  187. package/dist/slice/lock.js +137 -11
  188. package/dist/slice/record.d.ts +8 -5
  189. package/dist/slice/record.js +21 -13
  190. package/dist/story-ready/evaluate.d.ts +2 -0
  191. package/dist/story-ready/evaluate.js +13 -0
  192. package/dist/swarm/complete-cohort.d.ts +3 -0
  193. package/dist/swarm/complete-cohort.js +59 -11
  194. package/dist/swarm/finalize-cohort.js +33 -2
  195. package/dist/swarm/launch.d.ts +22 -0
  196. package/dist/swarm/launch.js +155 -0
  197. package/dist/swarm/routing-set-cli.d.ts +11 -1
  198. package/dist/swarm/routing-set-cli.js +13 -3
  199. package/dist/swarm/routing-verify.d.ts +12 -0
  200. package/dist/swarm/routing-verify.js +59 -20
  201. package/dist/swarm/routing.d.ts +14 -0
  202. package/dist/swarm/routing.js +53 -3
  203. package/dist/telemetry-coverage/evaluate.d.ts +42 -0
  204. package/dist/telemetry-coverage/evaluate.js +148 -0
  205. package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
  206. package/dist/telemetry-coverage/fake-trial.js +204 -0
  207. package/dist/telemetry-coverage/index.d.ts +5 -0
  208. package/dist/telemetry-coverage/index.js +5 -0
  209. package/dist/telemetry-coverage/kinds.d.ts +19 -0
  210. package/dist/telemetry-coverage/kinds.js +54 -0
  211. package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
  212. package/dist/telemetry-coverage/scan-callers.js +168 -0
  213. package/dist/triage/actions/index.js +4 -1
  214. package/dist/ts-check-lane/index.d.ts +3 -0
  215. package/dist/ts-check-lane/index.js +2 -0
  216. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  217. package/dist/ts-check-lane/progress-reporter.js +38 -0
  218. package/dist/ts-check-lane/progress.d.ts +32 -0
  219. package/dist/ts-check-lane/progress.js +57 -0
  220. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  221. package/dist/ts-check-lane/run-lane.js +8 -6
  222. package/dist/validate-content/validate-links.d.ts +8 -0
  223. package/dist/validate-content/validate-links.js +9 -15
  224. package/dist/value/feedback-file.js +12 -2
  225. package/dist/vbrief-build/index.d.ts +1 -0
  226. package/dist/vbrief-build/index.js +1 -0
  227. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  228. package/dist/vbrief-build/project-invariants-io.js +41 -0
  229. package/dist/vbrief-reconcile/graph.js +18 -1
  230. package/dist/vbrief-reconcile/index.d.ts +3 -1
  231. package/dist/vbrief-reconcile/index.js +2 -1
  232. package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
  233. package/dist/vbrief-reconcile/origin-freshness.js +221 -0
  234. package/dist/vbrief-reconcile/types.d.ts +13 -0
  235. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  236. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  237. package/dist/vbrief-validate/index.d.ts +1 -1
  238. package/dist/vbrief-validate/index.js +1 -1
  239. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  240. package/dist/vbrief-validate/plan-hooks.js +68 -0
  241. package/dist/verify-ac/evaluate.d.ts +7 -1
  242. package/dist/verify-ac/evaluate.js +34 -26
  243. package/dist/verify-ac/flag.d.ts +4 -0
  244. package/dist/verify-ac/flag.js +16 -0
  245. package/dist/verify-ac/index.d.ts +2 -2
  246. package/dist/verify-ac/index.js +2 -2
  247. package/dist/verify-source/contained-writes.js +2 -0
  248. package/dist/verify-source/index.d.ts +1 -0
  249. package/dist/verify-source/index.js +1 -0
  250. package/dist/verify-source/verify-stubs.d.ts +15 -1
  251. package/dist/verify-source/verify-stubs.js +20 -16
  252. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  253. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  254. package/dist/xbrief-migrate/migrate-project.js +2 -5
  255. package/package.json +3 -3
@@ -13,10 +13,10 @@
13
13
  * Directive thin wrappers (`isThinWrapperMarkdown`). Consumer-customized content
14
14
  * at a product filename is left untouched.
15
15
  */
16
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync } from "node:fs";
16
+ import { existsSync, readFileSync } from "node:fs";
17
17
  import { basename, dirname, join, resolve } from "node:path";
18
18
  import { assertDepositContained } from "../deposit/contain.js";
19
- import { containedWrite } from "../fs/contained-write.js";
19
+ import { containedMkdir, containedRemove, containedRename, containedWrite, } from "../fs/contained-write.js";
20
20
  import { isHostSlashCommandDepositEnabled, loadHostSlashCommandsPolicyFromProject, } from "../policy/host-slash-commands.js";
21
21
  import { emitHostCommandFiles, getHostCommandLayout, isThinWrapperMarkdown, listSlashEmitterHosts, } from "../slash/index.js";
22
22
  import { listProductCommands, logicalIdToFilename } from "../slash/product-set.js";
@@ -115,7 +115,7 @@ function writeHostCommandFileIfChanged(projectRoot, file) {
115
115
  }
116
116
  }
117
117
  const parent = dirname(absolute);
118
- mkdirSync(parent, { recursive: true });
118
+ containedMkdir({ root: projectRoot, target: parent });
119
119
  // Atomic replace via temp under project root (#2951).
120
120
  const tmpName = `${basename(absolute)}.deft-${process.pid}.tmp`;
121
121
  const temporary = join(parent, tmpName);
@@ -126,11 +126,16 @@ function writeHostCommandFileIfChanged(projectRoot, file) {
126
126
  data: file.contents,
127
127
  mode: "replace",
128
128
  });
129
- renameSync(temporary, absolute);
129
+ containedRename({
130
+ root: projectRoot,
131
+ from: temporary,
132
+ to: absolute,
133
+ mutation: false,
134
+ });
130
135
  }
131
136
  catch (err) {
132
137
  try {
133
- rmSync(temporary, { force: true });
138
+ containedRemove({ root: projectRoot, target: temporary, mutation: false });
134
139
  }
135
140
  catch {
136
141
  /* best-effort cleanup */
@@ -162,8 +167,9 @@ function stripManagedHostCommandFiles(projectRoot, hostId) {
162
167
  continue;
163
168
  }
164
169
  try {
165
- rmSync(absolute, { force: true });
166
- removed.push(file.relativePath);
170
+ if (containedRemove({ root: projectRoot, target: absolute }).removed) {
171
+ removed.push(file.relativePath);
172
+ }
167
173
  }
168
174
  catch {
169
175
  /* best-effort */
@@ -7,11 +7,18 @@
7
7
  */
8
8
  /** Rewrite legacy vbrief/.eval description paths for xbrief/schemas projection (#2670). */
9
9
  export declare function rewriteProjectedSchemaContent(content: string): string;
10
+ /** Fail closed when planned (source-rewritten) schema bytes still cite vbrief/.eval/. */
11
+ export declare function assertPlannedSchemaDescriptionRooted(rel: string, text: string): void;
10
12
  /**
11
13
  * Fail closed when a projected xbrief/schemas file still cites vbrief/.eval/.
12
14
  * Upstream vbrief/schemas/ may keep legacy paths; consumer copies must not (#2670).
15
+ *
16
+ * `skipRel` is dest files the collect record plans to replace (#3456 plan-note):
17
+ * never validate stale dest bytes a skipped write would have replaced.
13
18
  */
14
- export declare function assertProjectedSchemaDescriptionsRooted(projectDir: string, destinationDir: string): void;
19
+ export declare function assertProjectedSchemaDescriptionsRooted(projectDir: string, destinationDir: string, options?: {
20
+ readonly skipRel?: ReadonlySet<string>;
21
+ }): void;
15
22
  /**
16
23
  * Synchronize framework-owned xBRIEF schemas while preserving unknown consumer
17
24
  * files. The obsolete v0.6 root schema is the only destination-only file this
@@ -5,9 +5,9 @@
5
5
  * freshness. A current `.deft/core/VERSION` therefore cannot short-circuit
6
6
  * these repairs.
7
7
  */
8
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
8
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
9
9
  import { join, relative, resolve } from "node:path";
10
- import { containedWrite } from "../fs/contained-write.js";
10
+ import { containedMkdir, containedRemove, containedWrite } from "../fs/contained-write.js";
11
11
  import { assertDestinationNotSymlink } from "../fs/projection-containment.js";
12
12
  import { resolveLifecycleRoot } from "../layout/resolve.js";
13
13
  import { DEV_FALLBACK } from "../platform/constants.js";
@@ -50,20 +50,30 @@ export function rewriteProjectedSchemaContent(content) {
50
50
  ? content.replaceAll(LEGACY_EVAL_PATH_PREFIX, XBRIEF_EVAL_PATH_PREFIX)
51
51
  : content;
52
52
  }
53
+ /** Fail closed when planned (source-rewritten) schema bytes still cite vbrief/.eval/. */
54
+ export function assertPlannedSchemaDescriptionRooted(rel, text) {
55
+ if (text.includes(LEGACY_EVAL_PATH_PREFIX)) {
56
+ throw new Error(`projected xbrief schema still cites ${LEGACY_EVAL_PATH_PREFIX}: ${join(MIGRATED_ARTIFACT_DIR, "schemas", rel)}`);
57
+ }
58
+ }
53
59
  /**
54
60
  * Fail closed when a projected xbrief/schemas file still cites vbrief/.eval/.
55
61
  * Upstream vbrief/schemas/ may keep legacy paths; consumer copies must not (#2670).
62
+ *
63
+ * `skipRel` is dest files the collect record plans to replace (#3456 plan-note):
64
+ * never validate stale dest bytes a skipped write would have replaced.
56
65
  */
57
- export function assertProjectedSchemaDescriptionsRooted(projectDir, destinationDir) {
66
+ export function assertProjectedSchemaDescriptionsRooted(projectDir, destinationDir, options = {}) {
58
67
  assertDestinationNotSymlink(projectDir, destinationDir);
59
68
  if (!isDirectory(destinationDir))
60
69
  return;
70
+ const skipRel = options.skipRel;
61
71
  for (const rel of collectSchemaFiles(destinationDir)) {
72
+ if (skipRel?.has(rel))
73
+ continue;
62
74
  const full = join(destinationDir, rel);
63
75
  const text = readFileSync(full, "utf8");
64
- if (text.includes(LEGACY_EVAL_PATH_PREFIX)) {
65
- throw new Error(`projected xbrief schema still cites ${LEGACY_EVAL_PATH_PREFIX}: ${join(MIGRATED_ARTIFACT_DIR, "schemas", rel)}`);
66
- }
76
+ assertPlannedSchemaDescriptionRooted(rel, text);
67
77
  }
68
78
  }
69
79
  function writeFileIfChanged(projectDir, target, content) {
@@ -99,23 +109,26 @@ export function syncConsumerXbriefSchemas(projectDir, deftDir) {
99
109
  }
100
110
  const destinationDir = join(projectDir, MIGRATED_ARTIFACT_DIR, "schemas");
101
111
  assertDestinationNotSymlink(projectDir, destinationDir);
102
- mkdirSync(destinationDir, { recursive: true });
112
+ containedMkdir({ root: resolve(projectDir), target: destinationDir });
103
113
  let changed = false;
114
+ const plannedRel = new Set();
104
115
  for (const rel of collectSchemaFiles(sourceDir)) {
105
116
  if (rel === OBSOLETE_CORE_SCHEMA)
106
117
  continue;
107
118
  const source = join(sourceDir, rel);
108
119
  const destination = join(destinationDir, rel);
109
120
  const projected = rewriteProjectedSchemaContent(readFileSync(source, "utf8"));
121
+ // Planned content is the oracle. Dest bytes a skipped write would replace
122
+ // are not validated (#3456 plan-note).
123
+ assertPlannedSchemaDescriptionRooted(rel, projected);
124
+ plannedRel.add(rel);
110
125
  changed = writeFileIfChanged(projectDir, destination, projected) || changed;
111
126
  }
112
127
  const obsoleteDestination = join(destinationDir, OBSOLETE_CORE_SCHEMA);
113
- assertDestinationNotSymlink(projectDir, obsoleteDestination);
114
- if (existsSync(obsoleteDestination)) {
115
- rmSync(obsoleteDestination, { force: true });
128
+ if (containedRemove({ root: projectDir, target: obsoleteDestination }).removed) {
116
129
  changed = true;
117
130
  }
118
- assertProjectedSchemaDescriptionsRooted(projectDir, destinationDir);
131
+ assertProjectedSchemaDescriptionsRooted(projectDir, destinationDir, { skipRel: plannedRel });
119
132
  return changed;
120
133
  }
121
134
  function syncBareVersionMarkerWithPolicy(projectDir, version, allowRootFallback) {
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Hand-authored briefs run #3323 clause derivation on activate/promote (#3360).
3
+ *
4
+ * issue:ingest already stamps clauses. The dominant consumer path authors the
5
+ * brief by hand; #3334 only required plan.acceptance to exist. This module is
6
+ * the missing derive step.
7
+ */
8
+ import { type AcceptanceClause } from "../verify-ac/clauses.js";
9
+ /** One-line remediation when a stamp has no statement-traceable clause (#3398). */
10
+ export declare const CLAUSE_STAMP_IMPLEMENTATION_ONLY_REMEDIATION = "derive clauses from the statement's testable constraints";
11
+ export type ClauseProvenance = "statement" | "implementation";
12
+ export interface ProvenanceCounts {
13
+ readonly statement: number;
14
+ readonly implementation: number;
15
+ }
16
+ export interface TracedAcceptanceClause extends AcceptanceClause {
17
+ readonly provenance: ClauseProvenance;
18
+ }
19
+ export interface ClauseStampPreparation {
20
+ readonly ok: boolean;
21
+ readonly clauses: readonly TracedAcceptanceClause[];
22
+ readonly provenance_counts: ProvenanceCounts;
23
+ readonly ambiguity_attestation?: "none_found";
24
+ readonly remediation?: string;
25
+ }
26
+ export interface AmbiguityAttestationCheck {
27
+ readonly ok: boolean;
28
+ readonly attested: boolean;
29
+ readonly kind: "ambiguous-clause" | "none_found" | "missing";
30
+ readonly message: string;
31
+ }
32
+ /** True when activate/promote must run #3323 (absent, empty none_stated, or command-only). */
33
+ export declare function needsClauseDerivation(acceptance: unknown): boolean;
34
+ /** Task-statement text from title, narratives, and item Acceptance fields. */
35
+ export declare function collectTaskStatementFromPlan(plan: Record<string, unknown>): string;
36
+ export interface ClauseDerivationResult {
37
+ readonly applied: boolean;
38
+ readonly clauses: readonly (AcceptanceClause | TracedAcceptanceClause)[];
39
+ readonly notice: string;
40
+ }
41
+ /** Statement-traceable when the clause text or its identifiers appear in the statement. */
42
+ export declare function traceClauseProvenance(clause: AcceptanceClause, statement: string): ClauseProvenance;
43
+ export declare function countClauseProvenance(clauses: readonly TracedAcceptanceClause[]): ProvenanceCounts;
44
+ /** Fail closed when every clause is implementation-provenance; else attest ambiguity. */
45
+ export declare function prepareClauseStamp(clauses: readonly AcceptanceClause[], statement: string): ClauseStampPreparation;
46
+ /** Config-error surface for verify:ac: attestation or an ambiguous clause with readings. */
47
+ export declare function evaluateAmbiguityAttestation(acceptance: unknown): AmbiguityAttestationCheck;
48
+ /**
49
+ * Annotate stamped clauses with provenance and an ambiguity attestation.
50
+ * An all-implementation stamp is stripped (never sufficient alone).
51
+ */
52
+ export declare function applyClauseQualityToPlan(plan: Record<string, unknown>): ClauseDerivationResult;
53
+ /** Ingest path: strip an implementation-only stamp and record the remediation. */
54
+ export declare function applyClauseQualityForIngest(plan: Record<string, unknown>): ClauseDerivationResult;
55
+ /**
56
+ * Stamp derived clauses onto plan.acceptance in place. Headless: records
57
+ * chosen_reading, never blocks on a question.
58
+ */
59
+ export declare function applyClauseDerivationToPlan(plan: Record<string, unknown>, options?: {
60
+ readonly projectRoot?: string;
61
+ readonly emitStamp?: boolean;
62
+ }): ClauseDerivationResult;
63
+ /** Stable fingerprint of plan.acceptance for first-write / material-change detection (#3355). */
64
+ export declare function acceptanceFingerprint(acceptance: unknown): string | null;
65
+ /** True when next is a first write or a material change versus previous (#3355). */
66
+ export declare function isMaterialAcceptanceChange(previous: unknown, next: unknown): boolean;
67
+ /** Fail-open acceptance_stamp emission (same contract as issue:ingest / #3355). */
68
+ export declare function emitAcceptanceStampFromPlan(projectRoot: string, plan: unknown, env?: NodeJS.ProcessEnv): void;
69
+ /**
70
+ * Emit acceptance_stamp when plan.acceptance is first written or materially changed.
71
+ * State-observed: callers pass the before/after blocks from any lifecycle verb (#3355).
72
+ */
73
+ export declare function maybeEmitAcceptanceStampFromChange(projectRoot: string, previous: unknown, next: unknown, env?: NodeJS.ProcessEnv): boolean;
74
+ //# sourceMappingURL=clause-derivation.d.ts.map
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Hand-authored briefs run #3323 clause derivation on activate/promote (#3360).
3
+ *
4
+ * issue:ingest already stamps clauses. The dominant consumer path authors the
5
+ * brief by hand; #3334 only required plan.acceptance to exist. This module is
6
+ * the missing derive step.
7
+ */
8
+ import { ENV_RUN_SUMMARY_PATH, RunSummaryEmitter, } from "../run-summary/index.js";
9
+ import { deriveAcceptanceClauses, readAcceptanceClauses, serializeAcceptanceClauses, } from "../verify-ac/clauses.js";
10
+ /** One-line remediation when a stamp has no statement-traceable clause (#3398). */
11
+ export const CLAUSE_STAMP_IMPLEMENTATION_ONLY_REMEDIATION = "derive clauses from the statement's testable constraints";
12
+ const NARRATIVE_KEYS = [
13
+ "Overview",
14
+ "Description",
15
+ "Acceptance",
16
+ "AcceptanceCriteria",
17
+ "Acceptance sketch",
18
+ "AcceptanceSketch",
19
+ "Test",
20
+ "Verification",
21
+ "ImplementationPlan",
22
+ ];
23
+ function asRecord(value) {
24
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
25
+ return value;
26
+ }
27
+ return null;
28
+ }
29
+ function isNonEmptyString(value) {
30
+ return typeof value === "string" && value.trim().length > 0;
31
+ }
32
+ /** True when activate/promote must run #3323 (absent, empty none_stated, or command-only). */
33
+ export function needsClauseDerivation(acceptance) {
34
+ if (acceptance === undefined || acceptance === null) {
35
+ return true;
36
+ }
37
+ const rec = asRecord(acceptance);
38
+ if (rec === null) {
39
+ return true;
40
+ }
41
+ return !(Array.isArray(rec.clauses) && rec.clauses.length > 0);
42
+ }
43
+ /** Task-statement text from title, narratives, and item Acceptance fields. */
44
+ export function collectTaskStatementFromPlan(plan) {
45
+ const parts = [];
46
+ if (isNonEmptyString(plan.title)) {
47
+ parts.push(plan.title.trim());
48
+ }
49
+ const narratives = asRecord(plan.narratives);
50
+ if (narratives !== null) {
51
+ const seen = new Set();
52
+ for (const key of NARRATIVE_KEYS) {
53
+ const value = narratives[key];
54
+ if (isNonEmptyString(value)) {
55
+ parts.push(value.trim());
56
+ seen.add(key.toLowerCase());
57
+ }
58
+ }
59
+ for (const [key, value] of Object.entries(narratives)) {
60
+ if (seen.has(key.toLowerCase()) || !isNonEmptyString(value)) {
61
+ continue;
62
+ }
63
+ parts.push(value.trim());
64
+ }
65
+ }
66
+ if (Array.isArray(plan.items)) {
67
+ for (const item of plan.items) {
68
+ const rec = asRecord(item);
69
+ if (rec === null) {
70
+ continue;
71
+ }
72
+ const narrative = asRecord(rec.narrative);
73
+ const text = narrative?.Acceptance;
74
+ if (isNonEmptyString(text)) {
75
+ parts.push(text.trim());
76
+ }
77
+ }
78
+ }
79
+ return parts.join("\n\n");
80
+ }
81
+ function hasAmbiguousReadings(clause) {
82
+ return clause.ambiguous === true && (clause.readings?.length ?? 0) > 0;
83
+ }
84
+ function extractClauseTokens(text) {
85
+ const found = [];
86
+ const seen = new Set();
87
+ const push = (raw) => {
88
+ const token = raw.trim();
89
+ if (token.length < 2 || seen.has(token)) {
90
+ return;
91
+ }
92
+ seen.add(token);
93
+ found.push(token);
94
+ };
95
+ const quoted = /["'`]([^"'`\n]{2,80})["'`]/g;
96
+ let match = quoted.exec(text);
97
+ while (match !== null) {
98
+ push(match[1] ?? "");
99
+ match = quoted.exec(text);
100
+ }
101
+ const pathRe = /(?<![A-Za-z0-9_])((?:[A-Za-z0-9_.-]+\/)+[A-Za-z0-9_.-]+\.[A-Za-z][A-Za-z0-9]+)(?![A-Za-z0-9_])/g;
102
+ match = pathRe.exec(text);
103
+ while (match !== null) {
104
+ push(match[1] ?? "");
105
+ match = pathRe.exec(text);
106
+ }
107
+ const ident = /(?<![A-Za-z0-9_])([A-Za-z_][A-Za-z0-9_]*)(?![A-Za-z0-9_])/g;
108
+ match = ident.exec(text);
109
+ while (match !== null) {
110
+ const token = match[1] ?? "";
111
+ const camelOrPascal = /[a-z][A-Z]/.test(token) || /[A-Z][a-z]+[A-Z]/.test(token);
112
+ const codeShaped = camelOrPascal || token.includes("_");
113
+ if (codeShaped) {
114
+ push(token);
115
+ }
116
+ match = ident.exec(text);
117
+ }
118
+ return found;
119
+ }
120
+ /** Statement-traceable when the clause text or its identifiers appear in the statement. */
121
+ export function traceClauseProvenance(clause, statement) {
122
+ const normClause = clause.text.replace(/\s+/g, " ").trim();
123
+ const normStatement = statement.replace(/\s+/g, " ").trim();
124
+ if (normClause.length > 0 && normStatement.includes(normClause)) {
125
+ return "statement";
126
+ }
127
+ const tokens = extractClauseTokens(clause.text);
128
+ if (tokens.length === 0) {
129
+ return "implementation";
130
+ }
131
+ return tokens.every((token) => statement.includes(token)) ? "statement" : "implementation";
132
+ }
133
+ export function countClauseProvenance(clauses) {
134
+ let statement = 0;
135
+ let implementation = 0;
136
+ for (const clause of clauses) {
137
+ if (clause.provenance === "statement") {
138
+ statement += 1;
139
+ }
140
+ else {
141
+ implementation += 1;
142
+ }
143
+ }
144
+ return { statement, implementation };
145
+ }
146
+ /** Fail closed when every clause is implementation-provenance; else attest ambiguity. */
147
+ export function prepareClauseStamp(clauses, statement) {
148
+ const traced = clauses.map((clause) => ({
149
+ ...clause,
150
+ provenance: traceClauseProvenance(clause, statement),
151
+ }));
152
+ const provenance_counts = countClauseProvenance(traced);
153
+ if (traced.length > 0 && provenance_counts.statement === 0) {
154
+ return {
155
+ ok: false,
156
+ clauses: traced,
157
+ provenance_counts,
158
+ remediation: CLAUSE_STAMP_IMPLEMENTATION_ONLY_REMEDIATION,
159
+ };
160
+ }
161
+ return {
162
+ ok: true,
163
+ clauses: traced,
164
+ provenance_counts,
165
+ ambiguity_attestation: traced.some(hasAmbiguousReadings) ? undefined : "none_found",
166
+ };
167
+ }
168
+ const AMBIGUITY_ATTESTATION_MISSING = "verify:ac config error: missing ambiguity attestation; record at least one ambiguous: true clause with readings, or set ambiguity_attestation: none_found";
169
+ /** Config-error surface for verify:ac: attestation or an ambiguous clause with readings. */
170
+ export function evaluateAmbiguityAttestation(acceptance) {
171
+ const rec = asRecord(acceptance);
172
+ if (rec === null) {
173
+ return { ok: false, attested: false, kind: "missing", message: AMBIGUITY_ATTESTATION_MISSING };
174
+ }
175
+ const clauses = readAcceptanceClauses(rec);
176
+ if (clauses.some(hasAmbiguousReadings)) {
177
+ return { ok: true, attested: true, kind: "ambiguous-clause", message: "" };
178
+ }
179
+ if (rec.ambiguity_attestation === "none_found") {
180
+ return { ok: true, attested: true, kind: "none_found", message: "" };
181
+ }
182
+ return { ok: false, attested: false, kind: "missing", message: AMBIGUITY_ATTESTATION_MISSING };
183
+ }
184
+ function serializeTracedClauses(clauses) {
185
+ return serializeAcceptanceClauses(clauses).map((row, index) => ({
186
+ ...row,
187
+ provenance: clauses[index]?.provenance ?? "implementation",
188
+ }));
189
+ }
190
+ /**
191
+ * Annotate stamped clauses with provenance and an ambiguity attestation.
192
+ * An all-implementation stamp is stripped (never sufficient alone).
193
+ */
194
+ export function applyClauseQualityToPlan(plan) {
195
+ const existing = asRecord(plan.acceptance);
196
+ if (existing === null) {
197
+ return { applied: false, clauses: [], notice: "" };
198
+ }
199
+ const clauses = readAcceptanceClauses(existing);
200
+ if (clauses.length === 0) {
201
+ return { applied: false, clauses: [], notice: "" };
202
+ }
203
+ const prepared = prepareClauseStamp(clauses, collectTaskStatementFromPlan(plan));
204
+ if (!prepared.ok) {
205
+ const next = { ...existing };
206
+ delete next.clauses;
207
+ plan.acceptance = next;
208
+ return {
209
+ applied: false,
210
+ clauses: prepared.clauses,
211
+ notice: prepared.remediation ?? CLAUSE_STAMP_IMPLEMENTATION_ONLY_REMEDIATION,
212
+ };
213
+ }
214
+ const next = {
215
+ ...existing,
216
+ clauses: serializeTracedClauses(prepared.clauses),
217
+ };
218
+ if (prepared.ambiguity_attestation !== undefined &&
219
+ existing.ambiguity_attestation === undefined) {
220
+ next.ambiguity_attestation = prepared.ambiguity_attestation;
221
+ }
222
+ plan.acceptance = next;
223
+ return {
224
+ applied: true,
225
+ clauses: prepared.clauses,
226
+ notice: formatAmbiguousClauseNotice(prepared.clauses),
227
+ };
228
+ }
229
+ /** Ingest path: strip an implementation-only stamp and record the remediation. */
230
+ export function applyClauseQualityForIngest(plan) {
231
+ const quality = applyClauseQualityToPlan(plan);
232
+ if (!quality.applied && quality.notice.length > 0) {
233
+ const existing = asRecord(plan.acceptance);
234
+ if (existing !== null) {
235
+ plan.acceptance = {
236
+ ...existing,
237
+ derived_reason: quality.notice,
238
+ quality_notice: quality.notice,
239
+ };
240
+ }
241
+ }
242
+ return quality;
243
+ }
244
+ function formatAmbiguousClauseNotice(clauses) {
245
+ const flagged = clauses.filter((clause) => clause.ambiguous);
246
+ const lines = [
247
+ `#3323 clause derivation stamped ${clauses.length} clause(s)` +
248
+ (flagged.length > 0 ? `; flagged-ambiguous: ${flagged.length}` : ""),
249
+ ];
250
+ for (const clause of flagged) {
251
+ const chosen = clause.chosen_reading ?? 0;
252
+ const chosenPath = clause.readings?.[chosen]?.artifact_path ?? clause.artifact_path ?? "(none)";
253
+ lines.push(` clause ${clause.id}: two readings; chosen_reading=${chosen} (${chosenPath}) [headless #3323]`);
254
+ for (const [index, reading] of (clause.readings ?? []).entries()) {
255
+ lines.push(` reading ${index}: ${reading.artifact_path ?? "(none)"}`);
256
+ }
257
+ }
258
+ return lines.join("\n");
259
+ }
260
+ /**
261
+ * Stamp derived clauses onto plan.acceptance in place. Headless: records
262
+ * chosen_reading, never blocks on a question.
263
+ */
264
+ export function applyClauseDerivationToPlan(plan, options = {}) {
265
+ if (!needsClauseDerivation(plan.acceptance)) {
266
+ return {
267
+ applied: false,
268
+ clauses: readAcceptanceClauses(plan.acceptance),
269
+ notice: "",
270
+ };
271
+ }
272
+ const clauses = deriveAcceptanceClauses(collectTaskStatementFromPlan(plan));
273
+ if (clauses.length === 0) {
274
+ return { applied: false, clauses: [], notice: "" };
275
+ }
276
+ const existing = asRecord(plan.acceptance);
277
+ const commands = existing !== null && Array.isArray(existing.commands) ? existing.commands : [];
278
+ const hasCommands = commands.length > 0;
279
+ const noneStated = hasCommands ? existing?.none_stated === true : true;
280
+ const sourceRung = hasCommands && existing?.none_stated !== true
281
+ ? isNonEmptyString(existing?.source_rung)
282
+ ? existing.source_rung
283
+ : "stated"
284
+ : "derived";
285
+ const previousAcceptance = plan.acceptance;
286
+ plan.acceptance = {
287
+ ...(existing ?? {}),
288
+ commands: hasCommands ? commands : [],
289
+ none_stated: noneStated,
290
+ source_rung: sourceRung,
291
+ derived_reason: `derived ${clauses.length} independently testable clauses from the task statement before product edit (#3323)`,
292
+ clauses: serializeAcceptanceClauses(clauses),
293
+ };
294
+ const quality = applyClauseQualityToPlan(plan);
295
+ if (!quality.applied) {
296
+ const existing = asRecord(previousAcceptance);
297
+ if (existing !== null && quality.notice.length > 0) {
298
+ plan.acceptance = {
299
+ ...existing,
300
+ quality_notice: quality.notice,
301
+ derived_reason: quality.notice,
302
+ };
303
+ }
304
+ else {
305
+ plan.acceptance = previousAcceptance;
306
+ }
307
+ return {
308
+ applied: false,
309
+ clauses: quality.clauses,
310
+ notice: quality.notice,
311
+ };
312
+ }
313
+ if (options.emitStamp !== false && options.projectRoot !== undefined) {
314
+ emitAcceptanceStampFromPlan(options.projectRoot, plan);
315
+ }
316
+ return {
317
+ applied: true,
318
+ clauses: quality.clauses,
319
+ notice: quality.notice,
320
+ };
321
+ }
322
+ /** Stable fingerprint of plan.acceptance for first-write / material-change detection (#3355). */
323
+ export function acceptanceFingerprint(acceptance) {
324
+ const rec = asRecord(acceptance);
325
+ if (rec === null) {
326
+ return null;
327
+ }
328
+ const commands = Array.isArray(rec.commands) ? rec.commands.length : 0;
329
+ const clauses = Array.isArray(rec.clauses)
330
+ ? rec.clauses.map((entry, index) => {
331
+ const row = asRecord(entry);
332
+ if (row === null) {
333
+ return `${index}`;
334
+ }
335
+ return `${row.id ?? index}:${row.text ?? ""}:${row.artifact_path ?? ""}`;
336
+ })
337
+ : [];
338
+ const rung = typeof rec.source_rung === "string" ? rec.source_rung : "";
339
+ return `${rung}|${rec.none_stated === true}|${commands}|${clauses.join(";")}`;
340
+ }
341
+ /** True when next is a first write or a material change versus previous (#3355). */
342
+ export function isMaterialAcceptanceChange(previous, next) {
343
+ const nextFp = acceptanceFingerprint(next);
344
+ if (nextFp === null) {
345
+ return false;
346
+ }
347
+ return acceptanceFingerprint(previous) !== nextFp;
348
+ }
349
+ /** Fail-open acceptance_stamp emission (same contract as issue:ingest / #3355). */
350
+ export function emitAcceptanceStampFromPlan(projectRoot, plan, env = process.env) {
351
+ const rec = asRecord(plan);
352
+ if (rec === null) {
353
+ return;
354
+ }
355
+ const acceptance = asRecord(rec.acceptance);
356
+ if (acceptance === null) {
357
+ return;
358
+ }
359
+ const dest = env[ENV_RUN_SUMMARY_PATH];
360
+ if (dest === undefined || dest.trim().length === 0) {
361
+ return;
362
+ }
363
+ try {
364
+ const emitter = new RunSummaryEmitter({
365
+ projectRoot,
366
+ env,
367
+ component: "clause-derivation",
368
+ });
369
+ const commands = Array.isArray(acceptance.commands) ? acceptance.commands.length : 0;
370
+ const clauses = Array.isArray(acceptance.clauses) ? acceptance.clauses.length : 0;
371
+ const statement = collectTaskStatementFromPlan(rec);
372
+ const rawRows = Array.isArray(acceptance.clauses) ? acceptance.clauses : [];
373
+ const traced = readAcceptanceClauses(acceptance).map((clause, index) => {
374
+ const row = asRecord(rawRows[index]);
375
+ const stamped = row?.provenance === "statement" || row?.provenance === "implementation"
376
+ ? row.provenance
377
+ : undefined;
378
+ return {
379
+ ...clause,
380
+ provenance: stamped ??
381
+ (statement.trim().length > 0 ? traceClauseProvenance(clause, statement) : "statement"),
382
+ };
383
+ });
384
+ const payload = {
385
+ rung: typeof acceptance.source_rung === "string" ? acceptance.source_rung : "project_floor",
386
+ none_stated: acceptance.none_stated === true,
387
+ command_count: commands,
388
+ clause_count: clauses,
389
+ provenance_counts: countClauseProvenance(traced),
390
+ ambiguity_attested: evaluateAmbiguityAttestation(acceptance).attested,
391
+ };
392
+ emitter.emitAcceptanceStamp(payload);
393
+ }
394
+ catch {
395
+ // fail-open
396
+ }
397
+ }
398
+ /**
399
+ * Emit acceptance_stamp when plan.acceptance is first written or materially changed.
400
+ * State-observed: callers pass the before/after blocks from any lifecycle verb (#3355).
401
+ */
402
+ export function maybeEmitAcceptanceStampFromChange(projectRoot, previous, next, env = process.env) {
403
+ if (!isMaterialAcceptanceChange(previous, next)) {
404
+ return false;
405
+ }
406
+ emitAcceptanceStampFromPlan(projectRoot, { acceptance: next }, env);
407
+ return true;
408
+ }
409
+ //# sourceMappingURL=clause-derivation.js.map
@@ -1,4 +1,5 @@
1
1
  export * from "./candidates-log.js";
2
+ export * from "./clause-derivation.js";
2
3
  export * from "./github-auth-modes.js";
3
4
  export { resultToDict } from "./github-auth-modes.js";
4
5
  export * from "./github-body.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./candidates-log.js";
2
+ export * from "./clause-derivation.js";
2
3
  export * from "./github-auth-modes.js";
3
4
  export { resultToDict } from "./github-auth-modes.js";
4
5
  export * from "./github-body.js";
@@ -58,6 +58,8 @@ export declare function buildIssueVbrief(issue: Record<string, unknown>, status:
58
58
  infoRootKey?: typeof LEGACY_INFO_ROOT_KEY | typeof MIGRATED_INFO_ROOT_KEY;
59
59
  infoVersion?: string;
60
60
  }): [Record<string, unknown>, string];
61
+ /** Include a refused-stamp remediation on the ingest result so it is not silent. */
62
+ export declare function formatIngestCreatedMessage(folder: string, filename: string, plan: unknown, dryRun?: boolean): string;
61
63
  export declare function targetFilename(number: number, title: string, artifactSuffix?: typeof LEGACY_ARTIFACT_SUFFIX | typeof MIGRATED_ARTIFACT_SUFFIX): string;
62
64
  export interface FetchIssueOptions {
63
65
  readonly cwd?: string | null;
@@ -116,5 +118,5 @@ export declare function ingestSingleForAccept(n: number, repo: string, options?:
116
118
  projectRoot?: string | null;
117
119
  status?: IngestStatus;
118
120
  cacheRoot?: string | null;
119
- }): [IngestResult, string | null];
121
+ }): [IngestResult, string | null, string];
120
122
  //# sourceMappingURL=issue-ingest.d.ts.map