create-agdf 0.13.2 → 0.13.4
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/generated/.agdf/control/templates/RUN_STATE.md +22 -0
- package/generated/.agdf/control/templates/artefacts/OR.md +22 -0
- package/generated/.github/skills/agdf-delivery-closeout/SKILL.md +7 -0
- package/generated/.github/skills/agdf-interaction-locales.json +2 -4
- package/generated/.github/skills/agdf-release-or/SKILL.md +14 -4
- package/generated/.github/skills/contracts/closeout.md +49 -0
- package/generated/.github/skills/contracts/control-scaffold.md +2 -0
- package/generated/.github/skills/contracts/interaction.md +23 -12
- package/generated/.opencode/agdf-interaction-locales.json +2 -4
- package/generated/.opencode/contracts/closeout.md +49 -0
- package/generated/.opencode/contracts/control-scaffold.md +2 -0
- package/generated/.opencode/contracts/interaction.md +23 -12
- package/generated/.opencode/skills/agdf-delivery-closeout/SKILL.md +7 -0
- package/generated/.opencode/skills/agdf-release-or/SKILL.md +14 -4
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/templates/RUN_STATE.md +22 -0
- package/generated/plugins/agdf/control/templates/artefacts/OR.md +22 -0
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +2 -4
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/agent-skills-conformance.json +86 -0
- package/generated/plugins/agdf/meta/contracts/closeout.md +49 -0
- package/generated/plugins/agdf/meta/contracts/control-scaffold.md +2 -0
- package/generated/plugins/agdf/meta/contracts/interaction.md +23 -12
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +2 -4
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +13 -3
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +9 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +6 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +16 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/parent-reconciliation.js +284 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +39 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +42 -18
- package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/agent-skills-conformance.mjs +543 -0
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +31 -17
- package/generated/plugins/agdf/skills/delivery-closeout/SKILL.md +7 -0
- package/generated/plugins/agdf/skills/release-or/SKILL.md +14 -4
- package/generated/plugins/agdf/submission/openai/availability.md +1 -1
- package/generated/plugins/agdf/submission/openai/capability-matrix.json +2 -2
- package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
- package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +2 -4
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/submissions/openai/agdf/meta/agent-skills-conformance.json +86 -0
- package/generated/submissions/openai/agdf/meta/contracts/closeout.md +49 -0
- package/generated/submissions/openai/agdf/meta/contracts/control-scaffold.md +2 -0
- package/generated/submissions/openai/agdf/meta/contracts/interaction.md +23 -12
- package/generated/submissions/openai/agdf/skills/delivery-closeout/SKILL.md +7 -0
- package/generated/submissions/openai/agdf/skills/release-or/SKILL.md +14 -4
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +19 -15
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/control-evaluation/delivery-map.js +13 -3
- package/lib/control-evaluation/doctor.js +9 -2
- package/lib/control-evaluation/gate-check.js +6 -1
- package/lib/control-evaluation/gate-policy.js +16 -1
- package/lib/control-evaluation/parent-reconciliation.js +284 -0
- package/lib/control-state/run-state-parser.js +39 -1
- package/lib/interaction-presentation.js +42 -18
- package/lib/proportionality-benchmark/blind-prompt.js +2 -1
- package/lib/proportionality-benchmark/contracts.js +16 -7
- package/lib/proportionality-benchmark/corpus-loader.js +132 -21
- package/lib/proportionality-benchmark/evaluator.js +25 -15
- package/lib/proportionality-benchmark/index.js +1 -0
- package/lib/proportionality-benchmark/live-recorder.js +32 -10
- package/lib/proportionality-benchmark/profiles.js +102 -0
- package/lib/proportionality-benchmark/report.js +10 -1
- package/lib/proportionality-benchmark/source-fingerprint.js +6 -2
- package/package.json +4 -2
package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/parent-reconciliation.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { RUN_ID_PATTERN } from "../control-state/run-state-parser.js";
|
|
2
|
+
|
|
3
|
+
const parentPrefix = "parent_run:";
|
|
4
|
+
const childPrefix = "child_run:";
|
|
5
|
+
|
|
6
|
+
function filled(value) {
|
|
7
|
+
const text = String(value ?? "").trim();
|
|
8
|
+
return Boolean(text && text !== "none" && !text.includes("<"));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function exactTarget(value, prefix) {
|
|
12
|
+
const text = String(value ?? "").trim();
|
|
13
|
+
if (!text.startsWith(prefix)) return "";
|
|
14
|
+
const runId = text.slice(prefix.length);
|
|
15
|
+
return RUN_ID_PATTERN.test(runId) && `${prefix}${runId}` === text ? runId : "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function warning(runState, code, message, nextStep) {
|
|
19
|
+
return {
|
|
20
|
+
severity: "warn",
|
|
21
|
+
code,
|
|
22
|
+
message,
|
|
23
|
+
path: runState.path,
|
|
24
|
+
next_step: nextStep,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function invalidDispositionInput(runState) {
|
|
29
|
+
const input = runState.parent_reconciliation ?? {};
|
|
30
|
+
if (!input.present) return false;
|
|
31
|
+
const counts = input.field_counts ?? {};
|
|
32
|
+
return counts.disposition !== 1
|
|
33
|
+
|| counts.next_action !== 1
|
|
34
|
+
|| !["action_required", "accepted_open"].includes(input.disposition)
|
|
35
|
+
|| !filled(input.next_action);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function openResult(runState, {
|
|
39
|
+
code = "AGDF_PARENT_RECONCILIATION_OPEN",
|
|
40
|
+
targetRunId = "",
|
|
41
|
+
evidence = "",
|
|
42
|
+
missingEvidence,
|
|
43
|
+
nextAction,
|
|
44
|
+
} = {}) {
|
|
45
|
+
const input = runState.parent_reconciliation ?? {};
|
|
46
|
+
const fieldCounts = input.field_counts ?? {};
|
|
47
|
+
const validDisposition = ["action_required", "accepted_open"].includes(input.disposition)
|
|
48
|
+
&& fieldCounts.disposition === 1;
|
|
49
|
+
const validNextAction = filled(input.next_action) && fieldCounts.next_action === 1;
|
|
50
|
+
const declaredInputInvalid = input.present && (!validDisposition || !validNextAction);
|
|
51
|
+
const action = declaredInputInvalid ? nextAction : validNextAction ? input.next_action : nextAction;
|
|
52
|
+
const finalCode = declaredInputInvalid
|
|
53
|
+
? "AGDF_PARENT_RECONCILIATION_EVIDENCE_INVALID"
|
|
54
|
+
: code;
|
|
55
|
+
return {
|
|
56
|
+
result: {
|
|
57
|
+
outcome: "open",
|
|
58
|
+
target_run_id: targetRunId,
|
|
59
|
+
disposition: validDisposition ? input.disposition : "action_required",
|
|
60
|
+
evidence,
|
|
61
|
+
missing_evidence: missingEvidence,
|
|
62
|
+
next_action: action,
|
|
63
|
+
},
|
|
64
|
+
findings: [warning(
|
|
65
|
+
runState,
|
|
66
|
+
finalCode,
|
|
67
|
+
targetRunId
|
|
68
|
+
? `Child ${runState.run_id || "run"} has an open reconciliation handoff to Parent ${targetRunId}.`
|
|
69
|
+
: `Child ${runState.run_id || "run"} has invalid or ambiguous explicit Parent relationship evidence.`,
|
|
70
|
+
action,
|
|
71
|
+
)],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function evaluateParentReconciliation(runState, { loadRun } = {}) {
|
|
76
|
+
const rows = runState.artefact_chain.filter((row) =>
|
|
77
|
+
row.from === "OR" && row.relationship === "reconciles_with"
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (!rows.length) {
|
|
81
|
+
return {
|
|
82
|
+
result: {
|
|
83
|
+
outcome: "not_applicable",
|
|
84
|
+
target_run_id: "",
|
|
85
|
+
disposition: "not_applicable",
|
|
86
|
+
evidence: "",
|
|
87
|
+
missing_evidence: "none",
|
|
88
|
+
next_action: "none",
|
|
89
|
+
},
|
|
90
|
+
findings: [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (rows.length !== 1) {
|
|
95
|
+
return openResult(runState, {
|
|
96
|
+
code: "AGDF_PARENT_RECONCILIATION_EVIDENCE_INVALID",
|
|
97
|
+
missingEvidence: "Exactly one explicit Parent relationship is required.",
|
|
98
|
+
nextAction: "Retain exactly one evidenced OR reconciles_with parent_run:<run_id> relationship.",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (invalidDispositionInput(runState)) {
|
|
103
|
+
return openResult(runState, {
|
|
104
|
+
code: "AGDF_PARENT_RECONCILIATION_EVIDENCE_INVALID",
|
|
105
|
+
missingEvidence: "The Parent reconciliation disposition or next action is invalid or duplicated.",
|
|
106
|
+
nextAction: "Record one valid disposition and exactly one concrete Parent reconciliation next action.",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const row = rows[0];
|
|
111
|
+
const parentRunId = exactTarget(row.to, parentPrefix);
|
|
112
|
+
if (!parentRunId || parentRunId === runState.run_id || !filled(row.evidence)) {
|
|
113
|
+
return openResult(runState, {
|
|
114
|
+
code: "AGDF_PARENT_RECONCILIATION_EVIDENCE_INVALID",
|
|
115
|
+
targetRunId: parentRunId,
|
|
116
|
+
evidence: row.evidence,
|
|
117
|
+
missingEvidence: "The Parent run ID and concrete relationship evidence must be valid and unambiguous.",
|
|
118
|
+
nextAction: "Repair the explicit OR reconciles_with parent_run:<run_id> row and its evidence.",
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let parent;
|
|
123
|
+
try {
|
|
124
|
+
parent = loadRun?.(parentRunId);
|
|
125
|
+
} catch {
|
|
126
|
+
parent = null;
|
|
127
|
+
}
|
|
128
|
+
if (!parent?.content || parent.resolution_error) {
|
|
129
|
+
return openResult(runState, {
|
|
130
|
+
targetRunId: parentRunId,
|
|
131
|
+
evidence: row.evidence,
|
|
132
|
+
missingEvidence: "The named Parent run is unavailable.",
|
|
133
|
+
nextAction: `Restore or select Parent run ${parentRunId}, then re-run Delivery Map.`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const reciprocalRows = parent.artefact_chain.filter((candidate) =>
|
|
138
|
+
candidate.from === "Aggregate"
|
|
139
|
+
&& candidate.relationship === "includes"
|
|
140
|
+
&& candidate.to === `${childPrefix}${runState.run_id}`
|
|
141
|
+
);
|
|
142
|
+
if (reciprocalRows.length !== 1 || !filled(reciprocalRows[0]?.evidence)) {
|
|
143
|
+
return openResult(runState, {
|
|
144
|
+
targetRunId: parentRunId,
|
|
145
|
+
evidence: row.evidence,
|
|
146
|
+
missingEvidence: reciprocalRows.length > 1
|
|
147
|
+
? "The Parent contains ambiguous reciprocal Child relationships."
|
|
148
|
+
: "The Parent lacks one evidenced reciprocal Aggregate includes Child relationship.",
|
|
149
|
+
nextAction: `Reconcile Child ${runState.run_id} in Parent ${parentRunId} through the Parent's governed scope.`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
result: {
|
|
155
|
+
outcome: "resolved",
|
|
156
|
+
target_run_id: parentRunId,
|
|
157
|
+
disposition: "not_applicable",
|
|
158
|
+
evidence: reciprocalRows[0].evidence,
|
|
159
|
+
missing_evidence: "none",
|
|
160
|
+
next_action: "none",
|
|
161
|
+
},
|
|
162
|
+
findings: [],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function completedChild(runState, resolveFile) {
|
|
167
|
+
const orArtefact = runState?.artefacts?.get("OR");
|
|
168
|
+
return Boolean(
|
|
169
|
+
runState?.content
|
|
170
|
+
&& orArtefact?.status === "done"
|
|
171
|
+
&& filled(orArtefact.path)
|
|
172
|
+
&& resolveFile?.(orArtefact.path),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function evaluateProgrammeAggregation(runState, { loadRun, resolveFile } = {}) {
|
|
177
|
+
const rows = runState.artefact_chain.filter((row) =>
|
|
178
|
+
row.from === "Aggregate" && row.relationship === "includes"
|
|
179
|
+
);
|
|
180
|
+
const input = runState.programme_aggregation ?? {};
|
|
181
|
+
const explicitInput = filled(input.acceptance_ref)
|
|
182
|
+
|| filled(input.evidence)
|
|
183
|
+
|| (Boolean(input.missing_evidence) && input.missing_evidence !== "none");
|
|
184
|
+
const applicable = explicitInput || rows.length > 0;
|
|
185
|
+
if (!applicable) {
|
|
186
|
+
return {
|
|
187
|
+
result: {
|
|
188
|
+
applicable: false,
|
|
189
|
+
startable: false,
|
|
190
|
+
final_ready: false,
|
|
191
|
+
acceptance_ref: "",
|
|
192
|
+
evidence: [],
|
|
193
|
+
missing_evidence: [],
|
|
194
|
+
next_action: "none",
|
|
195
|
+
},
|
|
196
|
+
findings: [],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const invalidRows = [];
|
|
201
|
+
const seenChildRunIds = new Set();
|
|
202
|
+
for (const row of rows) {
|
|
203
|
+
const childRunId = exactTarget(row.to, childPrefix);
|
|
204
|
+
if (!childRunId || !filled(row.evidence) || seenChildRunIds.has(childRunId)) invalidRows.push(row);
|
|
205
|
+
else seenChildRunIds.add(childRunId);
|
|
206
|
+
}
|
|
207
|
+
const completedEvidence = [];
|
|
208
|
+
for (const row of rows) {
|
|
209
|
+
const childRunId = exactTarget(row.to, childPrefix);
|
|
210
|
+
if (!childRunId || !filled(row.evidence)) continue;
|
|
211
|
+
let child;
|
|
212
|
+
try {
|
|
213
|
+
child = loadRun?.(childRunId);
|
|
214
|
+
} catch {
|
|
215
|
+
child = null;
|
|
216
|
+
}
|
|
217
|
+
if (completedChild(child, resolveFile)) completedEvidence.push({ child_run_id: childRunId, evidence: row.evidence });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const fieldCounts = input.field_counts ?? {};
|
|
221
|
+
const acceptanceRefValid = fieldCounts.acceptance_ref === 1
|
|
222
|
+
&& filled(input.acceptance_ref)
|
|
223
|
+
&& input.acceptance_ref.startsWith(".agdf/control/artefacts/")
|
|
224
|
+
&& Boolean(resolveFile?.(input.acceptance_ref));
|
|
225
|
+
const missingEvidenceValid = fieldCounts.missing_evidence === 1
|
|
226
|
+
&& input.missing_evidence === "none";
|
|
227
|
+
const evidenceFieldValid = fieldCounts.evidence === 1 && filled(input.evidence);
|
|
228
|
+
const startable = completedEvidence.length > 0;
|
|
229
|
+
const finalReady = startable && acceptanceRefValid && missingEvidenceValid && evidenceFieldValid && invalidRows.length === 0;
|
|
230
|
+
const missingEvidence = [];
|
|
231
|
+
if (!startable) missingEvidence.push("No evidenced included Child has a completed OR.");
|
|
232
|
+
if (!acceptanceRefValid) missingEvidence.push("The declared programme acceptance artefact is missing or invalid.");
|
|
233
|
+
if (!evidenceFieldValid) missingEvidence.push("Programme aggregation evidence is missing or invalid.");
|
|
234
|
+
if (!missingEvidenceValid) missingEvidence.push(input.missing_evidence || "Programme missing-evidence state is not resolved.");
|
|
235
|
+
if (invalidRows.length) missingEvidence.push("One or more Aggregate includes Child rows are invalid.");
|
|
236
|
+
const nextAction = !startable
|
|
237
|
+
? "Link at least one evidenced completed Child OR in the Parent Artefact Chain."
|
|
238
|
+
: !acceptanceRefValid
|
|
239
|
+
? "Provide one valid repository-relative programme acceptance artefact reference."
|
|
240
|
+
: !evidenceFieldValid || !missingEvidenceValid
|
|
241
|
+
? "Resolve the declared programme evidence gaps before final readiness."
|
|
242
|
+
: invalidRows.length
|
|
243
|
+
? "Repair invalid Aggregate includes child_run:<run_id> rows."
|
|
244
|
+
: "none";
|
|
245
|
+
const findings = [];
|
|
246
|
+
if (invalidRows.length) {
|
|
247
|
+
findings.push(warning(
|
|
248
|
+
runState,
|
|
249
|
+
"AGDF_PROGRAMME_AGGREGATION_EVIDENCE_INVALID",
|
|
250
|
+
"Programme aggregation contains invalid explicit Child evidence.",
|
|
251
|
+
nextAction,
|
|
252
|
+
));
|
|
253
|
+
}
|
|
254
|
+
if (!finalReady) {
|
|
255
|
+
findings.push(warning(
|
|
256
|
+
runState,
|
|
257
|
+
"AGDF_PROGRAMME_AGGREGATION_NOT_FINAL",
|
|
258
|
+
`Programme aggregation for ${runState.run_id || "run"} is ${startable ? "startable but not final-ready" : "not startable"}.`,
|
|
259
|
+
nextAction,
|
|
260
|
+
));
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
result: {
|
|
264
|
+
applicable: true,
|
|
265
|
+
startable,
|
|
266
|
+
final_ready: finalReady,
|
|
267
|
+
acceptance_ref: input.acceptance_ref,
|
|
268
|
+
evidence: completedEvidence,
|
|
269
|
+
missing_evidence: missingEvidence,
|
|
270
|
+
next_action: nextAction,
|
|
271
|
+
},
|
|
272
|
+
findings,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function evaluateReconciliationState(runState, dependencies = {}) {
|
|
277
|
+
const parent = evaluateParentReconciliation(runState, dependencies);
|
|
278
|
+
const programme = evaluateProgrammeAggregation(runState, dependencies);
|
|
279
|
+
return {
|
|
280
|
+
parent_reconciliation: parent.result,
|
|
281
|
+
programme_aggregation: programme.result,
|
|
282
|
+
findings: [...parent.findings, ...programme.findings],
|
|
283
|
+
};
|
|
284
|
+
}
|
|
@@ -105,6 +105,15 @@ function field(c, k) {
|
|
|
105
105
|
function sectionField(c, h, k) {
|
|
106
106
|
return field(section(c, h), k);
|
|
107
107
|
}
|
|
108
|
+
function sectionScalar(c, h, k) {
|
|
109
|
+
const body = section(c, h);
|
|
110
|
+
const escaped = k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
111
|
+
const matches = [...body.matchAll(new RegExp(`^- ${escaped}:[^\\S\\r\\n]*(.*)$`, "gm"))];
|
|
112
|
+
return {
|
|
113
|
+
value: clean(matches[0]?.[1] ?? ""),
|
|
114
|
+
count: matches.length,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
108
117
|
function dataRows(c, h, header) {
|
|
109
118
|
return rows(section(c, h)).filter(
|
|
110
119
|
(r) =>
|
|
@@ -116,6 +125,7 @@ export function parseControlState(
|
|
|
116
125
|
content,
|
|
117
126
|
{ userGates = [], internalSteps = [], closeoutArtefacts = [] } = {},
|
|
118
127
|
) {
|
|
128
|
+
const metaValues = scalarFields(content).values;
|
|
119
129
|
const approvals = new Map();
|
|
120
130
|
for (const h of ["Approvals", "Gate Checklist"])
|
|
121
131
|
for (const [g, s, e] of rows(section(content, h))) {
|
|
@@ -146,8 +156,16 @@ export function parseControlState(
|
|
|
146
156
|
? "Mode/Slice Decision"
|
|
147
157
|
: "Mode / Slice Decision",
|
|
148
158
|
source = "Source And Scope State",
|
|
149
|
-
memory = "Knowledge Persistence Decision"
|
|
159
|
+
memory = "Knowledge Persistence Decision",
|
|
160
|
+
handoff = "Parent Reconciliation Handoff",
|
|
161
|
+
aggregation = "Programme Aggregation Readiness";
|
|
162
|
+
const disposition = sectionScalar(content, handoff, "parent_reconciliation_disposition");
|
|
163
|
+
const reconciliationNextAction = sectionScalar(content, handoff, "parent_reconciliation_next_action");
|
|
164
|
+
const acceptanceRef = sectionScalar(content, aggregation, "programme_acceptance_ref");
|
|
165
|
+
const aggregationEvidence = sectionScalar(content, aggregation, "programme_aggregation_evidence");
|
|
166
|
+
const aggregationMissingEvidence = sectionScalar(content, aggregation, "programme_aggregation_missing_evidence");
|
|
150
167
|
return {
|
|
168
|
+
run_id: clean(metaValues.get("run_id") ?? ""),
|
|
151
169
|
current_gate: field(content, "current_gate"),
|
|
152
170
|
next_allowed_action: field(content, "next_allowed_action"),
|
|
153
171
|
approvals,
|
|
@@ -223,5 +241,25 @@ export function parseControlState(
|
|
|
223
241
|
reason: sectionField(content, memory, "memory_reason"),
|
|
224
242
|
refs: sectionField(content, memory, "memory_refs"),
|
|
225
243
|
},
|
|
244
|
+
parent_reconciliation: {
|
|
245
|
+
present: Boolean(section(content, handoff).trim()),
|
|
246
|
+
disposition: disposition.value,
|
|
247
|
+
next_action: reconciliationNextAction.value,
|
|
248
|
+
field_counts: {
|
|
249
|
+
disposition: disposition.count,
|
|
250
|
+
next_action: reconciliationNextAction.count,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
programme_aggregation: {
|
|
254
|
+
present: Boolean(section(content, aggregation).trim()),
|
|
255
|
+
acceptance_ref: acceptanceRef.value,
|
|
256
|
+
evidence: aggregationEvidence.value,
|
|
257
|
+
missing_evidence: aggregationMissingEvidence.value,
|
|
258
|
+
field_counts: {
|
|
259
|
+
acceptance_ref: acceptanceRef.count,
|
|
260
|
+
evidence: aggregationEvidence.count,
|
|
261
|
+
missing_evidence: aggregationMissingEvidence.count,
|
|
262
|
+
},
|
|
263
|
+
},
|
|
226
264
|
};
|
|
227
265
|
}
|
|
@@ -11,11 +11,28 @@ const QUALITY_DIMENSIONS = Object.freeze([
|
|
|
11
11
|
Object.freeze({ id: "code_quality", owner: "code-review" }),
|
|
12
12
|
Object.freeze({ id: "qa_decision", owner: "qa-gate" }),
|
|
13
13
|
]);
|
|
14
|
+
const SCOPE_CLASSIFICATION_LIMITS = Object.freeze({
|
|
15
|
+
maxCodePointsPerField: 240,
|
|
16
|
+
minEscalationTriggers: 1,
|
|
17
|
+
maxEscalationTriggers: 3,
|
|
18
|
+
});
|
|
19
|
+
const SCOPE_CLASSIFICATION_MARKDOWN_CONTROL = /[\\`*_\[\]<>|]/;
|
|
20
|
+
const SCOPE_CLASSIFICATION_LINE_STRUCTURE = /^(?:[#>+\-]\s|\d+\.\s)/;
|
|
14
21
|
|
|
15
22
|
function plainObject(value) {
|
|
16
23
|
return value && typeof value === "object" && !Array.isArray(value);
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
function scopeClassificationText(value) {
|
|
27
|
+
if (typeof value !== "string") return null;
|
|
28
|
+
const normalized = value.trim();
|
|
29
|
+
if (!normalized || /[\r\n\u2028\u2029]/.test(value)) return null;
|
|
30
|
+
if (Array.from(normalized).length > SCOPE_CLASSIFICATION_LIMITS.maxCodePointsPerField) return null;
|
|
31
|
+
if (SCOPE_CLASSIFICATION_MARKDOWN_CONTROL.test(normalized)) return null;
|
|
32
|
+
if (SCOPE_CLASSIFICATION_LINE_STRUCTURE.test(normalized)) return null;
|
|
33
|
+
return normalized;
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
function flattenKeys(value, prefix = "") {
|
|
20
37
|
const keys = [];
|
|
21
38
|
for (const [key, child] of Object.entries(value ?? {})) {
|
|
@@ -439,22 +456,22 @@ export function renderScopeClassificationCard(classification, {
|
|
|
439
456
|
requestedLocale,
|
|
440
457
|
} = {}) {
|
|
441
458
|
if (!plainObject(classification)) return null;
|
|
442
|
-
const outcome =
|
|
443
|
-
|
|
444
|
-
const trivialBoundary = String(classification.trivial_boundary ?? "").trim();
|
|
445
|
-
const urTriggerEvaluation = String(classification.ur_trigger_evaluation ?? "").trim();
|
|
446
|
-
const allowedSummary = String(classification.allowed_summary ?? "").trim();
|
|
447
|
-
const forbiddenSummary = String(classification.forbidden_summary ?? "").trim();
|
|
448
|
-
const escalationTriggers = Array.isArray(classification.escalation_triggers)
|
|
449
|
-
? classification.escalation_triggers.map((item) => String(item ?? "").trim()).filter(Boolean)
|
|
450
|
-
: [];
|
|
451
|
-
const challengePath = String(classification.challenge_path ?? "").trim();
|
|
452
|
-
|
|
453
|
-
if (outcome !== "ungated") return null;
|
|
454
|
-
if (!["quick_task", "verified_change"].includes(mode)) return null;
|
|
459
|
+
const { outcome, mode, trivial_boundary: trivialBoundary } = classification;
|
|
460
|
+
if (outcome !== "ungated" || mode !== "quick_task") return null;
|
|
455
461
|
if (!["inside", "outside"].includes(trivialBoundary)) return null;
|
|
462
|
+
|
|
463
|
+
const urTriggerEvaluation = scopeClassificationText(classification.ur_trigger_evaluation);
|
|
464
|
+
const allowedSummary = scopeClassificationText(classification.allowed_summary);
|
|
465
|
+
const forbiddenSummary = scopeClassificationText(classification.forbidden_summary);
|
|
466
|
+
const challengePath = scopeClassificationText(classification.challenge_path);
|
|
456
467
|
if (!urTriggerEvaluation || !allowedSummary || !forbiddenSummary || !challengePath) return null;
|
|
457
|
-
|
|
468
|
+
|
|
469
|
+
if (!Array.isArray(classification.escalation_triggers)
|
|
470
|
+
|| classification.escalation_triggers.length < SCOPE_CLASSIFICATION_LIMITS.minEscalationTriggers
|
|
471
|
+
|| classification.escalation_triggers.length > SCOPE_CLASSIFICATION_LIMITS.maxEscalationTriggers) return null;
|
|
472
|
+
const escalationTriggers = classification.escalation_triggers.map(scopeClassificationText);
|
|
473
|
+
if (escalationTriggers.some((item) => !item)) return null;
|
|
474
|
+
if (new Set(escalationTriggers).size !== escalationTriggers.length) return null;
|
|
458
475
|
|
|
459
476
|
let locale;
|
|
460
477
|
try {
|
|
@@ -541,9 +558,15 @@ export function buildApprovalOrientationSnapshot({
|
|
|
541
558
|
const primaryHeading = String(pack.gateActionTitles?.[gate] ?? "").trim();
|
|
542
559
|
const artefactRefs = Object.freeze([...(humanPresentation.artefactRefs ?? [])].map((ref) => Object.freeze({ ...ref })));
|
|
543
560
|
const nextGate = String(statusCard.next_gate_after_approval ?? "none");
|
|
561
|
+
const nextUserGate = String(statusCard.next_user_gate ?? "").trim();
|
|
562
|
+
const userActionRequired = String(statusCard.user_action_required ?? "").trim();
|
|
563
|
+
const userActionSemanticsValid = (userActionRequired === "no" && nextUserGate === "none")
|
|
564
|
+
|| (userActionRequired === "yes" && REQUIRED_GATES.includes(nextUserGate) && nextGate === nextUserGate);
|
|
565
|
+
if (!userActionSemanticsValid) return null;
|
|
544
566
|
const narration = pack.primary.narration.gates[gate] ?? {};
|
|
545
|
-
const nextDecision =
|
|
546
|
-
|
|
567
|
+
const nextDecision = userActionRequired === "no"
|
|
568
|
+
? pack.primary.narration.noAction
|
|
569
|
+
: narration.userAction || `${pack.gateTitles[nextUserGate] ?? nextUserGate} ${pack.interaction.decisionFollows}`;
|
|
547
570
|
const statusFields = Object.freeze([
|
|
548
571
|
Object.freeze({ id: "selected_run", label: pack.statusCard.run, value: `${runTitle} · \`${runId}\`` }),
|
|
549
572
|
Object.freeze({ id: "readiness_status", label: pack.statusCard.title, value: pack.interaction.ready }),
|
|
@@ -638,8 +661,9 @@ export function validateApprovalOrientationSnapshot(snapshot, { registry, expect
|
|
|
638
661
|
const localizedGateTitle = gateTitle(registry, locale, gate);
|
|
639
662
|
const nextGate = String(snapshot.gate_transition_card?.next_gate ?? "none");
|
|
640
663
|
const narration = pack.primary.narration.gates[gate] ?? {};
|
|
641
|
-
const nextDecision =
|
|
642
|
-
|
|
664
|
+
const nextDecision = REQUIRED_GATES.includes(nextGate)
|
|
665
|
+
? narration.userAction || `${pack.gateTitles[nextGate] ?? nextGate} ${pack.interaction.decisionFollows}`
|
|
666
|
+
: pack.primary.narration.noAction;
|
|
643
667
|
const nextTransition = `${narration.agentNext ?? pack.primary.actions[gate] ?? ""}. ${nextDecision}.`;
|
|
644
668
|
const localeConsistent = resolvePresentationLocale(registry, locale) === locale
|
|
645
669
|
&& heading === pack.gateActionTitles?.[gate]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": "1",
|
|
3
3
|
"generated": true,
|
|
4
4
|
"source": "create-agdf/cli",
|
|
5
|
-
"version": "0.13.
|
|
5
|
+
"version": "0.13.4",
|
|
6
6
|
"entrypoint": "create-agdf/bin/agdf-validator.js",
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "a2fad4da3d4de2bd3fd5e11c93f0c539ea02ebd04bf2e63e9ea206bbcfbe357f"
|
|
8
8
|
}
|