create-agdf 0.8.1 → 0.8.2

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.
@@ -27,6 +27,7 @@ import {
27
27
  } from "../lib/control-state/index.js";
28
28
  import {
29
29
  buildArtefactRefs,
30
+ buildRunCandidates,
30
31
  canonicalizeLanguageTag,
31
32
  formatArtefactRefs,
32
33
  gateTitle,
@@ -1916,6 +1917,7 @@ function readRunState(targetDir, selection = {}) {
1916
1917
  let runPath = join(".agdf", "control", "AGDF_RUN.md");
1917
1918
  const canonicalRoot = join(targetDir, ".agdf", "control", "runs");
1918
1919
  let resolutionError;
1920
+ let candidateRuns = [];
1919
1921
  if (existsSync(canonicalRoot)) {
1920
1922
  try {
1921
1923
  const selected = resolveRuns(targetDir, {
@@ -1927,6 +1929,21 @@ function readRunState(targetDir, selection = {}) {
1927
1929
  : selected.run.path;
1928
1930
  } catch (error) {
1929
1931
  resolutionError = error.message;
1932
+ if (resolutionError.startsWith("AGDF_ACTIVE_RUN_AMBIGUOUS")) {
1933
+ const active = resolveRuns(targetDir, { allActive: true }).runs.map((run) => {
1934
+ const controlState = parseControlState(run.content, {
1935
+ userGates: userGateOrder,
1936
+ internalSteps: [...internalStepArtefacts],
1937
+ });
1938
+ return {
1939
+ ...run,
1940
+ control_state: controlState,
1941
+ current_artefact_heading: readArtefactHeading(targetDir, controlState.artefacts.get(controlState.current_gate)),
1942
+ ur_heading: readArtefactHeading(targetDir, controlState.artefacts.get("UR")),
1943
+ };
1944
+ });
1945
+ candidateRuns = buildRunCandidates(active);
1946
+ }
1930
1947
  }
1931
1948
  }
1932
1949
  if (resolutionError || !existsSync(join(targetDir, runPath))) {
@@ -1946,6 +1963,7 @@ function readRunState(targetDir, selection = {}) {
1946
1963
  quality_outlook: "",
1947
1964
  source_scope: {},
1948
1965
  memory: {},
1966
+ candidate_runs: candidateRuns,
1949
1967
  resolution_error: resolutionError,
1950
1968
  };
1951
1969
  }
@@ -2333,6 +2351,10 @@ function isGateSatisfied(runState, gate) {
2333
2351
  return isDurableGateArtefactSatisfied(runState, gate);
2334
2352
  }
2335
2353
 
2354
+ function qaRevisionRequired(runState) {
2355
+ return gateArtefactStatus(runState, "QA").status === "revise";
2356
+ }
2357
+
2336
2358
  function transitionDecisionForRunState(runState, verifiedChange = null) {
2337
2359
  if (gateApprovalStatus(runState, "UR") === "approved" && !isGateSatisfied(runState, "UR")) return durableArtefactBlock("UR", "PRD");
2338
2360
 
@@ -2533,6 +2555,18 @@ function transitionDecisionForRunState(runState, verifiedChange = null) {
2533
2555
  };
2534
2556
  }
2535
2557
 
2558
+ if (qaRevisionRequired(runState)) {
2559
+ return {
2560
+ status: "open",
2561
+ current_gate: "QA",
2562
+ blocking_reason: "qa_revise_required",
2563
+ missing_approval: "none",
2564
+ allowed: ["revise the implementation against the QA findings", "refresh CD+Tests and mandatory reviews", "rerun QA with refreshed evidence"],
2565
+ forbidden: ["request QA approval", "request UAT approval", "release", "claim delivery readiness"],
2566
+ next_allowed_action: "Resolve the QA revise findings, refresh CD+Tests and reviews, then rerun QA. Do not request Approval: QA from a revise report.",
2567
+ };
2568
+ }
2569
+
2536
2570
  if (gateApprovalStatus(runState, "QA") === "approved" && !isGateSatisfied(runState, "QA")) return durableArtefactBlock("QA", "UAT");
2537
2571
 
2538
2572
  if (isGateSatisfied(runState, "QA") && !isGateSatisfied(runState, "UAT")) {
@@ -2658,6 +2692,7 @@ function evaluateGateCheck(targetDir, selection = {}) {
2658
2692
  doctor_summary: doctorReport.summary,
2659
2693
  evidence_refs: runState.evidence_refs,
2660
2694
  quality_outlook: deriveQualityOutlook(runState, deliveryMap.findings),
2695
+ candidate_runs: runState.candidate_runs ?? [],
2661
2696
  status_card: statusCard,
2662
2697
  delivery_map: {
2663
2698
  relationships: deliveryMap.relationships,
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
84
84
  to the exact textual approval. Do not ask the user to request the buttons again
85
85
  and do not create a retry loop or simulated control.
86
86
 
87
+ State the outcome visibly: `presented`, `unavailable_before_invocation`,
88
+ `attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
89
+ configured locale why a native control was not usable, show the exact approval
90
+ value and confirm that authority is unchanged. This transient outcome is not
91
+ approval evidence. A new explicit user request may reopen the unchanged decision
92
+ only after fresh run/gate/artefact revalidation; never retry automatically.
93
+
87
94
  Surface behavior:
88
95
 
89
96
  - Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
382
382
  fallback. A host that does not apply the control does not trigger a second
383
383
  native prompt. AGDF must not simulate or force host-owned presentation.
384
384
 
385
+ An eligible interaction must make its presentation outcome visible and
386
+ distinguishable: `presented`, `unavailable_before_invocation`,
387
+ `attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
388
+ evidence only, never a persisted approval, selected-run authority or substitute
389
+ for post-response revalidation. A textual fallback names the outcome, gives the
390
+ exact approval value and confirms that authority is unchanged. A fresh explicit
391
+ user request may reopen the unchanged decision after revalidation; it is not an
392
+ automatic retry.
393
+
385
394
  A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
386
395
 
387
396
  Surface adapter rules:
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
382
382
  fallback. A host that does not apply the control does not trigger a second
383
383
  native prompt. AGDF must not simulate or force host-owned presentation.
384
384
 
385
+ An eligible interaction must make its presentation outcome visible and
386
+ distinguishable: `presented`, `unavailable_before_invocation`,
387
+ `attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
388
+ evidence only, never a persisted approval, selected-run authority or substitute
389
+ for post-response revalidation. A textual fallback names the outcome, gives the
390
+ exact approval value and confirms that authority is unchanged. A fresh explicit
391
+ user request may reopen the unchanged decision after revalidation; it is not an
392
+ automatic retry.
393
+
385
394
  A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
386
395
 
387
396
  Surface adapter rules:
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
84
84
  to the exact textual approval. Do not ask the user to request the buttons again
85
85
  and do not create a retry loop or simulated control.
86
86
 
87
+ State the outcome visibly: `presented`, `unavailable_before_invocation`,
88
+ `attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
89
+ configured locale why a native control was not usable, show the exact approval
90
+ value and confirm that authority is unchanged. This transient outcome is not
91
+ approval evidence. A new explicit user request may reopen the unchanged decision
92
+ only after fresh run/gate/artefact revalidation; never retry automatically.
93
+
87
94
  Surface behavior:
88
95
 
89
96
  - Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Codex-first operating system for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.8.1",
4
+ "version": "0.8.2",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Codex-first operating system for governed AI-assisted delivery.",
@@ -140,46 +140,55 @@
140
140
  "skillSet": [
141
141
  {
142
142
  "slug": "delivery-path-search",
143
+ "discovery": "optional",
143
144
  "useFor": "high-impact planning decisions with several plausible next delivery steps before implementation",
144
145
  "boundary": "read-only advisory search; never grants gate permission or replaces gate-check"
145
146
  },
146
147
  {
147
148
  "slug": "brownfield-analysis",
149
+ "discovery": "automatic",
148
150
  "useFor": "after gate-check permits Brownfield Review or implementation preparation, before non-trivial changes in existing systems",
149
151
  "boundary": "clarifies reuse, owners, risks and Mode/Slice Decision; never bypasses gate-check; Brownfield Review is not implementation permission"
150
152
  },
151
153
  {
152
154
  "slug": "clean-implementation-review",
155
+ "discovery": "automatic",
153
156
  "useFor": "inspect workarounds, fallbacks, parallel structures or symptom fixes",
154
157
  "boundary": "not a TP or QA substitute"
155
158
  },
156
159
  {
157
160
  "slug": "code-review",
161
+ "discovery": "automatic",
158
162
  "useFor": "mandatory CR step after code changes, focused on defects, regression and security findings",
159
163
  "boundary": "does not replace TP review, clean review or QA"
160
164
  },
161
165
  {
162
166
  "slug": "delivery-closeout",
167
+ "discovery": "automatic",
163
168
  "useFor": "commit/PR-near handoff after QA/OR/UAT",
164
169
  "boundary": "never performs VCS actions automatically"
165
170
  },
166
171
  {
167
172
  "slug": "gate-check",
173
+ "discovery": "start_here",
168
174
  "useFor": "new build/change intent, unclear approval, Structured Delivery, later-gate artefact requested",
169
175
  "boundary": "does not create later artefacts or skip Mode/Slice Decision after Brownfield Review"
170
176
  },
171
177
  {
172
178
  "slug": "qa-gate",
179
+ "discovery": "automatic",
173
180
  "useFor": "final QA decision",
174
181
  "boundary": "only instance for `pass | revise | block`"
175
182
  },
176
183
  {
177
184
  "slug": "release-or",
185
+ "discovery": "automatic",
178
186
  "useFor": "auditable closeout for every relevant run",
179
187
  "boundary": "not a QA substitute"
180
188
  },
181
189
  {
182
190
  "slug": "task-plan-review",
191
+ "discovery": "automatic",
183
192
  "useFor": "after implementation and before QA, verify TP coverage",
184
193
  "boundary": "no final QA decision"
185
194
  }
@@ -382,6 +382,15 @@ host control is presented, or the agent immediately uses the exact-text
382
382
  fallback. A host that does not apply the control does not trigger a second
383
383
  native prompt. AGDF must not simulate or force host-owned presentation.
384
384
 
385
+ An eligible interaction must make its presentation outcome visible and
386
+ distinguishable: `presented`, `unavailable_before_invocation`,
387
+ `attempted_not_applied`, or `unsafe_to_wait`. This is transient presentation
388
+ evidence only, never a persisted approval, selected-run authority or substitute
389
+ for post-response revalidation. A textual fallback names the outcome, gives the
390
+ exact approval value and confirms that authority is unchanged. A fresh explicit
391
+ user request may reopen the unchanged decision after revalidation; it is not an
392
+ automatic retry.
393
+
385
394
  A free-form native response is valid only when the existing exact-approval validator accepts it for the current gate after revalidation. A localized label, description, option position, recommendation style or host action never authorizes a gate. Revise, decline and cancel outcomes never advance a gate.
386
395
 
387
396
  Surface adapter rules:
@@ -84,6 +84,13 @@ apply or safely return the native question on that attempt, switch immediately
84
84
  to the exact textual approval. Do not ask the user to request the buttons again
85
85
  and do not create a retry loop or simulated control.
86
86
 
87
+ State the outcome visibly: `presented`, `unavailable_before_invocation`,
88
+ `attempted_not_applied` or `unsafe_to_wait`. For every fallback, say in the
89
+ configured locale why a native control was not usable, show the exact approval
90
+ value and confirm that authority is unchanged. This transient outcome is not
91
+ approval evidence. A new explicit user request may reopen the unchanged decision
92
+ only after fresh run/gate/artefact revalidation; never retry automatically.
93
+
87
94
  Surface behavior:
88
95
 
89
96
  - Codex: invoke the native short-question/request-user-input control on the first eligible attempt when callable, ask one gate question and omit auto-resolution; if it is not rendered or applied, use exact text immediately.
@@ -1,6 +1,7 @@
1
1
  const REQUIRED_GATES = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
2
2
  const ARTEFACT_ORDER = ["UR", "PRD", "SD", "TP"];
3
3
  const OUTCOMES = new Set(["approve", "revise", "decline", "cancel", "no_response", "timeout", "empty", "invalid", "stale"]);
4
+ const ATTEMPT_OUTCOMES = new Set(["presented", "unavailable_before_invocation", "attempted_not_applied", "unsafe_to_wait"]);
4
5
 
5
6
  function plainObject(value) {
6
7
  return value && typeof value === "object" && !Array.isArray(value);
@@ -111,6 +112,45 @@ export function resolveHumanRunTitle({ currentArtefactHeading, urHeading, runCon
111
112
  return [currentArtefactHeading, urHeading, objective].map(stripMarkdown).find(Boolean) || normalizedRunTitle(runId);
112
113
  }
113
114
 
115
+ function displaySafeTitle(value, fallback) {
116
+ const title = stripMarkdown(value).replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
117
+ return (title || fallback).slice(0, 100);
118
+ }
119
+
120
+ export function buildRunCandidates(runs) {
121
+ return [...(runs ?? [])]
122
+ .filter((run) => run?.valid && run?.meta?.lifecycle === "active" && typeof run.run_id === "string")
123
+ .map((run) => {
124
+ const currentGate = run.control_state?.current_gate || run.meta?.current_gate || "unknown";
125
+ const title = resolveHumanRunTitle({
126
+ currentArtefactHeading: run.current_artefact_heading,
127
+ urHeading: run.ur_heading,
128
+ runContent: "",
129
+ runId: run.run_id,
130
+ });
131
+ return {
132
+ run_id: run.run_id,
133
+ display_title: displaySafeTitle(title, normalizedRunTitle(run.run_id)),
134
+ current_gate: currentGate,
135
+ next_allowed_action: String(run.control_state?.next_allowed_action ?? "").trim(),
136
+ revision_id: String(run.meta?.revision_id ?? "").trim(),
137
+ };
138
+ })
139
+ .sort((left, right) => left.display_title.localeCompare(right.display_title) || left.run_id.localeCompare(right.run_id));
140
+ }
141
+
142
+ export function buildInteractionAttempt({ interactionId, runId, currentGate, surface, attemptOutcome, expectedApproval, fallbackReason = "" }) {
143
+ if (!ATTEMPT_OUTCOMES.has(attemptOutcome)) throw new Error("invalid interaction attempt outcome");
144
+ if (!String(interactionId ?? "").trim() || !String(runId ?? "").trim() || !String(currentGate ?? "").trim())
145
+ throw new Error("interaction attempt identity missing");
146
+ return Object.freeze({
147
+ interaction_id: String(interactionId), run_id: String(runId), current_gate: String(currentGate),
148
+ surface: String(surface ?? "fallback"), attempt_outcome: attemptOutcome,
149
+ expected_approval: String(expectedApproval ?? ""), fallback_reason: String(fallbackReason ?? ""),
150
+ authorizes: false,
151
+ });
152
+ }
153
+
114
154
  function safeArtefactPath(value) {
115
155
  const path = String(value ?? "").replace(/^`|`$/g, "").trim();
116
156
  if (!path || !/^[A-Za-z0-9._/-]+$/.test(path) || /^([a-z]+:|\/)/i.test(path)) return "";
@@ -166,4 +206,5 @@ export function normalizeInteractionOutcome(value, { expectedApproval, stale = f
166
206
  export const interactionPresentationConstants = Object.freeze({
167
207
  artefactOrder: Object.freeze([...ARTEFACT_ORDER]),
168
208
  outcomes: Object.freeze([...OUTCOMES]),
209
+ attemptOutcomes: Object.freeze([...ATTEMPT_OUTCOMES]),
169
210
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Bootstrap AGDF repository-local plugin files, Copilot/OpenCode instructions, skills, control files and machine-readable checks.",
5
5
  "type": "module",
6
6
  "files": [