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.
- package/CODE_OF_CONDUCT.md +32 -0
- package/README.md +172 -227
- package/demo/seeded-workspace/README.md +35 -0
- package/demo/seeded-workspace/TASKS.md +29 -0
- package/demo/seeded-workspace/martin.config.yaml +11 -0
- package/demo/seeded-workspace/package.json +8 -0
- package/demo/seeded-workspace/src/invoice-summary.js +11 -0
- package/demo/seeded-workspace/test/invoice-summary.test.js +20 -0
- package/dist/bin/martin-loop.js +0 -0
- package/dist/vendor/adapters/claude-cli.d.ts +19 -4
- package/dist/vendor/adapters/claude-cli.js +55 -24
- package/dist/vendor/adapters/cli-bridge.d.ts +1 -0
- package/dist/vendor/adapters/cli-bridge.js +154 -28
- package/dist/vendor/adapters/counter.d.ts +1 -0
- package/dist/vendor/adapters/counter.js +4 -0
- package/dist/vendor/adapters/git-baseline.d.ts +50 -0
- package/dist/vendor/adapters/git-baseline.js +233 -0
- package/dist/vendor/adapters/index.d.ts +1 -0
- package/dist/vendor/adapters/index.js +1 -0
- package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
- package/dist/vendor/adapters/openrouter-adapter.js +302 -0
- package/dist/vendor/adapters/usage.d.ts +48 -0
- package/dist/vendor/adapters/usage.js +66 -0
- package/dist/vendor/adapters/verifier-only.d.ts +7 -0
- package/dist/vendor/adapters/verifier-only.js +57 -0
- package/dist/vendor/cli/bin/exit.d.ts +12 -0
- package/dist/vendor/cli/bin/exit.js +28 -0
- package/dist/vendor/cli/commands/analyze.d.ts +5 -0
- package/dist/vendor/cli/commands/analyze.js +58 -0
- package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
- package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
- package/dist/vendor/cli/commands/audit.d.ts +8 -0
- package/dist/vendor/cli/commands/audit.js +199 -0
- package/dist/vendor/cli/commands/corpus.d.ts +5 -0
- package/dist/vendor/cli/commands/corpus.js +60 -0
- package/dist/vendor/cli/commands/doctor.d.ts +8 -0
- package/dist/vendor/cli/commands/doctor.js +219 -0
- package/dist/vendor/cli/commands/explain.d.ts +17 -0
- package/dist/vendor/cli/commands/explain.js +176 -0
- package/dist/vendor/cli/commands/export.d.ts +5 -0
- package/dist/vendor/cli/commands/export.js +60 -0
- package/dist/vendor/cli/commands/governance.d.ts +8 -0
- package/dist/vendor/cli/commands/governance.js +95 -0
- package/dist/vendor/cli/commands/improve.d.ts +18 -0
- package/dist/vendor/cli/commands/improve.js +396 -0
- package/dist/vendor/cli/commands/init.d.ts +8 -0
- package/dist/vendor/cli/commands/init.js +281 -0
- package/dist/vendor/cli/commands/migration.d.ts +8 -0
- package/dist/vendor/cli/commands/migration.js +67 -0
- package/dist/vendor/cli/commands/prior.d.ts +23 -0
- package/dist/vendor/cli/commands/prior.js +145 -0
- package/dist/vendor/cli/commands/resume.d.ts +21 -0
- package/dist/vendor/cli/commands/resume.js +73 -0
- package/dist/vendor/cli/commands/verify.d.ts +6 -0
- package/dist/vendor/cli/commands/verify.js +43 -0
- package/dist/vendor/cli/index.d.ts +6 -1
- package/dist/vendor/cli/index.js +124 -7
- package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
- package/dist/vendor/cli/research/public-corpus.js +151 -0
- package/dist/vendor/cli/ui/error-card.d.ts +38 -0
- package/dist/vendor/cli/ui/error-card.js +103 -0
- package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
- package/dist/vendor/cli/ui/mission-brief.js +173 -0
- package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
- package/dist/vendor/cli/ui/summary-card.js +102 -0
- package/dist/vendor/contracts/audit.d.ts +46 -0
- package/dist/vendor/contracts/audit.js +360 -0
- package/dist/vendor/contracts/index.d.ts +3 -1
- package/dist/vendor/contracts/post-phase15.d.ts +240 -0
- package/dist/vendor/contracts/post-phase15.js +166 -0
- package/dist/vendor/core/agent/mandates.d.ts +46 -0
- package/dist/vendor/core/agent/mandates.js +178 -0
- package/dist/vendor/core/agent/receipts.d.ts +38 -0
- package/dist/vendor/core/agent/receipts.js +131 -0
- package/dist/vendor/core/agent/signing.d.ts +17 -0
- package/dist/vendor/core/agent/signing.js +91 -0
- package/dist/vendor/core/attestation/sign.d.ts +25 -0
- package/dist/vendor/core/attestation/sign.js +216 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
- package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
- package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
- package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
- package/dist/vendor/core/autonomy/envelope.js +27 -0
- package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
- package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
- package/dist/vendor/core/autonomy/resume.d.ts +15 -0
- package/dist/vendor/core/autonomy/resume.js +23 -0
- package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
- package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
- package/dist/vendor/core/compiler.d.ts +2 -0
- package/dist/vendor/core/compiler.js +10 -4
- package/dist/vendor/core/context-distillation.d.ts +3 -0
- package/dist/vendor/core/context-distillation.js +44 -0
- package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
- package/dist/vendor/core/context-flow/compile-context.js +111 -0
- package/dist/vendor/core/context-flow/entities.d.ts +2 -0
- package/dist/vendor/core/context-flow/entities.js +44 -0
- package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
- package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
- package/dist/vendor/core/context-flow/index.d.ts +11 -0
- package/dist/vendor/core/context-flow/index.js +24 -0
- package/dist/vendor/core/context-flow/labels.d.ts +3 -0
- package/dist/vendor/core/context-flow/labels.js +17 -0
- package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
- package/dist/vendor/core/context-flow/normalizer.js +69 -0
- package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
- package/dist/vendor/core/context-flow/profiles.js +36 -0
- package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
- package/dist/vendor/core/context-flow/redaction.js +6 -0
- package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
- package/dist/vendor/core/context-flow/sensitivity.js +27 -0
- package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
- package/dist/vendor/core/context-flow/sync-preview.js +22 -0
- package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
- package/dist/vendor/core/context-flow/token-estimator.js +13 -0
- package/dist/vendor/core/context-flow/types.d.ts +91 -0
- package/dist/vendor/core/context-flow/types.js +2 -0
- package/dist/vendor/core/context-integrity.d.ts +26 -0
- package/dist/vendor/core/context-integrity.js +56 -0
- package/dist/vendor/core/context-utility.d.ts +47 -0
- package/dist/vendor/core/context-utility.js +405 -0
- package/dist/vendor/core/cost/pipeline.d.ts +92 -0
- package/dist/vendor/core/cost/pipeline.js +141 -0
- package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
- package/dist/vendor/core/cost/tagged-cost.js +55 -0
- package/dist/vendor/core/cost-governor.d.ts +2 -0
- package/dist/vendor/core/cost-governor.js +50 -0
- package/dist/vendor/core/cve/cve-check.d.ts +80 -0
- package/dist/vendor/core/cve/cve-check.js +172 -0
- package/dist/vendor/core/digital-twin/index.d.ts +27 -0
- package/dist/vendor/core/digital-twin/index.js +90 -0
- package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
- package/dist/vendor/core/drift/drift-graph.js +100 -0
- package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
- package/dist/vendor/core/drift/objective-lock.js +88 -0
- package/dist/vendor/core/drift/scope.d.ts +46 -0
- package/dist/vendor/core/drift/scope.js +102 -0
- package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
- package/dist/vendor/core/drift/signature-lock.js +202 -0
- package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
- package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
- package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
- package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
- package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
- package/dist/vendor/core/evidence/claim-audit.js +89 -0
- package/dist/vendor/core/exit-intelligence.d.ts +2 -0
- package/dist/vendor/core/exit-intelligence.js +58 -0
- package/dist/vendor/core/explain/formatter.d.ts +42 -0
- package/dist/vendor/core/explain/formatter.js +171 -0
- package/dist/vendor/core/explain/timeline.d.ts +29 -0
- package/dist/vendor/core/explain/timeline.js +213 -0
- package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
- package/dist/vendor/core/failure-taxonomy.js +76 -0
- package/dist/vendor/core/gateway/index.d.ts +10 -0
- package/dist/vendor/core/gateway/index.js +12 -0
- package/dist/vendor/core/gateway/registry.d.ts +40 -0
- package/dist/vendor/core/gateway/registry.js +97 -0
- package/dist/vendor/core/gateway/transport.d.ts +31 -0
- package/dist/vendor/core/gateway/transport.js +82 -0
- package/dist/vendor/core/gateway/vault.d.ts +19 -0
- package/dist/vendor/core/gateway/vault.js +29 -0
- package/dist/vendor/core/graph/adapters.d.ts +43 -0
- package/dist/vendor/core/graph/adapters.js +91 -0
- package/dist/vendor/core/graph/hotspots.d.ts +22 -0
- package/dist/vendor/core/graph/hotspots.js +30 -0
- package/dist/vendor/core/graph/index.d.ts +1 -0
- package/dist/vendor/core/graph/index.js +2 -0
- package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
- package/dist/vendor/core/honey/honey-tokens.js +44 -0
- package/dist/vendor/core/index.d.ts +7 -4
- package/dist/vendor/core/index.js +222 -64
- package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
- package/dist/vendor/core/learning/bayesian-update.js +60 -0
- package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
- package/dist/vendor/core/learning/prior-sets.js +111 -0
- package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
- package/dist/vendor/core/learning/promotion-gate.js +23 -0
- package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
- package/dist/vendor/core/leash/blast-radius.js +156 -0
- package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
- package/dist/vendor/core/leash/policy-leash.js +117 -0
- package/dist/vendor/core/memo/memo.d.ts +63 -0
- package/dist/vendor/core/memo/memo.js +97 -0
- package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
- package/dist/vendor/core/memory/learning-pipeline.js +391 -0
- package/dist/vendor/core/memory/palace.d.ts +84 -0
- package/dist/vendor/core/memory/palace.js +379 -0
- package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
- package/dist/vendor/core/merge/ast-merge.js +350 -0
- package/dist/vendor/core/merge/text-merge.d.ts +12 -0
- package/dist/vendor/core/merge/text-merge.js +182 -0
- package/dist/vendor/core/otel/tracer.d.ts +45 -0
- package/dist/vendor/core/otel/tracer.js +116 -0
- package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
- package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
- package/dist/vendor/core/parallel/scorer.d.ts +24 -0
- package/dist/vendor/core/parallel/scorer.js +65 -0
- package/dist/vendor/core/pattern-detection.d.ts +64 -0
- package/dist/vendor/core/pattern-detection.js +108 -0
- package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
- package/dist/vendor/core/persistence/checkpoint.js +156 -0
- package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
- package/dist/vendor/core/persistence/cleanup.js +131 -0
- package/dist/vendor/core/persistence/index.d.ts +2 -0
- package/dist/vendor/core/persistence/index.js +1 -0
- package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
- package/dist/vendor/core/persistence/runs-reader.js +84 -0
- package/dist/vendor/core/persistence/store.d.ts +6 -1
- package/dist/vendor/core/persistence/store.js +5 -0
- package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
- package/dist/vendor/core/policy/file-touch-quota.js +105 -0
- package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
- package/dist/vendor/core/policy/policy-loader.js +170 -0
- package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
- package/dist/vendor/core/policy/policy-schema.js +78 -0
- package/dist/vendor/core/policy.d.ts +6 -0
- package/dist/vendor/core/probe/probe.d.ts +49 -0
- package/dist/vendor/core/probe/probe.js +115 -0
- package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
- package/dist/vendor/core/proof/patch-proof.js +84 -0
- package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
- package/dist/vendor/core/proof/semantic-probe.js +82 -0
- package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
- package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
- package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
- package/dist/vendor/core/red-blue/red-phase.js +141 -0
- package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
- package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
- package/dist/vendor/core/replay/replay.d.ts +85 -0
- package/dist/vendor/core/replay/replay.js +109 -0
- package/dist/vendor/core/router/engine.d.ts +54 -0
- package/dist/vendor/core/router/engine.js +131 -0
- package/dist/vendor/core/router/index.d.ts +1 -0
- package/dist/vendor/core/router/index.js +2 -0
- package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
- package/dist/vendor/core/router/trust-calibration.js +127 -0
- package/dist/vendor/core/run-martin.d.ts +2 -0
- package/dist/vendor/core/run-martin.js +287 -0
- package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
- package/dist/vendor/core/security/cve-scanner.js +178 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
- package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
- package/dist/vendor/core/sentinel/progress-guard.js +46 -0
- package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
- package/dist/vendor/core/siem/siem-emitter.js +157 -0
- package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
- package/dist/vendor/core/strategy/attempt-brief.js +89 -0
- package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
- package/dist/vendor/core/summarize/diff-summary.js +204 -0
- package/dist/vendor/core/surface-signals.d.ts +21 -0
- package/dist/vendor/core/surface-signals.js +139 -0
- package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
- package/dist/vendor/core/truth/truth-wall.js +69 -0
- package/dist/vendor/core/truth-spine.d.ts +26 -0
- package/dist/vendor/core/truth-spine.js +62 -0
- package/dist/vendor/core/types.d.ts +115 -0
- package/dist/vendor/core/types.js +2 -0
- package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
- package/dist/vendor/core/verification/tiered-verify.js +29 -0
- package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
- package/dist/vendor/core/verifier-pyramid.js +111 -0
- package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
- package/dist/vendor/core/workflow-artifacts.js +668 -0
- package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
- package/dist/vendor/core/wrap/supervised-run.js +178 -0
- package/docs/assets/cli-animated.svg +139 -0
- package/docs/assets/cli-static.svg +34 -0
- package/docs/assets/github-hero-v2.svg +23 -0
- package/docs/assets/martin-raplph.png.jpg +0 -0
- package/docs/assets/martinloop-logo.png +0 -0
- package/docs/assets/nvidia-inception-program-light.png +0 -0
- package/docs/assets/nvidia-inception-program.png +0 -0
- package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
- package/docs/assets/side-by-side.svg +134 -0
- package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -0
- package/docs/oss/EXAMPLES.md +9 -1
- package/docs/oss/OSS-BOUNDARY-REPORT.json +109 -113
- package/docs/oss/OSS-BOUNDARY-REPORT.md +48 -48
- package/docs/oss/QUICKSTART.md +39 -4
- package/docs/oss/RALPH-LOOP-SAFETY.md +113 -0
- package/docs/oss/README.md +7 -4
- package/docs/oss/RELEASE-SURFACE-REPORT.json +46 -45
- package/docs/oss/RELEASE-SURFACE-REPORT.md +36 -35
- 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>;
|