gsdd-cli 0.18.5 → 0.19.1
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/LICENSE +21 -21
- package/README.md +610 -608
- package/agents/DISTILLATION.md +421 -421
- package/agents/README.md +62 -62
- package/agents/approach-explorer.md +370 -361
- package/agents/debugger.md +82 -82
- package/agents/executor.md +473 -394
- package/agents/integration-checker.md +318 -318
- package/agents/mapper.md +103 -103
- package/agents/planner.md +342 -313
- package/agents/researcher.md +84 -84
- package/agents/roadmapper.md +296 -296
- package/agents/synthesizer.md +236 -236
- package/agents/verifier.md +337 -337
- package/bin/adapters/agents.mjs +34 -34
- package/bin/adapters/claude.mjs +193 -191
- package/bin/adapters/codex.mjs +85 -85
- package/bin/adapters/index.mjs +20 -20
- package/bin/adapters/opencode.mjs +280 -278
- package/bin/gsdd.mjs +123 -116
- package/bin/lib/cli-utils.mjs +28 -28
- package/bin/lib/evidence-contract.mjs +325 -112
- package/bin/lib/file-ops.mjs +186 -144
- package/bin/lib/health-truth.mjs +196 -178
- package/bin/lib/health.mjs +246 -226
- package/bin/lib/init-flow.mjs +247 -231
- package/bin/lib/init-prompts.mjs +248 -247
- package/bin/lib/init-runtime.mjs +193 -190
- package/bin/lib/init.mjs +17 -17
- package/bin/lib/lifecycle-preflight.mjs +760 -326
- package/bin/lib/lifecycle-state.mjs +356 -267
- package/bin/lib/manifest.mjs +116 -114
- package/bin/lib/models.mjs +411 -411
- package/bin/lib/phase.mjs +365 -358
- package/bin/lib/plan-constants.mjs +35 -30
- package/bin/lib/provenance.mjs +109 -106
- package/bin/lib/rendering.mjs +119 -83
- package/bin/lib/runtime-freshness.mjs +214 -214
- package/bin/lib/session-fingerprint.mjs +91 -14
- package/bin/lib/templates.mjs +225 -224
- package/bin/lib/workspace-root.mjs +2 -1
- package/distilled/DESIGN.md +2461 -2323
- package/distilled/EVIDENCE-INDEX.md +418 -392
- package/distilled/README.md +196 -193
- package/distilled/SKILL.md +86 -85
- package/distilled/templates/agents.block.md +21 -21
- package/distilled/templates/agents.md +6 -6
- package/distilled/templates/approach.md +272 -232
- package/distilled/templates/auth-matrix.md +78 -78
- package/distilled/templates/brownfield-change/CHANGE.md +99 -0
- package/distilled/templates/brownfield-change/HANDOFF.md +38 -0
- package/distilled/templates/brownfield-change/VERIFICATION.md +56 -0
- package/distilled/templates/codebase/architecture.md +110 -110
- package/distilled/templates/codebase/concerns.md +95 -95
- package/distilled/templates/codebase/conventions.md +193 -193
- package/distilled/templates/codebase/stack.md +96 -96
- package/distilled/templates/delegates/approach-explorer.md +28 -25
- package/distilled/templates/delegates/mapper-arch.md +26 -26
- package/distilled/templates/delegates/mapper-concerns.md +27 -27
- package/distilled/templates/delegates/mapper-quality.md +28 -28
- package/distilled/templates/delegates/mapper-tech.md +25 -25
- package/distilled/templates/delegates/plan-checker.md +78 -68
- package/distilled/templates/delegates/researcher-architecture.md +30 -30
- package/distilled/templates/delegates/researcher-features.md +30 -30
- package/distilled/templates/delegates/researcher-pitfalls.md +30 -30
- package/distilled/templates/delegates/researcher-stack.md +30 -30
- package/distilled/templates/delegates/researcher-synthesizer.md +31 -31
- package/distilled/templates/research/architecture.md +57 -57
- package/distilled/templates/research/features.md +23 -23
- package/distilled/templates/research/pitfalls.md +46 -46
- package/distilled/templates/research/stack.md +45 -45
- package/distilled/templates/research/summary.md +67 -67
- package/distilled/templates/roadmap.md +74 -62
- package/distilled/templates/spec.md +110 -110
- package/distilled/workflows/audit-milestone.md +303 -271
- package/distilled/workflows/complete-milestone.md +349 -332
- package/distilled/workflows/execute.md +457 -450
- package/distilled/workflows/map-codebase.md +253 -253
- package/distilled/workflows/new-milestone.md +242 -238
- package/distilled/workflows/new-project.md +398 -398
- package/distilled/workflows/pause.md +160 -156
- package/distilled/workflows/plan-milestone-gaps.md +183 -183
- package/distilled/workflows/plan.md +454 -448
- package/distilled/workflows/progress.md +227 -223
- package/distilled/workflows/quick.md +351 -347
- package/distilled/workflows/resume.md +220 -212
- package/distilled/workflows/verify-work.md +260 -260
- package/distilled/workflows/verify.md +431 -429
- package/docs/BROWNFIELD-PROOF.md +95 -95
- package/docs/RUNTIME-SUPPORT.md +80 -69
- package/docs/USER-GUIDE.md +394 -386
- package/docs/VERIFICATION-DISCIPLINE.md +59 -59
- package/docs/claude/context-monitor.md +98 -98
- package/docs/proof/consumer-node-cli/README.md +37 -37
- package/docs/proof/consumer-node-cli/ROADMAP.md +14 -14
- package/docs/proof/consumer-node-cli/SPEC.md +17 -17
- package/docs/proof/consumer-node-cli/brief.md +9 -9
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-PLAN.md +34 -34
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-SUMMARY.md +10 -10
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-VERIFICATION.md +30 -30
- package/package.json +62 -61
|
@@ -1,112 +1,325 @@
|
|
|
1
|
-
const EVIDENCE_KINDS = Object.freeze(['code', 'test', 'runtime', 'delivery', 'human']);
|
|
2
|
-
const DELIVERY_POSTURES = Object.freeze(['repo_only', 'delivery_sensitive']);
|
|
3
|
-
const CLOSURE_SURFACES = Object.freeze(['verify', 'audit-milestone', 'complete-milestone']);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
requiredKinds: Object.freeze(['code'
|
|
26
|
-
recommendedKinds: Object.freeze(['test'
|
|
27
|
-
blockedSoloKinds: Object.freeze(['
|
|
28
|
-
}),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
requiredKinds: Object.freeze(['code', 'test'
|
|
38
|
-
recommendedKinds: Object.freeze(['human']),
|
|
39
|
-
blockedSoloKinds: Object.freeze(['
|
|
40
|
-
}),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
requiredKinds: Object.freeze(['code', 'test'
|
|
50
|
-
recommendedKinds: Object.freeze(['
|
|
51
|
-
blockedSoloKinds: Object.freeze(['
|
|
52
|
-
}),
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
const EVIDENCE_KINDS = Object.freeze(['code', 'test', 'runtime', 'delivery', 'human']);
|
|
2
|
+
const DELIVERY_POSTURES = Object.freeze(['repo_only', 'delivery_sensitive']);
|
|
3
|
+
const CLOSURE_SURFACES = Object.freeze(['verify', 'audit-milestone', 'complete-milestone']);
|
|
4
|
+
const RELEASE_CLAIM_POSTURES = Object.freeze([
|
|
5
|
+
'repo_closeout',
|
|
6
|
+
'runtime_validated_closeout',
|
|
7
|
+
'delivery_supported_closeout',
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
const LEGACY_EVIDENCE_ALIASES = Object.freeze({
|
|
11
|
+
code: 'code',
|
|
12
|
+
test: 'test',
|
|
13
|
+
runtime: 'runtime',
|
|
14
|
+
delivery: 'delivery',
|
|
15
|
+
human: 'human',
|
|
16
|
+
'code-evidence': 'code',
|
|
17
|
+
'repo-test': 'test',
|
|
18
|
+
'runtime-check': 'runtime',
|
|
19
|
+
'user-confirmation': 'human',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const EVIDENCE_MATRIX = Object.freeze({
|
|
23
|
+
verify: Object.freeze({
|
|
24
|
+
repo_only: Object.freeze({
|
|
25
|
+
requiredKinds: Object.freeze(['code']),
|
|
26
|
+
recommendedKinds: Object.freeze(['test']),
|
|
27
|
+
blockedSoloKinds: Object.freeze(['human', 'delivery']),
|
|
28
|
+
}),
|
|
29
|
+
delivery_sensitive: Object.freeze({
|
|
30
|
+
requiredKinds: Object.freeze(['code', 'runtime', 'delivery']),
|
|
31
|
+
recommendedKinds: Object.freeze(['test', 'human']),
|
|
32
|
+
blockedSoloKinds: Object.freeze(['code', 'human']),
|
|
33
|
+
}),
|
|
34
|
+
}),
|
|
35
|
+
'audit-milestone': Object.freeze({
|
|
36
|
+
repo_only: Object.freeze({
|
|
37
|
+
requiredKinds: Object.freeze(['code', 'test']),
|
|
38
|
+
recommendedKinds: Object.freeze(['runtime', 'human']),
|
|
39
|
+
blockedSoloKinds: Object.freeze(['human', 'delivery']),
|
|
40
|
+
}),
|
|
41
|
+
delivery_sensitive: Object.freeze({
|
|
42
|
+
requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
|
|
43
|
+
recommendedKinds: Object.freeze(['human']),
|
|
44
|
+
blockedSoloKinds: Object.freeze(['code', 'human']),
|
|
45
|
+
}),
|
|
46
|
+
}),
|
|
47
|
+
'complete-milestone': Object.freeze({
|
|
48
|
+
repo_only: Object.freeze({
|
|
49
|
+
requiredKinds: Object.freeze(['code', 'test']),
|
|
50
|
+
recommendedKinds: Object.freeze(['runtime']),
|
|
51
|
+
blockedSoloKinds: Object.freeze(['human', 'delivery']),
|
|
52
|
+
}),
|
|
53
|
+
delivery_sensitive: Object.freeze({
|
|
54
|
+
requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
|
|
55
|
+
recommendedKinds: Object.freeze(['human']),
|
|
56
|
+
blockedSoloKinds: Object.freeze(['code', 'human']),
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const CONTRADICTION_CATEGORIES = Object.freeze([
|
|
62
|
+
'evidence',
|
|
63
|
+
'public_surface',
|
|
64
|
+
'runtime',
|
|
65
|
+
'delivery',
|
|
66
|
+
'planning_drift',
|
|
67
|
+
'generated_surface',
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const CONTRADICTION_STATUSES = Object.freeze(['passed', 'failed', 'not_applicable']);
|
|
71
|
+
|
|
72
|
+
const RELEASE_CLAIM_MATRIX = Object.freeze({
|
|
73
|
+
repo_closeout: Object.freeze({
|
|
74
|
+
deliveryPosture: 'repo_only',
|
|
75
|
+
requiredClaimKinds: Object.freeze([]),
|
|
76
|
+
allowedClaim: 'Repo-local milestone or phase closeout is supported by planning and repository artifacts only.',
|
|
77
|
+
invalidClaim: 'Do not imply runtime validation, delivery, publication, or public support from repo-local closeout alone.',
|
|
78
|
+
}),
|
|
79
|
+
runtime_validated_closeout: Object.freeze({
|
|
80
|
+
deliveryPosture: 'repo_only',
|
|
81
|
+
requiredClaimKinds: Object.freeze(['runtime']),
|
|
82
|
+
allowedClaim: 'Runtime behavior or a runtime surface was directly executed and observed for the named runtime or surface.',
|
|
83
|
+
invalidClaim: 'Do not generalize validation from one runtime or generated surface to another.',
|
|
84
|
+
}),
|
|
85
|
+
delivery_supported_closeout: Object.freeze({
|
|
86
|
+
deliveryPosture: 'delivery_sensitive',
|
|
87
|
+
requiredClaimKinds: Object.freeze([]),
|
|
88
|
+
allowedClaim: 'Externally consumed release, support, install, or delivery claims are supported by the delivery-sensitive evidence bar.',
|
|
89
|
+
invalidClaim: 'Do not imply merge, package, tag, GitHub Release, publication, generated-surface freshness, or public support without matching delivery evidence.',
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const CONTRADICTION_BLOCKERS_BY_POSTURE = Object.freeze({
|
|
94
|
+
repo_closeout: Object.freeze(['evidence', 'public_surface', 'planning_drift']),
|
|
95
|
+
runtime_validated_closeout: Object.freeze(['evidence', 'runtime', 'generated_surface', 'planning_drift']),
|
|
96
|
+
delivery_supported_closeout: CONTRADICTION_CATEGORIES,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export { CLOSURE_SURFACES, DELIVERY_POSTURES, EVIDENCE_KINDS, RELEASE_CLAIM_POSTURES };
|
|
100
|
+
|
|
101
|
+
export function normalizeEvidenceKind(kind) {
|
|
102
|
+
if (!kind) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return LEGACY_EVIDENCE_ALIASES[kind] ?? null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function normalizeEvidenceKinds(kinds = []) {
|
|
110
|
+
const normalized = [];
|
|
111
|
+
for (const kind of kinds) {
|
|
112
|
+
const resolved = normalizeEvidenceKind(kind);
|
|
113
|
+
if (resolved && !normalized.includes(resolved)) {
|
|
114
|
+
normalized.push(resolved);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function isClosureSurface(surface) {
|
|
121
|
+
return CLOSURE_SURFACES.includes(surface);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function normalizeReleaseClaimPosture(posture) {
|
|
125
|
+
if (!posture) return 'repo_closeout';
|
|
126
|
+
return RELEASE_CLAIM_POSTURES.includes(posture) ? posture : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function getEvidenceContract(surface, deliveryPosture) {
|
|
130
|
+
const matrix = EVIDENCE_MATRIX[surface];
|
|
131
|
+
if (!matrix) {
|
|
132
|
+
throw new Error(`Unsupported closure evidence surface: ${surface}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const posture = matrix[deliveryPosture];
|
|
136
|
+
if (!posture) {
|
|
137
|
+
throw new Error(`Unsupported delivery posture for ${surface}: ${deliveryPosture}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
surface,
|
|
142
|
+
deliveryPosture,
|
|
143
|
+
supportedKinds: [...EVIDENCE_KINDS],
|
|
144
|
+
requiredKinds: [...posture.requiredKinds],
|
|
145
|
+
recommendedKinds: [...posture.recommendedKinds],
|
|
146
|
+
blockedSoloKinds: [...posture.blockedSoloKinds],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function describeEvidenceSurface(surface) {
|
|
151
|
+
if (!isClosureSurface(surface)) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
surface,
|
|
157
|
+
supportedKinds: [...EVIDENCE_KINDS],
|
|
158
|
+
deliveryPostures: DELIVERY_POSTURES.map((deliveryPosture) => getEvidenceContract(surface, deliveryPosture)),
|
|
159
|
+
releaseClaimPostures: RELEASE_CLAIM_POSTURES.map((releaseClaimPosture) => getReleaseClaimContract(surface, releaseClaimPosture)),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function uniqueKinds(kinds) {
|
|
164
|
+
return [...new Set(kinds)];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function getDowngradePosture(observedKinds) {
|
|
168
|
+
if (observedKinds.includes('runtime')) {
|
|
169
|
+
return 'runtime_validated_closeout';
|
|
170
|
+
}
|
|
171
|
+
return 'repo_closeout';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function getReleaseClaimContract(surface, releaseClaimPosture = 'repo_closeout') {
|
|
175
|
+
const posture = normalizeReleaseClaimPosture(releaseClaimPosture);
|
|
176
|
+
if (!posture) {
|
|
177
|
+
throw new Error(`Unsupported release claim posture: ${releaseClaimPosture}`);
|
|
178
|
+
}
|
|
179
|
+
const claim = RELEASE_CLAIM_MATRIX[posture];
|
|
180
|
+
const evidence = getEvidenceContract(surface, claim.deliveryPosture);
|
|
181
|
+
const requiredKinds = uniqueKinds([...evidence.requiredKinds, ...claim.requiredClaimKinds]);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
surface,
|
|
185
|
+
releaseClaimPosture: posture,
|
|
186
|
+
deliveryPosture: claim.deliveryPosture,
|
|
187
|
+
supportedKinds: [...EVIDENCE_KINDS],
|
|
188
|
+
requiredKinds,
|
|
189
|
+
requiredClaimKinds: [...claim.requiredClaimKinds],
|
|
190
|
+
allowedClaim: claim.allowedClaim,
|
|
191
|
+
invalidClaim: claim.invalidClaim,
|
|
192
|
+
waiverRule: 'Waivers may only narrow the release claim posture or defer an unsupported claim; they never satisfy missing required evidence for the stronger claim.',
|
|
193
|
+
deferralRule: 'Deferrals must name the unsupported claim, missing evidence kinds, and later workflow or milestone candidate when known.',
|
|
194
|
+
contradictionCategories: [...CONTRADICTION_CATEGORIES],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function evaluateReleaseClaimPosture({
|
|
199
|
+
surface,
|
|
200
|
+
releaseClaimPosture = 'repo_closeout',
|
|
201
|
+
observedKinds = [],
|
|
202
|
+
waivedKinds = [],
|
|
203
|
+
} = {}) {
|
|
204
|
+
const contract = getReleaseClaimContract(surface, releaseClaimPosture);
|
|
205
|
+
const observed = normalizeEvidenceKinds(observedKinds);
|
|
206
|
+
const waived = normalizeEvidenceKinds(waivedKinds);
|
|
207
|
+
const missingKinds = contract.requiredKinds.filter((kind) => !observed.includes(kind));
|
|
208
|
+
const invalidWaivers = waived.filter((kind) => missingKinds.includes(kind));
|
|
209
|
+
const hasUnsupportedStrongClaim = contract.releaseClaimPosture !== 'repo_closeout' && missingKinds.length > 0;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
surface: contract.surface,
|
|
213
|
+
releaseClaimPosture: contract.releaseClaimPosture,
|
|
214
|
+
deliveryPosture: contract.deliveryPosture,
|
|
215
|
+
requiredKinds: [...contract.requiredKinds],
|
|
216
|
+
observedKinds: observed,
|
|
217
|
+
missingKinds,
|
|
218
|
+
invalidWaivers,
|
|
219
|
+
status: missingKinds.length === 0 && invalidWaivers.length === 0 ? 'supported' : 'unsupported',
|
|
220
|
+
disposition: hasUnsupportedStrongClaim ? 'downgrade_or_defer' : missingKinds.length > 0 ? 'block_or_defer' : 'proceed',
|
|
221
|
+
downgradeTo: hasUnsupportedStrongClaim ? getDowngradePosture(observed) : null,
|
|
222
|
+
deferredClaims: hasUnsupportedStrongClaim
|
|
223
|
+
? [{ claim: contract.releaseClaimPosture, missingKinds }]
|
|
224
|
+
: [],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function evaluateReleaseClaimCloseoutContract({
|
|
229
|
+
surface,
|
|
230
|
+
deliveryPosture = null,
|
|
231
|
+
releaseClaimPosture = 'repo_closeout',
|
|
232
|
+
observedKinds = [],
|
|
233
|
+
waivedKinds = [],
|
|
234
|
+
unsupportedClaims = [],
|
|
235
|
+
deferrals = [],
|
|
236
|
+
contradictionChecks = {},
|
|
237
|
+
} = {}) {
|
|
238
|
+
const posture = evaluateReleaseClaimPosture({
|
|
239
|
+
surface,
|
|
240
|
+
releaseClaimPosture,
|
|
241
|
+
observedKinds,
|
|
242
|
+
waivedKinds,
|
|
243
|
+
});
|
|
244
|
+
const missingContradictionChecks = CONTRADICTION_CATEGORIES.filter((name) => !(name in contradictionChecks));
|
|
245
|
+
const failedContradictionChecks = Object.entries(contradictionChecks)
|
|
246
|
+
.filter(([, status]) => status === 'failed')
|
|
247
|
+
.map(([name]) => name);
|
|
248
|
+
const unknownContradictionChecks = Object.keys(contradictionChecks)
|
|
249
|
+
.filter((name) => !CONTRADICTION_CATEGORIES.includes(name));
|
|
250
|
+
const invalidContradictionChecks = Object.entries(contradictionChecks)
|
|
251
|
+
.filter(([, status]) => !CONTRADICTION_STATUSES.includes(status))
|
|
252
|
+
.map(([name]) => name);
|
|
253
|
+
const blockingContradictionChecks = failedContradictionChecks.filter((name) =>
|
|
254
|
+
CONTRADICTION_BLOCKERS_BY_POSTURE[posture.releaseClaimPosture].includes(name)
|
|
255
|
+
);
|
|
256
|
+
const unresolvedUnsupportedClaims = unsupportedClaims.filter((claim) =>
|
|
257
|
+
!deferrals.some((deferral) => namesUnsupportedClaim(deferral, claim))
|
|
258
|
+
);
|
|
259
|
+
const blockers = [];
|
|
260
|
+
|
|
261
|
+
if (deliveryPosture && deliveryPosture !== posture.deliveryPosture) {
|
|
262
|
+
blockers.push({
|
|
263
|
+
code: 'incompatible_release_claim_posture',
|
|
264
|
+
details: [`${deliveryPosture} cannot support ${posture.releaseClaimPosture}; expected ${posture.deliveryPosture}`],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (posture.missingKinds.length > 0) {
|
|
269
|
+
blockers.push({ code: 'missing_required_release_evidence', details: posture.missingKinds });
|
|
270
|
+
}
|
|
271
|
+
if (posture.invalidWaivers.length > 0) {
|
|
272
|
+
blockers.push({ code: 'invalid_release_waivers', details: posture.invalidWaivers });
|
|
273
|
+
}
|
|
274
|
+
if (unresolvedUnsupportedClaims.length > 0) {
|
|
275
|
+
blockers.push({ code: 'unsupported_release_claims', details: unresolvedUnsupportedClaims });
|
|
276
|
+
}
|
|
277
|
+
if (missingContradictionChecks.length > 0) {
|
|
278
|
+
blockers.push({ code: 'missing_release_contradiction_checks', details: missingContradictionChecks });
|
|
279
|
+
}
|
|
280
|
+
if (unknownContradictionChecks.length > 0) {
|
|
281
|
+
blockers.push({ code: 'unknown_release_contradiction_checks', details: unknownContradictionChecks });
|
|
282
|
+
}
|
|
283
|
+
if (invalidContradictionChecks.length > 0) {
|
|
284
|
+
blockers.push({ code: 'invalid_release_contradiction_checks', details: invalidContradictionChecks });
|
|
285
|
+
}
|
|
286
|
+
if (blockingContradictionChecks.length > 0) {
|
|
287
|
+
blockers.push({ code: 'failed_release_contradiction_checks', details: blockingContradictionChecks });
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
...posture,
|
|
292
|
+
unsupportedClaims: [...unsupportedClaims],
|
|
293
|
+
deferrals: [...deferrals],
|
|
294
|
+
failedContradictionChecks: blockingContradictionChecks,
|
|
295
|
+
allFailedContradictionChecks: failedContradictionChecks,
|
|
296
|
+
missingContradictionChecks,
|
|
297
|
+
unknownContradictionChecks,
|
|
298
|
+
invalidContradictionChecks,
|
|
299
|
+
unresolvedUnsupportedClaims,
|
|
300
|
+
blockers,
|
|
301
|
+
status: blockers.length === 0 ? 'supported' : 'unsupported',
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function namesUnsupportedClaim(deferral, claim) {
|
|
306
|
+
const normalizedDeferral = normalizeClaimText(deferral);
|
|
307
|
+
const normalizedClaim = normalizeClaimText(claim);
|
|
308
|
+
if (!normalizedDeferral || !normalizedClaim) return false;
|
|
309
|
+
return normalizedDeferral.includes(normalizedClaim) && isStructuredDeferral(normalizedDeferral);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function isStructuredDeferral(normalizedDeferral) {
|
|
313
|
+
const namesEvidenceKind = EVIDENCE_KINDS.some((kind) => normalizedDeferral.includes(kind));
|
|
314
|
+
const namesLaterTarget = /\b(later|next|future|workflow|milestone|phase|gsdd)\b/.test(normalizedDeferral);
|
|
315
|
+
return namesEvidenceKind && namesLaterTarget;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function normalizeClaimText(value) {
|
|
319
|
+
return String(value || '')
|
|
320
|
+
.trim()
|
|
321
|
+
.toLowerCase()
|
|
322
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
323
|
+
.replace(/\s+/g, ' ')
|
|
324
|
+
.trim();
|
|
325
|
+
}
|