martin-loop 0.1.5 → 1.3.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 (274) hide show
  1. package/CODE_OF_CONDUCT.md +32 -0
  2. package/LICENSE +21 -21
  3. package/README.md +307 -398
  4. package/demo/seeded-workspace/README.md +35 -35
  5. package/demo/seeded-workspace/TASKS.md +29 -29
  6. package/demo/seeded-workspace/martin.config.yaml +11 -11
  7. package/demo/seeded-workspace/package.json +8 -8
  8. package/demo/seeded-workspace/src/invoice-summary.js +11 -11
  9. package/demo/seeded-workspace/test/invoice-summary.test.js +20 -20
  10. package/dist/bin/martin-loop.js +0 -0
  11. package/dist/vendor/adapters/counter.d.ts +1 -0
  12. package/dist/vendor/adapters/counter.js +4 -0
  13. package/dist/vendor/adapters/git-baseline.d.ts +50 -0
  14. package/dist/vendor/adapters/git-baseline.js +233 -0
  15. package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
  16. package/dist/vendor/adapters/openrouter-adapter.js +302 -0
  17. package/dist/vendor/adapters/usage.d.ts +48 -0
  18. package/dist/vendor/adapters/usage.js +66 -0
  19. package/dist/vendor/cli/bin/exit.d.ts +12 -0
  20. package/dist/vendor/cli/bin/exit.js +28 -0
  21. package/dist/vendor/cli/commands/analyze.d.ts +5 -0
  22. package/dist/vendor/cli/commands/analyze.js +58 -0
  23. package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
  24. package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
  25. package/dist/vendor/cli/commands/audit.d.ts +8 -0
  26. package/dist/vendor/cli/commands/audit.js +199 -0
  27. package/dist/vendor/cli/commands/corpus.d.ts +5 -0
  28. package/dist/vendor/cli/commands/corpus.js +60 -0
  29. package/dist/vendor/cli/commands/doctor.d.ts +8 -0
  30. package/dist/vendor/cli/commands/doctor.js +219 -0
  31. package/dist/vendor/cli/commands/explain.d.ts +17 -0
  32. package/dist/vendor/cli/commands/explain.js +176 -0
  33. package/dist/vendor/cli/commands/export.d.ts +5 -0
  34. package/dist/vendor/cli/commands/export.js +60 -0
  35. package/dist/vendor/cli/commands/governance.d.ts +8 -0
  36. package/dist/vendor/cli/commands/governance.js +95 -0
  37. package/dist/vendor/cli/commands/improve.d.ts +18 -0
  38. package/dist/vendor/cli/commands/improve.js +396 -0
  39. package/dist/vendor/cli/commands/init.d.ts +8 -0
  40. package/dist/vendor/cli/commands/init.js +281 -0
  41. package/dist/vendor/cli/commands/migration.d.ts +8 -0
  42. package/dist/vendor/cli/commands/migration.js +67 -0
  43. package/dist/vendor/cli/commands/prior.d.ts +23 -0
  44. package/dist/vendor/cli/commands/prior.js +145 -0
  45. package/dist/vendor/cli/commands/resume.d.ts +21 -0
  46. package/dist/vendor/cli/commands/resume.js +73 -0
  47. package/dist/vendor/cli/commands/verify.d.ts +6 -0
  48. package/dist/vendor/cli/commands/verify.js +43 -0
  49. package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
  50. package/dist/vendor/cli/research/public-corpus.js +151 -0
  51. package/dist/vendor/cli/ui/error-card.d.ts +38 -0
  52. package/dist/vendor/cli/ui/error-card.js +103 -0
  53. package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
  54. package/dist/vendor/cli/ui/mission-brief.js +173 -0
  55. package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
  56. package/dist/vendor/cli/ui/summary-card.js +102 -0
  57. package/dist/vendor/contracts/audit.d.ts +46 -0
  58. package/dist/vendor/contracts/audit.js +360 -0
  59. package/dist/vendor/contracts/post-phase15.d.ts +240 -0
  60. package/dist/vendor/contracts/post-phase15.js +166 -0
  61. package/dist/vendor/core/agent/mandates.d.ts +46 -0
  62. package/dist/vendor/core/agent/mandates.js +178 -0
  63. package/dist/vendor/core/agent/receipts.d.ts +38 -0
  64. package/dist/vendor/core/agent/receipts.js +131 -0
  65. package/dist/vendor/core/agent/signing.d.ts +17 -0
  66. package/dist/vendor/core/agent/signing.js +91 -0
  67. package/dist/vendor/core/attestation/sign.d.ts +25 -0
  68. package/dist/vendor/core/attestation/sign.js +216 -0
  69. package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
  70. package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
  71. package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
  72. package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
  73. package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
  74. package/dist/vendor/core/autonomy/envelope.js +27 -0
  75. package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
  76. package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
  77. package/dist/vendor/core/autonomy/resume.d.ts +15 -0
  78. package/dist/vendor/core/autonomy/resume.js +23 -0
  79. package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
  80. package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
  81. package/dist/vendor/core/context-distillation.d.ts +3 -0
  82. package/dist/vendor/core/context-distillation.js +44 -0
  83. package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
  84. package/dist/vendor/core/context-flow/compile-context.js +111 -0
  85. package/dist/vendor/core/context-flow/entities.d.ts +2 -0
  86. package/dist/vendor/core/context-flow/entities.js +44 -0
  87. package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
  88. package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
  89. package/dist/vendor/core/context-flow/index.d.ts +11 -0
  90. package/dist/vendor/core/context-flow/index.js +24 -0
  91. package/dist/vendor/core/context-flow/labels.d.ts +3 -0
  92. package/dist/vendor/core/context-flow/labels.js +17 -0
  93. package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
  94. package/dist/vendor/core/context-flow/normalizer.js +69 -0
  95. package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
  96. package/dist/vendor/core/context-flow/profiles.js +36 -0
  97. package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
  98. package/dist/vendor/core/context-flow/redaction.js +6 -0
  99. package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
  100. package/dist/vendor/core/context-flow/sensitivity.js +27 -0
  101. package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
  102. package/dist/vendor/core/context-flow/sync-preview.js +22 -0
  103. package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
  104. package/dist/vendor/core/context-flow/token-estimator.js +13 -0
  105. package/dist/vendor/core/context-flow/types.d.ts +91 -0
  106. package/dist/vendor/core/context-flow/types.js +2 -0
  107. package/dist/vendor/core/context-utility.d.ts +47 -0
  108. package/dist/vendor/core/context-utility.js +405 -0
  109. package/dist/vendor/core/cost/pipeline.d.ts +92 -0
  110. package/dist/vendor/core/cost/pipeline.js +141 -0
  111. package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
  112. package/dist/vendor/core/cost/tagged-cost.js +55 -0
  113. package/dist/vendor/core/cost-governor.d.ts +2 -0
  114. package/dist/vendor/core/cost-governor.js +50 -0
  115. package/dist/vendor/core/cve/cve-check.d.ts +80 -0
  116. package/dist/vendor/core/cve/cve-check.js +172 -0
  117. package/dist/vendor/core/digital-twin/index.d.ts +27 -0
  118. package/dist/vendor/core/digital-twin/index.js +90 -0
  119. package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
  120. package/dist/vendor/core/drift/drift-graph.js +100 -0
  121. package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
  122. package/dist/vendor/core/drift/objective-lock.js +88 -0
  123. package/dist/vendor/core/drift/scope.d.ts +46 -0
  124. package/dist/vendor/core/drift/scope.js +102 -0
  125. package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
  126. package/dist/vendor/core/drift/signature-lock.js +202 -0
  127. package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
  128. package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
  129. package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
  130. package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
  131. package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
  132. package/dist/vendor/core/evidence/claim-audit.js +89 -0
  133. package/dist/vendor/core/exit-intelligence.d.ts +2 -0
  134. package/dist/vendor/core/exit-intelligence.js +58 -0
  135. package/dist/vendor/core/explain/formatter.d.ts +42 -0
  136. package/dist/vendor/core/explain/formatter.js +171 -0
  137. package/dist/vendor/core/explain/timeline.d.ts +29 -0
  138. package/dist/vendor/core/explain/timeline.js +213 -0
  139. package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
  140. package/dist/vendor/core/failure-taxonomy.js +76 -0
  141. package/dist/vendor/core/gateway/index.d.ts +10 -0
  142. package/dist/vendor/core/gateway/index.js +12 -0
  143. package/dist/vendor/core/gateway/registry.d.ts +40 -0
  144. package/dist/vendor/core/gateway/registry.js +97 -0
  145. package/dist/vendor/core/gateway/transport.d.ts +31 -0
  146. package/dist/vendor/core/gateway/transport.js +82 -0
  147. package/dist/vendor/core/gateway/vault.d.ts +19 -0
  148. package/dist/vendor/core/gateway/vault.js +29 -0
  149. package/dist/vendor/core/graph/adapters.d.ts +43 -0
  150. package/dist/vendor/core/graph/adapters.js +91 -0
  151. package/dist/vendor/core/graph/hotspots.d.ts +22 -0
  152. package/dist/vendor/core/graph/hotspots.js +30 -0
  153. package/dist/vendor/core/graph/index.d.ts +1 -0
  154. package/dist/vendor/core/graph/index.js +2 -0
  155. package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
  156. package/dist/vendor/core/honey/honey-tokens.js +44 -0
  157. package/dist/vendor/core/index.d.ts +2 -2
  158. package/dist/vendor/core/index.js +38 -12
  159. package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
  160. package/dist/vendor/core/learning/bayesian-update.js +60 -0
  161. package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
  162. package/dist/vendor/core/learning/prior-sets.js +111 -0
  163. package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
  164. package/dist/vendor/core/learning/promotion-gate.js +23 -0
  165. package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
  166. package/dist/vendor/core/leash/blast-radius.js +156 -0
  167. package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
  168. package/dist/vendor/core/leash/policy-leash.js +117 -0
  169. package/dist/vendor/core/memo/memo.d.ts +63 -0
  170. package/dist/vendor/core/memo/memo.js +97 -0
  171. package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
  172. package/dist/vendor/core/memory/learning-pipeline.js +391 -0
  173. package/dist/vendor/core/memory/palace.d.ts +84 -0
  174. package/dist/vendor/core/memory/palace.js +379 -0
  175. package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
  176. package/dist/vendor/core/merge/ast-merge.js +350 -0
  177. package/dist/vendor/core/merge/text-merge.d.ts +12 -0
  178. package/dist/vendor/core/merge/text-merge.js +182 -0
  179. package/dist/vendor/core/otel/tracer.d.ts +45 -0
  180. package/dist/vendor/core/otel/tracer.js +116 -0
  181. package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
  182. package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
  183. package/dist/vendor/core/parallel/scorer.d.ts +24 -0
  184. package/dist/vendor/core/parallel/scorer.js +65 -0
  185. package/dist/vendor/core/pattern-detection.d.ts +64 -0
  186. package/dist/vendor/core/pattern-detection.js +108 -0
  187. package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
  188. package/dist/vendor/core/persistence/checkpoint.js +156 -0
  189. package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
  190. package/dist/vendor/core/persistence/cleanup.js +131 -0
  191. package/dist/vendor/core/persistence/index.d.ts +2 -0
  192. package/dist/vendor/core/persistence/index.js +1 -0
  193. package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
  194. package/dist/vendor/core/persistence/runs-reader.js +84 -0
  195. package/dist/vendor/core/persistence/store.d.ts +6 -1
  196. package/dist/vendor/core/persistence/store.js +5 -0
  197. package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
  198. package/dist/vendor/core/policy/file-touch-quota.js +105 -0
  199. package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
  200. package/dist/vendor/core/policy/policy-loader.js +170 -0
  201. package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
  202. package/dist/vendor/core/policy/policy-schema.js +78 -0
  203. package/dist/vendor/core/probe/probe.d.ts +49 -0
  204. package/dist/vendor/core/probe/probe.js +115 -0
  205. package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
  206. package/dist/vendor/core/proof/patch-proof.js +84 -0
  207. package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
  208. package/dist/vendor/core/proof/semantic-probe.js +82 -0
  209. package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
  210. package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
  211. package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
  212. package/dist/vendor/core/red-blue/red-phase.js +141 -0
  213. package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
  214. package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
  215. package/dist/vendor/core/replay/replay.d.ts +85 -0
  216. package/dist/vendor/core/replay/replay.js +109 -0
  217. package/dist/vendor/core/router/engine.d.ts +54 -0
  218. package/dist/vendor/core/router/engine.js +131 -0
  219. package/dist/vendor/core/router/index.d.ts +1 -0
  220. package/dist/vendor/core/router/index.js +2 -0
  221. package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
  222. package/dist/vendor/core/router/trust-calibration.js +127 -0
  223. package/dist/vendor/core/run-martin.d.ts +2 -0
  224. package/dist/vendor/core/run-martin.js +287 -0
  225. package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
  226. package/dist/vendor/core/security/cve-scanner.js +178 -0
  227. package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
  228. package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
  229. package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
  230. package/dist/vendor/core/sentinel/progress-guard.js +46 -0
  231. package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
  232. package/dist/vendor/core/siem/siem-emitter.js +157 -0
  233. package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
  234. package/dist/vendor/core/strategy/attempt-brief.js +89 -0
  235. package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
  236. package/dist/vendor/core/summarize/diff-summary.js +204 -0
  237. package/dist/vendor/core/surface-signals.d.ts +21 -0
  238. package/dist/vendor/core/surface-signals.js +139 -0
  239. package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
  240. package/dist/vendor/core/truth/truth-wall.js +69 -0
  241. package/dist/vendor/core/truth-spine.d.ts +26 -0
  242. package/dist/vendor/core/truth-spine.js +62 -0
  243. package/dist/vendor/core/types.d.ts +115 -0
  244. package/dist/vendor/core/types.js +2 -0
  245. package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
  246. package/dist/vendor/core/verification/tiered-verify.js +29 -0
  247. package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
  248. package/dist/vendor/core/verifier-pyramid.js +111 -0
  249. package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
  250. package/dist/vendor/core/workflow-artifacts.js +668 -0
  251. package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
  252. package/dist/vendor/core/wrap/supervised-run.js +178 -0
  253. package/docs/assets/cli-animated.svg +139 -0
  254. package/docs/assets/cli-static.svg +34 -0
  255. package/docs/assets/github-hero-v2.svg +23 -0
  256. package/docs/assets/martin-raplph.png.jpg +0 -0
  257. package/docs/assets/martinloop-logo.png +0 -0
  258. package/docs/assets/nvidia-inception-program-light.png +0 -0
  259. package/docs/assets/nvidia-inception-program.png +0 -0
  260. package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
  261. package/docs/assets/side-by-side.svg +134 -0
  262. package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -142
  263. package/docs/oss/EXAMPLES.md +134 -134
  264. package/docs/oss/OSS-BOUNDARY-REPORT.json +1 -1
  265. package/docs/oss/OSS-BOUNDARY-REPORT.md +1 -1
  266. package/docs/oss/QUICKSTART.md +170 -165
  267. package/docs/oss/RALPH-LOOP-SAFETY.md +113 -113
  268. package/docs/oss/README.md +96 -96
  269. package/docs/oss/RELEASE-SURFACE-REPORT.json +2 -1
  270. package/docs/oss/RELEASE-SURFACE-REPORT.md +2 -1
  271. package/package.json +130 -58
  272. package/docs/distribution/DIRECTORY-SUBMISSIONS.md +0 -89
  273. package/docs/distribution/INTEGRATION-OUTREACH.md +0 -61
  274. package/docs/distribution/UNDER-3-CHALLENGE.md +0 -65
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Lightweight adjacency-list graph used by scope pruning (SLICE-02).
3
+ * Nodes are file paths (or symbol names). Edges represent import/reference
4
+ * relationships: for each node, the array contains its direct dependents.
5
+ */
6
+ export interface DriftGraph {
7
+ /** Complete set of known node identifiers (file paths or symbol names). */
8
+ nodes: Set<string>;
9
+ /** Adjacency list: node → list of directly connected nodes (1 hop). */
10
+ edges: Record<string, string[]>;
11
+ }
12
+ export interface DriftReport {
13
+ changedExports: string[];
14
+ affectedImporters: Array<{
15
+ file: string;
16
+ importedSymbol: string;
17
+ }>;
18
+ /** Importers with no test coverage for the changed symbol */
19
+ unvalidatedDownstream: string[];
20
+ /** true only if unvalidatedDownstream is empty */
21
+ safe: boolean;
22
+ }
23
+ export interface DriftInput {
24
+ /** Workspace root — ts-morph will glob all .ts files under it */
25
+ rootDir: string;
26
+ /** Path of the changed file, relative to rootDir (forward slashes) */
27
+ changedFile: string;
28
+ /** List of exported symbol names that changed */
29
+ changedExports: string[];
30
+ /** List of test file paths (absolute or relative to rootDir) that cover the changed symbols */
31
+ testFiles: string[];
32
+ }
33
+ /**
34
+ * Builds a DriftReport by walking the workspace with ts-morph.
35
+ *
36
+ * Algorithm:
37
+ * 1. If changedExports is empty → safe: true immediately (no public API touched)
38
+ * 2. Walk all .ts files (excluding node_modules) looking for imports of any changed symbol
39
+ * 3. For each importer, check if a test file also imports the same changed symbol
40
+ * 4. Importers without test coverage → unvalidatedDownstream → safe: false
41
+ */
42
+ export declare function buildDriftReport(input: DriftInput): Promise<DriftReport>;
43
+ /**
44
+ * Builds and writes drift-report.json to the run output directory.
45
+ * Only writes if changedExports is non-empty (no drift = no report needed).
46
+ */
47
+ export declare function emitDriftReport(input: DriftInput, runDir: string): Promise<DriftReport>;
@@ -0,0 +1,100 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { Project } from "ts-morph";
4
+ // ─── Core builder ─────────────────────────────────────────────────────────────
5
+ /**
6
+ * Builds a DriftReport by walking the workspace with ts-morph.
7
+ *
8
+ * Algorithm:
9
+ * 1. If changedExports is empty → safe: true immediately (no public API touched)
10
+ * 2. Walk all .ts files (excluding node_modules) looking for imports of any changed symbol
11
+ * 3. For each importer, check if a test file also imports the same changed symbol
12
+ * 4. Importers without test coverage → unvalidatedDownstream → safe: false
13
+ */
14
+ export async function buildDriftReport(input) {
15
+ if (input.changedExports.length === 0) {
16
+ return {
17
+ changedExports: [],
18
+ affectedImporters: [],
19
+ unvalidatedDownstream: [],
20
+ safe: true
21
+ };
22
+ }
23
+ const project = new Project({
24
+ skipAddingFilesFromTsConfig: true
25
+ });
26
+ // Add all .ts files from rootDir (not node_modules, not .d.ts)
27
+ project.addSourceFilesAtPaths([
28
+ normalizePath(join(input.rootDir, "**/*.ts")),
29
+ `!${normalizePath(join(input.rootDir, "**/node_modules/**"))}`,
30
+ `!${normalizePath(join(input.rootDir, "**/*.d.ts"))}`
31
+ ]);
32
+ const changedFilePath = normalizePath(join(input.rootDir, input.changedFile));
33
+ const affectedImporters = [];
34
+ for (const sourceFile of project.getSourceFiles()) {
35
+ const filePath = normalizePath(sourceFile.getFilePath());
36
+ // Skip the changed file itself
37
+ if (filePath === changedFilePath)
38
+ continue;
39
+ // Check import declarations for any of the changed symbols
40
+ for (const importDecl of sourceFile.getImportDeclarations()) {
41
+ const namedImports = importDecl.getNamedImports();
42
+ for (const namedImport of namedImports) {
43
+ const symbolName = namedImport.getName();
44
+ if (input.changedExports.includes(symbolName)) {
45
+ affectedImporters.push({
46
+ file: filePath,
47
+ importedSymbol: symbolName
48
+ });
49
+ }
50
+ }
51
+ }
52
+ }
53
+ // Determine which importers are test files (by path convention or explicit list)
54
+ const testFilePaths = new Set(input.testFiles.map(f => normalizePath(f.startsWith("/") || /^[A-Za-z]:/.test(f)
55
+ ? f
56
+ : join(input.rootDir, f))));
57
+ // Also treat files matching *.test.ts or *.spec.ts as test files
58
+ const testSymbolsCovered = new Set();
59
+ for (const importer of affectedImporters) {
60
+ const isTestFile = testFilePaths.has(importer.file) ||
61
+ /\.(test|spec)\.[tj]s$/.test(importer.file);
62
+ if (isTestFile) {
63
+ testSymbolsCovered.add(importer.importedSymbol);
64
+ }
65
+ }
66
+ // unvalidatedDownstream = non-test importers whose symbol has no test coverage
67
+ const unvalidatedDownstream = [];
68
+ for (const importer of affectedImporters) {
69
+ const isTestFile = testFilePaths.has(importer.file) ||
70
+ /\.(test|spec)\.[tj]s$/.test(importer.file);
71
+ if (!isTestFile && !testSymbolsCovered.has(importer.importedSymbol)) {
72
+ if (!unvalidatedDownstream.includes(importer.file)) {
73
+ unvalidatedDownstream.push(importer.file);
74
+ }
75
+ }
76
+ }
77
+ return {
78
+ changedExports: input.changedExports,
79
+ affectedImporters,
80
+ unvalidatedDownstream,
81
+ safe: unvalidatedDownstream.length === 0
82
+ };
83
+ }
84
+ // ─── Emitter ──────────────────────────────────────────────────────────────────
85
+ /**
86
+ * Builds and writes drift-report.json to the run output directory.
87
+ * Only writes if changedExports is non-empty (no drift = no report needed).
88
+ */
89
+ export async function emitDriftReport(input, runDir) {
90
+ const report = await buildDriftReport(input);
91
+ if (input.changedExports.length > 0) {
92
+ await writeFile(join(runDir, "drift-report.json"), JSON.stringify(report, null, 2), "utf8");
93
+ }
94
+ return report;
95
+ }
96
+ // ─── Internal helpers ─────────────────────────────────────────────────────────
97
+ function normalizePath(p) {
98
+ return p.replace(/\\/g, "/");
99
+ }
100
+ //# sourceMappingURL=drift-graph.js.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * objective-lock.ts — SLICE-05
3
+ *
4
+ * Cryptographic objective invariant lock.
5
+ *
6
+ * At attempt 1, the loop objective, verificationPlan, and acceptanceCriteria
7
+ * are hashed together into a SHA-256 lock. Every subsequent attempt re-hashes
8
+ * the live inputs and hard-fails with `objective_drift` if the hash differs.
9
+ *
10
+ * Legitimate scope changes require an explicit `widenObjectiveLock()` call,
11
+ * which produces an audit entry proving who authorized the change and why.
12
+ */
13
+ export interface ObjectiveLockInput {
14
+ objective: string;
15
+ verificationPlan: string[];
16
+ acceptanceCriteria?: string[];
17
+ }
18
+ export interface ObjectiveLock {
19
+ /** SHA-256 hex digest of the canonical lock payload. */
20
+ sha256: string;
21
+ /** ISO timestamp when the lock was created. */
22
+ lockedAt: string;
23
+ }
24
+ export interface ObjectiveLockCheckResult {
25
+ drifted: boolean;
26
+ /** Present only when drifted:true. */
27
+ reason?: string;
28
+ expectedHash?: string;
29
+ actualHash?: string;
30
+ }
31
+ export interface ObjectiveWidenAuditEntry {
32
+ previousHash: string;
33
+ newHash: string;
34
+ authorizedBy: string;
35
+ reason: string;
36
+ widenedAt: string;
37
+ }
38
+ export interface ObjectiveWidenResult {
39
+ newLock: ObjectiveLock;
40
+ auditEntry: ObjectiveWidenAuditEntry;
41
+ }
42
+ /**
43
+ * Creates a new ObjectiveLock for the given inputs.
44
+ * Call once at loop start (attempt 1). Store in the loop record.
45
+ */
46
+ export declare function createObjectiveLock(input: ObjectiveLockInput, now?: string): ObjectiveLock;
47
+ /**
48
+ * Checks whether the live inputs still match the lock created at attempt 1.
49
+ *
50
+ * Returns `{ drifted: false }` if everything is consistent.
51
+ * Returns `{ drifted: true, reason, expectedHash, actualHash }` if the lock
52
+ * has been violated — the caller MUST exit the loop with lifecycleState
53
+ * `objective_drift`.
54
+ */
55
+ export declare function checkObjectiveLock(lock: ObjectiveLock, currentInput: ObjectiveLockInput): ObjectiveLockCheckResult;
56
+ /**
57
+ * Authorizes a legitimate scope change. Returns a new lock covering the
58
+ * new inputs and an immutable audit entry recording who widened it and why.
59
+ *
60
+ * The audit entry MUST be appended to the loop's ledger.jsonl before the
61
+ * run continues with the new lock.
62
+ */
63
+ export declare function widenObjectiveLock(options: {
64
+ currentLock: ObjectiveLock;
65
+ newInput: ObjectiveLockInput;
66
+ authorizedBy: string;
67
+ reason: string;
68
+ now?: string;
69
+ }): ObjectiveWidenResult;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * objective-lock.ts — SLICE-05
3
+ *
4
+ * Cryptographic objective invariant lock.
5
+ *
6
+ * At attempt 1, the loop objective, verificationPlan, and acceptanceCriteria
7
+ * are hashed together into a SHA-256 lock. Every subsequent attempt re-hashes
8
+ * the live inputs and hard-fails with `objective_drift` if the hash differs.
9
+ *
10
+ * Legitimate scope changes require an explicit `widenObjectiveLock()` call,
11
+ * which produces an audit entry proving who authorized the change and why.
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ // ---------------------------------------------------------------------------
15
+ // Public API
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Creates a new ObjectiveLock for the given inputs.
19
+ * Call once at loop start (attempt 1). Store in the loop record.
20
+ */
21
+ export function createObjectiveLock(input, now = new Date().toISOString()) {
22
+ return {
23
+ sha256: computeHash(input),
24
+ lockedAt: now
25
+ };
26
+ }
27
+ /**
28
+ * Checks whether the live inputs still match the lock created at attempt 1.
29
+ *
30
+ * Returns `{ drifted: false }` if everything is consistent.
31
+ * Returns `{ drifted: true, reason, expectedHash, actualHash }` if the lock
32
+ * has been violated — the caller MUST exit the loop with lifecycleState
33
+ * `objective_drift`.
34
+ */
35
+ export function checkObjectiveLock(lock, currentInput) {
36
+ const currentHash = computeHash(currentInput);
37
+ if (currentHash === lock.sha256) {
38
+ return { drifted: false };
39
+ }
40
+ return {
41
+ drifted: true,
42
+ reason: `Objective lock violated: expected hash ${lock.sha256.slice(0, 12)}… ` +
43
+ `but got ${currentHash.slice(0, 12)}… — run aborted with lifecycle state objective_drift`,
44
+ expectedHash: lock.sha256,
45
+ actualHash: currentHash
46
+ };
47
+ }
48
+ /**
49
+ * Authorizes a legitimate scope change. Returns a new lock covering the
50
+ * new inputs and an immutable audit entry recording who widened it and why.
51
+ *
52
+ * The audit entry MUST be appended to the loop's ledger.jsonl before the
53
+ * run continues with the new lock.
54
+ */
55
+ export function widenObjectiveLock(options) {
56
+ const widenedAt = options.now ?? new Date().toISOString();
57
+ const newLock = createObjectiveLock(options.newInput, widenedAt);
58
+ const auditEntry = {
59
+ previousHash: options.currentLock.sha256,
60
+ newHash: newLock.sha256,
61
+ authorizedBy: options.authorizedBy,
62
+ reason: options.reason,
63
+ widenedAt
64
+ };
65
+ return { newLock, auditEntry };
66
+ }
67
+ // ---------------------------------------------------------------------------
68
+ // Internal — canonical hash computation
69
+ // ---------------------------------------------------------------------------
70
+ /**
71
+ * Produces a deterministic SHA-256 hex digest over:
72
+ * - objective (exact text, case-sensitive)
73
+ * - verificationPlan (ordered — step order matters)
74
+ * - acceptanceCriteria (sorted — order-independent)
75
+ *
76
+ * The canonical payload is a stable JSON string to ensure cross-platform
77
+ * determinism regardless of property insertion order.
78
+ */
79
+ function computeHash(input) {
80
+ const sortedCriteria = [...(input.acceptanceCriteria ?? [])].sort();
81
+ const canonical = JSON.stringify({
82
+ objective: input.objective,
83
+ verificationPlan: input.verificationPlan,
84
+ acceptanceCriteria: sortedCriteria
85
+ });
86
+ return createHash("sha256").update(canonical, "utf8").digest("hex");
87
+ }
88
+ //# sourceMappingURL=objective-lock.js.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * scope.ts — SLICE-02
3
+ *
4
+ * Drift-graph–scoped context pruning.
5
+ *
6
+ * Uses the existing DriftGraph to prune model input context to only the files
7
+ * within N hops of the objective's named symbols/paths. Prevents the model
8
+ * from seeing irrelevant files and keeps token budgets tight.
9
+ */
10
+ import type { DriftGraph } from "./drift-graph.js";
11
+ export interface ScopePruningResult {
12
+ /** The pruned (or fallback) file list to pass to the model. */
13
+ files: string[];
14
+ /** Number of files in the original compiledFiles list. */
15
+ filesIn: number;
16
+ /** Number of files returned after pruning. */
17
+ filesOut: number;
18
+ /** filesIn - filesOut */
19
+ prunedCount: number;
20
+ /** true when the BFS intersection was empty and we fell back to the full set. */
21
+ fallback: boolean;
22
+ }
23
+ /**
24
+ * Extracts file-like identifiers from an objective string.
25
+ *
26
+ * Matches (in priority order):
27
+ * 1. Quoted paths — "src/parser.ts"
28
+ * 2. Bare paths ending in .ts / .js / .tsx / .jsx
29
+ * 3. camelCase / PascalCase tokens that look like module/symbol names
30
+ *
31
+ * Note: intentionally uses regex, not AST (that's SLICE-06).
32
+ */
33
+ export declare function extractFilesFromObjective(objective: string): string[];
34
+ /**
35
+ * Prunes `compiledFiles` to only those reachable from the objective's seed
36
+ * nodes within `maxHops` traversal steps in `graph`.
37
+ *
38
+ * Falls back to the full compiledFiles set when the BFS result has no
39
+ * intersection with compiledFiles (e.g. graph uses different path conventions).
40
+ */
41
+ export declare function scopeContextByDriftGraph(options: {
42
+ objective: string;
43
+ graph: DriftGraph;
44
+ compiledFiles: string[];
45
+ maxHops?: number;
46
+ }): ScopePruningResult;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * scope.ts — SLICE-02
3
+ *
4
+ * Drift-graph–scoped context pruning.
5
+ *
6
+ * Uses the existing DriftGraph to prune model input context to only the files
7
+ * within N hops of the objective's named symbols/paths. Prevents the model
8
+ * from seeing irrelevant files and keeps token budgets tight.
9
+ */
10
+ // ─── Public API ───────────────────────────────────────────────────────────────
11
+ /**
12
+ * Extracts file-like identifiers from an objective string.
13
+ *
14
+ * Matches (in priority order):
15
+ * 1. Quoted paths — "src/parser.ts"
16
+ * 2. Bare paths ending in .ts / .js / .tsx / .jsx
17
+ * 3. camelCase / PascalCase tokens that look like module/symbol names
18
+ *
19
+ * Note: intentionally uses regex, not AST (that's SLICE-06).
20
+ */
21
+ export function extractFilesFromObjective(objective) {
22
+ const found = new Set();
23
+ // 1. Quoted file paths — single or double quotes
24
+ const quotedRe = /["']([^"'\n]+(?:\.(?:ts|tsx|js|jsx)|[A-Za-z0-9_/.-]+))["']/g;
25
+ for (const match of objective.matchAll(quotedRe)) {
26
+ if (match[1])
27
+ found.add(match[1]);
28
+ }
29
+ // 2. Bare paths ending in a recognised extension (not already captured in quotes)
30
+ const barePathRe = /(?<![/"'])([^\s"']+\.(?:ts|tsx|js|jsx))(?![/"'])/g;
31
+ for (const match of objective.matchAll(barePathRe)) {
32
+ if (match[1])
33
+ found.add(match[1]);
34
+ }
35
+ // 3. camelCase / PascalCase identifiers (potential module / symbol names)
36
+ // Must start with an uppercase letter or have an internal uppercase letter,
37
+ // and be at least 4 chars so we avoid common short words.
38
+ const camelCaseRe = /\b(?:[A-Z][a-zA-Z0-9]{3,}|[a-z][a-z0-9]*[A-Z][a-zA-Z0-9]{2,})\b/g;
39
+ for (const match of objective.matchAll(camelCaseRe)) {
40
+ found.add(match[0]);
41
+ }
42
+ return [...found];
43
+ }
44
+ /**
45
+ * Prunes `compiledFiles` to only those reachable from the objective's seed
46
+ * nodes within `maxHops` traversal steps in `graph`.
47
+ *
48
+ * Falls back to the full compiledFiles set when the BFS result has no
49
+ * intersection with compiledFiles (e.g. graph uses different path conventions).
50
+ */
51
+ export function scopeContextByDriftGraph(options) {
52
+ const { objective, graph, compiledFiles, maxHops = 2 } = options;
53
+ const filesIn = compiledFiles.length;
54
+ // Extract seed identifiers from objective text
55
+ const seeds = extractFilesFromObjective(objective);
56
+ // BFS from all seed nodes that exist in the graph
57
+ const reachable = new Set();
58
+ const queue = [];
59
+ for (const seed of seeds) {
60
+ if (graph.nodes.has(seed)) {
61
+ queue.push({ node: seed, depth: 0 });
62
+ reachable.add(seed);
63
+ }
64
+ }
65
+ // Process BFS queue
66
+ let head = 0;
67
+ while (head < queue.length) {
68
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
69
+ const item = queue[head++];
70
+ if (item.depth >= maxHops)
71
+ continue;
72
+ const neighbors = graph.edges[item.node] ?? [];
73
+ for (const neighbor of neighbors) {
74
+ if (!reachable.has(neighbor)) {
75
+ reachable.add(neighbor);
76
+ queue.push({ node: neighbor, depth: item.depth + 1 });
77
+ }
78
+ }
79
+ }
80
+ // Intersect BFS result with compiledFiles (preserve original ordering)
81
+ const compiledSet = new Set(compiledFiles);
82
+ const pruned = compiledFiles.filter(f => reachable.has(f));
83
+ // Fallback: if intersection is empty return the full original set
84
+ if (pruned.length === 0) {
85
+ return {
86
+ files: [...compiledFiles],
87
+ filesIn,
88
+ filesOut: filesIn,
89
+ prunedCount: 0,
90
+ fallback: true
91
+ };
92
+ }
93
+ const filesOut = pruned.length;
94
+ return {
95
+ files: pruned,
96
+ filesIn,
97
+ filesOut,
98
+ prunedCount: filesIn - filesOut,
99
+ fallback: false
100
+ };
101
+ }
102
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * signature-lock.ts — SLICE-06
3
+ *
4
+ * AST-level signature lock: extracts named symbols from an objective,
5
+ * snapshots their TypeScript signatures before the first attempt, then
6
+ * rejects any patch that silently changes a signature without authorization.
7
+ *
8
+ * Authorization phrases in the objective (e.g. "add parameter", "rename")
9
+ * allow signature changes for the named symbol.
10
+ */
11
+ export interface SignatureSnapshot {
12
+ symbolName: string;
13
+ filePath: string;
14
+ params: string[];
15
+ returnType: string;
16
+ modifiers: string[];
17
+ kind: "function" | "method" | "class" | "unknown";
18
+ }
19
+ export interface SignatureLockResult {
20
+ blocked: boolean;
21
+ reasonCode?: "silent_signature_drift";
22
+ reason?: string;
23
+ driftedSymbols: Array<{
24
+ symbolName: string;
25
+ before: SignatureSnapshot;
26
+ after: SignatureSnapshot;
27
+ }>;
28
+ }
29
+ export declare function isSignatureChangeAuthorized(objective: string, symbolName: string): boolean;
30
+ /**
31
+ * Extracts likely symbol names from the objective string.
32
+ * Looks for: camelCase, PascalCase, snake_case, and `backtick` quoted names.
33
+ */
34
+ export declare function extractSymbolsFromObjective(objective: string): string[];
35
+ export declare function snapshotsEqual(a: SignatureSnapshot, b: SignatureSnapshot): boolean;
36
+ export declare class SignatureLockStore {
37
+ private snapshots;
38
+ record(snapshot: SignatureSnapshot): void;
39
+ get(symbolName: string): SignatureSnapshot | undefined;
40
+ has(symbolName: string): boolean;
41
+ clear(): void;
42
+ }
43
+ export declare function checkSignatureDrift(objective: string, before: SignatureSnapshot[], after: SignatureSnapshot[]): SignatureLockResult;
44
+ /**
45
+ * Extracts SignatureSnapshots for named symbols from TypeScript source code.
46
+ * Uses ts-morph if available; falls back to a regex-based approximation.
47
+ */
48
+ export declare function extractSignaturesFromSource(sourceCode: string, filePath: string, targetSymbols: string[]): Promise<SignatureSnapshot[]>;