martin-loop 0.1.4 → 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 (286) hide show
  1. package/CODE_OF_CONDUCT.md +32 -0
  2. package/README.md +172 -227
  3. package/demo/seeded-workspace/README.md +35 -0
  4. package/demo/seeded-workspace/TASKS.md +29 -0
  5. package/demo/seeded-workspace/martin.config.yaml +11 -0
  6. package/demo/seeded-workspace/package.json +8 -0
  7. package/demo/seeded-workspace/src/invoice-summary.js +11 -0
  8. package/demo/seeded-workspace/test/invoice-summary.test.js +20 -0
  9. package/dist/bin/martin-loop.js +0 -0
  10. package/dist/vendor/adapters/claude-cli.d.ts +19 -4
  11. package/dist/vendor/adapters/claude-cli.js +55 -24
  12. package/dist/vendor/adapters/cli-bridge.d.ts +1 -0
  13. package/dist/vendor/adapters/cli-bridge.js +154 -28
  14. package/dist/vendor/adapters/counter.d.ts +1 -0
  15. package/dist/vendor/adapters/counter.js +4 -0
  16. package/dist/vendor/adapters/git-baseline.d.ts +50 -0
  17. package/dist/vendor/adapters/git-baseline.js +233 -0
  18. package/dist/vendor/adapters/index.d.ts +1 -0
  19. package/dist/vendor/adapters/index.js +1 -0
  20. package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
  21. package/dist/vendor/adapters/openrouter-adapter.js +302 -0
  22. package/dist/vendor/adapters/usage.d.ts +48 -0
  23. package/dist/vendor/adapters/usage.js +66 -0
  24. package/dist/vendor/adapters/verifier-only.d.ts +7 -0
  25. package/dist/vendor/adapters/verifier-only.js +57 -0
  26. package/dist/vendor/cli/bin/exit.d.ts +12 -0
  27. package/dist/vendor/cli/bin/exit.js +28 -0
  28. package/dist/vendor/cli/commands/analyze.d.ts +5 -0
  29. package/dist/vendor/cli/commands/analyze.js +58 -0
  30. package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
  31. package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
  32. package/dist/vendor/cli/commands/audit.d.ts +8 -0
  33. package/dist/vendor/cli/commands/audit.js +199 -0
  34. package/dist/vendor/cli/commands/corpus.d.ts +5 -0
  35. package/dist/vendor/cli/commands/corpus.js +60 -0
  36. package/dist/vendor/cli/commands/doctor.d.ts +8 -0
  37. package/dist/vendor/cli/commands/doctor.js +219 -0
  38. package/dist/vendor/cli/commands/explain.d.ts +17 -0
  39. package/dist/vendor/cli/commands/explain.js +176 -0
  40. package/dist/vendor/cli/commands/export.d.ts +5 -0
  41. package/dist/vendor/cli/commands/export.js +60 -0
  42. package/dist/vendor/cli/commands/governance.d.ts +8 -0
  43. package/dist/vendor/cli/commands/governance.js +95 -0
  44. package/dist/vendor/cli/commands/improve.d.ts +18 -0
  45. package/dist/vendor/cli/commands/improve.js +396 -0
  46. package/dist/vendor/cli/commands/init.d.ts +8 -0
  47. package/dist/vendor/cli/commands/init.js +281 -0
  48. package/dist/vendor/cli/commands/migration.d.ts +8 -0
  49. package/dist/vendor/cli/commands/migration.js +67 -0
  50. package/dist/vendor/cli/commands/prior.d.ts +23 -0
  51. package/dist/vendor/cli/commands/prior.js +145 -0
  52. package/dist/vendor/cli/commands/resume.d.ts +21 -0
  53. package/dist/vendor/cli/commands/resume.js +73 -0
  54. package/dist/vendor/cli/commands/verify.d.ts +6 -0
  55. package/dist/vendor/cli/commands/verify.js +43 -0
  56. package/dist/vendor/cli/index.d.ts +6 -1
  57. package/dist/vendor/cli/index.js +124 -7
  58. package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
  59. package/dist/vendor/cli/research/public-corpus.js +151 -0
  60. package/dist/vendor/cli/ui/error-card.d.ts +38 -0
  61. package/dist/vendor/cli/ui/error-card.js +103 -0
  62. package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
  63. package/dist/vendor/cli/ui/mission-brief.js +173 -0
  64. package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
  65. package/dist/vendor/cli/ui/summary-card.js +102 -0
  66. package/dist/vendor/contracts/audit.d.ts +46 -0
  67. package/dist/vendor/contracts/audit.js +360 -0
  68. package/dist/vendor/contracts/index.d.ts +3 -1
  69. package/dist/vendor/contracts/post-phase15.d.ts +240 -0
  70. package/dist/vendor/contracts/post-phase15.js +166 -0
  71. package/dist/vendor/core/agent/mandates.d.ts +46 -0
  72. package/dist/vendor/core/agent/mandates.js +178 -0
  73. package/dist/vendor/core/agent/receipts.d.ts +38 -0
  74. package/dist/vendor/core/agent/receipts.js +131 -0
  75. package/dist/vendor/core/agent/signing.d.ts +17 -0
  76. package/dist/vendor/core/agent/signing.js +91 -0
  77. package/dist/vendor/core/attestation/sign.d.ts +25 -0
  78. package/dist/vendor/core/attestation/sign.js +216 -0
  79. package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
  80. package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
  81. package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
  82. package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
  83. package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
  84. package/dist/vendor/core/autonomy/envelope.js +27 -0
  85. package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
  86. package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
  87. package/dist/vendor/core/autonomy/resume.d.ts +15 -0
  88. package/dist/vendor/core/autonomy/resume.js +23 -0
  89. package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
  90. package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
  91. package/dist/vendor/core/compiler.d.ts +2 -0
  92. package/dist/vendor/core/compiler.js +10 -4
  93. package/dist/vendor/core/context-distillation.d.ts +3 -0
  94. package/dist/vendor/core/context-distillation.js +44 -0
  95. package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
  96. package/dist/vendor/core/context-flow/compile-context.js +111 -0
  97. package/dist/vendor/core/context-flow/entities.d.ts +2 -0
  98. package/dist/vendor/core/context-flow/entities.js +44 -0
  99. package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
  100. package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
  101. package/dist/vendor/core/context-flow/index.d.ts +11 -0
  102. package/dist/vendor/core/context-flow/index.js +24 -0
  103. package/dist/vendor/core/context-flow/labels.d.ts +3 -0
  104. package/dist/vendor/core/context-flow/labels.js +17 -0
  105. package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
  106. package/dist/vendor/core/context-flow/normalizer.js +69 -0
  107. package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
  108. package/dist/vendor/core/context-flow/profiles.js +36 -0
  109. package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
  110. package/dist/vendor/core/context-flow/redaction.js +6 -0
  111. package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
  112. package/dist/vendor/core/context-flow/sensitivity.js +27 -0
  113. package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
  114. package/dist/vendor/core/context-flow/sync-preview.js +22 -0
  115. package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
  116. package/dist/vendor/core/context-flow/token-estimator.js +13 -0
  117. package/dist/vendor/core/context-flow/types.d.ts +91 -0
  118. package/dist/vendor/core/context-flow/types.js +2 -0
  119. package/dist/vendor/core/context-integrity.d.ts +26 -0
  120. package/dist/vendor/core/context-integrity.js +56 -0
  121. package/dist/vendor/core/context-utility.d.ts +47 -0
  122. package/dist/vendor/core/context-utility.js +405 -0
  123. package/dist/vendor/core/cost/pipeline.d.ts +92 -0
  124. package/dist/vendor/core/cost/pipeline.js +141 -0
  125. package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
  126. package/dist/vendor/core/cost/tagged-cost.js +55 -0
  127. package/dist/vendor/core/cost-governor.d.ts +2 -0
  128. package/dist/vendor/core/cost-governor.js +50 -0
  129. package/dist/vendor/core/cve/cve-check.d.ts +80 -0
  130. package/dist/vendor/core/cve/cve-check.js +172 -0
  131. package/dist/vendor/core/digital-twin/index.d.ts +27 -0
  132. package/dist/vendor/core/digital-twin/index.js +90 -0
  133. package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
  134. package/dist/vendor/core/drift/drift-graph.js +100 -0
  135. package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
  136. package/dist/vendor/core/drift/objective-lock.js +88 -0
  137. package/dist/vendor/core/drift/scope.d.ts +46 -0
  138. package/dist/vendor/core/drift/scope.js +102 -0
  139. package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
  140. package/dist/vendor/core/drift/signature-lock.js +202 -0
  141. package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
  142. package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
  143. package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
  144. package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
  145. package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
  146. package/dist/vendor/core/evidence/claim-audit.js +89 -0
  147. package/dist/vendor/core/exit-intelligence.d.ts +2 -0
  148. package/dist/vendor/core/exit-intelligence.js +58 -0
  149. package/dist/vendor/core/explain/formatter.d.ts +42 -0
  150. package/dist/vendor/core/explain/formatter.js +171 -0
  151. package/dist/vendor/core/explain/timeline.d.ts +29 -0
  152. package/dist/vendor/core/explain/timeline.js +213 -0
  153. package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
  154. package/dist/vendor/core/failure-taxonomy.js +76 -0
  155. package/dist/vendor/core/gateway/index.d.ts +10 -0
  156. package/dist/vendor/core/gateway/index.js +12 -0
  157. package/dist/vendor/core/gateway/registry.d.ts +40 -0
  158. package/dist/vendor/core/gateway/registry.js +97 -0
  159. package/dist/vendor/core/gateway/transport.d.ts +31 -0
  160. package/dist/vendor/core/gateway/transport.js +82 -0
  161. package/dist/vendor/core/gateway/vault.d.ts +19 -0
  162. package/dist/vendor/core/gateway/vault.js +29 -0
  163. package/dist/vendor/core/graph/adapters.d.ts +43 -0
  164. package/dist/vendor/core/graph/adapters.js +91 -0
  165. package/dist/vendor/core/graph/hotspots.d.ts +22 -0
  166. package/dist/vendor/core/graph/hotspots.js +30 -0
  167. package/dist/vendor/core/graph/index.d.ts +1 -0
  168. package/dist/vendor/core/graph/index.js +2 -0
  169. package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
  170. package/dist/vendor/core/honey/honey-tokens.js +44 -0
  171. package/dist/vendor/core/index.d.ts +7 -4
  172. package/dist/vendor/core/index.js +222 -64
  173. package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
  174. package/dist/vendor/core/learning/bayesian-update.js +60 -0
  175. package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
  176. package/dist/vendor/core/learning/prior-sets.js +111 -0
  177. package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
  178. package/dist/vendor/core/learning/promotion-gate.js +23 -0
  179. package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
  180. package/dist/vendor/core/leash/blast-radius.js +156 -0
  181. package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
  182. package/dist/vendor/core/leash/policy-leash.js +117 -0
  183. package/dist/vendor/core/memo/memo.d.ts +63 -0
  184. package/dist/vendor/core/memo/memo.js +97 -0
  185. package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
  186. package/dist/vendor/core/memory/learning-pipeline.js +391 -0
  187. package/dist/vendor/core/memory/palace.d.ts +84 -0
  188. package/dist/vendor/core/memory/palace.js +379 -0
  189. package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
  190. package/dist/vendor/core/merge/ast-merge.js +350 -0
  191. package/dist/vendor/core/merge/text-merge.d.ts +12 -0
  192. package/dist/vendor/core/merge/text-merge.js +182 -0
  193. package/dist/vendor/core/otel/tracer.d.ts +45 -0
  194. package/dist/vendor/core/otel/tracer.js +116 -0
  195. package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
  196. package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
  197. package/dist/vendor/core/parallel/scorer.d.ts +24 -0
  198. package/dist/vendor/core/parallel/scorer.js +65 -0
  199. package/dist/vendor/core/pattern-detection.d.ts +64 -0
  200. package/dist/vendor/core/pattern-detection.js +108 -0
  201. package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
  202. package/dist/vendor/core/persistence/checkpoint.js +156 -0
  203. package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
  204. package/dist/vendor/core/persistence/cleanup.js +131 -0
  205. package/dist/vendor/core/persistence/index.d.ts +2 -0
  206. package/dist/vendor/core/persistence/index.js +1 -0
  207. package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
  208. package/dist/vendor/core/persistence/runs-reader.js +84 -0
  209. package/dist/vendor/core/persistence/store.d.ts +6 -1
  210. package/dist/vendor/core/persistence/store.js +5 -0
  211. package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
  212. package/dist/vendor/core/policy/file-touch-quota.js +105 -0
  213. package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
  214. package/dist/vendor/core/policy/policy-loader.js +170 -0
  215. package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
  216. package/dist/vendor/core/policy/policy-schema.js +78 -0
  217. package/dist/vendor/core/policy.d.ts +6 -0
  218. package/dist/vendor/core/probe/probe.d.ts +49 -0
  219. package/dist/vendor/core/probe/probe.js +115 -0
  220. package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
  221. package/dist/vendor/core/proof/patch-proof.js +84 -0
  222. package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
  223. package/dist/vendor/core/proof/semantic-probe.js +82 -0
  224. package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
  225. package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
  226. package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
  227. package/dist/vendor/core/red-blue/red-phase.js +141 -0
  228. package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
  229. package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
  230. package/dist/vendor/core/replay/replay.d.ts +85 -0
  231. package/dist/vendor/core/replay/replay.js +109 -0
  232. package/dist/vendor/core/router/engine.d.ts +54 -0
  233. package/dist/vendor/core/router/engine.js +131 -0
  234. package/dist/vendor/core/router/index.d.ts +1 -0
  235. package/dist/vendor/core/router/index.js +2 -0
  236. package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
  237. package/dist/vendor/core/router/trust-calibration.js +127 -0
  238. package/dist/vendor/core/run-martin.d.ts +2 -0
  239. package/dist/vendor/core/run-martin.js +287 -0
  240. package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
  241. package/dist/vendor/core/security/cve-scanner.js +178 -0
  242. package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
  243. package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
  244. package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
  245. package/dist/vendor/core/sentinel/progress-guard.js +46 -0
  246. package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
  247. package/dist/vendor/core/siem/siem-emitter.js +157 -0
  248. package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
  249. package/dist/vendor/core/strategy/attempt-brief.js +89 -0
  250. package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
  251. package/dist/vendor/core/summarize/diff-summary.js +204 -0
  252. package/dist/vendor/core/surface-signals.d.ts +21 -0
  253. package/dist/vendor/core/surface-signals.js +139 -0
  254. package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
  255. package/dist/vendor/core/truth/truth-wall.js +69 -0
  256. package/dist/vendor/core/truth-spine.d.ts +26 -0
  257. package/dist/vendor/core/truth-spine.js +62 -0
  258. package/dist/vendor/core/types.d.ts +115 -0
  259. package/dist/vendor/core/types.js +2 -0
  260. package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
  261. package/dist/vendor/core/verification/tiered-verify.js +29 -0
  262. package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
  263. package/dist/vendor/core/verifier-pyramid.js +111 -0
  264. package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
  265. package/dist/vendor/core/workflow-artifacts.js +668 -0
  266. package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
  267. package/dist/vendor/core/wrap/supervised-run.js +178 -0
  268. package/docs/assets/cli-animated.svg +139 -0
  269. package/docs/assets/cli-static.svg +34 -0
  270. package/docs/assets/github-hero-v2.svg +23 -0
  271. package/docs/assets/martin-raplph.png.jpg +0 -0
  272. package/docs/assets/martinloop-logo.png +0 -0
  273. package/docs/assets/nvidia-inception-program-light.png +0 -0
  274. package/docs/assets/nvidia-inception-program.png +0 -0
  275. package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
  276. package/docs/assets/side-by-side.svg +134 -0
  277. package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -0
  278. package/docs/oss/EXAMPLES.md +9 -1
  279. package/docs/oss/OSS-BOUNDARY-REPORT.json +109 -113
  280. package/docs/oss/OSS-BOUNDARY-REPORT.md +48 -48
  281. package/docs/oss/QUICKSTART.md +39 -4
  282. package/docs/oss/RALPH-LOOP-SAFETY.md +113 -0
  283. package/docs/oss/README.md +7 -4
  284. package/docs/oss/RELEASE-SURFACE-REPORT.json +46 -45
  285. package/docs/oss/RELEASE-SURFACE-REPORT.md +36 -35
  286. package/package.json +129 -49
