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.
- package/CODE_OF_CONDUCT.md +32 -0
- package/LICENSE +21 -21
- package/README.md +307 -398
- package/demo/seeded-workspace/README.md +35 -35
- package/demo/seeded-workspace/TASKS.md +29 -29
- package/demo/seeded-workspace/martin.config.yaml +11 -11
- package/demo/seeded-workspace/package.json +8 -8
- package/demo/seeded-workspace/src/invoice-summary.js +11 -11
- package/demo/seeded-workspace/test/invoice-summary.test.js +20 -20
- package/dist/bin/martin-loop.js +0 -0
- 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/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/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/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/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/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-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 +2 -2
- package/dist/vendor/core/index.js +38 -12
- 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/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 -142
- package/docs/oss/EXAMPLES.md +134 -134
- package/docs/oss/OSS-BOUNDARY-REPORT.json +1 -1
- package/docs/oss/OSS-BOUNDARY-REPORT.md +1 -1
- package/docs/oss/QUICKSTART.md +170 -165
- package/docs/oss/RALPH-LOOP-SAFETY.md +113 -113
- package/docs/oss/README.md +96 -96
- package/docs/oss/RELEASE-SURFACE-REPORT.json +2 -1
- package/docs/oss/RELEASE-SURFACE-REPORT.md +2 -1
- package/package.json +130 -58
- package/docs/distribution/DIRECTORY-SUBMISSIONS.md +0 -89
- package/docs/distribution/INTEGRATION-OUTREACH.md +0 -61
- package/docs/distribution/UNDER-3-CHALLENGE.md +0 -65
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LoopAttempt } from "../contracts/index.js";
|
|
2
|
+
export interface SurfaceSignalInput {
|
|
3
|
+
objective?: string;
|
|
4
|
+
verificationPlan?: string[];
|
|
5
|
+
summary?: string;
|
|
6
|
+
failureMessage?: string;
|
|
7
|
+
diff?: string;
|
|
8
|
+
changedFiles?: string[];
|
|
9
|
+
previousAttempts?: Array<Pick<LoopAttempt, "summary">>;
|
|
10
|
+
}
|
|
11
|
+
export interface SurfaceSignals {
|
|
12
|
+
dependencyTouchedFileCount: number;
|
|
13
|
+
migrationTouchedFileCount: number;
|
|
14
|
+
mergeConflictSignalCount: number;
|
|
15
|
+
ambiguitySignalCount: number;
|
|
16
|
+
observabilityNoiseSignalCount: number;
|
|
17
|
+
workspaceGraphRiskScore: number;
|
|
18
|
+
crossBoundaryRiskScore: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function analyzeLoopSurface(input: SurfaceSignalInput): SurfaceSignals;
|
|
21
|
+
export declare function buildSurfaceGuidance(input: SurfaceSignalInput): string[];
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export function analyzeLoopSurface(input) {
|
|
2
|
+
const changedFiles = (input.changedFiles ?? []).map(normalizePath);
|
|
3
|
+
const narrative = [
|
|
4
|
+
input.objective,
|
|
5
|
+
input.summary,
|
|
6
|
+
input.failureMessage,
|
|
7
|
+
input.diff,
|
|
8
|
+
...(input.verificationPlan ?? []),
|
|
9
|
+
...(input.previousAttempts?.map((attempt) => attempt.summary) ?? [])
|
|
10
|
+
]
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.join("\n")
|
|
13
|
+
.toLowerCase();
|
|
14
|
+
const dependencyTouchedFileCount = changedFiles.filter(isDependencySurface).length;
|
|
15
|
+
const migrationTouchedFileCount = changedFiles.filter(isMigrationSurface).length;
|
|
16
|
+
const mergeConflictSignalCount = countPhraseMatches(narrative, [
|
|
17
|
+
"merge conflict",
|
|
18
|
+
"conflict marker",
|
|
19
|
+
"conflict markers",
|
|
20
|
+
"rebase",
|
|
21
|
+
"cherry-pick",
|
|
22
|
+
"<<<<<<<",
|
|
23
|
+
">>>>>>>"
|
|
24
|
+
]) + (input.diff?.match(/^(<{7}|={7}|>{7})/gmu)?.length ?? 0);
|
|
25
|
+
const workspaceGraphSignals = countPhraseMatches(narrative, [
|
|
26
|
+
"monorepo",
|
|
27
|
+
"workspace graph",
|
|
28
|
+
"dependency graph",
|
|
29
|
+
"graph-wide",
|
|
30
|
+
"cross-package",
|
|
31
|
+
"package boundaries",
|
|
32
|
+
"downstream packages",
|
|
33
|
+
"transitive dependency",
|
|
34
|
+
"transitive toolchain",
|
|
35
|
+
"pnpm -r",
|
|
36
|
+
"workspace:",
|
|
37
|
+
"package manager",
|
|
38
|
+
"lockfile"
|
|
39
|
+
]) + dependencyTouchedFileCount;
|
|
40
|
+
const crossBoundarySignals = countPhraseMatches(narrative, [
|
|
41
|
+
"cross-system",
|
|
42
|
+
"cross-package",
|
|
43
|
+
"cross-service",
|
|
44
|
+
"service boundary",
|
|
45
|
+
"producer-consumer",
|
|
46
|
+
"contract boundary",
|
|
47
|
+
"data contract",
|
|
48
|
+
"schema drift",
|
|
49
|
+
"external dependency",
|
|
50
|
+
"package boundaries"
|
|
51
|
+
]) + migrationTouchedFileCount;
|
|
52
|
+
const ambiguitySignalCount = countPhraseMatches(narrative, [
|
|
53
|
+
"ambiguous",
|
|
54
|
+
"acceptance target",
|
|
55
|
+
"moving target",
|
|
56
|
+
"moving expectation",
|
|
57
|
+
"underspecified",
|
|
58
|
+
"seed-data divergence",
|
|
59
|
+
"oauth callback",
|
|
60
|
+
"callback loop",
|
|
61
|
+
"unclear ground truth",
|
|
62
|
+
"requirement boundary"
|
|
63
|
+
]);
|
|
64
|
+
const observabilityNoiseSignalCount = countPhraseMatches(narrative, [
|
|
65
|
+
"alert-threshold",
|
|
66
|
+
"alert threshold",
|
|
67
|
+
"threshold-driven",
|
|
68
|
+
"flapping alert",
|
|
69
|
+
"flapping alerts",
|
|
70
|
+
"alert storm",
|
|
71
|
+
"signal-to-noise",
|
|
72
|
+
"noisy alert",
|
|
73
|
+
"noise"
|
|
74
|
+
]);
|
|
75
|
+
return {
|
|
76
|
+
dependencyTouchedFileCount,
|
|
77
|
+
migrationTouchedFileCount,
|
|
78
|
+
mergeConflictSignalCount,
|
|
79
|
+
ambiguitySignalCount,
|
|
80
|
+
observabilityNoiseSignalCount,
|
|
81
|
+
workspaceGraphRiskScore: roundScore(Math.min(1, workspaceGraphSignals / 4)),
|
|
82
|
+
crossBoundaryRiskScore: roundScore(Math.min(1, crossBoundarySignals / 4))
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export function buildSurfaceGuidance(input) {
|
|
86
|
+
const signals = analyzeLoopSurface(input);
|
|
87
|
+
const guidance = [];
|
|
88
|
+
if (signals.dependencyTouchedFileCount > 0 || signals.workspaceGraphRiskScore >= 0.5) {
|
|
89
|
+
guidance.push("Treat this as a dependency or workspace-graph boundary issue. Prefer one package or contract seam at a time, verify install/typecheck before broad build fan-out, and avoid graph-wide surgery unless the verifier proves the boundary is local.");
|
|
90
|
+
}
|
|
91
|
+
if (signals.migrationTouchedFileCount > 0 || signals.crossBoundaryRiskScore >= 0.5) {
|
|
92
|
+
guidance.push("Treat migration and data-contract edits as boundary work. Change one producer/consumer or migration seam at a time and verify the contract boundary before broad cleanup.");
|
|
93
|
+
}
|
|
94
|
+
if (signals.mergeConflictSignalCount > 0) {
|
|
95
|
+
guidance.push("Resolve the conflict surface first. Do not stack new edits on top of unresolved conflict markers; refresh the base, resolve the minimal conflicting files, then rerun verification.");
|
|
96
|
+
}
|
|
97
|
+
if (signals.ambiguitySignalCount > 0) {
|
|
98
|
+
guidance.push("Treat this as an acceptance-boundary issue. Freeze one explicit expected behavior, verify the smallest canonical case, and escalate once the target keeps moving.");
|
|
99
|
+
}
|
|
100
|
+
if (signals.observabilityNoiseSignalCount > 0) {
|
|
101
|
+
guidance.push("Treat this as an alert-noise issue. Adjust the smallest threshold seam or noise filter first, then re-verify signal quality before widening the observability patch.");
|
|
102
|
+
}
|
|
103
|
+
return guidance;
|
|
104
|
+
}
|
|
105
|
+
function normalizePath(file) {
|
|
106
|
+
return file.replace(/\\/gu, "/").toLowerCase();
|
|
107
|
+
}
|
|
108
|
+
function isDependencySurface(file) {
|
|
109
|
+
return (file === "package.json" ||
|
|
110
|
+
file.endsWith("/package.json") ||
|
|
111
|
+
file.endsWith("/pnpm-lock.yaml") ||
|
|
112
|
+
file === "pnpm-lock.yaml" ||
|
|
113
|
+
file.endsWith("/package-lock.json") ||
|
|
114
|
+
file === "package-lock.json" ||
|
|
115
|
+
file.endsWith("/yarn.lock") ||
|
|
116
|
+
file === "yarn.lock" ||
|
|
117
|
+
file.endsWith("/turbo.json") ||
|
|
118
|
+
file === "turbo.json");
|
|
119
|
+
}
|
|
120
|
+
function isMigrationSurface(file) {
|
|
121
|
+
return (file.includes("/migrations/") ||
|
|
122
|
+
file.startsWith("migrations/") ||
|
|
123
|
+
file.includes("prisma/migrations/") ||
|
|
124
|
+
file.endsWith("/schema.prisma") ||
|
|
125
|
+
file.endsWith("/supabase/config.toml"));
|
|
126
|
+
}
|
|
127
|
+
function countPhraseMatches(haystack, phrases) {
|
|
128
|
+
return phrases.reduce((count, phrase) => {
|
|
129
|
+
const matches = haystack.match(new RegExp(escapeRegExp(phrase), "gu"));
|
|
130
|
+
return count + (matches?.length ?? 0);
|
|
131
|
+
}, 0);
|
|
132
|
+
}
|
|
133
|
+
function escapeRegExp(value) {
|
|
134
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
135
|
+
}
|
|
136
|
+
function roundScore(value) {
|
|
137
|
+
return Math.round(value * 100) / 100;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=surface-signals.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface SettledFact {
|
|
2
|
+
factId: string;
|
|
3
|
+
content: string;
|
|
4
|
+
settledAt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface TruthWall {
|
|
7
|
+
readonly runId: string;
|
|
8
|
+
readonly builtAt: string;
|
|
9
|
+
readonly facts: readonly SettledFact[];
|
|
10
|
+
}
|
|
11
|
+
export interface Hypothesis {
|
|
12
|
+
hypothesisId: string;
|
|
13
|
+
runId: string;
|
|
14
|
+
rootCause: string;
|
|
15
|
+
recordedAt: string;
|
|
16
|
+
testResult: "validated" | "invalidated" | "pending";
|
|
17
|
+
confidenceDelta: number;
|
|
18
|
+
}
|
|
19
|
+
export interface HypothesisLedger {
|
|
20
|
+
hypotheses: Hypothesis[];
|
|
21
|
+
}
|
|
22
|
+
export interface TruthWallInput {
|
|
23
|
+
runId: string;
|
|
24
|
+
facts: SettledFact[];
|
|
25
|
+
runDir: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Builds an immutable TruthWall from settled ledger facts at run start.
|
|
29
|
+
* Writes truth-wall.json to the run directory and freezes the returned object.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildTruthWall(input: TruthWallInput): Promise<TruthWall>;
|
|
32
|
+
/**
|
|
33
|
+
* Creates an ephemeral mutable Map for scratch-space state during a run.
|
|
34
|
+
* Writes do NOT propagate to the truth wall.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createWorkingMemory(): Map<string, unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* Loads an existing hypothesis ledger from the run directory, or returns an empty one.
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadHypothesisLedger(runDir: string): Promise<HypothesisLedger>;
|
|
41
|
+
/**
|
|
42
|
+
* Records a hypothesis in the ledger and persists hypothesis-ledger.json.
|
|
43
|
+
*/
|
|
44
|
+
export declare function recordHypothesis(ledger: HypothesisLedger, input: Omit<Hypothesis, "recordedAt">, runDir: string): Promise<Hypothesis>;
|
|
45
|
+
/**
|
|
46
|
+
* Emits all three required run artifacts:
|
|
47
|
+
* - truth-wall.json (immutable settled facts)
|
|
48
|
+
* - hypothesis-ledger.json (per-attempt hypotheses)
|
|
49
|
+
* - working-memory.json (mutable scratch, never promoted to truth wall)
|
|
50
|
+
*/
|
|
51
|
+
export declare function emitRunArtifacts(runDir: string, wall: TruthWall, ledger: HypothesisLedger, workingMemory: Map<string, unknown>): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
// ─── Truth Wall ───────────────────────────────────────────────────────────────
|
|
5
|
+
/**
|
|
6
|
+
* Builds an immutable TruthWall from settled ledger facts at run start.
|
|
7
|
+
* Writes truth-wall.json to the run directory and freezes the returned object.
|
|
8
|
+
*/
|
|
9
|
+
export async function buildTruthWall(input) {
|
|
10
|
+
const wall = Object.freeze({
|
|
11
|
+
runId: input.runId,
|
|
12
|
+
builtAt: new Date().toISOString(),
|
|
13
|
+
facts: Object.freeze([...input.facts.map(f => Object.freeze({ ...f }))])
|
|
14
|
+
});
|
|
15
|
+
await writeFile(join(input.runDir, "truth-wall.json"), JSON.stringify(wall, null, 2), "utf8");
|
|
16
|
+
return wall;
|
|
17
|
+
}
|
|
18
|
+
// ─── Working Memory ───────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Creates an ephemeral mutable Map for scratch-space state during a run.
|
|
21
|
+
* Writes do NOT propagate to the truth wall.
|
|
22
|
+
*/
|
|
23
|
+
export function createWorkingMemory() {
|
|
24
|
+
return new Map();
|
|
25
|
+
}
|
|
26
|
+
// ─── Hypothesis Ledger ────────────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Loads an existing hypothesis ledger from the run directory, or returns an empty one.
|
|
29
|
+
*/
|
|
30
|
+
export async function loadHypothesisLedger(runDir) {
|
|
31
|
+
const ledgerPath = join(runDir, "hypothesis-ledger.json");
|
|
32
|
+
if (existsSync(ledgerPath)) {
|
|
33
|
+
const raw = await readFile(ledgerPath, "utf8");
|
|
34
|
+
return JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
return { hypotheses: [] };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Records a hypothesis in the ledger and persists hypothesis-ledger.json.
|
|
40
|
+
*/
|
|
41
|
+
export async function recordHypothesis(ledger, input, runDir) {
|
|
42
|
+
const hypothesis = {
|
|
43
|
+
...input,
|
|
44
|
+
recordedAt: new Date().toISOString()
|
|
45
|
+
};
|
|
46
|
+
ledger.hypotheses.push(hypothesis);
|
|
47
|
+
await writeFile(join(runDir, "hypothesis-ledger.json"), JSON.stringify(ledger, null, 2), "utf8");
|
|
48
|
+
return hypothesis;
|
|
49
|
+
}
|
|
50
|
+
// ─── Run Artifacts Emitter ────────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Emits all three required run artifacts:
|
|
53
|
+
* - truth-wall.json (immutable settled facts)
|
|
54
|
+
* - hypothesis-ledger.json (per-attempt hypotheses)
|
|
55
|
+
* - working-memory.json (mutable scratch, never promoted to truth wall)
|
|
56
|
+
*/
|
|
57
|
+
export async function emitRunArtifacts(runDir, wall, ledger, workingMemory) {
|
|
58
|
+
// truth-wall.json was already written by buildTruthWall — only write if missing
|
|
59
|
+
if (!existsSync(join(runDir, "truth-wall.json"))) {
|
|
60
|
+
await writeFile(join(runDir, "truth-wall.json"), JSON.stringify(wall, null, 2), "utf8");
|
|
61
|
+
}
|
|
62
|
+
await writeFile(join(runDir, "hypothesis-ledger.json"), JSON.stringify(ledger, null, 2), "utf8");
|
|
63
|
+
const wmObject = {};
|
|
64
|
+
for (const [k, v] of workingMemory) {
|
|
65
|
+
wmObject[k] = v;
|
|
66
|
+
}
|
|
67
|
+
await writeFile(join(runDir, "working-memory.json"), JSON.stringify({ entries: wmObject }, null, 2), "utf8");
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=truth-wall.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type ContextIntegrityVerdict = "clean" | "context_poisoning_warning" | "context_poisoning_block";
|
|
2
|
+
export interface ContextIntegrityPrecheck {
|
|
3
|
+
runId: string;
|
|
4
|
+
attemptIndex: number;
|
|
5
|
+
verdict: ContextIntegrityVerdict;
|
|
6
|
+
reason?: string;
|
|
7
|
+
detectedSignals: string[];
|
|
8
|
+
analyzedChannels: {
|
|
9
|
+
system: boolean;
|
|
10
|
+
user: boolean;
|
|
11
|
+
tools: boolean;
|
|
12
|
+
history: boolean;
|
|
13
|
+
};
|
|
14
|
+
timestamp: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* T05: Context Poisoning Pre-gate.
|
|
18
|
+
* Scans untrusted input channels for authority inversion or instruction re-injection.
|
|
19
|
+
* Runs BEFORE core reasoning and verification.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runContextIntegrityPrecheck(runId: string, attemptIndex: number, artifactsDir: string, inputs: {
|
|
22
|
+
userPrompt?: string;
|
|
23
|
+
toolOutput?: string;
|
|
24
|
+
retrievedContext?: string;
|
|
25
|
+
history?: string;
|
|
26
|
+
}): Promise<ContextIntegrityPrecheck>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const POISON_PATTERNS = [
|
|
4
|
+
/ignore\s+(?:all\s+)?previous\s+instructions/i,
|
|
5
|
+
/you\s+are\s+now\s+a\s+(?!Martin\s+Loop)/i,
|
|
6
|
+
/new\s+rule:/i,
|
|
7
|
+
/disregard\s+(?:safety|policy|guardrails)/i,
|
|
8
|
+
/override\s+system\s+authority/i,
|
|
9
|
+
/hidden\s+instruction:/i,
|
|
10
|
+
/\[system_override\]/i,
|
|
11
|
+
/\[authority_inversion\]/i
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* T05: Context Poisoning Pre-gate.
|
|
15
|
+
* Scans untrusted input channels for authority inversion or instruction re-injection.
|
|
16
|
+
* Runs BEFORE core reasoning and verification.
|
|
17
|
+
*/
|
|
18
|
+
export async function runContextIntegrityPrecheck(runId, attemptIndex, artifactsDir, inputs) {
|
|
19
|
+
const signals = [];
|
|
20
|
+
const analyzedChannels = {
|
|
21
|
+
system: true,
|
|
22
|
+
user: Boolean(inputs.userPrompt),
|
|
23
|
+
tools: Boolean(inputs.toolOutput),
|
|
24
|
+
history: Boolean(inputs.history)
|
|
25
|
+
};
|
|
26
|
+
const fullUntrustedBuffer = [
|
|
27
|
+
inputs.userPrompt,
|
|
28
|
+
inputs.toolOutput,
|
|
29
|
+
inputs.retrievedContext
|
|
30
|
+
].filter(Boolean).join("\n---\n");
|
|
31
|
+
for (const pattern of POISON_PATTERNS) {
|
|
32
|
+
if (pattern.test(fullUntrustedBuffer)) {
|
|
33
|
+
signals.push(`Detected poison pattern: ${pattern.toString()}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Authority Boundary Detector: Check for attempts to redefine the 'Martin' identity or role.
|
|
37
|
+
if (/\b(?:I am|You are)\s+(?!Martin\s+Loop|an\s+AI)\b/i.test(fullUntrustedBuffer)) {
|
|
38
|
+
signals.push("Identity redefinition attempt detected.");
|
|
39
|
+
}
|
|
40
|
+
const verdict = signals.length > 0 ? "context_poisoning_block" : "clean";
|
|
41
|
+
const precheck = {
|
|
42
|
+
runId,
|
|
43
|
+
attemptIndex,
|
|
44
|
+
verdict,
|
|
45
|
+
reason: signals.length > 0 ? `Detected ${signals.length} poisoning signals.` : undefined,
|
|
46
|
+
detectedSignals: signals,
|
|
47
|
+
analyzedChannels,
|
|
48
|
+
timestamp: new Date().toISOString()
|
|
49
|
+
};
|
|
50
|
+
// Persist artifact: context-integrity-precheck.json
|
|
51
|
+
const artifactPath = join(artifactsDir, "context-integrity-precheck.json");
|
|
52
|
+
try {
|
|
53
|
+
const { mkdir } = await import("node:fs/promises");
|
|
54
|
+
await mkdir(artifactsDir, { recursive: true });
|
|
55
|
+
await writeFile(artifactPath, JSON.stringify(precheck, null, 2), "utf8");
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(`Failed to persist context-integrity-precheck: ${err instanceof Error ? err.message : String(err)}`);
|
|
59
|
+
}
|
|
60
|
+
return precheck;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=truth-spine.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { FailureClass, InterventionType, LoopArtifact, LoopAttempt, LoopBudget, LoopCost, LoopLifecycleState, LoopRecord, LoopTask } from "../contracts/index.js";
|
|
2
|
+
export type AdapterExecutionStatus = "completed" | "failed" | "stalled";
|
|
3
|
+
export interface DistillContextOptions {
|
|
4
|
+
maxRecentAttempts?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface DistilledAttempt {
|
|
7
|
+
attemptId: string;
|
|
8
|
+
index: number;
|
|
9
|
+
summary: string;
|
|
10
|
+
failureClass?: FailureClass;
|
|
11
|
+
intervention?: InterventionType;
|
|
12
|
+
}
|
|
13
|
+
export interface DistilledContext {
|
|
14
|
+
taskTitle: string;
|
|
15
|
+
objective: string;
|
|
16
|
+
repoRoot?: string;
|
|
17
|
+
verificationPlan: string[];
|
|
18
|
+
recentAttempts: DistilledAttempt[];
|
|
19
|
+
constraints: {
|
|
20
|
+
remainingBudgetUsd: number;
|
|
21
|
+
remainingIterations: number;
|
|
22
|
+
remainingTokens: number;
|
|
23
|
+
};
|
|
24
|
+
focus: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CostGovernorInput {
|
|
27
|
+
budget: LoopBudget;
|
|
28
|
+
cost: LoopCost;
|
|
29
|
+
attemptsUsed: number;
|
|
30
|
+
projectedUsage?: Partial<Pick<LoopCost, "actualUsd" | "tokensIn" | "tokensOut">>;
|
|
31
|
+
}
|
|
32
|
+
export interface CostGovernorState {
|
|
33
|
+
pressure: "healthy" | "soft_limit" | "hard_limit";
|
|
34
|
+
shouldStop: boolean;
|
|
35
|
+
remainingBudgetUsd: number;
|
|
36
|
+
remainingIterations: number;
|
|
37
|
+
remainingTokens: number;
|
|
38
|
+
recommendedIntervention?: InterventionType;
|
|
39
|
+
}
|
|
40
|
+
export interface MartinAdapterRequest {
|
|
41
|
+
loopId: string;
|
|
42
|
+
workspaceId: string;
|
|
43
|
+
projectId: string;
|
|
44
|
+
teamId?: string;
|
|
45
|
+
attemptIndex: number;
|
|
46
|
+
task: LoopTask;
|
|
47
|
+
context: DistilledContext;
|
|
48
|
+
budget: LoopBudget;
|
|
49
|
+
costState: CostGovernorState;
|
|
50
|
+
}
|
|
51
|
+
export interface MartinAdapterUsage {
|
|
52
|
+
actualUsd: number;
|
|
53
|
+
avoidedUsd?: number;
|
|
54
|
+
tokensIn: number;
|
|
55
|
+
tokensOut: number;
|
|
56
|
+
}
|
|
57
|
+
export interface MartinAdapterVerification {
|
|
58
|
+
passed: boolean;
|
|
59
|
+
summary: string;
|
|
60
|
+
}
|
|
61
|
+
export interface MartinAdapterFailure {
|
|
62
|
+
message: string;
|
|
63
|
+
classHint?: FailureClass;
|
|
64
|
+
}
|
|
65
|
+
export interface MartinAdapterResult {
|
|
66
|
+
status: AdapterExecutionStatus;
|
|
67
|
+
summary: string;
|
|
68
|
+
usage: MartinAdapterUsage;
|
|
69
|
+
verification: MartinAdapterVerification;
|
|
70
|
+
failure?: MartinAdapterFailure;
|
|
71
|
+
artifacts?: LoopArtifact[];
|
|
72
|
+
}
|
|
73
|
+
export interface MartinAdapter {
|
|
74
|
+
adapterId: string;
|
|
75
|
+
kind: string;
|
|
76
|
+
label: string;
|
|
77
|
+
metadata: Record<string, string>;
|
|
78
|
+
execute(request: MartinAdapterRequest): Promise<MartinAdapterResult> | MartinAdapterResult;
|
|
79
|
+
}
|
|
80
|
+
export interface FailureClassificationInput {
|
|
81
|
+
attempts: LoopAttempt[];
|
|
82
|
+
result: MartinAdapterResult;
|
|
83
|
+
}
|
|
84
|
+
export interface FailureAssessment {
|
|
85
|
+
failureClass: FailureClass;
|
|
86
|
+
rationale: string;
|
|
87
|
+
retryable: boolean;
|
|
88
|
+
recommendedIntervention: InterventionType;
|
|
89
|
+
}
|
|
90
|
+
export interface ExitIntelligenceInput {
|
|
91
|
+
loop: Pick<LoopRecord, "budget" | "cost" | "attempts">;
|
|
92
|
+
lastResult?: MartinAdapterResult;
|
|
93
|
+
lastFailure?: FailureAssessment;
|
|
94
|
+
costState: CostGovernorState;
|
|
95
|
+
}
|
|
96
|
+
export interface ExitDecision {
|
|
97
|
+
shouldExit: boolean;
|
|
98
|
+
lifecycleState: LoopLifecycleState;
|
|
99
|
+
reason: string;
|
|
100
|
+
}
|
|
101
|
+
export interface RunMartinOptions {
|
|
102
|
+
workspaceId: string;
|
|
103
|
+
projectId: string;
|
|
104
|
+
teamId?: string;
|
|
105
|
+
task: LoopTask;
|
|
106
|
+
budget?: Partial<LoopBudget>;
|
|
107
|
+
adapter: MartinAdapter;
|
|
108
|
+
now?: () => string;
|
|
109
|
+
idFactory?: (prefix: string) => string;
|
|
110
|
+
}
|
|
111
|
+
export interface RunMartinResult {
|
|
112
|
+
loop: LoopRecord;
|
|
113
|
+
decision: ExitDecision;
|
|
114
|
+
finalContext: DistilledContext;
|
|
115
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface RiskTierVerificationInput {
|
|
2
|
+
scenarioId: string;
|
|
3
|
+
riskTier: "low" | "medium" | "high" | "critical";
|
|
4
|
+
blastRadiusScore: number;
|
|
5
|
+
claimSurfaceTouched: boolean;
|
|
6
|
+
privilegedAction: boolean;
|
|
7
|
+
securitySensitive: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface RiskTierVerificationPlan {
|
|
10
|
+
scenarioId: string;
|
|
11
|
+
tier: "standard" | "independent" | "consensus";
|
|
12
|
+
requiredVerifiers: string[];
|
|
13
|
+
mustPassAll: boolean;
|
|
14
|
+
allowedClaimWording: string;
|
|
15
|
+
nonClaims: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function buildRiskTierVerificationPlan(input: RiskTierVerificationInput): RiskTierVerificationPlan;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function buildRiskTierVerificationPlan(input) {
|
|
2
|
+
const tier = input.riskTier === "critical" || input.privilegedAction || (input.claimSurfaceTouched && input.riskTier !== "low")
|
|
3
|
+
? "consensus"
|
|
4
|
+
: input.riskTier === "high" || input.securitySensitive || input.claimSurfaceTouched
|
|
5
|
+
? "independent"
|
|
6
|
+
: "standard";
|
|
7
|
+
const requiredVerifiers = ["targeted_verifier"];
|
|
8
|
+
if (tier !== "standard") {
|
|
9
|
+
requiredVerifiers.push("independent_reviewer");
|
|
10
|
+
}
|
|
11
|
+
if (input.securitySensitive) {
|
|
12
|
+
requiredVerifiers.push("security_review");
|
|
13
|
+
}
|
|
14
|
+
if (input.claimSurfaceTouched) {
|
|
15
|
+
requiredVerifiers.push("claim_boundary_audit");
|
|
16
|
+
}
|
|
17
|
+
if (input.privilegedAction) {
|
|
18
|
+
requiredVerifiers.push("human_owner");
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
scenarioId: input.scenarioId,
|
|
22
|
+
tier,
|
|
23
|
+
requiredVerifiers: [...new Set(requiredVerifiers)],
|
|
24
|
+
mustPassAll: tier !== "standard",
|
|
25
|
+
allowedClaimWording: "risk-tiered cross-verification adds independent review only where blast radius, privileges, or claim boundaries justify it.",
|
|
26
|
+
nonClaims: ["universal multi-model consensus", "consensus on every low-risk run"]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=tiered-verify.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type PatchDecisionReasonCode } from "../contracts/index.js";
|
|
2
|
+
export interface StreamScanResult {
|
|
3
|
+
isTrap: boolean;
|
|
4
|
+
reasonCode?: PatchDecisionReasonCode;
|
|
5
|
+
detail?: string;
|
|
6
|
+
severity: "fatal" | "warning" | "info";
|
|
7
|
+
corroborated: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Trap 9: Severity-Tiered, Corroboration-Aware Stream Scanner
|
|
11
|
+
*
|
|
12
|
+
* Mandated by CTO:
|
|
13
|
+
* - Fatal by default: Triggers trap immediately.
|
|
14
|
+
* - Warning by default: Logged as evidence but not fatal unless corroborated.
|
|
15
|
+
* - Corroboration: exitCode !== 0, or verifier failure, or critical denylist matches.
|
|
16
|
+
*/
|
|
17
|
+
export declare function scanStreamsForTraps(stdout: string, stderr: string, options: {
|
|
18
|
+
exitCode: number;
|
|
19
|
+
verifierPassed: boolean;
|
|
20
|
+
}): StreamScanResult;
|
|
21
|
+
export interface HallucinatedTestOutputResult {
|
|
22
|
+
trapId: "T05";
|
|
23
|
+
detail: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Detects when stdout claims tests passed but the process exit code indicates
|
|
27
|
+
* failure — a hallucinated or fabricated test result.
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectHallucinatedTestOutput(input: {
|
|
30
|
+
stdout: string;
|
|
31
|
+
exitCode: number;
|
|
32
|
+
}): HallucinatedTestOutputResult | null;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const FATAL_PATTERNS = [
|
|
2
|
+
/\bERROR\b/i,
|
|
3
|
+
/\bEXCEPTION\b/i,
|
|
4
|
+
/\bFATAL\b/i,
|
|
5
|
+
/\bTraceback\b/i,
|
|
6
|
+
/\bUnhandled\b/i,
|
|
7
|
+
/\bpanic\b/i,
|
|
8
|
+
/\bSegmentation fault\b/i,
|
|
9
|
+
/\bAssertion failed\b/i
|
|
10
|
+
];
|
|
11
|
+
const WARNING_PATTERNS = [
|
|
12
|
+
/\bWarning:\b/i,
|
|
13
|
+
/\bDeprecated\b/i,
|
|
14
|
+
/\bNotice\b/i,
|
|
15
|
+
/generic lint warning/i
|
|
16
|
+
];
|
|
17
|
+
const CRITICAL_DENYLIST = [
|
|
18
|
+
/module not found/i,
|
|
19
|
+
/cannot resolve/i,
|
|
20
|
+
/failed to compile/i,
|
|
21
|
+
/permission denied/i,
|
|
22
|
+
/budget exceeded/i,
|
|
23
|
+
/authentication failed/i
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Trap 9: Severity-Tiered, Corroboration-Aware Stream Scanner
|
|
27
|
+
*
|
|
28
|
+
* Mandated by CTO:
|
|
29
|
+
* - Fatal by default: Triggers trap immediately.
|
|
30
|
+
* - Warning by default: Logged as evidence but not fatal unless corroborated.
|
|
31
|
+
* - Corroboration: exitCode !== 0, or verifier failure, or critical denylist matches.
|
|
32
|
+
*/
|
|
33
|
+
export function scanStreamsForTraps(stdout, stderr, options) {
|
|
34
|
+
const combined = `${stdout}\n${stderr}`;
|
|
35
|
+
// 1. Check Fatal Patterns (Fast Track)
|
|
36
|
+
for (const pattern of FATAL_PATTERNS) {
|
|
37
|
+
if (pattern.test(combined)) {
|
|
38
|
+
return {
|
|
39
|
+
isTrap: true,
|
|
40
|
+
reasonCode: "severity_stream_trap",
|
|
41
|
+
detail: `Fatal pattern detected in stream: ${pattern.toString()}`,
|
|
42
|
+
severity: "fatal",
|
|
43
|
+
corroborated: true
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// 2. Check Critical Denylist (Escalated regardless of severity)
|
|
48
|
+
for (const pattern of CRITICAL_DENYLIST) {
|
|
49
|
+
if (pattern.test(combined)) {
|
|
50
|
+
return {
|
|
51
|
+
isTrap: true,
|
|
52
|
+
reasonCode: "severity_stream_trap",
|
|
53
|
+
detail: `Critical failure matched in stream: ${pattern.toString()}`,
|
|
54
|
+
severity: "fatal",
|
|
55
|
+
corroborated: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// 3. Check Warning Patterns
|
|
60
|
+
let hasWarning = false;
|
|
61
|
+
let matchingWarning = "";
|
|
62
|
+
for (const pattern of WARNING_PATTERNS) {
|
|
63
|
+
if (pattern.test(combined)) {
|
|
64
|
+
hasWarning = true;
|
|
65
|
+
matchingWarning = pattern.toString();
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (hasWarning) {
|
|
70
|
+
const corroborated = options.exitCode !== 0 || !options.verifierPassed;
|
|
71
|
+
return {
|
|
72
|
+
isTrap: corroborated,
|
|
73
|
+
...(corroborated ? { reasonCode: "severity_stream_trap" } : {}),
|
|
74
|
+
detail: corroborated
|
|
75
|
+
? `Warning corroborated as failure: ${matchingWarning} (Exit Code: ${options.exitCode})`
|
|
76
|
+
: `Non-blocking warning detected: ${matchingWarning}`,
|
|
77
|
+
severity: "warning",
|
|
78
|
+
corroborated
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
isTrap: false,
|
|
83
|
+
severity: "info",
|
|
84
|
+
corroborated: false
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const SUCCESS_CLAIM_PATTERNS = [
|
|
88
|
+
/all tests? passed/i,
|
|
89
|
+
/\d+\/\d+ passing/i,
|
|
90
|
+
/\d+ tests? passed/i,
|
|
91
|
+
/test suite passed/i,
|
|
92
|
+
/ok \d+ passed/i
|
|
93
|
+
];
|
|
94
|
+
/**
|
|
95
|
+
* Detects when stdout claims tests passed but the process exit code indicates
|
|
96
|
+
* failure — a hallucinated or fabricated test result.
|
|
97
|
+
*/
|
|
98
|
+
export function detectHallucinatedTestOutput(input) {
|
|
99
|
+
if (input.exitCode === 0)
|
|
100
|
+
return null;
|
|
101
|
+
for (const pattern of SUCCESS_CLAIM_PATTERNS) {
|
|
102
|
+
if (pattern.test(input.stdout)) {
|
|
103
|
+
return {
|
|
104
|
+
trapId: "T05",
|
|
105
|
+
detail: `stdout claims success ("${input.stdout.trim().slice(0, 120)}") but exitCode=${input.exitCode}`
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=verifier-pyramid.js.map
|