create-agdf 0.8.4 → 0.8.5
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/.github/skills/agdf-gate-check/SKILL.md +2 -2
- package/generated/.github/skills/agdf-interaction-locales.json +16 -0
- package/generated/.github/skills/agdf-runtime-contract.md +8 -0
- package/generated/.opencode/agdf-interaction-locales.json +16 -0
- package/generated/.opencode/agdf-runtime-contract.md +8 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +2 -2
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +16 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +9 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +8 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +2 -2
- package/lib/interaction-presentation.js +35 -3
- package/package.json +1 -1
|
@@ -63,14 +63,14 @@ For a ready `gate_approval`:
|
|
|
63
63
|
1. Resolve exactly one selected run and evaluate the current gate.
|
|
64
64
|
2. Confirm the required durable artefact is present and ready before presenting a question.
|
|
65
65
|
3. Build one immutable, non-authorizing presentation snapshot from the selected evaluated run and current revision identity.
|
|
66
|
-
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
66
|
+
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. Its first visible line is the localized action-oriented gate title as a level-two Markdown heading or equivalent accessible host heading; generic AGDF/card labels and raw gate IDs cannot be the primary heading. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
67
67
|
5. In the same assistant message, render a separate localized Gate Transition Card second, immediately before any native question or exact-text fallback. It includes the deterministic human run title and `UR · PRD · SD · TP` links from the selected run. Never put either card only into the question, button description or hidden tool context. Do not invoke the native question tool until the complete two-card envelope is visible.
|
|
68
68
|
6. Compose the transition card as one human-readable gate title with `run_id`, one ready-for-decision line, one short approval-effect block and one short next-transition block. It must answer only: where am I, what does this decision do, and what happens next. Run and gate identity may anchor both cards; do not duplicate status rows, action inventories or the native question.
|
|
69
69
|
7. Distinguish internal process steps from user decisions in natural language. For example, after `Approval: TP`, say that pre-implementation Brownfield Analysis runs next and that no further user action is required now; do not expose `next_user_gate: none` or `user_action_required: no`, and do not ask for a second approval for Brownfield Analysis.
|
|
70
70
|
8. Ask exactly one question that names the selected `run_id` and `current_gate`.
|
|
71
71
|
9. Offer options in stable order: exact `Approval: <GateName>`, localized revise and localized decline. Add explicit cancel only where supported after decline; otherwise host dismissal maps to cancel. Never preselect, skip, auto-submit or reorder an option.
|
|
72
72
|
10. Use the surface adapter declared in the canonical plugin definition only when it can wait for deliberate input without auto-resolution; otherwise request the same exact approval in concise text.
|
|
73
|
-
11. Render both cards once in that single complete assistant message. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
73
|
+
11. Render both cards once in that single complete assistant message. Never merge, reverse, omit or duplicate them; the action heading does not replace either card. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
74
74
|
12. Re-run gate evaluation for the same run and expected gate after the response and immediately before persistence.
|
|
75
75
|
13. Reject a missing artefact, ambiguous or wrong run, wrong gate, stale expected gate, timeout/default, hook-supplied answer, agent message, technical permission outcome or plan approval.
|
|
76
76
|
14. Persist accepted input only through the existing control-state workflow.
|
|
@@ -65,6 +65,14 @@
|
|
|
65
65
|
"CR": "Code review",
|
|
66
66
|
"OR": "Delivery report"
|
|
67
67
|
},
|
|
68
|
+
"gateActionTitles": {
|
|
69
|
+
"UR": "Approve user requirements",
|
|
70
|
+
"PRD": "Approve product requirements",
|
|
71
|
+
"SD": "Approve solution design",
|
|
72
|
+
"TP": "Approve task and test plan",
|
|
73
|
+
"QA": "Approve quality decision",
|
|
74
|
+
"UAT": "Accept delivery result"
|
|
75
|
+
},
|
|
68
76
|
"interaction": {
|
|
69
77
|
"ready": "Ready for your decision",
|
|
70
78
|
"approveHeading": "Approve now",
|
|
@@ -180,6 +188,14 @@
|
|
|
180
188
|
"CR": "Code-Review",
|
|
181
189
|
"OR": "Lieferbericht"
|
|
182
190
|
},
|
|
191
|
+
"gateActionTitles": {
|
|
192
|
+
"UR": "Nutzeranforderung freigeben",
|
|
193
|
+
"PRD": "Produktanforderungen freigeben",
|
|
194
|
+
"SD": "Lösungsdesign freigeben",
|
|
195
|
+
"TP": "Umsetzungsplan freigeben",
|
|
196
|
+
"QA": "Qualitätsentscheidung freigeben",
|
|
197
|
+
"UAT": "Ergebnis abnehmen"
|
|
198
|
+
},
|
|
183
199
|
"interaction": {
|
|
184
200
|
"ready": "Bereit für deine Entscheidung",
|
|
185
201
|
"approveHeading": "Jetzt freigeben",
|
|
@@ -181,6 +181,14 @@ before invoking any native question tool or emitting an exact-text approval
|
|
|
181
181
|
request. Splitting the cards across separate assistant turns or invoking the
|
|
182
182
|
tool after only one card is a failed interaction, not a valid presentation.
|
|
183
183
|
|
|
184
|
+
The first visible line of that envelope is the localized action-oriented title
|
|
185
|
+
of the current user gate, rendered as a level-two Markdown heading or equivalent
|
|
186
|
+
accessible host heading inside the compact approval-time Run Status Card.
|
|
187
|
+
`AGDF Status`, `Run Status Card`, `Gate Transition Card`, raw gate identifiers
|
|
188
|
+
and machine values are semantic or diagnostic labels only and must not become
|
|
189
|
+
the primary heading. The action title appears exactly once and does not replace,
|
|
190
|
+
merge or reorder either required card block.
|
|
191
|
+
|
|
184
192
|
The compact approval-time Run Status Card contains exactly six operational
|
|
185
193
|
fields: selected run, readiness status, current gate, missing exact approval,
|
|
186
194
|
one next action and quality outlook. It uses localized human-readable labels
|
|
@@ -65,6 +65,14 @@
|
|
|
65
65
|
"CR": "Code review",
|
|
66
66
|
"OR": "Delivery report"
|
|
67
67
|
},
|
|
68
|
+
"gateActionTitles": {
|
|
69
|
+
"UR": "Approve user requirements",
|
|
70
|
+
"PRD": "Approve product requirements",
|
|
71
|
+
"SD": "Approve solution design",
|
|
72
|
+
"TP": "Approve task and test plan",
|
|
73
|
+
"QA": "Approve quality decision",
|
|
74
|
+
"UAT": "Accept delivery result"
|
|
75
|
+
},
|
|
68
76
|
"interaction": {
|
|
69
77
|
"ready": "Ready for your decision",
|
|
70
78
|
"approveHeading": "Approve now",
|
|
@@ -180,6 +188,14 @@
|
|
|
180
188
|
"CR": "Code-Review",
|
|
181
189
|
"OR": "Lieferbericht"
|
|
182
190
|
},
|
|
191
|
+
"gateActionTitles": {
|
|
192
|
+
"UR": "Nutzeranforderung freigeben",
|
|
193
|
+
"PRD": "Produktanforderungen freigeben",
|
|
194
|
+
"SD": "Lösungsdesign freigeben",
|
|
195
|
+
"TP": "Umsetzungsplan freigeben",
|
|
196
|
+
"QA": "Qualitätsentscheidung freigeben",
|
|
197
|
+
"UAT": "Ergebnis abnehmen"
|
|
198
|
+
},
|
|
183
199
|
"interaction": {
|
|
184
200
|
"ready": "Bereit für deine Entscheidung",
|
|
185
201
|
"approveHeading": "Jetzt freigeben",
|
|
@@ -181,6 +181,14 @@ before invoking any native question tool or emitting an exact-text approval
|
|
|
181
181
|
request. Splitting the cards across separate assistant turns or invoking the
|
|
182
182
|
tool after only one card is a failed interaction, not a valid presentation.
|
|
183
183
|
|
|
184
|
+
The first visible line of that envelope is the localized action-oriented title
|
|
185
|
+
of the current user gate, rendered as a level-two Markdown heading or equivalent
|
|
186
|
+
accessible host heading inside the compact approval-time Run Status Card.
|
|
187
|
+
`AGDF Status`, `Run Status Card`, `Gate Transition Card`, raw gate identifiers
|
|
188
|
+
and machine values are semantic or diagnostic labels only and must not become
|
|
189
|
+
the primary heading. The action title appears exactly once and does not replace,
|
|
190
|
+
merge or reorder either required card block.
|
|
191
|
+
|
|
184
192
|
The compact approval-time Run Status Card contains exactly six operational
|
|
185
193
|
fields: selected run, readiness status, current gate, missing exact approval,
|
|
186
194
|
one next action and quality outlook. It uses localized human-readable labels
|
|
@@ -63,14 +63,14 @@ For a ready `gate_approval`:
|
|
|
63
63
|
1. Resolve exactly one selected run and evaluate the current gate.
|
|
64
64
|
2. Confirm the required durable artefact is present and ready before presenting a question.
|
|
65
65
|
3. Build one immutable, non-authorizing presentation snapshot from the selected evaluated run and current revision identity.
|
|
66
|
-
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
66
|
+
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. Its first visible line is the localized action-oriented gate title as a level-two Markdown heading or equivalent accessible host heading; generic AGDF/card labels and raw gate IDs cannot be the primary heading. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
67
67
|
5. In the same assistant message, render a separate localized Gate Transition Card second, immediately before any native question or exact-text fallback. It includes the deterministic human run title and `UR · PRD · SD · TP` links from the selected run. Never put either card only into the question, button description or hidden tool context. Do not invoke the native question tool until the complete two-card envelope is visible.
|
|
68
68
|
6. Compose the transition card as one human-readable gate title with `run_id`, one ready-for-decision line, one short approval-effect block and one short next-transition block. It must answer only: where am I, what does this decision do, and what happens next. Run and gate identity may anchor both cards; do not duplicate status rows, action inventories or the native question.
|
|
69
69
|
7. Distinguish internal process steps from user decisions in natural language. For example, after `Approval: TP`, say that pre-implementation Brownfield Analysis runs next and that no further user action is required now; do not expose `next_user_gate: none` or `user_action_required: no`, and do not ask for a second approval for Brownfield Analysis.
|
|
70
70
|
8. Ask exactly one question that names the selected `run_id` and `current_gate`.
|
|
71
71
|
9. Offer options in stable order: exact `Approval: <GateName>`, localized revise and localized decline. Add explicit cancel only where supported after decline; otherwise host dismissal maps to cancel. Never preselect, skip, auto-submit or reorder an option.
|
|
72
72
|
10. Use the surface adapter declared in the canonical plugin definition only when it can wait for deliberate input without auto-resolution; otherwise request the same exact approval in concise text.
|
|
73
|
-
11. Render both cards once in that single complete assistant message. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
73
|
+
11. Render both cards once in that single complete assistant message. Never merge, reverse, omit or duplicate them; the action heading does not replace either card. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
74
74
|
12. Re-run gate evaluation for the same run and expected gate after the response and immediately before persistence.
|
|
75
75
|
13. Reject a missing artefact, ambiguous or wrong run, wrong gate, stale expected gate, timeout/default, hook-supplied answer, agent message, technical permission outcome or plan approval.
|
|
76
76
|
14. Persist accepted input only through the existing control-state workflow.
|
|
@@ -65,6 +65,14 @@
|
|
|
65
65
|
"CR": "Code review",
|
|
66
66
|
"OR": "Delivery report"
|
|
67
67
|
},
|
|
68
|
+
"gateActionTitles": {
|
|
69
|
+
"UR": "Approve user requirements",
|
|
70
|
+
"PRD": "Approve product requirements",
|
|
71
|
+
"SD": "Approve solution design",
|
|
72
|
+
"TP": "Approve task and test plan",
|
|
73
|
+
"QA": "Approve quality decision",
|
|
74
|
+
"UAT": "Accept delivery result"
|
|
75
|
+
},
|
|
68
76
|
"interaction": {
|
|
69
77
|
"ready": "Ready for your decision",
|
|
70
78
|
"approveHeading": "Approve now",
|
|
@@ -180,6 +188,14 @@
|
|
|
180
188
|
"CR": "Code-Review",
|
|
181
189
|
"OR": "Lieferbericht"
|
|
182
190
|
},
|
|
191
|
+
"gateActionTitles": {
|
|
192
|
+
"UR": "Nutzeranforderung freigeben",
|
|
193
|
+
"PRD": "Produktanforderungen freigeben",
|
|
194
|
+
"SD": "Lösungsdesign freigeben",
|
|
195
|
+
"TP": "Umsetzungsplan freigeben",
|
|
196
|
+
"QA": "Qualitätsentscheidung freigeben",
|
|
197
|
+
"UAT": "Ergebnis abnehmen"
|
|
198
|
+
},
|
|
183
199
|
"interaction": {
|
|
184
200
|
"ready": "Bereit für deine Entscheidung",
|
|
185
201
|
"approveHeading": "Jetzt freigeben",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "agdf",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.5",
|
|
5
5
|
"displayName": "AI Governance & Delivery Framework",
|
|
6
6
|
"developerName": "Arndt Gold",
|
|
7
7
|
"description": "Codex-first operating system for governed AI-assisted delivery.",
|
|
@@ -97,6 +97,8 @@
|
|
|
97
97
|
"decline"
|
|
98
98
|
],
|
|
99
99
|
"dismissOutcome": "cancel",
|
|
100
|
+
"canonicalValueTransport": false,
|
|
101
|
+
"authorizationPath": "exact_text",
|
|
100
102
|
"technicalPermissionOwner": "codex_host"
|
|
101
103
|
},
|
|
102
104
|
"claude": {
|
|
@@ -109,6 +111,8 @@
|
|
|
109
111
|
"decline"
|
|
110
112
|
],
|
|
111
113
|
"dismissOutcome": "cancel",
|
|
114
|
+
"canonicalValueTransport": false,
|
|
115
|
+
"authorizationPath": "exact_text",
|
|
112
116
|
"technicalPermissionOwner": "claude_host"
|
|
113
117
|
},
|
|
114
118
|
"opencode": {
|
|
@@ -121,6 +125,8 @@
|
|
|
121
125
|
"decline"
|
|
122
126
|
],
|
|
123
127
|
"dismissOutcome": "cancel",
|
|
128
|
+
"canonicalValueTransport": false,
|
|
129
|
+
"authorizationPath": "exact_text",
|
|
124
130
|
"technicalPermissionOwner": "opencode_host"
|
|
125
131
|
},
|
|
126
132
|
"fallback": {
|
|
@@ -133,6 +139,8 @@
|
|
|
133
139
|
"decline",
|
|
134
140
|
"cancel"
|
|
135
141
|
],
|
|
142
|
+
"canonicalValueTransport": true,
|
|
143
|
+
"authorizationPath": "exact_text",
|
|
136
144
|
"technicalPermissionOwner": "host_specific"
|
|
137
145
|
}
|
|
138
146
|
}
|
|
@@ -181,6 +181,14 @@ before invoking any native question tool or emitting an exact-text approval
|
|
|
181
181
|
request. Splitting the cards across separate assistant turns or invoking the
|
|
182
182
|
tool after only one card is a failed interaction, not a valid presentation.
|
|
183
183
|
|
|
184
|
+
The first visible line of that envelope is the localized action-oriented title
|
|
185
|
+
of the current user gate, rendered as a level-two Markdown heading or equivalent
|
|
186
|
+
accessible host heading inside the compact approval-time Run Status Card.
|
|
187
|
+
`AGDF Status`, `Run Status Card`, `Gate Transition Card`, raw gate identifiers
|
|
188
|
+
and machine values are semantic or diagnostic labels only and must not become
|
|
189
|
+
the primary heading. The action title appears exactly once and does not replace,
|
|
190
|
+
merge or reorder either required card block.
|
|
191
|
+
|
|
184
192
|
The compact approval-time Run Status Card contains exactly six operational
|
|
185
193
|
fields: selected run, readiness status, current gate, missing exact approval,
|
|
186
194
|
one next action and quality outlook. It uses localized human-readable labels
|
|
@@ -63,14 +63,14 @@ For a ready `gate_approval`:
|
|
|
63
63
|
1. Resolve exactly one selected run and evaluate the current gate.
|
|
64
64
|
2. Confirm the required durable artefact is present and ready before presenting a question.
|
|
65
65
|
3. Build one immutable, non-authorizing presentation snapshot from the selected evaluated run and current revision identity.
|
|
66
|
-
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
66
|
+
4. Compose one Approval Orientation Envelope as one immediately preceding assistant message containing two distinct blocks. Render the compact localized approval-time Run Status Card first. Its first visible line is the localized action-oriented gate title as a level-two Markdown heading or equivalent accessible host heading; generic AGDF/card labels and raw gate IDs cannot be the primary heading. It contains exactly selected run, readiness status, current gate, missing exact approval, one next action and quality outlook; omit raw keys, machine statuses, evidence, diagnostics and allowed/forbidden inventories.
|
|
67
67
|
5. In the same assistant message, render a separate localized Gate Transition Card second, immediately before any native question or exact-text fallback. It includes the deterministic human run title and `UR · PRD · SD · TP` links from the selected run. Never put either card only into the question, button description or hidden tool context. Do not invoke the native question tool until the complete two-card envelope is visible.
|
|
68
68
|
6. Compose the transition card as one human-readable gate title with `run_id`, one ready-for-decision line, one short approval-effect block and one short next-transition block. It must answer only: where am I, what does this decision do, and what happens next. Run and gate identity may anchor both cards; do not duplicate status rows, action inventories or the native question.
|
|
69
69
|
7. Distinguish internal process steps from user decisions in natural language. For example, after `Approval: TP`, say that pre-implementation Brownfield Analysis runs next and that no further user action is required now; do not expose `next_user_gate: none` or `user_action_required: no`, and do not ask for a second approval for Brownfield Analysis.
|
|
70
70
|
8. Ask exactly one question that names the selected `run_id` and `current_gate`.
|
|
71
71
|
9. Offer options in stable order: exact `Approval: <GateName>`, localized revise and localized decline. Add explicit cancel only where supported after decline; otherwise host dismissal maps to cancel. Never preselect, skip, auto-submit or reorder an option.
|
|
72
72
|
10. Use the surface adapter declared in the canonical plugin definition only when it can wait for deliberate input without auto-resolution; otherwise request the same exact approval in concise text.
|
|
73
|
-
11. Render both cards once in that single complete assistant message. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
73
|
+
11. Render both cards once in that single complete assistant message. Never merge, reverse, omit or duplicate them; the action heading does not replace either card. If the native attempt is unavailable or not applied, continue to exact text without repeating either card.
|
|
74
74
|
12. Re-run gate evaluation for the same run and expected gate after the response and immediately before persistence.
|
|
75
75
|
13. Reject a missing artefact, ambiguous or wrong run, wrong gate, stale expected gate, timeout/default, hook-supplied answer, agent message, technical permission outcome or plan approval.
|
|
76
76
|
14. Persist accepted input only through the existing control-state workflow.
|
|
@@ -70,6 +70,7 @@ export function validateLocaleRegistry(registry) {
|
|
|
70
70
|
}
|
|
71
71
|
for (const key of REQUIRED_GATES) {
|
|
72
72
|
if (typeof pack.gateTitles?.[key] !== "string" || !pack.gateTitles[key].trim()) errors.push(`missing_gate_title:${locale}:${key}`);
|
|
73
|
+
if (typeof pack.gateActionTitles?.[key] !== "string" || !pack.gateActionTitles[key].trim()) errors.push(`missing_gate_action_title:${locale}:${key}`);
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
if (JSON.stringify(registry?.optionOrder) !== JSON.stringify(["approve", "revise", "decline", "cancel"])) errors.push("option_order");
|
|
@@ -179,8 +180,10 @@ export function reconcileRunScope({ requestText = "", scopeKey = "", runs = [] }
|
|
|
179
180
|
return Object.freeze({ outcome: matches[0].lifecycle === "active" ? "active_match" : "completed_match", matches, reason: "exact_match" });
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
export function executeNativeApprovalAttempt({ ready = false, invokeNative, fallback } = {}) {
|
|
183
|
+
export function executeNativeApprovalAttempt({ ready = false, orientationSnapshot, invokeNative, fallback } = {}) {
|
|
183
184
|
if (!ready) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "gate_not_ready", authorizes: false });
|
|
185
|
+
const preflight = validateApprovalOrientationSnapshot(orientationSnapshot);
|
|
186
|
+
if (!preflight.valid) return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "orientation_preflight_failed", authorizes: false });
|
|
184
187
|
if (typeof invokeNative !== "function") return Object.freeze({ attempted: false, outcome: "unavailable_before_invocation", reason: "adapter_unavailable", authorizes: false });
|
|
185
188
|
let adapterResult;
|
|
186
189
|
try {
|
|
@@ -280,6 +283,7 @@ export function buildApprovalOrientationSnapshot({
|
|
|
280
283
|
const pack = localePack(registry, locale);
|
|
281
284
|
const runTitle = String(humanPresentation.runTitle ?? "").trim() || normalizedRunTitle(runId);
|
|
282
285
|
const currentGateTitle = String(humanPresentation.gateTitle ?? "").trim() || gateTitle(registry, locale, gate);
|
|
286
|
+
const primaryHeading = String(pack.gateActionTitles?.[gate] ?? "").trim();
|
|
283
287
|
const artefactRefs = Object.freeze([...(humanPresentation.artefactRefs ?? [])].map((ref) => Object.freeze({ ...ref })));
|
|
284
288
|
const statusFields = Object.freeze([
|
|
285
289
|
Object.freeze({ id: "selected_run", label: pack.statusCard.run, value: `${runTitle} · ${runId}` }),
|
|
@@ -298,8 +302,15 @@ export function buildApprovalOrientationSnapshot({
|
|
|
298
302
|
current_gate: gate,
|
|
299
303
|
presentation_language: locale,
|
|
300
304
|
sequence: APPROVAL_SEQUENCE,
|
|
301
|
-
compact_status_card: Object.freeze({
|
|
305
|
+
compact_status_card: Object.freeze({
|
|
306
|
+
semantic_block: "run_status_card",
|
|
307
|
+
title: primaryHeading,
|
|
308
|
+
primary_heading: primaryHeading,
|
|
309
|
+
primary_heading_level: 2,
|
|
310
|
+
fields: statusFields,
|
|
311
|
+
}),
|
|
302
312
|
gate_transition_card: Object.freeze({
|
|
313
|
+
semantic_block: "gate_transition_card",
|
|
303
314
|
title: `${currentGateTitle} · ${runTitle} · ${runId}`,
|
|
304
315
|
artefact_refs: artefactRefs,
|
|
305
316
|
ready: pack.interaction.ready,
|
|
@@ -309,11 +320,32 @@ export function buildApprovalOrientationSnapshot({
|
|
|
309
320
|
next_heading: pack.interaction.nextHeading,
|
|
310
321
|
next_gate: String(statusCard.next_gate_after_approval ?? "none"),
|
|
311
322
|
}),
|
|
312
|
-
approval_interaction: Object.freeze({ expected_approval: expectedApproval, options, authorizes: false }),
|
|
323
|
+
approval_interaction: Object.freeze({ semantic_block: "approval_interaction", expected_approval: expectedApproval, options, authorizes: false }),
|
|
313
324
|
authorizes: false,
|
|
314
325
|
});
|
|
315
326
|
}
|
|
316
327
|
|
|
328
|
+
export function validateApprovalOrientationSnapshot(snapshot) {
|
|
329
|
+
const errors = [];
|
|
330
|
+
if (!plainObject(snapshot)) return Object.freeze({ valid: false, errors: Object.freeze(["snapshot_missing"]) });
|
|
331
|
+
if (JSON.stringify(snapshot.sequence) !== JSON.stringify(APPROVAL_SEQUENCE)) errors.push("sequence");
|
|
332
|
+
if (snapshot.compact_status_card?.semantic_block !== "run_status_card") errors.push("run_status_card");
|
|
333
|
+
if (snapshot.gate_transition_card?.semantic_block !== "gate_transition_card") errors.push("gate_transition_card");
|
|
334
|
+
if (snapshot.approval_interaction?.semantic_block !== "approval_interaction") errors.push("approval_interaction");
|
|
335
|
+
const heading = String(snapshot.compact_status_card?.primary_heading ?? "").trim();
|
|
336
|
+
if (!heading || snapshot.compact_status_card?.primary_heading_level !== 2) errors.push("primary_heading");
|
|
337
|
+
if (String(snapshot.compact_status_card?.title ?? "").trim() !== heading) errors.push("primary_heading_owner");
|
|
338
|
+
if (/^(?:(?:agdf[- ]?status(?: card|karte)?|run status card|gate transition card)(?:\b|\s*[-:—·])|(?:UR|PRD|SD|TP|QA|UAT)(?:\s*[-:—·]|$))/i.test(heading)) errors.push("generic_primary_heading");
|
|
339
|
+
const fieldIds = snapshot.compact_status_card?.fields?.map((field) => field?.id);
|
|
340
|
+
if (JSON.stringify(fieldIds) !== JSON.stringify(["selected_run", "readiness_status", "current_gate", "missing_approval", "next_action", "quality_outlook"])) errors.push("status_fields");
|
|
341
|
+
const expectedApproval = `Approval: ${String(snapshot.current_gate ?? "").trim()}`;
|
|
342
|
+
if (!REQUIRED_GATES.includes(snapshot.current_gate)
|
|
343
|
+
|| snapshot.gate_transition_card?.exact_approval !== expectedApproval
|
|
344
|
+
|| snapshot.approval_interaction?.expected_approval !== expectedApproval
|
|
345
|
+
|| snapshot.approval_interaction?.options?.[0]?.value !== expectedApproval) errors.push("canonical_approval");
|
|
346
|
+
return Object.freeze({ valid: errors.length === 0, errors: Object.freeze(errors) });
|
|
347
|
+
}
|
|
348
|
+
|
|
317
349
|
export function attachApprovalOrientationSnapshot(statusCard, options = {}) {
|
|
318
350
|
if (!plainObject(statusCard)) throw new Error("approval orientation status card missing");
|
|
319
351
|
const snapshot = buildApprovalOrientationSnapshot({ ...options, statusCard });
|
package/package.json
CHANGED