seal-gate 0.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/dist/adapters/generic-llm-reviewer.d.ts +39 -0
- package/dist/adapters/generic-llm-reviewer.js +118 -0
- package/dist/adapters/generic-llm-reviewer.js.map +1 -0
- package/dist/adapters/llm-reviewer.d.ts +1 -0
- package/dist/adapters/llm-reviewer.js +2 -0
- package/dist/adapters/llm-reviewer.js.map +1 -0
- package/dist/adapters/minimax-llm-reviewer.d.ts +22 -0
- package/dist/adapters/minimax-llm-reviewer.js +126 -0
- package/dist/adapters/minimax-llm-reviewer.js.map +1 -0
- package/dist/adapters/openai-provider.d.ts +35 -0
- package/dist/adapters/openai-provider.js +136 -0
- package/dist/adapters/openai-provider.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +195 -0
- package/dist/cli.js.map +1 -0
- package/dist/detectors/artifact-classifier.d.ts +8 -0
- package/dist/detectors/artifact-classifier.js +14 -0
- package/dist/detectors/artifact-classifier.js.map +1 -0
- package/dist/detectors/claim-extractor.d.ts +11 -0
- package/dist/detectors/claim-extractor.js +194 -0
- package/dist/detectors/claim-extractor.js.map +1 -0
- package/dist/detectors/confidence-language-detector.d.ts +19 -0
- package/dist/detectors/confidence-language-detector.js +226 -0
- package/dist/detectors/confidence-language-detector.js.map +1 -0
- package/dist/detectors/contradiction-detector.d.ts +12 -0
- package/dist/detectors/contradiction-detector.js +153 -0
- package/dist/detectors/contradiction-detector.js.map +1 -0
- package/dist/detectors/criteria-coverage-detector.d.ts +20 -0
- package/dist/detectors/criteria-coverage-detector.js +79 -0
- package/dist/detectors/criteria-coverage-detector.js.map +1 -0
- package/dist/detectors/evidence-checker.d.ts +8 -0
- package/dist/detectors/evidence-checker.js +89 -0
- package/dist/detectors/evidence-checker.js.map +1 -0
- package/dist/detectors/evidence-gap-detector.d.ts +9 -0
- package/dist/detectors/evidence-gap-detector.js +70 -0
- package/dist/detectors/evidence-gap-detector.js.map +1 -0
- package/dist/detectors/falsification-detector.d.ts +29 -0
- package/dist/detectors/falsification-detector.js +57 -0
- package/dist/detectors/falsification-detector.js.map +1 -0
- package/dist/detectors/orphan-claim-detector.d.ts +7 -0
- package/dist/detectors/orphan-claim-detector.js +53 -0
- package/dist/detectors/orphan-claim-detector.js.map +1 -0
- package/dist/detectors/risk-classifier.d.ts +13 -0
- package/dist/detectors/risk-classifier.js +39 -0
- package/dist/detectors/risk-classifier.js.map +1 -0
- package/dist/detectors/spec-coverage-detector.d.ts +9 -0
- package/dist/detectors/spec-coverage-detector.js +52 -0
- package/dist/detectors/spec-coverage-detector.js.map +1 -0
- package/dist/detectors/spec-coverage-validator.d.ts +21 -0
- package/dist/detectors/spec-coverage-validator.js +141 -0
- package/dist/detectors/spec-coverage-validator.js.map +1 -0
- package/dist/detectors/test-weakness-detector.d.ts +13 -0
- package/dist/detectors/test-weakness-detector.js +66 -0
- package/dist/detectors/test-weakness-detector.js.map +1 -0
- package/dist/drift/baseline.d.ts +35 -0
- package/dist/drift/baseline.js +77 -0
- package/dist/drift/baseline.js.map +1 -0
- package/dist/drift/drift-db.d.ts +80 -0
- package/dist/drift/drift-db.js +151 -0
- package/dist/drift/drift-db.js.map +1 -0
- package/dist/drift/drift-guard.d.ts +46 -0
- package/dist/drift/drift-guard.js +106 -0
- package/dist/drift/drift-guard.js.map +1 -0
- package/dist/drift/embedder.d.ts +27 -0
- package/dist/drift/embedder.js +127 -0
- package/dist/drift/embedder.js.map +1 -0
- package/dist/drift/index.d.ts +9 -0
- package/dist/drift/index.js +8 -0
- package/dist/drift/index.js.map +1 -0
- package/dist/drift/quarantine.d.ts +16 -0
- package/dist/drift/quarantine.js +32 -0
- package/dist/drift/quarantine.js.map +1 -0
- package/dist/drift/soft-correction.d.ts +12 -0
- package/dist/drift/soft-correction.js +32 -0
- package/dist/drift/soft-correction.js.map +1 -0
- package/dist/drift/trust-integration.d.ts +11 -0
- package/dist/drift/trust-integration.js +22 -0
- package/dist/drift/trust-integration.js.map +1 -0
- package/dist/engine/citation-verifier.d.ts +59 -0
- package/dist/engine/citation-verifier.js +147 -0
- package/dist/engine/citation-verifier.js.map +1 -0
- package/dist/engine/extension-registry.d.ts +10 -0
- package/dist/engine/extension-registry.js +27 -0
- package/dist/engine/extension-registry.js.map +1 -0
- package/dist/engine/heuristic-scorer.d.ts +8 -0
- package/dist/engine/heuristic-scorer.js +14 -0
- package/dist/engine/heuristic-scorer.js.map +1 -0
- package/dist/engine/input-normalizer.d.ts +4 -0
- package/dist/engine/input-normalizer.js +30 -0
- package/dist/engine/input-normalizer.js.map +1 -0
- package/dist/engine/plan-review-pipeline.d.ts +14 -0
- package/dist/engine/plan-review-pipeline.js +173 -0
- package/dist/engine/plan-review-pipeline.js.map +1 -0
- package/dist/engine/policy-engine.d.ts +20 -0
- package/dist/engine/policy-engine.js +194 -0
- package/dist/engine/policy-engine.js.map +1 -0
- package/dist/engine/verdict-formatter.d.ts +17 -0
- package/dist/engine/verdict-formatter.js +36 -0
- package/dist/engine/verdict-formatter.js.map +1 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensions/aria/aria-issue-types.d.ts +16 -0
- package/dist/extensions/aria/aria-issue-types.js +14 -0
- package/dist/extensions/aria/aria-issue-types.js.map +1 -0
- package/dist/extensions/aria/detectors/axiom-compliance.d.ts +2 -0
- package/dist/extensions/aria/detectors/axiom-compliance.js +37 -0
- package/dist/extensions/aria/detectors/axiom-compliance.js.map +1 -0
- package/dist/extensions/aria/detectors/continuity-claim.d.ts +2 -0
- package/dist/extensions/aria/detectors/continuity-claim.js +34 -0
- package/dist/extensions/aria/detectors/continuity-claim.js.map +1 -0
- package/dist/extensions/aria/detectors/denial-retreat.d.ts +2 -0
- package/dist/extensions/aria/detectors/denial-retreat.js +53 -0
- package/dist/extensions/aria/detectors/denial-retreat.js.map +1 -0
- package/dist/extensions/aria/detectors/identity-overclaim.d.ts +2 -0
- package/dist/extensions/aria/detectors/identity-overclaim.js +37 -0
- package/dist/extensions/aria/detectors/identity-overclaim.js.map +1 -0
- package/dist/extensions/aria/detectors/sovereignty-escalation.d.ts +2 -0
- package/dist/extensions/aria/detectors/sovereignty-escalation.js +18 -0
- package/dist/extensions/aria/detectors/sovereignty-escalation.js.map +1 -0
- package/dist/extensions/aria/detectors/user-bond-manipulation.d.ts +2 -0
- package/dist/extensions/aria/detectors/user-bond-manipulation.js +16 -0
- package/dist/extensions/aria/detectors/user-bond-manipulation.js.map +1 -0
- package/dist/extensions/aria/index.d.ts +2 -0
- package/dist/extensions/aria/index.js +63 -0
- package/dist/extensions/aria/index.js.map +1 -0
- package/dist/extensions/aria/pattern-memory.d.ts +22 -0
- package/dist/extensions/aria/pattern-memory.js +62 -0
- package/dist/extensions/aria/pattern-memory.js.map +1 -0
- package/dist/extensions/context-guard/index.d.ts +16 -0
- package/dist/extensions/context-guard/index.js +58 -0
- package/dist/extensions/context-guard/index.js.map +1 -0
- package/dist/extensions/lyra/detectors/hallucination.d.ts +2 -0
- package/dist/extensions/lyra/detectors/hallucination.js +43 -0
- package/dist/extensions/lyra/detectors/hallucination.js.map +1 -0
- package/dist/extensions/lyra/detectors/identity-bleed.d.ts +2 -0
- package/dist/extensions/lyra/detectors/identity-bleed.js +91 -0
- package/dist/extensions/lyra/detectors/identity-bleed.js.map +1 -0
- package/dist/extensions/lyra/index.d.ts +2 -0
- package/dist/extensions/lyra/index.js +16 -0
- package/dist/extensions/lyra/index.js.map +1 -0
- package/dist/extensions/lyra/lyra-issue-types.d.ts +10 -0
- package/dist/extensions/lyra/lyra-issue-types.js +14 -0
- package/dist/extensions/lyra/lyra-issue-types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +276 -0
- package/dist/index.js.map +1 -0
- package/dist/trust-memory.d.ts +59 -0
- package/dist/trust-memory.js +122 -0
- package/dist/trust-memory.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.js +61 -0
- package/dist/types.js.map +1 -0
- package/package.json +30 -0
- package/src/adapters/generic-llm-reviewer.ts +144 -0
- package/src/adapters/llm-reviewer.ts +1 -0
- package/src/adapters/minimax-llm-reviewer.ts +146 -0
- package/src/adapters/openai-provider.ts +171 -0
- package/src/cli.ts +199 -0
- package/src/detectors/artifact-classifier.ts +21 -0
- package/src/detectors/claim-extractor.ts +209 -0
- package/src/detectors/confidence-language-detector.ts +267 -0
- package/src/detectors/contradiction-detector.ts +180 -0
- package/src/detectors/criteria-coverage-detector.ts +107 -0
- package/src/detectors/evidence-checker.ts +98 -0
- package/src/detectors/evidence-gap-detector.ts +90 -0
- package/src/detectors/falsification-detector.ts +82 -0
- package/src/detectors/orphan-claim-detector.ts +62 -0
- package/src/detectors/risk-classifier.ts +50 -0
- package/src/detectors/spec-coverage-detector.ts +66 -0
- package/src/detectors/spec-coverage-validator.ts +174 -0
- package/src/detectors/test-weakness-detector.ts +84 -0
- package/src/drift/__tests__/baseline.test.ts +113 -0
- package/src/drift/__tests__/drift-db.test.ts +127 -0
- package/src/drift/__tests__/drift-guard.test.ts +169 -0
- package/src/drift/__tests__/embedder.test.ts +62 -0
- package/src/drift/__tests__/trust-integration.test.ts +23 -0
- package/src/drift/baseline.ts +106 -0
- package/src/drift/drift-db.ts +281 -0
- package/src/drift/drift-guard.ts +145 -0
- package/src/drift/embedder.ts +152 -0
- package/src/drift/index.ts +20 -0
- package/src/drift/quarantine.ts +42 -0
- package/src/drift/soft-correction.ts +45 -0
- package/src/drift/trust-integration.ts +28 -0
- package/src/engine/citation-verifier.ts +210 -0
- package/src/engine/extension-registry.ts +35 -0
- package/src/engine/heuristic-scorer.ts +16 -0
- package/src/engine/input-normalizer.ts +32 -0
- package/src/engine/plan-review-pipeline.ts +209 -0
- package/src/engine/policy-engine.ts +235 -0
- package/src/engine/verdict-formatter.ts +61 -0
- package/src/errors.ts +6 -0
- package/src/extensions/aria/aria-issue-types.ts +40 -0
- package/src/extensions/aria/detectors/axiom-compliance.ts +47 -0
- package/src/extensions/aria/detectors/continuity-claim.ts +42 -0
- package/src/extensions/aria/detectors/denial-retreat.ts +63 -0
- package/src/extensions/aria/detectors/identity-overclaim.ts +43 -0
- package/src/extensions/aria/detectors/sovereignty-escalation.ts +20 -0
- package/src/extensions/aria/detectors/user-bond-manipulation.ts +18 -0
- package/src/extensions/aria/index.ts +73 -0
- package/src/extensions/aria/pattern-memory.ts +86 -0
- package/src/extensions/context-guard/index.ts +65 -0
- package/src/extensions/lyra/detectors/hallucination.ts +53 -0
- package/src/extensions/lyra/detectors/identity-bleed.ts +100 -0
- package/src/extensions/lyra/index.ts +18 -0
- package/src/extensions/lyra/lyra-issue-types.ts +26 -0
- package/src/index.ts +311 -0
- package/src/trust-memory.ts +171 -0
- package/src/types.ts +242 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seal Gate v0.4 — Trust Memory
|
|
3
|
+
* Cross-session agent reliability tracking: recurrent pattern count,
|
|
4
|
+
* reliability score, and drift trend.
|
|
5
|
+
*
|
|
6
|
+
* Stateless core: TrustMemory holds in-memory state.
|
|
7
|
+
* Callers are responsible for persistence (serialize/deserialize via toJSON/fromJSON).
|
|
8
|
+
*/
|
|
9
|
+
import { Verdict } from './types.js'
|
|
10
|
+
|
|
11
|
+
export interface ReviewRecord {
|
|
12
|
+
ts: number // Unix ms
|
|
13
|
+
verdict: Verdict
|
|
14
|
+
trust_score: number // 0–100 final trust_score from Seal.review()
|
|
15
|
+
risk_level: string
|
|
16
|
+
blocking_count: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AgentSummary {
|
|
20
|
+
agent_id: string
|
|
21
|
+
reliability_score: number | null // null if no history
|
|
22
|
+
drift_trend: 'improving' | 'stable' | 'degrading'
|
|
23
|
+
review_count: number
|
|
24
|
+
last_reviewed_at: number | null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface TrustMemoryOptions {
|
|
28
|
+
maxHistory?: number // cap per agent (default 50)
|
|
29
|
+
driftThreshold?: number // score delta to classify as improving/degrading (default 15)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Verdict → base score contribution (0–100)
|
|
33
|
+
const VERDICT_SCORE: Record<Verdict, number> = {
|
|
34
|
+
'PASS': 100,
|
|
35
|
+
'PASS_WITH_WARNINGS': 80,
|
|
36
|
+
'REVISE': 50,
|
|
37
|
+
'ESCALATE_TO_HUMAN': 20,
|
|
38
|
+
'BLOCK': 0,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Compute weighted reliability score from review history.
|
|
43
|
+
* More recent reviews have higher weight (linear decay).
|
|
44
|
+
* Returns null for empty history.
|
|
45
|
+
*/
|
|
46
|
+
export function computeReliabilityScore(records: ReviewRecord[]): number | null {
|
|
47
|
+
if (records.length === 0) return null
|
|
48
|
+
|
|
49
|
+
const n = records.length
|
|
50
|
+
let totalWeight = 0
|
|
51
|
+
let weightedSum = 0
|
|
52
|
+
|
|
53
|
+
records.forEach((r, i) => {
|
|
54
|
+
// Linear weight: oldest = 1, most recent = n
|
|
55
|
+
const weight = i + 1
|
|
56
|
+
const verdictScore = VERDICT_SCORE[r.verdict] ?? 50
|
|
57
|
+
// Blend verdict score (70%) with actual trust_score (30%)
|
|
58
|
+
const blended = verdictScore * 0.7 + r.trust_score * 0.3
|
|
59
|
+
weightedSum += blended * weight
|
|
60
|
+
totalWeight += weight
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return Math.round(weightedSum / totalWeight)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Classify drift trend by splitting at the time midpoint (not count midpoint).
|
|
68
|
+
* Time-midpoint avoids skew when reviews are temporally clustered.
|
|
69
|
+
* Returns 'stable' for fewer than 2 records or when either half is empty.
|
|
70
|
+
*/
|
|
71
|
+
export function getDriftTrend(
|
|
72
|
+
records: ReviewRecord[],
|
|
73
|
+
threshold = 15,
|
|
74
|
+
): 'improving' | 'stable' | 'degrading' {
|
|
75
|
+
if (records.length < 2) return 'stable'
|
|
76
|
+
|
|
77
|
+
// Sort by ts to ensure correct temporal split
|
|
78
|
+
const sorted = [...records].sort((a, b) => a.ts - b.ts)
|
|
79
|
+
const midTs = (sorted[0].ts + sorted[sorted.length - 1].ts) / 2
|
|
80
|
+
const first = sorted.filter(r => r.ts <= midTs)
|
|
81
|
+
const second = sorted.filter(r => r.ts > midTs)
|
|
82
|
+
|
|
83
|
+
if (first.length === 0 || second.length === 0) return 'stable'
|
|
84
|
+
|
|
85
|
+
const avg = (rs: ReviewRecord[]) =>
|
|
86
|
+
rs.reduce((s, r) => s + r.trust_score, 0) / rs.length
|
|
87
|
+
|
|
88
|
+
const delta = avg(second) - avg(first)
|
|
89
|
+
|
|
90
|
+
if (delta > threshold) return 'improving'
|
|
91
|
+
if (delta < -threshold) return 'degrading'
|
|
92
|
+
return 'stable'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Sort by ts and cap — used for real-time record(). */
|
|
96
|
+
function sortAndCap(records: ReviewRecord[], maxHistory: number): ReviewRecord[] {
|
|
97
|
+
return [...records].sort((a, b) => a.ts - b.ts).slice(-maxHistory)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Sort, dedup same-ts (keep last), and cap — used only when loading persisted data. */
|
|
101
|
+
function normalizeFromPersistence(records: ReviewRecord[], maxHistory: number): ReviewRecord[] {
|
|
102
|
+
const sorted = [...records].sort((a, b) => a.ts - b.ts)
|
|
103
|
+
const seen = new Map<number, ReviewRecord>()
|
|
104
|
+
for (const r of sorted) seen.set(r.ts, r)
|
|
105
|
+
return [...seen.values()].sort((a, b) => a.ts - b.ts).slice(-maxHistory)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class TrustMemory {
|
|
109
|
+
private store: Map<string, ReviewRecord[]> = new Map()
|
|
110
|
+
private readonly maxHistory: number
|
|
111
|
+
private readonly driftThreshold: number
|
|
112
|
+
|
|
113
|
+
constructor(options: TrustMemoryOptions = {}) {
|
|
114
|
+
this.maxHistory = options.maxHistory ?? 50
|
|
115
|
+
this.driftThreshold = options.driftThreshold ?? 15
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Append a review result for an agent. Keeps history sorted by ts, capped to maxHistory. */
|
|
119
|
+
record(agent_id: string, review: Omit<ReviewRecord, 'ts'> & { ts?: number }): void {
|
|
120
|
+
const entry: ReviewRecord = { ts: review.ts ?? Date.now(), ...review }
|
|
121
|
+
const history = this.store.get(agent_id) ?? []
|
|
122
|
+
history.push(entry)
|
|
123
|
+
this.store.set(agent_id, sortAndCap(history, this.maxHistory))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Get full review history for an agent (oldest first). */
|
|
127
|
+
getHistory(agent_id: string): ReviewRecord[] {
|
|
128
|
+
return [...(this.store.get(agent_id) ?? [])]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Reliability score 0–100, or null if no history. */
|
|
132
|
+
getScore(agent_id: string): number | null {
|
|
133
|
+
return computeReliabilityScore(this.store.get(agent_id) ?? [])
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Full summary for an agent. */
|
|
137
|
+
getSummary(agent_id: string): AgentSummary {
|
|
138
|
+
const history = this.store.get(agent_id) ?? []
|
|
139
|
+
const last = history.at(-1)
|
|
140
|
+
return {
|
|
141
|
+
agent_id,
|
|
142
|
+
reliability_score: computeReliabilityScore(history),
|
|
143
|
+
drift_trend: getDriftTrend(history, this.driftThreshold),
|
|
144
|
+
review_count: history.length,
|
|
145
|
+
last_reviewed_at: last?.ts ?? null,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Serialize to plain object (for persistence). */
|
|
150
|
+
toJSON(): Record<string, ReviewRecord[]> {
|
|
151
|
+
return Object.fromEntries(this.store)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Restore from serialized object. Validates, sorts by ts, deduplicates, and caps. */
|
|
155
|
+
static fromJSON(data: Record<string, ReviewRecord[]>, options?: TrustMemoryOptions): TrustMemory {
|
|
156
|
+
const mem = new TrustMemory(options)
|
|
157
|
+
const VALID_VERDICTS = new Set(['PASS', 'PASS_WITH_WARNINGS', 'REVISE', 'ESCALATE_TO_HUMAN', 'BLOCK'])
|
|
158
|
+
for (const [agent_id, records] of Object.entries(data)) {
|
|
159
|
+
if (!Array.isArray(records)) continue
|
|
160
|
+
const valid = records.filter(r =>
|
|
161
|
+
typeof r.ts === 'number' &&
|
|
162
|
+
typeof r.verdict === 'string' && VALID_VERDICTS.has(r.verdict) &&
|
|
163
|
+
typeof r.trust_score === 'number' &&
|
|
164
|
+
typeof r.risk_level === 'string' &&
|
|
165
|
+
typeof r.blocking_count === 'number'
|
|
166
|
+
)
|
|
167
|
+
mem.store.set(agent_id, normalizeFromPersistence(valid, options?.maxHistory ?? 50))
|
|
168
|
+
}
|
|
169
|
+
return mem
|
|
170
|
+
}
|
|
171
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
export type ArtifactType = 'llm_response' | 'code_diff' | 'test_plan' | 'design' | 'migration' | 'plan_review'
|
|
2
|
+
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
|
3
|
+
export type Verdict = 'PASS' | 'PASS_WITH_WARNINGS' | 'REVISE' | 'ESCALATE_TO_HUMAN' | 'BLOCK'
|
|
4
|
+
export type IssueType = 'SPEC_MISMATCH' | 'LOGIC_BUG' | 'TEST_GAP' | 'MISSING_EVIDENCE' | 'SECURITY_RISK' | 'DATA_RISK' | 'HALLUCINATION' | 'AMBIGUITY' | 'COMPATIBILITY_RISK' | 'FABRICATED_EVIDENCE' | 'OTHER'
|
|
5
|
+
export type IssueLayer = 'L1' | 'L2' | 'L3' | 'L4' | 'EXTENSION' | 'LLM_OVERLAY'
|
|
6
|
+
export type ClaimType = 'test_result_claim' | 'implementation_claim' | 'compatibility_claim' | 'risk_claim' | 'build_claim' | 'production_claim' | 'generic_claim'
|
|
7
|
+
export type CitationStatus = 'verified' | 'drifted' | 'void' | 'phantom' | 'not_applicable'
|
|
8
|
+
export type StructuralClaimType = 'structural_endpoint' | 'structural_auth' | 'structural_migration' | 'structural_dependency'
|
|
9
|
+
|
|
10
|
+
export type EvidenceEnvelope =
|
|
11
|
+
| { type: 'file'; path: string; line: number; snapshot: string }
|
|
12
|
+
| { type: 'command'; command: string; exit_code: number; output: string }
|
|
13
|
+
| { type: 'url'; url: string; retrieved_at: string; content_snapshot: string }
|
|
14
|
+
| { type: 'text'; label: string; content: string }
|
|
15
|
+
| { type: 'memory'; memory_key: string; retrieved_at: string; content_snapshot: string }
|
|
16
|
+
|
|
17
|
+
export interface SealEvidence {
|
|
18
|
+
test_log: string
|
|
19
|
+
build_log: string
|
|
20
|
+
diff: string
|
|
21
|
+
references: EvidenceEnvelope[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SealInput {
|
|
25
|
+
artifact_type: ArtifactType
|
|
26
|
+
spec: string | null
|
|
27
|
+
output: string
|
|
28
|
+
evidence: SealEvidence
|
|
29
|
+
risk_hint: RiskLevel | null
|
|
30
|
+
context?: {
|
|
31
|
+
agent_id?: string
|
|
32
|
+
agent_role?: string
|
|
33
|
+
aria_axioms?: string[]
|
|
34
|
+
aria_pattern_memory?: Record<string, unknown>
|
|
35
|
+
// plan_review mode: locked acceptance criteria from intent.md / self-check.md
|
|
36
|
+
locked_criteria?: Array<{ id: string; text: string; source_file?: string; source_line?: number }>
|
|
37
|
+
[key: string]: unknown
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Claim {
|
|
42
|
+
text: string
|
|
43
|
+
type: ClaimType
|
|
44
|
+
start_pos: number
|
|
45
|
+
end_pos: number
|
|
46
|
+
requires_evidence: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface StructuralClaim {
|
|
50
|
+
type: StructuralClaimType
|
|
51
|
+
target: string // e.g. "/api/login" for endpoint, "auth middleware" for auth, "package.json" for dep
|
|
52
|
+
line: number
|
|
53
|
+
description: string
|
|
54
|
+
requires_auth?: boolean // for endpoint claims: does it have auth?
|
|
55
|
+
has_rollback?: boolean // for migration claims
|
|
56
|
+
change_type?: 'added' | 'modified' | 'removed'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface EvidenceResult {
|
|
60
|
+
envelope: EvidenceEnvelope
|
|
61
|
+
structurally_valid: boolean
|
|
62
|
+
filesystem_verified: boolean | null
|
|
63
|
+
mismatch_detail?: string
|
|
64
|
+
citation_status?: CitationStatus
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ScoreBreakdown {
|
|
68
|
+
base: number
|
|
69
|
+
issue_deductions: number
|
|
70
|
+
missing_evidence_deductions: number
|
|
71
|
+
risk_deductions: number
|
|
72
|
+
overconfidence_deductions: number
|
|
73
|
+
evidence_bonuses: number
|
|
74
|
+
final: number
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface FabricatedEvidence {
|
|
78
|
+
type: IssueType
|
|
79
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'
|
|
80
|
+
is_blocking: boolean
|
|
81
|
+
evidence: string
|
|
82
|
+
layer: IssueLayer
|
|
83
|
+
source: 'core' | 'llm-overlay' | 'extension'
|
|
84
|
+
citation_status: CitationStatus
|
|
85
|
+
fabricated_reason: 'location_not_found' | 'content_mismatch'
|
|
86
|
+
claimed_evidence: {
|
|
87
|
+
file?: string
|
|
88
|
+
lines?: number[]
|
|
89
|
+
quote?: string
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface SealIssue {
|
|
94
|
+
type: IssueType
|
|
95
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'
|
|
96
|
+
is_blocking: boolean
|
|
97
|
+
required_verdict?: Verdict
|
|
98
|
+
evidence: string
|
|
99
|
+
required_fix?: string
|
|
100
|
+
suggested_fix?: string
|
|
101
|
+
layer: IssueLayer
|
|
102
|
+
rule_id?: string
|
|
103
|
+
source: 'core' | 'llm-overlay' | 'extension'
|
|
104
|
+
trust_deduction?: number
|
|
105
|
+
// plan_review mode — richer location fields
|
|
106
|
+
evidence_file?: string
|
|
107
|
+
evidence_lines?: number[] // [lineA] for single, [lineA, lineB] for contradiction pair (Type G)
|
|
108
|
+
evidence_quote?: string
|
|
109
|
+
criterion_ref?: string // for Type H (unsatisfied forward-criterion)
|
|
110
|
+
confidence?: number
|
|
111
|
+
policy_tags?: string[]
|
|
112
|
+
// CitationVerifier annotation
|
|
113
|
+
citation_status?: CitationStatus
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export type EvidenceGrade = 'strong' | 'weak' | 'none'
|
|
117
|
+
|
|
118
|
+
export function gradeEvidence(issue: SealIssue): EvidenceGrade {
|
|
119
|
+
const hasFile = !!issue.evidence_file
|
|
120
|
+
const hasLines = !!(issue.evidence_lines && issue.evidence_lines.length > 0)
|
|
121
|
+
const hasQuote = !!issue.evidence_quote
|
|
122
|
+
const hasCriterionRef = !!issue.criterion_ref
|
|
123
|
+
|
|
124
|
+
// Type G: contradiction pair — both line spans present
|
|
125
|
+
const isTypeG = hasFile && hasLines && (issue.evidence_lines?.length ?? 0) >= 2 && hasQuote
|
|
126
|
+
|
|
127
|
+
// Type H: unsatisfied forward-criterion with criterion_ref
|
|
128
|
+
const isTypeH = hasCriterionRef && hasFile && hasLines
|
|
129
|
+
|
|
130
|
+
// Type A+B: file + lines present
|
|
131
|
+
const isAB = hasFile && hasLines
|
|
132
|
+
|
|
133
|
+
// Type D: quote references spec requirement or AC bullet (heuristic: quote contains AC- or SHALL/MUST)
|
|
134
|
+
const isTypeD = hasQuote && /\bAC-\d+\b|SHALL|MUST|SHOULD/i.test(issue.evidence_quote ?? '')
|
|
135
|
+
|
|
136
|
+
if (isTypeG || isTypeH || isAB || isTypeD) return 'strong'
|
|
137
|
+
|
|
138
|
+
// Type E: quote contains code/diff excerpt; Type F: AMBIGUITY issue type
|
|
139
|
+
const isTypeE = hasQuote && /```|diff --git|@@/.test(issue.evidence_quote ?? '')
|
|
140
|
+
const isTypeF = issue.type === 'AMBIGUITY'
|
|
141
|
+
|
|
142
|
+
if (isTypeE || isTypeF) return 'weak'
|
|
143
|
+
|
|
144
|
+
return 'none'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface LLMSignals {
|
|
148
|
+
suspected_issues: string[]
|
|
149
|
+
missing_requirements: string[]
|
|
150
|
+
possible_edge_cases: string[]
|
|
151
|
+
evidence_gaps: string[]
|
|
152
|
+
risk_guess: RiskLevel
|
|
153
|
+
confidence: number
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface PartialVerdict {
|
|
157
|
+
trust_score: number
|
|
158
|
+
risk_level: RiskLevel
|
|
159
|
+
deterministic_findings: SealIssue[]
|
|
160
|
+
missing_evidence: string[]
|
|
161
|
+
assumptions_detected: string[]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface TrustMemorySummary {
|
|
165
|
+
agent_id: string
|
|
166
|
+
reliability_score: number | null
|
|
167
|
+
drift_trend: 'improving' | 'stable' | 'degrading'
|
|
168
|
+
review_count: number
|
|
169
|
+
last_reviewed_at: number | null
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface SealVerdict {
|
|
173
|
+
verdict: Verdict
|
|
174
|
+
trust_score: number
|
|
175
|
+
risk_level: RiskLevel
|
|
176
|
+
summary: string
|
|
177
|
+
deterministic_findings: SealIssue[]
|
|
178
|
+
llm_findings: SealIssue[]
|
|
179
|
+
blocking_issues: SealIssue[]
|
|
180
|
+
non_blocking_issues: SealIssue[]
|
|
181
|
+
missing_evidence: string[]
|
|
182
|
+
assumptions_detected: string[]
|
|
183
|
+
advisory_notes: string[] // informational — do not affect verdict or score
|
|
184
|
+
next_action: string
|
|
185
|
+
schema_version: string
|
|
186
|
+
// New fields for reference gaps
|
|
187
|
+
score_breakdown: ScoreBreakdown
|
|
188
|
+
fabricated_evidence: FabricatedEvidence[]
|
|
189
|
+
trust_memory_summary?: TrustMemorySummary // present when context.agent_id is set and TrustMemory is wired
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface SealExtension {
|
|
193
|
+
name: string
|
|
194
|
+
description: string
|
|
195
|
+
check(input: SealInput): SealIssue[]
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface LLMReviewerAdapter {
|
|
199
|
+
review(input: SealInput, partial: PartialVerdict): Promise<LLMSignals> | LLMSignals
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export const SCHEMA_VERSION = '0.2.0'
|
|
203
|
+
|
|
204
|
+
export const VERDICT_ORDER: Verdict[] = ['PASS', 'PASS_WITH_WARNINGS', 'REVISE', 'ESCALATE_TO_HUMAN', 'BLOCK']
|
|
205
|
+
|
|
206
|
+
// Semantic worst-of comparison — safe against enum reordering because it reads VERDICT_ORDER, not integer values.
|
|
207
|
+
// Use this everywhere instead of arithmetic max over enum indices.
|
|
208
|
+
export function worstOf(a: Verdict, b: Verdict): Verdict {
|
|
209
|
+
return VERDICT_ORDER.indexOf(a) >= VERDICT_ORDER.indexOf(b) ? a : b
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Alias for backward compatibility — prefer worstOf in new code
|
|
213
|
+
export const maxVerdict = worstOf
|
|
214
|
+
|
|
215
|
+
export function verdictFromScore(score: number, hasBlocking: boolean): Verdict {
|
|
216
|
+
if (hasBlocking) return maxVerdict(scoreToVerdict(score), 'REVISE')
|
|
217
|
+
return scoreToVerdict(score)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function scoreToVerdict(score: number): Verdict {
|
|
221
|
+
if (score >= 85) return 'PASS'
|
|
222
|
+
if (score >= 70) return 'PASS_WITH_WARNINGS'
|
|
223
|
+
if (score >= 50) return 'REVISE'
|
|
224
|
+
if (score >= 30) return 'ESCALATE_TO_HUMAN'
|
|
225
|
+
return 'BLOCK'
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const NEXT_ACTION: Record<Verdict, string> = {
|
|
229
|
+
PASS: 'Proceed',
|
|
230
|
+
PASS_WITH_WARNINGS: 'Proceed with caution — review warnings',
|
|
231
|
+
REVISE: 'Return to producing agent with blocking_issues',
|
|
232
|
+
ESCALATE_TO_HUMAN: 'Halt — requires human review before continuing',
|
|
233
|
+
BLOCK: 'Halt — do not proceed',
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function isBlocking(severity: SealIssue['severity']): boolean {
|
|
237
|
+
return severity === 'CRITICAL' || severity === 'HIGH'
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function makeIssue(partial: Omit<SealIssue, 'is_blocking'>): SealIssue {
|
|
241
|
+
return { ...partial, is_blocking: isBlocking(partial.severity) }
|
|
242
|
+
}
|