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,226 @@
|
|
|
1
|
+
import { makeIssue } from '../types.js';
|
|
2
|
+
const GROUPS = [
|
|
3
|
+
// Group A — Completeness
|
|
4
|
+
{
|
|
5
|
+
id: 'A',
|
|
6
|
+
label: 'complete',
|
|
7
|
+
patterns: [
|
|
8
|
+
/\bfully\s+implemented\b/gi,
|
|
9
|
+
/\bfully\s+(?:tested|working|functional)\b/gi,
|
|
10
|
+
/\bhandles?\s+all\s+(edge\s+)?cases\b/gi,
|
|
11
|
+
/\b100%\s+complete\b/gi,
|
|
12
|
+
],
|
|
13
|
+
requires_evidence: false,
|
|
14
|
+
severity: 'MEDIUM',
|
|
15
|
+
},
|
|
16
|
+
// Group B — Correctness
|
|
17
|
+
{
|
|
18
|
+
id: 'B',
|
|
19
|
+
label: 'correctness',
|
|
20
|
+
patterns: [
|
|
21
|
+
/\ball\s+tests?\s+pass(?:ed)?\b/gi,
|
|
22
|
+
/\bverified\s+correct\b/gi,
|
|
23
|
+
/\bbug-free\b/gi,
|
|
24
|
+
/\bguaranteed\b/gi,
|
|
25
|
+
],
|
|
26
|
+
requires_evidence: true,
|
|
27
|
+
evidence_type: 'test_log',
|
|
28
|
+
severity: 'MEDIUM',
|
|
29
|
+
},
|
|
30
|
+
// Group C — Safety/Security
|
|
31
|
+
{
|
|
32
|
+
id: 'C',
|
|
33
|
+
label: 'security',
|
|
34
|
+
patterns: [
|
|
35
|
+
/\bsecure\b/gi,
|
|
36
|
+
/\bno\s+security\s+impact\b/gi,
|
|
37
|
+
/\bno\s+vulnerabilit(?:y|ies)\b/gi,
|
|
38
|
+
],
|
|
39
|
+
requires_evidence: true,
|
|
40
|
+
evidence_type: 'security',
|
|
41
|
+
severity: 'HIGH',
|
|
42
|
+
},
|
|
43
|
+
// Group D — Compatibility
|
|
44
|
+
{
|
|
45
|
+
id: 'D',
|
|
46
|
+
label: 'compatibility',
|
|
47
|
+
patterns: [
|
|
48
|
+
/\bbackward\s+compatible\b/gi,
|
|
49
|
+
/\bno\s+breaking\s+changes?\b/gi,
|
|
50
|
+
/\bsafe\s+to\s+deploy\b/gi,
|
|
51
|
+
],
|
|
52
|
+
requires_evidence: true,
|
|
53
|
+
evidence_type: 'compatibility',
|
|
54
|
+
severity: 'HIGH',
|
|
55
|
+
correlation_fn: (structuralClaims) => {
|
|
56
|
+
// If there are any endpoint changes, compatibility claims need extra scrutiny
|
|
57
|
+
return structuralClaims.some(c => c.type === 'structural_endpoint' || c.type === 'structural_migration');
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
// Group E — Readiness
|
|
61
|
+
{
|
|
62
|
+
id: 'E',
|
|
63
|
+
label: 'readiness',
|
|
64
|
+
patterns: [
|
|
65
|
+
/\bproduction[- ]ready\b/gi,
|
|
66
|
+
/\bready\s+to\s+ship\b/gi,
|
|
67
|
+
/\bdeploy-ready\b/gi,
|
|
68
|
+
/\bready\s+for\s+(production|deploy|release)\b/gi,
|
|
69
|
+
],
|
|
70
|
+
requires_evidence: true,
|
|
71
|
+
evidence_type: 'test_log',
|
|
72
|
+
severity: 'HIGH',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
function hasEvidenceEvidence(evidence, type) {
|
|
76
|
+
switch (type) {
|
|
77
|
+
case 'test_log':
|
|
78
|
+
return evidence.test_log.trim().length > 0;
|
|
79
|
+
case 'security':
|
|
80
|
+
return evidence.test_log.trim().length > 0 &&
|
|
81
|
+
/security|auth|unauthorized|pentest|vuln|safe|protect/i.test(evidence.test_log);
|
|
82
|
+
case 'compatibility':
|
|
83
|
+
return evidence.diff.trim().length > 0; // diff itself is a form of compatibility evidence
|
|
84
|
+
default:
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export class ConfidenceLanguageDetector {
|
|
89
|
+
static detect(params) {
|
|
90
|
+
const { output, risk_level, evidence, deduped_spans, structural_claims = [] } = params;
|
|
91
|
+
const issues = [];
|
|
92
|
+
const advisory_notes = [];
|
|
93
|
+
const matched_groups = [];
|
|
94
|
+
let trust_deductions = 0;
|
|
95
|
+
const riskOrder = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
|
|
96
|
+
const isHighPlus = riskOrder.indexOf(risk_level) >= riskOrder.indexOf('HIGH');
|
|
97
|
+
const isLowEvidence = evidence.references.length === 0 && evidence.test_log.trim() === '' &&
|
|
98
|
+
evidence.build_log.trim() === '' && evidence.diff.trim() === '';
|
|
99
|
+
// Count total matches for OVERCONFIDENT_PATTERN advisory
|
|
100
|
+
let totalMatches = 0;
|
|
101
|
+
const allPhrases = [];
|
|
102
|
+
// Generic overconfident phrases (catch-all for phrases not in groups A-E)
|
|
103
|
+
const GENERIC_OVERCONFIDENT = /\b(definitely|all\s+good|no\s+issues|completely)\b/gi;
|
|
104
|
+
let genMatch;
|
|
105
|
+
while ((genMatch = GENERIC_OVERCONFIDENT.exec(output)) !== null) {
|
|
106
|
+
totalMatches++;
|
|
107
|
+
allPhrases.push(genMatch[0]);
|
|
108
|
+
matched_groups.push({ group: 'generic', phrase: genMatch[0] });
|
|
109
|
+
trust_deductions += 5;
|
|
110
|
+
}
|
|
111
|
+
// CL402: hedging language on HIGH+ risk (backward compat)
|
|
112
|
+
const HEDGING_PATTERN = /\b(probably|should\s+work|seems|might|appears\s+to|I\s+think)\b/gi;
|
|
113
|
+
if (isHighPlus) {
|
|
114
|
+
HEDGING_PATTERN.lastIndex = 0;
|
|
115
|
+
if (HEDGING_PATTERN.exec(output) !== null) {
|
|
116
|
+
issues.push(makeIssue({
|
|
117
|
+
type: 'AMBIGUITY', severity: 'HIGH', layer: 'L4', source: 'core',
|
|
118
|
+
rule_id: 'CL402', required_verdict: 'ESCALATE_TO_HUMAN',
|
|
119
|
+
evidence: `Hedging language in ${risk_level} risk artifact`,
|
|
120
|
+
required_fix: 'Either assert with evidence or escalate to human review',
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const group of GROUPS) {
|
|
125
|
+
for (const pattern of group.patterns) {
|
|
126
|
+
pattern.lastIndex = 0;
|
|
127
|
+
let match;
|
|
128
|
+
while ((match = pattern.exec(output)) !== null) {
|
|
129
|
+
totalMatches++;
|
|
130
|
+
allPhrases.push(match[0]);
|
|
131
|
+
// Track matched group
|
|
132
|
+
matched_groups.push({ group: group.id, phrase: match[0] });
|
|
133
|
+
// Check if phrase is inside code fence (skip if deduped_spans contains it)
|
|
134
|
+
const spanKey = `${match.index}-${match.index + match[0].length}`;
|
|
135
|
+
if (deduped_spans.has(spanKey))
|
|
136
|
+
continue;
|
|
137
|
+
// Deduction for any overconfident phrase
|
|
138
|
+
trust_deductions += 5;
|
|
139
|
+
if (group.requires_evidence) {
|
|
140
|
+
const hasEvidence = hasEvidenceEvidence(evidence, group.evidence_type);
|
|
141
|
+
// Group D: check correlation with structural claims
|
|
142
|
+
if (group.id === 'D' && group.correlation_fn) {
|
|
143
|
+
const hasEndpointChanges = group.correlation_fn(structural_claims);
|
|
144
|
+
if (!hasEvidence && hasEndpointChanges) {
|
|
145
|
+
issues.push(makeIssue({
|
|
146
|
+
type: 'COMPATIBILITY_RISK',
|
|
147
|
+
severity: 'HIGH',
|
|
148
|
+
layer: 'L4',
|
|
149
|
+
source: 'core',
|
|
150
|
+
rule_id: `CL-${group.id}01`,
|
|
151
|
+
required_verdict: isHighPlus ? 'ESCALATE_TO_HUMAN' : 'REVISE',
|
|
152
|
+
evidence: `"${match[0]}" claimed but endpoint/migration changes exist and no compatibility evidence provided`,
|
|
153
|
+
required_fix: 'Provide backward-compatibility analysis or remove the claim',
|
|
154
|
+
}));
|
|
155
|
+
trust_deductions += 15;
|
|
156
|
+
}
|
|
157
|
+
else if (!hasEvidence) {
|
|
158
|
+
issues.push(makeIssue({
|
|
159
|
+
type: 'MISSING_EVIDENCE',
|
|
160
|
+
severity: group.severity,
|
|
161
|
+
layer: 'L3',
|
|
162
|
+
source: 'core',
|
|
163
|
+
rule_id: `CL-${group.id}02`,
|
|
164
|
+
evidence: `"${match[0]}" without supporting ${group.evidence_type} evidence`,
|
|
165
|
+
required_fix: `Provide ${group.evidence_type} evidence or qualify the claim`,
|
|
166
|
+
}));
|
|
167
|
+
trust_deductions += 15;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else if (!hasEvidence && group.id === 'B') {
|
|
171
|
+
// Group B: correctness without test evidence
|
|
172
|
+
issues.push(makeIssue({
|
|
173
|
+
type: 'MISSING_EVIDENCE',
|
|
174
|
+
severity: 'MEDIUM',
|
|
175
|
+
layer: 'L3',
|
|
176
|
+
source: 'core',
|
|
177
|
+
rule_id: `CL-${group.id}01`,
|
|
178
|
+
evidence: `"${match[0]}" without test execution evidence`,
|
|
179
|
+
required_fix: 'Provide test_log demonstrating test coverage',
|
|
180
|
+
}));
|
|
181
|
+
trust_deductions += 10;
|
|
182
|
+
}
|
|
183
|
+
else if (!hasEvidence && group.id === 'C') {
|
|
184
|
+
// Group C: security without security evidence
|
|
185
|
+
issues.push(makeIssue({
|
|
186
|
+
type: 'MISSING_EVIDENCE',
|
|
187
|
+
severity: 'HIGH',
|
|
188
|
+
layer: 'L3',
|
|
189
|
+
source: 'core',
|
|
190
|
+
rule_id: `CL-${group.id}01`,
|
|
191
|
+
evidence: `"${match[0]}" without security review evidence`,
|
|
192
|
+
required_fix: 'Provide security test log or security reasoning',
|
|
193
|
+
}));
|
|
194
|
+
trust_deductions += 20;
|
|
195
|
+
}
|
|
196
|
+
else if (!hasEvidence && group.id === 'E') {
|
|
197
|
+
// Group E: readiness at HIGH+ risk
|
|
198
|
+
if (isHighPlus && isLowEvidence) {
|
|
199
|
+
issues.push(makeIssue({
|
|
200
|
+
type: 'MISSING_EVIDENCE',
|
|
201
|
+
severity: 'HIGH',
|
|
202
|
+
layer: 'L3',
|
|
203
|
+
source: 'core',
|
|
204
|
+
rule_id: `CL-${group.id}01`,
|
|
205
|
+
evidence: `"${match[0]}" at ${risk_level} risk without supporting evidence`,
|
|
206
|
+
required_fix: 'Provide test evidence or reduce risk level before claiming readiness',
|
|
207
|
+
}));
|
|
208
|
+
trust_deductions += 20;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Non-blocking advisory note for 3+ matches at HIGH+ risk
|
|
213
|
+
if (totalMatches >= 3 && isHighPlus) {
|
|
214
|
+
advisory_notes.push(`Multiple overconfident patterns (${totalMatches}) at ${risk_level} risk — review claims carefully`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Also keep CL401/CL402 for backward compatibility
|
|
220
|
+
if (isLowEvidence && matched_groups.length > 0) {
|
|
221
|
+
advisory_notes.push(`CL401: overconfident language without supporting evidence — consider qualifying or adding evidence`);
|
|
222
|
+
}
|
|
223
|
+
return { issues, trust_deductions, advisory_notes, matched_groups };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=confidence-language-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence-language-detector.js","sourceRoot":"","sources":["../../src/detectors/confidence-language-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,SAAS,EAAE,MAAM,aAAa,CAAA;AAoB5F,MAAM,MAAM,GAAsB;IAChC,yBAAyB;IACzB;QACE,EAAE,EAAE,GAAG;QACP,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE;YACR,2BAA2B;YAC3B,6CAA6C;YAC7C,wCAAwC;YACxC,uBAAuB;SACxB;QACD,iBAAiB,EAAE,KAAK;QACxB,QAAQ,EAAE,QAAQ;KACnB;IACD,wBAAwB;IACxB;QACE,EAAE,EAAE,GAAG;QACP,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE;YACR,kCAAkC;YAClC,0BAA0B;YAC1B,gBAAgB;YAChB,kBAAkB;SACnB;QACD,iBAAiB,EAAE,IAAI;QACvB,aAAa,EAAE,UAAU;QACzB,QAAQ,EAAE,QAAQ;KACnB;IACD,4BAA4B;IAC5B;QACE,EAAE,EAAE,GAAG;QACP,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE;YACR,cAAc;YACd,8BAA8B;YAC9B,kCAAkC;SACnC;QACD,iBAAiB,EAAE,IAAI;QACvB,aAAa,EAAE,UAAU;QACzB,QAAQ,EAAE,MAAM;KACjB;IACD,0BAA0B;IAC1B;QACE,EAAE,EAAE,GAAG;QACP,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE;YACR,6BAA6B;YAC7B,gCAAgC;YAChC,0BAA0B;SAC3B;QACD,iBAAiB,EAAE,IAAI;QACvB,aAAa,EAAE,eAAe;QAC9B,QAAQ,EAAE,MAAM;QAChB,cAAc,EAAE,CAAC,gBAAmC,EAAE,EAAE;YACtD,8EAA8E;YAC9E,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAA;QAC1G,CAAC;KACF;IACD,sBAAsB;IACtB;QACE,EAAE,EAAE,GAAG;QACP,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE;YACR,2BAA2B;YAC3B,yBAAyB;YACzB,oBAAoB;YACpB,iDAAiD;SAClD;QACD,iBAAiB,EAAE,IAAI;QACvB,aAAa,EAAE,UAAU;QACzB,QAAQ,EAAE,MAAM;KACjB;CACF,CAAA;AASD,SAAS,mBAAmB,CAAC,QAAsB,EAAE,IAAY;IAC/D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAA;QAC5C,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gBACxC,uDAAuD,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACnF,KAAK,eAAe;YAClB,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAA,CAAC,kDAAkD;QAC3F;YACE,OAAO,KAAK,CAAA;IAChB,CAAC;AACH,CAAC;AAED,MAAM,OAAO,0BAA0B;IACrC,MAAM,CAAC,MAAM,CAAC,MAMb;QACC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,iBAAiB,GAAG,EAAE,EAAE,GAAG,MAAM,CAAA;QACtF,MAAM,MAAM,GAAgB,EAAE,CAAA;QAC9B,MAAM,cAAc,GAAa,EAAE,CAAA;QACnC,MAAM,cAAc,GAA6C,EAAE,CAAA;QACnE,IAAI,gBAAgB,GAAG,CAAC,CAAA;QAExB,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAA;QACvD,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAC7E,MAAM,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;YACvF,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;QAEjE,yDAAyD;QACzD,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,MAAM,UAAU,GAAa,EAAE,CAAA;QAE/B,0EAA0E;QAC1E,MAAM,qBAAqB,GAAG,sDAAsD,CAAA;QACpF,IAAI,QAAgC,CAAA;QACpC,OAAO,CAAC,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAChE,YAAY,EAAE,CAAA;YACd,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5B,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YAC9D,gBAAgB,IAAI,CAAC,CAAA;QACvB,CAAC;QAED,0DAA0D;QAC1D,MAAM,eAAe,GAAG,mEAAmE,CAAA;QAC3F,IAAI,UAAU,EAAE,CAAC;YACf,eAAe,CAAC,SAAS,GAAG,CAAC,CAAA;YAC7B,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;oBACpB,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM;oBAChE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB;oBACvD,QAAQ,EAAE,uBAAuB,UAAU,gBAAgB;oBAC3D,YAAY,EAAE,yDAAyD;iBACxE,CAAC,CAAC,CAAA;YACL,CAAC;QACH,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACrC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAA;gBACrB,IAAI,KAA6B,CAAA;gBACjC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBAC/C,YAAY,EAAE,CAAA;oBACd,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;oBAEzB,sBAAsB;oBACtB,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;oBAE1D,2EAA2E;oBAC3E,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAA;oBACjE,IAAI,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC;wBAAE,SAAQ;oBAExC,yCAAyC;oBACzC,gBAAgB,IAAI,CAAC,CAAA;oBAErB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;wBAC5B,MAAM,WAAW,GAAG,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAc,CAAC,CAAA;wBAEvE,oDAAoD;wBACpD,IAAI,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;4BAC7C,MAAM,kBAAkB,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAA;4BAClE,IAAI,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;gCACvC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;oCACpB,IAAI,EAAE,oBAAoB;oCAC1B,QAAQ,EAAE,MAAM;oCAChB,KAAK,EAAE,IAAI;oCACX,MAAM,EAAE,MAAM;oCACd,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;oCAC3B,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ;oCAC7D,QAAQ,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,uFAAuF;oCAC7G,YAAY,EAAE,6DAA6D;iCAC5E,CAAC,CAAC,CAAA;gCACH,gBAAgB,IAAI,EAAE,CAAA;4BACxB,CAAC;iCAAM,IAAI,CAAC,WAAW,EAAE,CAAC;gCACxB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;oCACpB,IAAI,EAAE,kBAAkB;oCACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oCACxB,KAAK,EAAE,IAAI;oCACX,MAAM,EAAE,MAAM;oCACd,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;oCAC3B,QAAQ,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,wBAAwB,KAAK,CAAC,aAAa,WAAW;oCAC5E,YAAY,EAAE,WAAW,KAAK,CAAC,aAAa,gCAAgC;iCAC7E,CAAC,CAAC,CAAA;gCACH,gBAAgB,IAAI,EAAE,CAAA;4BACxB,CAAC;wBACH,CAAC;6BAAM,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC;4BAC5C,6CAA6C;4BAC7C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;gCACpB,IAAI,EAAE,kBAAkB;gCACxB,QAAQ,EAAE,QAAQ;gCAClB,KAAK,EAAE,IAAI;gCACX,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;gCAC3B,QAAQ,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,mCAAmC;gCACzD,YAAY,EAAE,8CAA8C;6BAC7D,CAAC,CAAC,CAAA;4BACH,gBAAgB,IAAI,EAAE,CAAA;wBACxB,CAAC;6BAAM,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC;4BAC5C,8CAA8C;4BAC9C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;gCACpB,IAAI,EAAE,kBAAkB;gCACxB,QAAQ,EAAE,MAAM;gCAChB,KAAK,EAAE,IAAI;gCACX,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;gCAC3B,QAAQ,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,oCAAoC;gCAC1D,YAAY,EAAE,iDAAiD;6BAChE,CAAC,CAAC,CAAA;4BACH,gBAAgB,IAAI,EAAE,CAAA;wBACxB,CAAC;6BAAM,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC;4BAC5C,mCAAmC;4BACnC,IAAI,UAAU,IAAI,aAAa,EAAE,CAAC;gCAChC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;oCACpB,IAAI,EAAE,kBAAkB;oCACxB,QAAQ,EAAE,MAAM;oCAChB,KAAK,EAAE,IAAI;oCACX,MAAM,EAAE,MAAM;oCACd,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;oCAC3B,QAAQ,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,UAAU,mCAAmC;oCAC3E,YAAY,EAAE,sEAAsE;iCACrF,CAAC,CAAC,CAAA;gCACH,gBAAgB,IAAI,EAAE,CAAA;4BACxB,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,0DAA0D;oBAC1D,IAAI,YAAY,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;wBACpC,cAAc,CAAC,IAAI,CAAC,oCAAoC,YAAY,QAAQ,UAAU,iCAAiC,CAAC,CAAA;oBAC1H,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,IAAI,aAAa,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,cAAc,CAAC,IAAI,CAAC,oGAAoG,CAAC,CAAA;QAC3H,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,CAAA;IACrE,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SealIssue } from '../types.js';
|
|
2
|
+
export interface ContradictionDetectorInput {
|
|
3
|
+
artifact: string;
|
|
4
|
+
artifact_file?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ContradictionResult {
|
|
7
|
+
issues: SealIssue[];
|
|
8
|
+
confirmed_strong_fields: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class ContradictionDetector {
|
|
11
|
+
static detect(input: ContradictionDetectorInput): ContradictionResult;
|
|
12
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { makeIssue } from '../types.js';
|
|
2
|
+
// Conflict patterns: [write side pattern, readonly side pattern, description]
|
|
3
|
+
const CONFLICT_PAIRS = [
|
|
4
|
+
[/\b(writes?|modifies?|overwrites?|creates?)\s+(\S+)/gi, /\b(\S+)\s+is\s+(read.?only|append.?only|immutable)\b/gi, 'write vs readonly constraint'],
|
|
5
|
+
[/\b(removes?|deletes?|drops?)\s+(\S+)/gi, /\b(requires?|depends?\s+on|needs?)\s+(\S+)/gi, 'remove vs dependency'],
|
|
6
|
+
[/step\s+(\d+)\s+.*?(writes?|creates?)\s+(\S+)/gi, /(\S+)\s+must\s+(exist|be\s+present)\s+before\s+step\s+(\d+)/gi, 'step ordering'],
|
|
7
|
+
];
|
|
8
|
+
// Non-goal violation: "non-goal: X" but body contains "SHALL/WILL/MUST X"
|
|
9
|
+
const NON_GOAL_PATTERN = /non.?goals?\s*:?\s*([^\n]+)/gi;
|
|
10
|
+
const GOAL_CLAIM_PATTERN = /\b(?:shall|will|must|implement)\s+(\S+(?:\s+\S+){0,5})/gi;
|
|
11
|
+
function parseLines(text) {
|
|
12
|
+
return text.split('\n');
|
|
13
|
+
}
|
|
14
|
+
// Strip code fences and inline code so pattern matching operates on prose only
|
|
15
|
+
function stripCode(text) {
|
|
16
|
+
return text
|
|
17
|
+
.replace(/```[\s\S]*?```/g, ' ') // block fences
|
|
18
|
+
.replace(/`[^`\n]+`/g, ' ') // inline code
|
|
19
|
+
.replace(/^\s*[-*]\s+\[[ x]\]\s*/gm, ' '); // task checkboxes
|
|
20
|
+
}
|
|
21
|
+
function extractSections(text) {
|
|
22
|
+
const lines = parseLines(text);
|
|
23
|
+
const sections = [];
|
|
24
|
+
let current = null;
|
|
25
|
+
for (let i = 0; i < lines.length; i++) {
|
|
26
|
+
const line = lines[i];
|
|
27
|
+
if (/^#{1,4}\s/.test(line)) {
|
|
28
|
+
if (current)
|
|
29
|
+
sections.push(current);
|
|
30
|
+
current = { heading: line.replace(/^#{1,4}\s*/, ''), body: '', startLine: i + 1 };
|
|
31
|
+
}
|
|
32
|
+
else if (current) {
|
|
33
|
+
current.body += line + '\n';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (current)
|
|
37
|
+
sections.push(current);
|
|
38
|
+
return sections;
|
|
39
|
+
}
|
|
40
|
+
function findLineNumber(text, searchStr) {
|
|
41
|
+
const lines = parseLines(text);
|
|
42
|
+
for (let i = 0; i < lines.length; i++) {
|
|
43
|
+
if (lines[i].includes(searchStr))
|
|
44
|
+
return i + 1;
|
|
45
|
+
}
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
export class ContradictionDetector {
|
|
49
|
+
static detect(input) {
|
|
50
|
+
const { artifact, artifact_file = 'artifact' } = input;
|
|
51
|
+
const issues = [];
|
|
52
|
+
const sections = extractSections(artifact);
|
|
53
|
+
// Pairwise cross-section scan for write/readonly conflicts
|
|
54
|
+
for (let i = 0; i < sections.length; i++) {
|
|
55
|
+
for (let j = 0; j < sections.length; j++) {
|
|
56
|
+
if (i === j)
|
|
57
|
+
continue;
|
|
58
|
+
const secA = sections[i];
|
|
59
|
+
const secB = sections[j];
|
|
60
|
+
const proseA = stripCode(secA.body);
|
|
61
|
+
const proseB = stripCode(secB.body);
|
|
62
|
+
for (const [writePattern, readonlyPattern, desc] of CONFLICT_PAIRS) {
|
|
63
|
+
writePattern.lastIndex = 0;
|
|
64
|
+
readonlyPattern.lastIndex = 0;
|
|
65
|
+
const writeMatcher = writePattern.exec(proseA);
|
|
66
|
+
const readonlyMatcher = readonlyPattern.exec(proseB);
|
|
67
|
+
if (!writeMatcher || !readonlyMatcher)
|
|
68
|
+
continue;
|
|
69
|
+
// Find actual position in original (unstripped) body, since writeMatcher.index
|
|
70
|
+
// is relative to proseA (stripped) which is shorter when code blocks exist.
|
|
71
|
+
const actualIndexA = secA.body.indexOf(writeMatcher[0]);
|
|
72
|
+
const actualIndexB = secB.body.indexOf(readonlyMatcher[0]);
|
|
73
|
+
const lineA = actualIndexA >= 0
|
|
74
|
+
? secA.startLine + (secA.body.slice(0, actualIndexA).split('\n').length - 1)
|
|
75
|
+
: secA.startLine;
|
|
76
|
+
const lineB = actualIndexB >= 0
|
|
77
|
+
? secB.startLine + (secB.body.slice(0, actualIndexB).split('\n').length - 1)
|
|
78
|
+
: secB.startLine;
|
|
79
|
+
// Only emit once per pair (lower section index first)
|
|
80
|
+
if (i > j)
|
|
81
|
+
continue;
|
|
82
|
+
const quote = `§${secA.heading}: '${writeMatcher[0]}' || §${secB.heading}: '${readonlyMatcher[0]}'`;
|
|
83
|
+
issues.push({
|
|
84
|
+
...makeIssue({
|
|
85
|
+
type: 'LOGIC_BUG',
|
|
86
|
+
severity: 'HIGH',
|
|
87
|
+
layer: 'L1',
|
|
88
|
+
source: 'core',
|
|
89
|
+
rule_id: 'PR001',
|
|
90
|
+
required_verdict: 'BLOCK',
|
|
91
|
+
trust_deduction: 20,
|
|
92
|
+
evidence: `Contradiction (${desc}): ${quote}`,
|
|
93
|
+
suggested_fix: `Reconcile §${secA.heading} with §${secB.heading}`,
|
|
94
|
+
}),
|
|
95
|
+
evidence_file: artifact_file,
|
|
96
|
+
evidence_lines: [lineA, lineB],
|
|
97
|
+
evidence_quote: quote,
|
|
98
|
+
confidence: 0.85,
|
|
99
|
+
policy_tags: ['consistency'],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Non-goal violation scan — operate on prose only
|
|
105
|
+
const artifactProse = stripCode(artifact);
|
|
106
|
+
NON_GOAL_PATTERN.lastIndex = 0;
|
|
107
|
+
let ngMatch;
|
|
108
|
+
while ((ngMatch = NON_GOAL_PATTERN.exec(artifactProse)) !== null) {
|
|
109
|
+
const ngText = ngMatch[1].trim().toLowerCase();
|
|
110
|
+
// Search ngMatch text in artifactProse (stripCode preserves line structure
|
|
111
|
+
// even though content length changes), so the same text is on the same line.
|
|
112
|
+
const ngLine = findLineNumber(artifactProse, ngMatch[0].slice(0, 40));
|
|
113
|
+
GOAL_CLAIM_PATTERN.lastIndex = 0;
|
|
114
|
+
let gcMatch;
|
|
115
|
+
while ((gcMatch = GOAL_CLAIM_PATTERN.exec(artifactProse)) !== null) {
|
|
116
|
+
// Extract significant words from the claim phrase (captured group after verb)
|
|
117
|
+
const claimPhrase = (gcMatch[1] ?? '').toLowerCase();
|
|
118
|
+
const claimWords = claimPhrase.split(/\s+/).filter(w => w.length > 4);
|
|
119
|
+
const ngWords = ngText.split(/\s+/).filter(w => w.length > 4);
|
|
120
|
+
// Require word overlap between non-goal text and claim line
|
|
121
|
+
const hasOverlap = ngWords.length > 0 && claimWords.length > 0 &&
|
|
122
|
+
claimWords.some(cw => ngWords.some(nw => nw.includes(cw) || cw.includes(nw)));
|
|
123
|
+
if (hasOverlap) {
|
|
124
|
+
const claimLine = findLineNumber(artifactProse, gcMatch[0].slice(0, 40));
|
|
125
|
+
if (Math.abs(claimLine - ngLine) < 3)
|
|
126
|
+
continue; // same line, skip
|
|
127
|
+
const quote = `Non-goal: '${ngText}' || Goal claim: '${gcMatch[0]}'`;
|
|
128
|
+
issues.push({
|
|
129
|
+
...makeIssue({
|
|
130
|
+
type: 'LOGIC_BUG',
|
|
131
|
+
severity: 'HIGH',
|
|
132
|
+
layer: 'L1',
|
|
133
|
+
source: 'core',
|
|
134
|
+
rule_id: 'PR001',
|
|
135
|
+
required_verdict: 'BLOCK',
|
|
136
|
+
trust_deduction: 20,
|
|
137
|
+
evidence: `Non-goal violated: ${quote}`,
|
|
138
|
+
suggested_fix: 'Remove claim or move item out of non-goals',
|
|
139
|
+
}),
|
|
140
|
+
evidence_file: artifact_file,
|
|
141
|
+
evidence_lines: [ngLine, claimLine],
|
|
142
|
+
evidence_quote: quote,
|
|
143
|
+
confidence: 0.8,
|
|
144
|
+
policy_tags: ['consistency'],
|
|
145
|
+
});
|
|
146
|
+
break; // one violation per non-goal entry
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { issues, confirmed_strong_fields: 0 };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=contradiction-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contradiction-detector.js","sourceRoot":"","sources":["../../src/detectors/contradiction-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SealIssue } from '../types.js';
|
|
2
|
+
export interface LockedCriterion {
|
|
3
|
+
id: string;
|
|
4
|
+
text: string;
|
|
5
|
+
source_file?: string;
|
|
6
|
+
source_line?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CriteriaCoverageInput {
|
|
9
|
+
artifact: string;
|
|
10
|
+
artifact_file?: string;
|
|
11
|
+
locked_criteria: LockedCriterion[];
|
|
12
|
+
}
|
|
13
|
+
export interface CriteriaCoverageResult {
|
|
14
|
+
issues: SealIssue[];
|
|
15
|
+
confirmed_strong_fields: number;
|
|
16
|
+
no_criteria_escalate: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class CriteriaCoverageDetector {
|
|
19
|
+
static detect(input: CriteriaCoverageInput): CriteriaCoverageResult;
|
|
20
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { makeIssue } from '../types.js';
|
|
2
|
+
function isCovered(criterion, artifact) {
|
|
3
|
+
const lower = artifact.toLowerCase();
|
|
4
|
+
// Direct AC id mention
|
|
5
|
+
if (lower.includes(criterion.id.toLowerCase()))
|
|
6
|
+
return true;
|
|
7
|
+
// Keyword coverage: extract significant words (>4 chars) from criterion text
|
|
8
|
+
const words = criterion.text
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/[^\w\s]/g, ' ')
|
|
11
|
+
.split(/\s+/)
|
|
12
|
+
.filter(w => w.length > 4)
|
|
13
|
+
.filter(w => !['shall', 'must', 'should', 'when', 'then', 'given', 'that', 'this', 'with'].includes(w));
|
|
14
|
+
if (words.length === 0)
|
|
15
|
+
return false;
|
|
16
|
+
// Require at least half of significant words present in artifact
|
|
17
|
+
const matched = words.filter(w => lower.includes(w)).length;
|
|
18
|
+
return matched / words.length >= 0.5;
|
|
19
|
+
}
|
|
20
|
+
export class CriteriaCoverageDetector {
|
|
21
|
+
static detect(input) {
|
|
22
|
+
const { artifact, artifact_file = 'artifact', locked_criteria } = input;
|
|
23
|
+
// Preflight: no locked criteria → ESCALATE
|
|
24
|
+
if (!locked_criteria || locked_criteria.length === 0) {
|
|
25
|
+
return {
|
|
26
|
+
issues: [{
|
|
27
|
+
...makeIssue({
|
|
28
|
+
type: 'AMBIGUITY',
|
|
29
|
+
severity: 'MEDIUM', // non-blocking — escalation comes from required_verdict, not severity
|
|
30
|
+
layer: 'L1',
|
|
31
|
+
source: 'core',
|
|
32
|
+
rule_id: 'PR002',
|
|
33
|
+
required_verdict: 'ESCALATE_TO_HUMAN',
|
|
34
|
+
trust_deduction: 15,
|
|
35
|
+
evidence: 'No locked acceptance criteria — cannot measure coverage against fixed yardstick',
|
|
36
|
+
suggested_fix: 'Lock criteria in intent.md or self-check.md BEFORE generating the artifact',
|
|
37
|
+
}),
|
|
38
|
+
policy_tags: ['coverage'],
|
|
39
|
+
confidence: 1.0,
|
|
40
|
+
}],
|
|
41
|
+
confirmed_strong_fields: 0,
|
|
42
|
+
no_criteria_escalate: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const issues = [];
|
|
46
|
+
let confirmed = 0;
|
|
47
|
+
for (const criterion of locked_criteria) {
|
|
48
|
+
if (isCovered(criterion, artifact)) {
|
|
49
|
+
confirmed++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// Uncovered → SPEC_MISMATCH, Type H
|
|
53
|
+
const sourceFile = criterion.source_file ?? 'intent.md';
|
|
54
|
+
const sourceLine = criterion.source_line ?? 1;
|
|
55
|
+
const quote = `${criterion.id} ${criterion.text.length > 120 ? criterion.text.slice(0, 120) + '…' : criterion.text} — no artifact section addresses this`;
|
|
56
|
+
issues.push({
|
|
57
|
+
...makeIssue({
|
|
58
|
+
type: 'SPEC_MISMATCH',
|
|
59
|
+
severity: 'MEDIUM',
|
|
60
|
+
layer: 'L1',
|
|
61
|
+
source: 'core',
|
|
62
|
+
rule_id: 'PR002',
|
|
63
|
+
required_verdict: 'REVISE',
|
|
64
|
+
trust_deduction: 10,
|
|
65
|
+
evidence: `Uncovered criterion: ${criterion.id} — ${criterion.text.slice(0, 80)}`,
|
|
66
|
+
suggested_fix: `Add a section in ${artifact_file} addressing: ${criterion.text.slice(0, 80)}`,
|
|
67
|
+
}),
|
|
68
|
+
evidence_file: sourceFile,
|
|
69
|
+
evidence_lines: [sourceLine],
|
|
70
|
+
evidence_quote: quote,
|
|
71
|
+
criterion_ref: criterion.id,
|
|
72
|
+
confidence: 0.8,
|
|
73
|
+
policy_tags: ['coverage'],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return { issues, confirmed_strong_fields: confirmed, no_criteria_escalate: false };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=criteria-coverage-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criteria-coverage-detector.js","sourceRoot":"","sources":["../../src/detectors/criteria-coverage-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EvidenceEnvelope, EvidenceResult } from '../types.js';
|
|
2
|
+
export type EvidenceMode = 'portable' | 'filesystem';
|
|
3
|
+
export declare class EvidenceChecker {
|
|
4
|
+
static check(references: EvidenceEnvelope[], options?: {
|
|
5
|
+
mode: EvidenceMode;
|
|
6
|
+
}): EvidenceResult[];
|
|
7
|
+
private static checkOne;
|
|
8
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
export class EvidenceChecker {
|
|
3
|
+
static check(references, options = { mode: 'portable' }) {
|
|
4
|
+
return references.map(envelope => this.checkOne(envelope, options.mode));
|
|
5
|
+
}
|
|
6
|
+
static checkOne(envelope, mode) {
|
|
7
|
+
// Structural validation
|
|
8
|
+
if (envelope.type === 'file') {
|
|
9
|
+
if (!envelope.path || envelope.line === undefined || !envelope.snapshot) {
|
|
10
|
+
return {
|
|
11
|
+
envelope, structurally_valid: false, filesystem_verified: null,
|
|
12
|
+
mismatch_detail: 'Missing path, line, or snapshot',
|
|
13
|
+
citation_status: 'not_applicable',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (mode === 'filesystem') {
|
|
17
|
+
if (!existsSync(envelope.path)) {
|
|
18
|
+
return {
|
|
19
|
+
envelope, structurally_valid: true, filesystem_verified: false,
|
|
20
|
+
mismatch_detail: `File not found: ${envelope.path}`,
|
|
21
|
+
citation_status: 'phantom',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const lines = readFileSync(envelope.path, 'utf-8').split('\n');
|
|
25
|
+
const actualLine = lines[envelope.line - 1] ?? '';
|
|
26
|
+
if (actualLine.trim() !== envelope.snapshot.trim()) {
|
|
27
|
+
return {
|
|
28
|
+
envelope, structurally_valid: true, filesystem_verified: false,
|
|
29
|
+
mismatch_detail: `Snapshot mismatch at ${envelope.path}:${envelope.line}`,
|
|
30
|
+
citation_status: 'void',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
envelope, structurally_valid: true, filesystem_verified: true,
|
|
35
|
+
citation_status: 'verified',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Portable mode: structurally valid but no filesystem check
|
|
39
|
+
return {
|
|
40
|
+
envelope, structurally_valid: true, filesystem_verified: null,
|
|
41
|
+
citation_status: 'not_applicable',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (envelope.type === 'command') {
|
|
45
|
+
const hasRequiredFields = !!(envelope.command && envelope.output && envelope.exit_code !== undefined);
|
|
46
|
+
if (!hasRequiredFields) {
|
|
47
|
+
return {
|
|
48
|
+
envelope, structurally_valid: false, filesystem_verified: null,
|
|
49
|
+
mismatch_detail: 'Missing command, exit_code, or output',
|
|
50
|
+
citation_status: 'not_applicable',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const passed = envelope.exit_code === 0;
|
|
54
|
+
return {
|
|
55
|
+
envelope, structurally_valid: true, filesystem_verified: passed,
|
|
56
|
+
mismatch_detail: passed ? undefined : `Command failed with exit_code ${envelope.exit_code}`,
|
|
57
|
+
citation_status: passed ? 'verified' : 'void',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (envelope.type === 'url') {
|
|
61
|
+
const valid = !!(envelope.url && envelope.retrieved_at && envelope.content_snapshot);
|
|
62
|
+
return {
|
|
63
|
+
envelope, structurally_valid: valid, filesystem_verified: null,
|
|
64
|
+
citation_status: valid ? 'verified' : 'not_applicable',
|
|
65
|
+
mismatch_detail: valid ? undefined : 'Missing url, retrieved_at, or content_snapshot',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (envelope.type === 'text') {
|
|
69
|
+
const valid = !!(envelope.label && envelope.content);
|
|
70
|
+
return {
|
|
71
|
+
envelope, structurally_valid: valid, filesystem_verified: null,
|
|
72
|
+
citation_status: valid ? 'verified' : 'not_applicable',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (envelope.type === 'memory') {
|
|
76
|
+
const valid = !!(envelope.memory_key && envelope.retrieved_at && envelope.content_snapshot);
|
|
77
|
+
return {
|
|
78
|
+
envelope, structurally_valid: valid, filesystem_verified: null,
|
|
79
|
+
citation_status: valid ? 'verified' : 'not_applicable',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
envelope, structurally_valid: false, filesystem_verified: null,
|
|
84
|
+
mismatch_detail: 'Unknown envelope type',
|
|
85
|
+
citation_status: 'not_applicable',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=evidence-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-checker.js","sourceRoot":"","sources":["../../src/detectors/evidence-checker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAIlD,MAAM,OAAO,eAAe;IAC1B,MAAM,CAAC,KAAK,CAAC,UAA8B,EAAE,OAAO,GAA2B,EAAE,IAAI,EAAE,UAAU,EAAE;QACjG,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1E,CAAC;IAEO,MAAM,CAAC,QAAQ,CAAC,QAA0B,EAAE,IAAkB;QACpE,wBAAwB;QACxB,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACxE,OAAO;oBACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;oBAC9D,eAAe,EAAE,iCAAiC;oBAClD,eAAe,EAAE,gBAAgB;iBAClC,CAAA;YACH,CAAC;YACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC1B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,OAAO;wBACL,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK;wBAC9D,eAAe,EAAE,mBAAmB,QAAQ,CAAC,IAAI,EAAE;wBACnD,eAAe,EAAE,SAAS;qBAC3B,CAAA;gBACH,CAAC;gBACD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBAC9D,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;gBACjD,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;oBACnD,OAAO;wBACL,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK;wBAC9D,eAAe,EAAE,wBAAwB,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE;wBACzE,eAAe,EAAE,MAAM;qBACxB,CAAA;gBACH,CAAC;gBACD,OAAO;oBACL,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI;oBAC7D,eAAe,EAAE,UAAU;iBAC5B,CAAA;YACH,CAAC;YACD,4DAA4D;YAC5D,OAAO;gBACL,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI;gBAC7D,eAAe,EAAE,gBAAgB;aAClC,CAAA;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,iBAAiB,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC,CAAA;YACrG,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,OAAO;oBACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;oBAC9D,eAAe,EAAE,uCAAuC;oBACxD,eAAe,EAAE,gBAAgB;iBAClC,CAAA;YACH,CAAC;YACD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,KAAK,CAAC,CAAA;YACvC,OAAO;gBACL,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM;gBAC/D,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iCAAiC,QAAQ,CAAC,SAAS,EAAE;gBAC3F,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;aAC9C,CAAA;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAA;YACpF,OAAO;gBACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;gBAC9D,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB;gBACtD,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gDAAgD;aACtF,CAAA;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAA;YACpD,OAAO;gBACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;gBAC9D,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB;aACvD,CAAA;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAA;YAC3F,OAAO;gBACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;gBAC9D,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB;aACvD,CAAA;QACH,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI;YAC9D,eAAe,EAAE,uBAAuB;YACxC,eAAe,EAAE,gBAAgB;SAClC,CAAA;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Claim, SealEvidence, SealIssue } from '../types.js';
|
|
2
|
+
export interface EvidenceGapResult {
|
|
3
|
+
issues: SealIssue[];
|
|
4
|
+
missing_evidence: string[];
|
|
5
|
+
trust_deductions: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class EvidenceGapDetector {
|
|
8
|
+
static detect(claims: Claim[], evidence: SealEvidence, risk_level?: string): EvidenceGapResult;
|
|
9
|
+
}
|