create-agdf 0.10.1 → 0.10.3
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/README.md +21 -13
- package/bin/agdf-validator.js +11 -0
- package/generated/.agdf/control/README.md +3 -3
- package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +1 -1
- package/generated/.github/skills/agdf-delivery-path-search/SKILL.md +7 -6
- package/generated/.github/skills/agdf-gate-check/SKILL.md +35 -105
- package/generated/.github/skills/agdf-interaction-locales.json +10 -0
- package/generated/.github/skills/agdf-release-or/SKILL.md +1 -1
- package/generated/.github/skills/contracts/gate-transition.md +4 -2
- package/generated/.github/skills/contracts/interaction.md +23 -0
- package/generated/.github/skills/contracts/modes.md +12 -1
- package/generated/.opencode/agdf-interaction-locales.json +10 -0
- package/generated/.opencode/contracts/gate-transition.md +4 -2
- package/generated/.opencode/contracts/interaction.md +23 -0
- package/generated/.opencode/contracts/modes.md +12 -1
- package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +1 -1
- package/generated/.opencode/skills/agdf-delivery-path-search/SKILL.md +7 -6
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +35 -105
- package/generated/.opencode/skills/agdf-release-or/SKILL.md +1 -1
- package/generated/plugins/agdf/.claude-plugin/plugin.json +19 -0
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/README.md +3 -3
- package/generated/plugins/agdf/hooks/session-start.sh +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +10 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/contracts/gate-transition.md +4 -2
- package/generated/plugins/agdf/meta/contracts/interaction.md +23 -0
- package/generated/plugins/agdf/meta/contracts/modes.md +12 -1
- package/generated/plugins/agdf/runtime/agdf-local.js +11 -0
- package/generated/plugins/agdf/runtime/create-agdf/NOTICE +10 -0
- package/generated/plugins/agdf/runtime/create-agdf/bin/agdf-validator.js +11 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +426 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +220 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +136 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +75 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +156 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/runtime-context.js +83 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +46 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +291 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +265 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +450 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +283 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/required-files.js +9 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +217 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +344 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/verified-change.js +156 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/aggregate.js +18 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/gate-approval-validator.js +49 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/index.js +7 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/legacy-migration.js +95 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +227 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-repository.js +68 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js +45 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js +97 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/candidate-policy.js +99 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +237 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +44 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +53 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/protocol.js +13 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/claude.js +40 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/codex.js +38 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/generators/protocol.js +12 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +39 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/scoring.js +21 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +154 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +161 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +14 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/transports/read-only-guard.js +43 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +670 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +142 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/validator-application.js +40 -0
- package/generated/plugins/agdf/runtime/create-agdf/package.json +66 -0
- package/generated/plugins/agdf/runtime/runtime-manifest.json +8 -0
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +1055 -0
- package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +1 -1
- package/generated/plugins/agdf/skills/delivery-path-search/SKILL.md +7 -6
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +35 -105
- package/generated/plugins/agdf/skills/release-or/SKILL.md +1 -1
- package/lib/cli/application.js +16 -54
- package/lib/cli/command-registry.js +9 -11
- package/lib/cli/validation-handlers.js +46 -0
- package/lib/control-evaluation/doctor.js +1 -1
- package/lib/control-evaluation/gate-check.js +23 -32
- package/lib/control-evaluation/required-files.js +9 -0
- package/lib/installers/local-marketplace.js +322 -0
- package/lib/installers/opencode.js +84 -6
- package/lib/installers/plugin-installers.js +102 -26
- package/lib/interaction-presentation.js +80 -0
- package/lib/runtime/local-validator.js +142 -0
- package/lib/runtime/validator-application.js +40 -0
- package/lib/scaffold/plan.js +1 -7
- package/lib/scaffold/presentation.js +2 -2
- package/opencode-plugin.js +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { attachApprovalOrientationSnapshot, buildArtefactRefs, buildQualityReadiness, gateTitle, localePack, renderApprovalOrientationSnapshot, renderOperationalStatusCard, resolveHumanRunTitle } from '../interaction-presentation.js';
|
|
2
|
+
import { interactionLocales, resolveConfiguredChatLanguage } from '../cli/runtime-context.js';
|
|
3
|
+
import { evaluateDoctor } from './doctor.js';
|
|
4
|
+
import { analyzeDeliveryMap, deriveQualityOutlook } from './delivery-map.js';
|
|
5
|
+
import { transitionDecisionForRunState } from './gate-policy.js';
|
|
6
|
+
import { evaluateVerifiedChange, extractField, verifiedChangeEscalationTargets } from './verified-change.js';
|
|
7
|
+
import { gateApprovalStatus, modeSliceDecision, readArtefactHeading, readRunState, resolvedArtefactFile } from './run-state.js';
|
|
8
|
+
import { isPlaceholderValue } from './shared.js';
|
|
9
|
+
|
|
10
|
+
const nextSkillByGate = {
|
|
11
|
+
UR: "gate-check",
|
|
12
|
+
"Brownfield Review": "brownfield-analysis",
|
|
13
|
+
"Mode/Slice Decision": "gate-check",
|
|
14
|
+
"Quick Task Execution": "none",
|
|
15
|
+
"Verified Change Execution": "gate-check",
|
|
16
|
+
PRD: "gate-check",
|
|
17
|
+
SD: "gate-check",
|
|
18
|
+
TP: "gate-check",
|
|
19
|
+
"Brownfield Analysis": "brownfield-analysis",
|
|
20
|
+
"CD+Tests": "none",
|
|
21
|
+
CR: "code-review",
|
|
22
|
+
QA: "qa-gate",
|
|
23
|
+
UAT: "delivery-closeout",
|
|
24
|
+
OR: "release-or",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function postApprovalTransition(missingApproval) {
|
|
28
|
+
const transitions = new Map([
|
|
29
|
+
["Approval: UR", {
|
|
30
|
+
next_gate_after_approval: "Brownfield Review",
|
|
31
|
+
allowed_after_approval: "Run Brownfield Review and proportional routing as one internal operation; no user action is required now.",
|
|
32
|
+
internal_next_step: "Brownfield Review and proportional routing",
|
|
33
|
+
next_user_gate: "none",
|
|
34
|
+
user_action_required: "no",
|
|
35
|
+
}],
|
|
36
|
+
["Approval: PRD", {
|
|
37
|
+
next_gate_after_approval: "SD",
|
|
38
|
+
allowed_after_approval: "Draft Solution Design; implementation remains forbidden.",
|
|
39
|
+
internal_next_step: "draft Solution Design",
|
|
40
|
+
next_user_gate: "SD",
|
|
41
|
+
user_action_required: "yes",
|
|
42
|
+
}],
|
|
43
|
+
["Approval: SD", {
|
|
44
|
+
next_gate_after_approval: "TP",
|
|
45
|
+
allowed_after_approval: "Draft Task/Test Plan; implementation remains forbidden.",
|
|
46
|
+
internal_next_step: "draft Task/Test Plan",
|
|
47
|
+
next_user_gate: "TP",
|
|
48
|
+
user_action_required: "yes",
|
|
49
|
+
}],
|
|
50
|
+
["Approval: TP", {
|
|
51
|
+
next_gate_after_approval: "none",
|
|
52
|
+
allowed_after_approval: "Run implementation-prep Brownfield Analysis before CD+Tests; no further user approval is required at this internal step.",
|
|
53
|
+
internal_next_step: "pre-implementation Brownfield Analysis",
|
|
54
|
+
next_user_gate: "none",
|
|
55
|
+
user_action_required: "no",
|
|
56
|
+
}],
|
|
57
|
+
["Approval: QA", {
|
|
58
|
+
next_gate_after_approval: "UAT",
|
|
59
|
+
allowed_after_approval: "Request UAT when QA has passed; release remains gated.",
|
|
60
|
+
internal_next_step: "prepare UAT evidence",
|
|
61
|
+
next_user_gate: "UAT",
|
|
62
|
+
user_action_required: "yes",
|
|
63
|
+
}],
|
|
64
|
+
["Approval: UAT", {
|
|
65
|
+
next_gate_after_approval: "OR",
|
|
66
|
+
allowed_after_approval: "Produce OR or delivery closeout; VCS and release actions still require explicit instruction.",
|
|
67
|
+
internal_next_step: "OR or delivery closeout",
|
|
68
|
+
next_user_gate: "none",
|
|
69
|
+
user_action_required: "no",
|
|
70
|
+
}],
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
return transitions.get(missingApproval) ?? {
|
|
74
|
+
next_gate_after_approval: "none",
|
|
75
|
+
allowed_after_approval: "none",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const BREADCRUMB_PATH_TEMPLATES = {
|
|
80
|
+
structured_delivery: ["UR", "PRD", "SD", "TP", "QA", "UAT"],
|
|
81
|
+
structured_slice: ["UR", "PRD", "SD", "TP", "QA", "UAT"],
|
|
82
|
+
verified_change: ["UR", "Verified Change", "OR"],
|
|
83
|
+
quick_task: ["UR", "Compact Delivery"],
|
|
84
|
+
block: ["UR", "Block"],
|
|
85
|
+
undecided: ["UR"],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const BREADCRUMB_STANDARD_GATES = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
|
|
89
|
+
|
|
90
|
+
export function isReadyUserGateApproval({ status, currentGate, missingApproval }) {
|
|
91
|
+
return status === "open"
|
|
92
|
+
&& BREADCRUMB_STANDARD_GATES.includes(currentGate)
|
|
93
|
+
&& missingApproval === `Approval: ${currentGate}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function buildBreadcrumbPath(modeSliceDecision, currentGate, runState) {
|
|
97
|
+
const gates = BREADCRUMB_PATH_TEMPLATES[modeSliceDecision] ?? ["UR"];
|
|
98
|
+
return gates.map((gate) => {
|
|
99
|
+
if (BREADCRUMB_STANDARD_GATES.includes(gate)) {
|
|
100
|
+
if (gateApprovalStatus(runState, gate) === "approved") return { gate, status: "fulfilled" };
|
|
101
|
+
if (gate === currentGate) return { gate, status: "current" };
|
|
102
|
+
return { gate, status: "open" };
|
|
103
|
+
}
|
|
104
|
+
if (gate === currentGate) return { gate, status: "current" };
|
|
105
|
+
if ((gate === "Verified Change" || gate === "Compact Delivery") && currentGate === "OR")
|
|
106
|
+
return { gate, status: "fulfilled" };
|
|
107
|
+
if (gate === "Verified Change" && modeSliceDecision === "verified_change")
|
|
108
|
+
return { gate, status: "current" };
|
|
109
|
+
if (gate === "Compact Delivery" && modeSliceDecision === "quick_task")
|
|
110
|
+
return { gate, status: "current" };
|
|
111
|
+
if (gate === "Block" && modeSliceDecision === "block")
|
|
112
|
+
return { gate, status: "current" };
|
|
113
|
+
if (gate === "OR" && currentGate === "OR")
|
|
114
|
+
return { gate, status: "current" };
|
|
115
|
+
return { gate, status: "open" };
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function buildStatusCard({
|
|
120
|
+
status,
|
|
121
|
+
currentGate,
|
|
122
|
+
allowed = [],
|
|
123
|
+
forbidden = [],
|
|
124
|
+
blockingReason = "none",
|
|
125
|
+
missingApproval = "none",
|
|
126
|
+
nextAllowedAction,
|
|
127
|
+
runState,
|
|
128
|
+
chatLanguage = "en",
|
|
129
|
+
findings = [],
|
|
130
|
+
}) {
|
|
131
|
+
const qualityOutlook = deriveQualityOutlook(runState, findings);
|
|
132
|
+
const postApproval = postApprovalTransition(missingApproval);
|
|
133
|
+
const isUserGateApproval = isReadyUserGateApproval({ status, currentGate, missingApproval });
|
|
134
|
+
const lifecycle = extractField(runState.content ?? "", "lifecycle") || "unknown";
|
|
135
|
+
const nativeAttemptRequired = false;
|
|
136
|
+
const interactionKind = status === "open" && isUserGateApproval ? "gate_approval" : status === "blocked" ? "blocked" : "status";
|
|
137
|
+
return {
|
|
138
|
+
run_id: extractField(runState.content ?? "", "run_id") || "unknown",
|
|
139
|
+
presentation_language: chatLanguage,
|
|
140
|
+
mode: extractField(runState.content ?? "", "mode") || "unknown",
|
|
141
|
+
lifecycle,
|
|
142
|
+
delivery_state: lifecycle === "completed" && currentGate === "OR" ? "completed_closeout_pending" : lifecycle,
|
|
143
|
+
status,
|
|
144
|
+
current_gate: currentGate,
|
|
145
|
+
mode_slice_decision: runState.mode_slice_decision?.decision || "undecided",
|
|
146
|
+
breadcrumb: buildBreadcrumbPath(
|
|
147
|
+
runState.mode_slice_decision?.decision || "undecided",
|
|
148
|
+
currentGate,
|
|
149
|
+
runState,
|
|
150
|
+
),
|
|
151
|
+
allowed_now: allowed,
|
|
152
|
+
forbidden_now: forbidden,
|
|
153
|
+
blocking_condition: blockingReason || "none",
|
|
154
|
+
missing_approval: missingApproval || "none",
|
|
155
|
+
next_gate_after_approval: postApproval.next_gate_after_approval,
|
|
156
|
+
allowed_after_approval: postApproval.allowed_after_approval,
|
|
157
|
+
user_visible_outcome_after_approval: postApproval.allowed_after_approval,
|
|
158
|
+
internal_next_step: postApproval.internal_next_step || (isUserGateApproval ? "none" : nextAllowedAction),
|
|
159
|
+
next_user_gate: postApproval.next_user_gate || "none",
|
|
160
|
+
user_action_required: postApproval.user_action_required || (isUserGateApproval ? "yes" : "no"),
|
|
161
|
+
evidence: runState.evidence_refs,
|
|
162
|
+
next_skill: nextSkillByGate[currentGate] ?? "gate-check",
|
|
163
|
+
next_step: nextAllowedAction,
|
|
164
|
+
quality_outlook: qualityOutlook,
|
|
165
|
+
interaction_kind: interactionKind,
|
|
166
|
+
native_attempt_required: nativeAttemptRequired,
|
|
167
|
+
native_preflight_outcome: isUserGateApproval ? "unavailable_before_invocation" : "not_applicable",
|
|
168
|
+
native_preflight_reason: isUserGateApproval ? "capability_missing" : "none",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function statusFromReviewArtefact(artefact) {
|
|
173
|
+
if (!artefact) return "unknown";
|
|
174
|
+
const text = `${artefact.status ?? ""} ${artefact.notes ?? ""}`.toLowerCase();
|
|
175
|
+
for (const status of ["block", "revise", "warn", "pass"]) {
|
|
176
|
+
if (new RegExp(`\\b${status}(?:ed)?\\b`).test(text)) return status;
|
|
177
|
+
}
|
|
178
|
+
return "unknown";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function qualityReadinessForRunState(runState, nextAction) {
|
|
182
|
+
const artefacts = runState.artefacts;
|
|
183
|
+
const plan = artefacts.get("TP Review");
|
|
184
|
+
const clean = artefacts.get("Clean Implementation Review") ?? artefacts.get("Clean Review");
|
|
185
|
+
const code = artefacts.get("CR") ?? artefacts.get("Code Review");
|
|
186
|
+
const qa = artefacts.get("QA");
|
|
187
|
+
if (![plan, clean, code, qa].some(Boolean)) return null;
|
|
188
|
+
const reviewRows = [plan, clean, code, qa].filter(Boolean);
|
|
189
|
+
const decisive = reviewRows.find((artefact) => /\b(?:block|revise)\b/i.test(`${artefact.status ?? ""} ${artefact.notes ?? ""}`));
|
|
190
|
+
const readiness = buildQualityReadiness({
|
|
191
|
+
planCoverage: statusFromReviewArtefact(plan),
|
|
192
|
+
solutionIntegrity: statusFromReviewArtefact(clean),
|
|
193
|
+
codeQuality: statusFromReviewArtefact(code),
|
|
194
|
+
qaDecision: statusFromReviewArtefact(qa),
|
|
195
|
+
decisiveReason: decisive?.notes ?? "",
|
|
196
|
+
nextAction,
|
|
197
|
+
});
|
|
198
|
+
if (!readiness) return null;
|
|
199
|
+
return Object.freeze({ ...readiness, decisive_reference: decisive?.path ?? "" });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function buildHumanPresentation(targetDir, runState, currentGate, presentationLocale) {
|
|
203
|
+
const currentArtefactHeading = readArtefactHeading(targetDir, runState.artefacts.get(currentGate));
|
|
204
|
+
const urHeading = readArtefactHeading(targetDir, runState.artefacts.get("UR"));
|
|
205
|
+
return {
|
|
206
|
+
runTitle: resolveHumanRunTitle({
|
|
207
|
+
currentArtefactHeading,
|
|
208
|
+
urHeading,
|
|
209
|
+
runContent: runState.content,
|
|
210
|
+
runId: extractField(runState.content ?? "", "run_id") || "unknown",
|
|
211
|
+
}),
|
|
212
|
+
gateTitle: gateTitle(interactionLocales, presentationLocale, currentGate),
|
|
213
|
+
artefactRefs: buildArtefactRefs(runState.artefacts, interactionLocales, presentationLocale, {
|
|
214
|
+
pathExists(path) {
|
|
215
|
+
return Boolean(resolvedArtefactFile(targetDir, path));
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function evaluateGateCheck(targetDir, selection = {}) {
|
|
222
|
+
const doctorReport = evaluateDoctor(targetDir, selection);
|
|
223
|
+
const runState = readRunState(targetDir, selection);
|
|
224
|
+
const verifiedChange = modeSliceDecision(runState) === "verified_change"
|
|
225
|
+
? evaluateVerifiedChange(targetDir, runState)
|
|
226
|
+
: null;
|
|
227
|
+
const transitionDecision = transitionDecisionForRunState(runState, verifiedChange);
|
|
228
|
+
const deliveryMap = analyzeDeliveryMap(runState);
|
|
229
|
+
const doctorBlocker = doctorReport.findings.find((finding) => finding.severity === "block");
|
|
230
|
+
const doctorRevise = doctorReport.findings.find((finding) => finding.severity === "revise");
|
|
231
|
+
const routesInvalidVerifiedChange = modeSliceDecision(runState) === "verified_change"
|
|
232
|
+
&& verifiedChange?.status === "invalid"
|
|
233
|
+
&& verifiedChangeEscalationTargets.has(verifiedChange.escalation_target);
|
|
234
|
+
|
|
235
|
+
let status = transitionDecision.status;
|
|
236
|
+
let currentGate = transitionDecision.current_gate;
|
|
237
|
+
let blockingReason = transitionDecision.blocking_reason;
|
|
238
|
+
let missingApproval = transitionDecision.missing_approval;
|
|
239
|
+
let allowed = transitionDecision.allowed;
|
|
240
|
+
let forbidden = transitionDecision.forbidden;
|
|
241
|
+
let nextAllowedAction = modeSliceDecision(runState) === "verified_change"
|
|
242
|
+
? transitionDecision.next_allowed_action
|
|
243
|
+
: isPlaceholderValue(runState.next_allowed_action)
|
|
244
|
+
? transitionDecision.next_allowed_action
|
|
245
|
+
: runState.next_allowed_action;
|
|
246
|
+
|
|
247
|
+
if (doctorBlocker?.code === "AGDF_CONTROL_FILE_MISSING") {
|
|
248
|
+
status = "blocked";
|
|
249
|
+
blockingReason = doctorBlocker.code;
|
|
250
|
+
currentGate = "UR";
|
|
251
|
+
missingApproval = "Approval: UR";
|
|
252
|
+
allowed = [
|
|
253
|
+
"draft the minimal UR for the requested change in the response",
|
|
254
|
+
"request exact approval: Approval: UR",
|
|
255
|
+
"run npx --yes @agdf/cli@latest init only when durable control state or deterministic setup is explicitly needed",
|
|
256
|
+
];
|
|
257
|
+
forbidden = ["create PRD", "create SD", "create TP", "run Brownfield Analysis", "implement code", "claim QA or release readiness"];
|
|
258
|
+
nextAllowedAction = "Draft the minimal UR for the request in the response, then ask for exact approval: Approval: UR. Do not write a full .agdf/control scaffold unless durable control state or deterministic setup is explicitly needed.";
|
|
259
|
+
} else if (doctorBlocker && !routesInvalidVerifiedChange) {
|
|
260
|
+
status = "blocked";
|
|
261
|
+
blockingReason = doctorBlocker.code;
|
|
262
|
+
allowed = ["repair the AGDF control scaffold", ...transitionDecision.allowed, "run doctor again"];
|
|
263
|
+
forbidden = ["create later-gate artefacts beyond the current allowed gate", "implement gated work", "claim QA or release readiness"];
|
|
264
|
+
nextAllowedAction = doctorBlocker.next_step;
|
|
265
|
+
} else if (doctorRevise && !routesInvalidVerifiedChange) {
|
|
266
|
+
status = "blocked";
|
|
267
|
+
blockingReason = doctorRevise.code;
|
|
268
|
+
allowed = [...new Set(["complete the current control-state fields", ...transitionDecision.allowed, "run doctor again"])];
|
|
269
|
+
forbidden = ["create later-gate artefacts beyond the current allowed gate", "implement gated work before the gate allows it", "claim QA or release readiness"];
|
|
270
|
+
nextAllowedAction = transitionDecision.current_gate === "UR"
|
|
271
|
+
? "Fill the current UR control state, persist the UR draft, and request exact approval: Approval: UR."
|
|
272
|
+
: doctorRevise.next_step;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const postApproval = postApprovalTransition(missingApproval);
|
|
276
|
+
const presentationLocale = resolveConfiguredChatLanguage(targetDir);
|
|
277
|
+
const statusCard = buildStatusCard({
|
|
278
|
+
status,
|
|
279
|
+
currentGate,
|
|
280
|
+
allowed,
|
|
281
|
+
forbidden,
|
|
282
|
+
blockingReason,
|
|
283
|
+
missingApproval,
|
|
284
|
+
nextAllowedAction,
|
|
285
|
+
runState,
|
|
286
|
+
chatLanguage: presentationLocale,
|
|
287
|
+
findings: deliveryMap.findings,
|
|
288
|
+
});
|
|
289
|
+
const humanPresentation = buildHumanPresentation(targetDir, runState, currentGate, presentationLocale);
|
|
290
|
+
Object.defineProperty(statusCard, "humanPresentation", {
|
|
291
|
+
value: humanPresentation,
|
|
292
|
+
enumerable: false,
|
|
293
|
+
});
|
|
294
|
+
const revisionId = extractField(runState.content ?? "", "revision_id");
|
|
295
|
+
const statusPresentation = renderOperationalStatusCard(statusCard, {
|
|
296
|
+
registry: interactionLocales,
|
|
297
|
+
humanPresentation,
|
|
298
|
+
revisionId,
|
|
299
|
+
});
|
|
300
|
+
const approvalOrientation = attachApprovalOrientationSnapshot(statusCard, {
|
|
301
|
+
ready: isReadyUserGateApproval({ status, currentGate, missingApproval }),
|
|
302
|
+
humanPresentation,
|
|
303
|
+
revisionId,
|
|
304
|
+
registry: interactionLocales,
|
|
305
|
+
requestedLocale: presentationLocale,
|
|
306
|
+
});
|
|
307
|
+
Object.defineProperty(statusCard, "runState", {
|
|
308
|
+
value: runState,
|
|
309
|
+
enumerable: false,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
schema_version: "1",
|
|
314
|
+
status,
|
|
315
|
+
current_gate: currentGate,
|
|
316
|
+
blocking_reason: blockingReason,
|
|
317
|
+
missing_approval: missingApproval,
|
|
318
|
+
next_gate_after_approval: postApproval.next_gate_after_approval,
|
|
319
|
+
allowed_after_approval: postApproval.allowed_after_approval,
|
|
320
|
+
allowed,
|
|
321
|
+
forbidden,
|
|
322
|
+
next_allowed_action: nextAllowedAction,
|
|
323
|
+
doctor_status: doctorReport.status,
|
|
324
|
+
doctor_summary: doctorReport.summary,
|
|
325
|
+
evidence_refs: runState.evidence_refs,
|
|
326
|
+
quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
|
|
327
|
+
interaction_kind: statusCard.interaction_kind,
|
|
328
|
+
native_attempt_required: statusCard.native_attempt_required,
|
|
329
|
+
candidate_runs: runState.candidate_runs ?? [],
|
|
330
|
+
status_card: statusCard,
|
|
331
|
+
status_presentation: statusPresentation,
|
|
332
|
+
approval_presentation: renderApprovalOrientationSnapshot(approvalOrientation, {
|
|
333
|
+
registry: interactionLocales,
|
|
334
|
+
expectedIdentity: {
|
|
335
|
+
run_id: statusCard.run_id,
|
|
336
|
+
revision_id: revisionId,
|
|
337
|
+
current_gate: currentGate,
|
|
338
|
+
presentation_language: statusCard.presentation_language,
|
|
339
|
+
},
|
|
340
|
+
}),
|
|
341
|
+
delivery_map: {
|
|
342
|
+
relationships: deliveryMap.relationships,
|
|
343
|
+
mode_slice_decision: runState.mode_slice_decision,
|
|
344
|
+
context_graph: deliveryMap.context_graph,
|
|
345
|
+
source_scope: deliveryMap.source_scope,
|
|
346
|
+
memory: deliveryMap.memory,
|
|
347
|
+
findings: deliveryMap.findings,
|
|
348
|
+
},
|
|
349
|
+
verified_change: verifiedChange,
|
|
350
|
+
doctor_report: doctorReport,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function canonicalApprovalForReport(report) {
|
|
355
|
+
const gate = String(report?.current_gate ?? "").trim();
|
|
356
|
+
const approval = String(report?.missing_approval ?? "").trim();
|
|
357
|
+
return isReadyUserGateApproval({ status: report?.status, currentGate: gate, missingApproval: approval })
|
|
358
|
+
? approval
|
|
359
|
+
: "";
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function printApprovalEnvelope(report, { io = console, reEvaluate } = {}) {
|
|
363
|
+
if (report?.approval_presentation) {
|
|
364
|
+
io.log(report.approval_presentation.blocks.run_status_card.markdown);
|
|
365
|
+
io.log("");
|
|
366
|
+
io.log(report.approval_presentation.blocks.gate_transition_card.markdown);
|
|
367
|
+
io.log("");
|
|
368
|
+
io.log(report.approval_presentation.approval_interaction.exact_text_fallback);
|
|
369
|
+
return Object.freeze({ outcome: "rendered", requested_decision: true, status: report.status });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const initialApproval = canonicalApprovalForReport(report);
|
|
373
|
+
let refreshed = report;
|
|
374
|
+
if (initialApproval && typeof reEvaluate === "function") {
|
|
375
|
+
try {
|
|
376
|
+
refreshed = reEvaluate();
|
|
377
|
+
} catch {
|
|
378
|
+
refreshed = { ...report, status: "blocked", blocking_reason: "fresh_gate_evaluation_failed", missing_approval: "none" };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const pack = localePack(interactionLocales, refreshed?.status_card?.presentation_language || report?.status_card?.presentation_language || "en");
|
|
382
|
+
const refreshedApproval = canonicalApprovalForReport(refreshed);
|
|
383
|
+
if (initialApproval && refreshedApproval) {
|
|
384
|
+
io.log(pack.interaction.presentationFailure);
|
|
385
|
+
io.log(pack.interaction.exactTextRequest.replace("{approval}", refreshedApproval));
|
|
386
|
+
return Object.freeze({ outcome: "exact_text_recovery", requested_decision: true, status: refreshed.status });
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const blockingReason = String(refreshed?.blocking_reason ?? "").trim();
|
|
390
|
+
const reason = String(
|
|
391
|
+
blockingReason && blockingReason !== "none"
|
|
392
|
+
? blockingReason
|
|
393
|
+
: refreshed?.next_allowed_action || "gate_not_ready",
|
|
394
|
+
).trim();
|
|
395
|
+
io.log(pack.interaction.nonReadyDecision.replace("{reason}", reason));
|
|
396
|
+
return Object.freeze({ outcome: "non_ready", requested_decision: false, status: refreshed?.status || "blocked" });
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function printGateCheckStatusCard(report, io) {
|
|
400
|
+
const card = report.status_card;
|
|
401
|
+
if (!report.status_presentation?.markdown) {
|
|
402
|
+
io.log(localePack(interactionLocales, card?.presentation_language || "en").interaction.statusPresentationFailure);
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
io.log(report.status_presentation.markdown);
|
|
406
|
+
const primary = localePack(interactionLocales, card.presentation_language).primary;
|
|
407
|
+
const readiness = qualityReadinessForRunState(card.runState, report.next_allowed_action);
|
|
408
|
+
if (readiness) {
|
|
409
|
+
const quality = localePack(interactionLocales, card.presentation_language).qualityReadiness;
|
|
410
|
+
io.log("");
|
|
411
|
+
io.log(`${quality.title}: ${primary.status[readiness.status] ?? readiness.status}`);
|
|
412
|
+
for (const row of readiness.rows) {
|
|
413
|
+
io.log(`${quality.rows[row.id]}: ${primary.status[row.status] ?? quality.unknown}`);
|
|
414
|
+
}
|
|
415
|
+
const reason = readiness.decisive_reason
|
|
416
|
+
|| (readiness.status === "pass" ? primary.none : quality.fallbackReasons[readiness.decisive_dimension] || primary.none);
|
|
417
|
+
io.log(`${quality.reason}: ${reason}`);
|
|
418
|
+
if (readiness.status !== "pass" && readiness.decisive_reference) io.log(`${quality.reference}: ${readiness.decisive_reference}`);
|
|
419
|
+
io.log(`${quality.nextAction}: ${readiness.next_action || primary.none}`);
|
|
420
|
+
io.log(`${quality.decisionOwner}: ${quality.decisionOwnerValue}`);
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export function printGateCheckReport(report, json, statusCard = false, io = console) {
|
|
426
|
+
if (json) {
|
|
427
|
+
io.log(JSON.stringify(report, null, 2));
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (statusCard) {
|
|
432
|
+
return printGateCheckStatusCard(report, io);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
io.log(`AGDF gate-check: ${report.status}`);
|
|
436
|
+
io.log(`Current gate: ${report.current_gate}`);
|
|
437
|
+
io.log(`Blocking reason: ${report.blocking_reason}`);
|
|
438
|
+
io.log(`Missing approval: ${report.missing_approval}`);
|
|
439
|
+
io.log(`Quality outlook: ${report.quality_outlook}`);
|
|
440
|
+
io.log(`Doctor: ${report.doctor_status} (${report.doctor_summary.findings} findings)`);
|
|
441
|
+
io.log("");
|
|
442
|
+
io.log("Allowed:");
|
|
443
|
+
for (const item of report.allowed) io.log(`- ${item}`);
|
|
444
|
+
io.log("");
|
|
445
|
+
io.log("Forbidden:");
|
|
446
|
+
for (const item of report.forbidden) io.log(`- ${item}`);
|
|
447
|
+
io.log("");
|
|
448
|
+
io.log(`Next allowed action: ${report.next_allowed_action}`);
|
|
449
|
+
return true;
|
|
450
|
+
}
|