create-agdf 0.6.9 → 0.7.0

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.
@@ -32,14 +32,23 @@ const generatedRoot = join(packageRoot, "generated");
32
32
  const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
33
33
  const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
34
34
  const pluginInstallCommand = "npx --yes @agdf/cli@latest claude";
35
- const npmCommand = process.platform === "win32" ? process.execPath : "npm";
36
- const npmPrefixArgs = process.platform === "win32" ? [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")] : [];
35
+ const testNpmCliPath = process.env.NODE_ENV === "test" ? process.env.AGDF_TEST_NPM_CLI_PATH || "" : "";
36
+ const npmCommand = testNpmCliPath
37
+ ? process.execPath
38
+ : process.platform === "win32"
39
+ ? process.execPath
40
+ : "npm";
41
+ const npmPrefixArgs = testNpmCliPath
42
+ ? [testNpmCliPath]
43
+ : process.platform === "win32"
44
+ ? [join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")]
45
+ : [];
37
46
  const allowedTargets = new Set(["codex", "codex-repo", "claude", "copilot", "opencode", "opencode-status", "opencode-repo", "both", "init", "config", "doctor", "gate-check", "delivery-map", "delivery-path-search", "run-create", "run-migrate", "run-render-legacy"]);
38
47
  const agdfFragmentPath = "AGENTS.agdf.md";
39
48
  const openCodeConfigFragmentPath = "opencode.agdf.json";
40
49
  const userGateOrder = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
41
50
  const durableGateArtefacts = new Set(["UR", "PRD", "SD", "TP", "QA"]);
42
- const internalStepArtefacts = new Set(["Brownfield Review"]);
51
+ const internalStepArtefacts = new Set(["Brownfield Review", "Brownfield Analysis", "CD+Tests", "CR"]);
43
52
  const deliveryRelationships = [
44
53
  { from: "UR", relationship: "approved_by", to: "Approval: UR", requiredBy: "UR" },
45
54
  { from: "PRD", relationship: "derived_from", to: "UR", requiredBy: "PRD" },
@@ -62,21 +71,6 @@ const nextSkillByGate = {
62
71
  UAT: "delivery-closeout",
63
72
  OR: "release-or",
64
73
  };
65
- const gateProgressOrder = [
66
- "UR",
67
- "Brownfield Review",
68
- "Mode/Slice Decision",
69
- "Quick Task Execution",
70
- "PRD",
71
- "SD",
72
- "TP",
73
- "Brownfield Analysis",
74
- "CD+Tests",
75
- "CR",
76
- "QA",
77
- "UAT",
78
- "OR",
79
- ];
80
74
  const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
81
75
  const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
82
76
  const openCodeSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.opencode.skillPrefix}${skill.slug}`);
@@ -481,6 +475,7 @@ function defaultOpenCodeConfigDir() {
481
475
 
482
476
  function installOpenCodeGlobalPlugin(configDir) {
483
477
  assertGlobalOpenCodeSurfaceWritable(configDir);
478
+ const previousPackage = resolveOpenCodePackage(configDir);
484
479
  const configPath = join(configDir, "opencode.json");
485
480
  let config = {};
486
481
 
@@ -528,15 +523,21 @@ function installOpenCodeGlobalPlugin(configDir) {
528
523
 
529
524
  mkdirSync(configDir, { recursive: true });
530
525
  try {
531
- execFileSync(npmCommand, [...npmPrefixArgs, "install", "--silent", "--save-prod", "--prefix", configDir, packageRoot], { stdio: "pipe" });
526
+ const packageSpecifier = `${pluginDefinition.opencode.npmPackage}@${pluginDefinition.version}`;
527
+ execFileSync(npmCommand, [...npmPrefixArgs, "install", "--silent", "--save-prod", "--save-exact", packageSpecifier], {
528
+ cwd: configDir,
529
+ stdio: "pipe",
530
+ });
532
531
  } catch (error) {
533
532
  throw new Error(`Failed to install ${pluginDefinition.opencode.npmPackage} into the OpenCode config directory: ${(error.stderr || error.message).toString().trim()}`);
534
533
  }
535
534
  writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
535
+ const installedPackage = resolveOpenCodePackage(configDir);
536
536
 
537
537
  return {
538
538
  configPath,
539
539
  added: !alreadyInstalled,
540
+ transition: openCodePackageTransition(previousPackage, installedPackage),
540
541
  };
541
542
  }
542
543
 
@@ -661,24 +662,64 @@ function isOpenCodeRepositorySurfacePresent(targetDir) {
661
662
  function resolveOpenCodePackage(configDir) {
662
663
  const packageName = pluginDefinition.opencode.npmPackage;
663
664
  try {
665
+ const resolvedPath = execFileSync(process.execPath, ["-e", `process.stdout.write(require.resolve(${JSON.stringify(packageName)}))`], {
666
+ cwd: configDir,
667
+ encoding: "utf8",
668
+ stdio: "pipe",
669
+ });
670
+ let installedVersion = "";
671
+ try {
672
+ const packageManifest = JSON.parse(readFileSync(join(dirname(resolvedPath), "package.json"), "utf8"));
673
+ installedVersion = typeof packageManifest.version === "string" && packageManifest.version.trim() ? packageManifest.version.trim() : "";
674
+ } catch {
675
+ installedVersion = "";
676
+ }
664
677
  return {
665
678
  loadable: true,
666
- path: execFileSync(process.execPath, ["-e", `process.stdout.write(require.resolve(${JSON.stringify(packageName)}))`], {
667
- cwd: configDir,
668
- encoding: "utf8",
669
- stdio: "pipe",
670
- }),
679
+ path: resolvedPath,
680
+ installed_version: installedVersion,
671
681
  error: "",
672
682
  };
673
683
  } catch (error) {
674
684
  return {
675
685
  loadable: false,
676
686
  path: "",
687
+ installed_version: "",
677
688
  error: (error.stderr || error.message || "package not resolvable").toString().trim(),
678
689
  };
679
690
  }
680
691
  }
681
692
 
693
+ function openCodePackageVersionStatus(packageState) {
694
+ if (!packageState.loadable) return "unloadable";
695
+ if (!packageState.installed_version) return "unknown";
696
+ return packageState.installed_version === pluginDefinition.version ? "current" : "outdated";
697
+ }
698
+
699
+ function openCodePackageTransition(previousPackage, installedPackage) {
700
+ const previousVersion = previousPackage.loadable ? previousPackage.installed_version : "";
701
+ const installedVersion = installedPackage.loadable ? installedPackage.installed_version : "";
702
+ if (!installedVersion || (previousPackage.loadable && !previousVersion)) {
703
+ return {
704
+ previous_version: previousVersion,
705
+ installed_version: installedVersion,
706
+ status: "unknown",
707
+ };
708
+ }
709
+ if (!previousPackage.loadable) {
710
+ return {
711
+ previous_version: "",
712
+ installed_version: installedVersion,
713
+ status: "installed",
714
+ };
715
+ }
716
+ return {
717
+ previous_version: previousVersion,
718
+ installed_version: installedVersion,
719
+ status: previousVersion === installedVersion ? "unchanged" : "updated",
720
+ };
721
+ }
722
+
682
723
  function evaluateGlobalOpenCodeSurface(configDir) {
683
724
  const paths = globalOpenCodeConfigPaths(configDir);
684
725
  const skillCount = globalOpenCodeSkillNames.filter((skillName) => existsSync(join(paths.skills, skillName, "SKILL.md"))).length;
@@ -693,12 +734,13 @@ function evaluateGlobalOpenCodeSurface(configDir) {
693
734
  };
694
735
  }
695
736
 
696
- function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir()) {
737
+ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null) {
697
738
  const configPath = join(configDir, "opencode.json");
698
739
  const configState = readOpenCodeConfig(configPath);
699
740
  const plugins = Array.isArray(configState.config.plugin) ? configState.config.plugin : [];
700
741
  const globalConfigured = plugins.includes(pluginDefinition.opencode.npmPackage);
701
742
  const packageState = resolveOpenCodePackage(configDir);
743
+ const packageVersionStatus = openCodePackageVersionStatus(packageState);
702
744
  const globalNativeSurface = evaluateGlobalOpenCodeSurface(configDir);
703
745
  const sessionSignals = {
704
746
  active: process.env.AGDF_PLUGIN_ACTIVE === "1",
@@ -714,6 +756,8 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
714
756
  if (configState.parseError) findings.push(`OpenCode global config is not valid JSON: ${configState.parseError}`);
715
757
  if (!globalConfigured) findings.push(`OpenCode global config does not include ${pluginDefinition.opencode.npmPackage}.`);
716
758
  if (!packageState.loadable) findings.push(`${pluginDefinition.opencode.npmPackage} is not loadable from the OpenCode config directory.`);
759
+ if (packageVersionStatus === "outdated") findings.push(`${pluginDefinition.opencode.npmPackage} version ${packageState.installed_version} is outdated; expected ${pluginDefinition.version}.`);
760
+ if (packageVersionStatus === "unknown" && packageState.loadable) findings.push(`${pluginDefinition.opencode.npmPackage} is loadable but its installed version is unknown.`);
717
761
  if (!globalNativeSurface.complete) findings.push(`Global OpenCode native skill surface is incomplete (${globalNativeSurface.skill_count}/${globalNativeSurface.expected_skill_count} skills).`);
718
762
  if (!sessionSignals.active) findings.push("No active AGDF OpenCode session signal is visible in this process.");
719
763
  if (!repositorySurface) findings.push("Current repository does not contain the AGDF OpenCode surface.");
@@ -731,6 +775,10 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
731
775
  name: pluginDefinition.opencode.npmPackage,
732
776
  loadable: packageState.loadable,
733
777
  resolved_path: packageState.path,
778
+ installed_version: packageState.installed_version || null,
779
+ expected_version: pluginDefinition.version,
780
+ version_status: packageVersionStatus,
781
+ ...(transition ? { transition } : {}),
734
782
  error: packageState.error,
735
783
  },
736
784
  global_native_surface: globalNativeSurface,
@@ -744,7 +792,9 @@ function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(
744
792
  },
745
793
  visible_entrypoint: repositorySurface ? `${pluginDefinition.opencode.skillPrefix}gate-check (native skill)` : "none until opencode-repo is installed for this repository",
746
794
  findings,
747
- next_step: !globalNativeSurface.complete
795
+ next_step: packageVersionStatus !== "current"
796
+ ? "Run npx --yes @agdf/cli@latest opencode to install or repair the OpenCode package version."
797
+ : !globalNativeSurface.complete
748
798
  ? "Run npx --yes @agdf/cli@latest opencode to install or repair the global native OpenCode skill surface."
749
799
  : repositorySurface
750
800
  ? `Restart OpenCode if needed, then load ${pluginDefinition.opencode.skillPrefix}gate-check through the native skill tool for new build/change intent.`
@@ -764,6 +814,18 @@ function printOpenCodeStatus(report, json) {
764
814
  if (report.global_config.parse_error) console.log(`Config parse error: ${report.global_config.parse_error}`);
765
815
  console.log(`Package loadable: ${report.package.loadable ? "yes" : "no"}`);
766
816
  if (report.package.resolved_path) console.log(`Package path: ${report.package.resolved_path}`);
817
+ console.log(`Package version: ${report.package.installed_version || "unknown"}`);
818
+ console.log(`Expected version: ${report.package.expected_version}`);
819
+ console.log(`Version status: ${report.package.version_status}`);
820
+ if (report.package.transition?.status === "updated") {
821
+ console.log(`Version transition: ${report.package.transition.previous_version} -> ${report.package.transition.installed_version}`);
822
+ } else if (report.package.transition?.status === "installed") {
823
+ console.log(`Version transition: new install (${report.package.transition.installed_version || "unknown"})`);
824
+ } else if (report.package.transition?.status === "unchanged") {
825
+ console.log(`Version transition: unchanged (${report.package.transition.installed_version})`);
826
+ } else if (report.package.transition?.status === "unknown") {
827
+ console.log("Version transition: unknown");
828
+ }
767
829
  console.log(`Global native skills: ${report.global_native_surface.complete ? "complete" : "incomplete"} (${report.global_native_surface.skill_count}/${report.global_native_surface.expected_skill_count})`);
768
830
  console.log(`Global skill path: ${report.global_native_surface.path}`);
769
831
  console.log(`Session active signal: ${report.session.active ? "yes" : "no"}`);
@@ -1753,20 +1815,6 @@ function readRunState(targetDir, selection = {}) {
1753
1815
  };
1754
1816
  }
1755
1817
 
1756
- function firstUnapprovedGate(approvals) {
1757
- for (const gate of userGateOrder) {
1758
- const status = approvals.get(gate)?.status ?? "";
1759
- if (status !== "approved" && status !== "not_applicable") return gate;
1760
- }
1761
- return "OR";
1762
- }
1763
-
1764
- function normalizeCurrentGate(value, fallbackGate) {
1765
- if (isPlaceholderValue(value)) return fallbackGate;
1766
- const normalized = value.replace(/`/g, "").trim();
1767
- return normalized || fallbackGate;
1768
- }
1769
-
1770
1818
  function gateApprovalStatus(runState, gate) {
1771
1819
  if (!userGateOrder.includes(gate)) return "not_applicable";
1772
1820
  return runState.approvals.get(gate)?.status ?? "";
@@ -1820,7 +1868,9 @@ function analyzeDurableGateArtefactConsistency(runState) {
1820
1868
  function isInternalStepSatisfied(runState, step) {
1821
1869
  const artefact = runState.artefacts.get(step);
1822
1870
  if (!artefact) return false;
1823
- return artefact.status === "done" || artefact.status === "not_applicable";
1871
+ if (artefact.status === "done") return true;
1872
+ return artefact.status === "not_applicable"
1873
+ && (step === "Brownfield Review" || step === "Brownfield Analysis");
1824
1874
  }
1825
1875
 
1826
1876
  function modeSliceDecision(runState) {
@@ -2039,15 +2089,6 @@ function buildStatusCard({
2039
2089
  };
2040
2090
  }
2041
2091
 
2042
- function effectiveCurrentGate(runState, transitionDecision) {
2043
- if (transitionDecision.status !== "open") return transitionDecision.current_gate;
2044
- const explicitGate = normalizeCurrentGate(runState.current_gate, "");
2045
- const explicitIndex = gateProgressOrder.indexOf(explicitGate);
2046
- const fallbackIndex = gateProgressOrder.indexOf(transitionDecision.current_gate);
2047
- if (explicitIndex === -1 || fallbackIndex === -1) return transitionDecision.current_gate;
2048
- return explicitIndex > fallbackIndex ? explicitGate : transitionDecision.current_gate;
2049
- }
2050
-
2051
2092
  function durableArtefactBlock(gate, nextGate) {
2052
2093
  const label = gate === "QA" ? "QA report" : `${gate} artefact`;
2053
2094
  const stablePath = gate === "QA" ? ".agdf/control/artefacts/<key>/QA_REPORT.md" : `.agdf/control/artefacts/<key>/${gate}.md`;
@@ -2192,6 +2233,43 @@ function transitionDecisionForRunState(runState) {
2192
2233
  };
2193
2234
  }
2194
2235
 
2236
+ const implementationStepsRequired = gateApprovalStatus(runState, "TP") === "approved";
2237
+ if (implementationStepsRequired && !isInternalStepSatisfied(runState, "Brownfield Analysis")) {
2238
+ return {
2239
+ status: "open",
2240
+ current_gate: "Brownfield Analysis",
2241
+ blocking_reason: "none",
2242
+ missing_approval: "none",
2243
+ allowed: ["run Brownfield Analysis for the approved TP scope", "verify existing owners, reuse paths and regression risks"],
2244
+ forbidden: ["implement before Brownfield evidence supports the approved TP path", "claim QA or release readiness"],
2245
+ next_allowed_action: "Run Brownfield Analysis for the approved TP scope before CD+Tests.",
2246
+ };
2247
+ }
2248
+
2249
+ if (implementationStepsRequired && !isInternalStepSatisfied(runState, "CD+Tests")) {
2250
+ return {
2251
+ status: "open",
2252
+ current_gate: "CD+Tests",
2253
+ blocking_reason: "none",
2254
+ missing_approval: "none",
2255
+ allowed: ["implement the approved TP tasks", "run the approved test plan", "record implementation and test evidence"],
2256
+ forbidden: ["claim QA pass", "request UAT approval", "release"],
2257
+ next_allowed_action: "Implement the approved TP scope, run its tests, and record CD+Tests evidence before CR.",
2258
+ };
2259
+ }
2260
+
2261
+ if (implementationStepsRequired && !isInternalStepSatisfied(runState, "CR")) {
2262
+ return {
2263
+ status: "open",
2264
+ current_gate: "CR",
2265
+ blocking_reason: "none",
2266
+ missing_approval: "none",
2267
+ allowed: ["run mandatory code review", "record correctness, regression, security and maintainability findings", "fix blocking review findings"],
2268
+ forbidden: ["claim QA pass", "request UAT approval", "release"],
2269
+ next_allowed_action: "Run Code Review for the implemented TP scope and resolve blocking findings before QA.",
2270
+ };
2271
+ }
2272
+
2195
2273
  if (gateApprovalStatus(runState, "QA") === "approved" && !isGateSatisfied(runState, "QA")) return durableArtefactBlock("QA", "UAT");
2196
2274
 
2197
2275
  if (isGateSatisfied(runState, "QA") && !isGateSatisfied(runState, "UAT")) {
@@ -2220,12 +2298,12 @@ function transitionDecisionForRunState(runState) {
2220
2298
 
2221
2299
  return {
2222
2300
  status: "open",
2223
- current_gate: "Brownfield Analysis",
2301
+ current_gate: "QA",
2224
2302
  blocking_reason: "none",
2225
- missing_approval: "none",
2226
- allowed: ["run Brownfield Analysis for the approved TP scope", "verify existing owners, reuse paths and regression risks"],
2227
- forbidden: ["implement before Brownfield evidence supports the approved TP path", "claim QA or release readiness"],
2228
- next_allowed_action: "Run Brownfield Analysis for the approved TP scope before CD+Tests.",
2303
+ missing_approval: "Approval: QA",
2304
+ allowed: ["run QA gate", "persist or refine the QA report", "request exact QA approval"],
2305
+ forbidden: ["request UAT approval", "release", "claim delivery readiness before QA approval and report evidence"],
2306
+ next_allowed_action: "Run the QA gate, persist the QA report, and request exact approval: Approval: QA",
2229
2307
  };
2230
2308
  }
2231
2309
 
@@ -2238,7 +2316,7 @@ function evaluateGateCheck(targetDir, selection = {}) {
2238
2316
  const doctorRevise = doctorReport.findings.find((finding) => finding.severity === "revise");
2239
2317
 
2240
2318
  let status = transitionDecision.status;
2241
- let currentGate = effectiveCurrentGate(runState, transitionDecision);
2319
+ let currentGate = transitionDecision.current_gate;
2242
2320
  let blockingReason = transitionDecision.blocking_reason;
2243
2321
  let missingApproval = transitionDecision.missing_approval;
2244
2322
  let allowed = transitionDecision.allowed;
@@ -2413,7 +2491,7 @@ function evaluateDeliveryMap(targetDir, selection = {}) {
2413
2491
  const runState = readRunState(targetDir, selection);
2414
2492
  const map = analyzeDeliveryMap(runState);
2415
2493
  const gateDecision = transitionDecisionForRunState(runState);
2416
- const currentGate = effectiveCurrentGate(runState, gateDecision);
2494
+ const currentGate = gateDecision.current_gate;
2417
2495
 
2418
2496
  const severityRank = { block: 3, revise: 2, warn: 1 };
2419
2497
  const deliverySeverity = map.findings.reduce((max, finding) => Math.max(max, severityRank[finding.severity] ?? 0), 0);
@@ -2647,7 +2725,7 @@ async function main() {
2647
2725
  const result = installOpenCodeGlobalPlugin(configDir);
2648
2726
  installOpenCodeGlobalSurface(configDir);
2649
2727
  console.log(`AGDF OpenCode global plugin ${result.added ? "installed" : "already present"}: ${result.configPath}`);
2650
- const report = evaluateOpenCodeStatus(options.dir, configDir);
2728
+ const report = evaluateOpenCodeStatus(options.dir, configDir, result.transition);
2651
2729
  printOpenCodeStatus(report, false);
2652
2730
  console.log("Restart OpenCode so it loads the updated global plugin config.");
2653
2731
  } catch (error) {
@@ -37,6 +37,27 @@ Describe the trustworthy outcome.
37
37
  | QA | missing | |
38
38
  | UAT | missing | |
39
39
 
40
+ ## Artefacts
41
+
42
+ | Type | Path | Status | Notes |
43
+ |---|---|---|---|
44
+ | UR | | draft | |
45
+ | Brownfield Review | | missing | |
46
+ | PRD | | missing | |
47
+ | SD | | missing | |
48
+ | TP | | missing | |
49
+ | Brownfield Analysis | | missing | |
50
+ | CD+Tests | | missing | |
51
+ | CR | | missing | |
52
+ | QA | | missing | |
53
+
54
+ ## Mode/Slice Decision
55
+
56
+ - decision:
57
+ - required_next_gate:
58
+ - scope_reason:
59
+ - evidence:
60
+
40
61
  ## Evidence
41
62
 
42
63
  | Evidence | Source | Covers | Strength |
@@ -233,6 +233,7 @@ section or any other existing line.
233
233
 
234
234
  - User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
235
235
  - Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
236
+ - On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
236
237
  - Exact approval formula: `Approval: <GateName>`
237
238
  - Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
238
239
  - Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
293
294
  | `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
294
295
  | `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
295
296
  | Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
297
+ | `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
298
+ | `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
296
299
  | `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
300
+ | QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
301
+ | UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
297
302
 
298
303
  ## Brownfield Modes
299
304
 
@@ -233,6 +233,7 @@ section or any other existing line.
233
233
 
234
234
  - User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
235
235
  - Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
236
+ - On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
236
237
  - Exact approval formula: `Approval: <GateName>`
237
238
  - Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
238
239
  - Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
293
294
  | `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
294
295
  | `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
295
296
  | Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
297
+ | `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
298
+ | `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
296
299
  | `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
300
+ | QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
301
+ | UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
297
302
 
298
303
  ## Brownfield Modes
299
304
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "Codex-first operating system for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -37,6 +37,27 @@ Describe the trustworthy outcome.
37
37
  | QA | missing | |
38
38
  | UAT | missing | |
39
39
 
40
+ ## Artefacts
41
+
42
+ | Type | Path | Status | Notes |
43
+ |---|---|---|---|
44
+ | UR | | draft | |
45
+ | Brownfield Review | | missing | |
46
+ | PRD | | missing | |
47
+ | SD | | missing | |
48
+ | TP | | missing | |
49
+ | Brownfield Analysis | | missing | |
50
+ | CD+Tests | | missing | |
51
+ | CR | | missing | |
52
+ | QA | | missing | |
53
+
54
+ ## Mode/Slice Decision
55
+
56
+ - decision:
57
+ - required_next_gate:
58
+ - scope_reason:
59
+ - evidence:
60
+
40
61
  ## Evidence
41
62
 
42
63
  | Evidence | Source | Covers | Strength |
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.6.9",
4
+ "version": "0.7.0",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Codex-first operating system for governed AI-assisted delivery.",
@@ -233,6 +233,7 @@ section or any other existing line.
233
233
 
234
234
  - User gates: `UR -> PRD -> SD -> TP -> QA -> UAT`
235
235
  - Internal mandatory steps: `Brownfield Review -> Mode/Slice Decision -> Brownfield Analysis -> CD+Tests -> CR -> OR`
236
+ - On the approved-TP path, `CD+Tests` and `CR` are satisfied only by `done`; `not_applicable` may satisfy Brownfield Review or Brownfield Analysis, but it must not bypass implementation/test evidence or mandatory Code Review.
236
237
  - Exact approval formula: `Approval: <GateName>`
237
238
  - Legacy alias: `Freigabe: <GateName>` may be accepted when reviewing older German runs, but all new outputs must use `Approval: <GateName>`.
238
239
  - Implicit consent is not approval. Phrases such as "ok", "go ahead", "do it", "approved", "continue", "leg los" or "looks good" are work intent, not gate approval.
@@ -293,7 +294,11 @@ This table is the canonical transition model. Skills may reference it, but must
293
294
  | `SD` approved and SD artefact persisted or linked, TP missing or draft | `TP` | draft/refine Task/Test Plan, task IDs, evidence plan, persist/link TP, request `Approval: TP` | implementation, QA, release | `Approval: TP` |
294
295
  | `TP` approved and TP artefact persisted or linked, Brownfield Analysis missing | `Brownfield Analysis` | run Brownfield Analysis for approved TP scope | implementation, QA, release | none |
295
296
  | Brownfield Analysis passed for approved TP | `CD+Tests` | implement approved TP tasks and run tests | QA pass, UAT, release | none |
297
+ | `CD+Tests` done for approved TP, CR missing | `CR` | run mandatory Code Review and resolve blocking findings | QA pass, UAT, release | none |
298
+ | `CR` done, QA not approved | `QA` | run QA gate, persist/refine QA report, request `Approval: QA` | UAT, release | `Approval: QA` |
296
299
  | `QA` approved but QA report missing or not pass | `QA` | persist/link QA report with `pass` decision or revise/block evidence | UAT, release | none |
300
+ | QA approved and QA report is `pass` or `passed`, UAT not approved | `UAT` | request `Approval: UAT`, prepare non-operative delivery summary | release and automatic VCS actions | `Approval: UAT` |
301
+ | UAT approved | `OR` | produce OR or delivery closeout; prepare VCS handoff only when requested | automatic commit, push, PR or release | none |
297
302
 
298
303
  ## Brownfield Modes
299
304
 
@@ -101,11 +101,13 @@ export function parseControlState(
101
101
  const approvals = new Map();
102
102
  for (const h of ["Approvals", "Gate Checklist"])
103
103
  for (const [g, s, e] of rows(section(content, h))) {
104
- if (userGates.includes(g))
104
+ if (userGates.includes(g)) {
105
+ const status = clean(s);
105
106
  approvals.set(g, {
106
- status: clean(s) === "passed" && g === "QA" ? "approved" : clean(s),
107
+ status: g === "QA" && (status === "pass" || status === "passed") ? "approved" : status,
107
108
  evidence: e ?? "",
108
109
  });
110
+ }
109
111
  }
110
112
  const artefacts = new Map();
111
113
  for (const [t, p, s, n] of rows(section(content, "Artefacts"))) {
@@ -113,7 +115,9 @@ export function parseControlState(
113
115
  artefacts.set(t, { path: p ?? "", status: clean(s), notes: n ?? "" });
114
116
  }
115
117
  const mapRows = (h, header, fn) => dataRows(content, h, header).map(fn);
116
- const mode = "Mode / Slice Decision",
118
+ const mode = section(content, "Mode/Slice Decision").trim()
119
+ ? "Mode/Slice Decision"
120
+ : "Mode / Slice Decision",
117
121
  source = "Source And Scope State",
118
122
  memory = "Knowledge Persistence Decision";
119
123
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
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": [