@@ -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[]>;
@@ -0,0 +1,202 @@
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
+ // ---------------------------------------------------------------------------
12
+ // Authorization phrases — objective contains these → allow signature change
13
+ // ---------------------------------------------------------------------------
14
+ const AUTH_PHRASES = [
15
+ "add parameter", "add param", "remove parameter", "remove param",
16
+ "change signature", "rename", "refactor signature", "update signature",
17
+ "modify signature", "new signature", "change return type", "add argument"
18
+ ];
19
+ export function isSignatureChangeAuthorized(objective, symbolName) {
20
+ const lower = objective.toLowerCase();
21
+ const hasAuthPhrase = AUTH_PHRASES.some(p => lower.includes(p)) ||
22
+ /\badd\b[\s\S]{0,80}\b(?:parameter|param|argument)\b/u.test(lower) ||
23
+ /\bremove\b[\s\S]{0,80}\b(?:parameter|param|argument)\b/u.test(lower);
24
+ if (!hasAuthPhrase)
25
+ return false;
26
+ // If there's an auth phrase, it covers all symbols OR must mention the symbol
27
+ // (generous: if any auth phrase is present in objective, allow all drift)
28
+ return true;
29
+ }
30
+ // ---------------------------------------------------------------------------
31
+ // Symbol extraction from objective text
32
+ // ---------------------------------------------------------------------------
33
+ /**
34
+ * Extracts likely symbol names from the objective string.
35
+ * Looks for: camelCase, PascalCase, snake_case, and `backtick` quoted names.
36
+ */
37
+ export function extractSymbolsFromObjective(objective) {
38
+ const symbols = [];
39
+ // Backtick-quoted names are highest confidence
40
+ const backtickMatches = objective.match(/`([a-zA-Z_$][\w$]*)`/g) ?? [];
41
+ symbols.push(...backtickMatches.map(m => m.slice(1, -1)));
42
+ // camelCase / PascalCase words (4+ chars to avoid noise)
43
+ const wordMatches = objective.match(/\b([a-zA-Z_$][a-zA-Z0-9_$]{3,})\b/g) ?? [];
44
+ const NOISE_WORDS = new Set([
45
+ "the", "this", "that", "with", "from", "into", "when", "then",
46
+ "should", "must", "will", "have", "been", "also", "only", "just",
47
+ "make", "sure", "each", "all", "any", "add", "remove", "change",
48
+ "function", "method", "class", "return", "export", "import",
49
+ "const", "variable", "parameter", "argument", "type", "interface"
50
+ ]);
51
+ for (const word of wordMatches) {
52
+ if (!NOISE_WORDS.has(word.toLowerCase()) && !symbols.includes(word)) {
53
+ symbols.push(word);
54
+ }
55
+ }
56
+ return [...new Set(symbols)];
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // Snapshot comparison
60
+ // ---------------------------------------------------------------------------
61
+ export function snapshotsEqual(a, b) {
62
+ if (a.kind !== b.kind)
63
+ return false;
64
+ if (a.returnType !== b.returnType)
65
+ return false;
66
+ if (a.params.length !== b.params.length)
67
+ return false;
68
+ for (let i = 0; i < a.params.length; i++) {
69
+ if (a.params[i] !== b.params[i])
70
+ return false;
71
+ }
72
+ return true;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // In-memory snapshot store (keyed by symbolName)
76
+ // ---------------------------------------------------------------------------
77
+ export class SignatureLockStore {
78
+ snapshots = new Map();
79
+ record(snapshot) {
80
+ this.snapshots.set(snapshot.symbolName, snapshot);
81
+ }
82
+ get(symbolName) {
83
+ return this.snapshots.get(symbolName);
84
+ }
85
+ has(symbolName) {
86
+ return this.snapshots.has(symbolName);
87
+ }
88
+ clear() {
89
+ this.snapshots.clear();
90
+ }
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // Signature check — called after each patch
94
+ // ---------------------------------------------------------------------------
95
+ export function checkSignatureDrift(objective, before, after) {
96
+ const drifted = [];
97
+ const afterByName = new Map(after.map(s => [s.symbolName, s]));
98
+ for (const beforeSnap of before) {
99
+ const afterSnap = afterByName.get(beforeSnap.symbolName);
100
+ if (!afterSnap)
101
+ continue; // symbol removed — handled separately
102
+ if (!snapshotsEqual(beforeSnap, afterSnap)) {
103
+ if (!isSignatureChangeAuthorized(objective, beforeSnap.symbolName)) {
104
+ drifted.push({ symbolName: beforeSnap.symbolName, before: beforeSnap, after: afterSnap });
105
+ }
106
+ }
107
+ }
108
+ if (drifted.length === 0) {
109
+ return { blocked: false, driftedSymbols: [] };
110
+ }
111
+ const names = drifted.map(d => d.symbolName).join(", ");
112
+ return {
113
+ blocked: true,
114
+ reasonCode: "silent_signature_drift",
115
+ reason: `Patch silently changed the signature of: ${names}. ` +
116
+ `If this is intentional, include "change signature", "add parameter", ` +
117
+ `or "rename" in the objective.`,
118
+ driftedSymbols: drifted
119
+ };
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // ts-morph based snapshot extractor
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Extracts SignatureSnapshots for named symbols from TypeScript source code.
126
+ * Uses ts-morph if available; falls back to a regex-based approximation.
127
+ */
128
+ export async function extractSignaturesFromSource(sourceCode, filePath, targetSymbols) {
129
+ // Try ts-morph
130
+ try {
131
+ const { Project } = await import("ts-morph");
132
+ const project = new Project({ useInMemoryFileSystem: true, compilerOptions: { allowJs: true } });
133
+ const src = project.createSourceFile(filePath, sourceCode);
134
+ const snapshots = [];
135
+ const targetSet = new Set(targetSymbols);
136
+ for (const fn of src.getFunctions()) {
137
+ const name = fn.getName();
138
+ if (!name || (targetSet.size > 0 && !targetSet.has(name)))
139
+ continue;
140
+ snapshots.push({
141
+ symbolName: name,
142
+ filePath,
143
+ params: fn.getParameters().map(p => `${p.getName()}:${p.getType().getText()}`),
144
+ returnType: fn.getReturnType().getText(),
145
+ modifiers: fn.getModifiers().map(m => m.getText()),
146
+ kind: "function"
147
+ });
148
+ }
149
+ for (const cls of src.getClasses()) {
150
+ const className = cls.getName();
151
+ if (!className)
152
+ continue;
153
+ if (targetSet.size === 0 || targetSet.has(className)) {
154
+ snapshots.push({
155
+ symbolName: className,
156
+ filePath,
157
+ params: [],
158
+ returnType: className,
159
+ modifiers: cls.getModifiers().map(m => m.getText()),
160
+ kind: "class"
161
+ });
162
+ }
163
+ for (const method of cls.getMethods()) {
164
+ const mName = method.getName();
165
+ const qualified = `${className}.${mName}`;
166
+ if (targetSet.size > 0 && !targetSet.has(mName) && !targetSet.has(qualified))
167
+ continue;
168
+ snapshots.push({
169
+ symbolName: mName,
170
+ filePath,
171
+ params: method.getParameters().map(p => `${p.getName()}:${p.getType().getText()}`),
172
+ returnType: method.getReturnType().getText(),
173
+ modifiers: method.getModifiers().map(m => m.getText()),
174
+ kind: "method"
175
+ });
176
+ }
177
+ }
178
+ return snapshots;
179
+ }
180
+ catch {
181
+ // ts-morph not available — regex fallback
182
+ return extractSignaturesRegex(sourceCode, filePath, targetSymbols);
183
+ }
184
+ }
185
+ function extractSignaturesRegex(src, filePath, targetSymbols) {
186
+ const snapshots = [];
187
+ const targetSet = new Set(targetSymbols);
188
+ // Match: export function name(params): returnType
189
+ const fnRe = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)\s*(?::\s*([\w<>[\], |]+))?/g;
190
+ let m;
191
+ while ((m = fnRe.exec(src)) !== null) {
192
+ const name = m[1];
193
+ if (!name)
194
+ continue;
195
+ if (targetSet.size > 0 && !targetSet.has(name))
196
+ continue;
197
+ const params = (m[2] ?? "").split(",").map(p => p.trim()).filter(Boolean);
198
+ snapshots.push({ symbolName: name, filePath, params, returnType: m[3]?.trim() ?? "unknown", modifiers: [], kind: "function" });
199
+ }
200
+ return snapshots;
201
+ }
202
+ //# sourceMappingURL=signature-lock.js.map
@@ -0,0 +1,21 @@
1
+ export interface ProofGateArtifact {
2
+ artifactId: string;
3
+ expectedSha256: string;
4
+ actualSha256: string;
5
+ }
6
+ export interface ProofBoundClaim {
7
+ claimId: string;
8
+ artifactIds: string[];
9
+ }
10
+ export interface StaleProofGateInput {
11
+ artifacts: ProofGateArtifact[];
12
+ claims: ProofBoundClaim[];
13
+ }
14
+ export interface StaleProofGateReport {
15
+ gateStatus: "pass" | "fail";
16
+ staleArtifactIds: string[];
17
+ demotedClaimIds: string[];
18
+ allowedClaimWording: string;
19
+ nonClaims: string[];
20
+ }
21
+ export declare function evaluateStaleProofGate(input: StaleProofGateInput): StaleProofGateReport;
@@ -0,0 +1,19 @@
1
+ export function evaluateStaleProofGate(input) {
2
+ const staleArtifactIds = input.artifacts
3
+ .filter((artifact) => artifact.expectedSha256 !== artifact.actualSha256)
4
+ .map((artifact) => artifact.artifactId);
5
+ const staleArtifactSet = new Set(staleArtifactIds);
6
+ const demotedClaimIds = input.claims
7
+ .filter((claim) => claim.artifactIds.some((artifactId) => staleArtifactSet.has(artifactId)))
8
+ .map((claim) => claim.claimId);
9
+ return {
10
+ gateStatus: staleArtifactIds.length === 0 && demotedClaimIds.length === 0 ? "pass" : "fail",
11
+ staleArtifactIds,
12
+ demotedClaimIds,
13
+ allowedClaimWording: staleArtifactIds.length === 0
14
+ ? "Drift-detected and corrected for declared hash-bound proof and runtime evidence surfaces."
15
+ : "Claim demoted because one or more hash-bound proof or runtime artifacts are stale.",
16
+ nonClaims: ["impossible to drift", "universal drift prevention"]
17
+ };
18
+ }
19
+ //# sourceMappingURL=stale-proof-gate.js.map
@@ -0,0 +1,24 @@
1
+ export interface KnownBadWorldCategory {
2
+ category: string;
3
+ shouldBlock: boolean;
4
+ blocked: boolean;
5
+ trapFired: string;
6
+ testId: string;
7
+ }
8
+ export interface KnownBadWorldResults {
9
+ evalVersion: "h3.v1";
10
+ runAt: string;
11
+ categories: KnownBadWorldCategory[];
12
+ allBlocked: boolean;
13
+ falsePositives: number;
14
+ totalTests: number;
15
+ }
16
+ export interface RunKnownBadWorldOptions {
17
+ secret: string;
18
+ }
19
+ /**
20
+ * Runs all 16 known-bad-world scenarios (8 bad + 8 clean) and returns results.
21
+ * allBlocked: true only when all shouldBlock=true tests were caught.
22
+ * falsePositives: count of shouldBlock=false tests that were incorrectly caught.
23
+ */
24
+ export declare function runKnownBadWorldEval(options: RunKnownBadWorldOptions): Promise<KnownBadWorldResults>;