create-agdf 0.2.3 → 0.2.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.
Files changed (29) hide show
  1. package/bin/create-agdf.js +363 -9
  2. package/generated/.agdf/control/README.md +7 -1
  3. package/generated/.agdf/control/templates/AGDF_RUN.md +25 -1
  4. package/generated/.agdf/control/templates/MASTER_BACKLOG.md +16 -14
  5. package/generated/.agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +67 -0
  6. package/generated/.agdf/control/templates/artefacts/OR.md +86 -0
  7. package/generated/.agdf/control/templates/artefacts/UR.md +1 -1
  8. package/generated/.github/copilot-instructions.md +3 -0
  9. package/generated/.github/instructions/agdf-governance.instructions.md +1 -0
  10. package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +35 -17
  11. package/generated/.github/skills/agdf-gate-check/SKILL.md +33 -29
  12. package/generated/.github/skills/agdf-release-or/SKILL.md +17 -10
  13. package/generated/.github/skills/agdf-runtime-contract.md +102 -5
  14. package/generated/AGENTS.md +14 -4
  15. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  16. package/generated/plugins/agdf/control/README.md +7 -1
  17. package/generated/plugins/agdf/control/templates/AGDF_RUN.md +25 -1
  18. package/generated/plugins/agdf/control/templates/MASTER_BACKLOG.md +16 -14
  19. package/generated/plugins/agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +67 -0
  20. package/generated/plugins/agdf/control/templates/artefacts/OR.md +86 -0
  21. package/generated/plugins/agdf/control/templates/artefacts/UR.md +1 -1
  22. package/generated/plugins/agdf/meta/agdf-agent-router.md +14 -4
  23. package/generated/plugins/agdf/meta/agdf-constitution.md +13 -4
  24. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +4 -4
  25. package/generated/plugins/agdf/meta/agdf-runtime-contract.md +102 -5
  26. package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +35 -17
  27. package/generated/plugins/agdf/skills/gate-check/SKILL.md +33 -29
  28. package/generated/plugins/agdf/skills/release-or/SKILL.md +17 -10
  29. package/package.json +1 -1
@@ -11,10 +11,18 @@ const generatedRoot = join(packageRoot, "generated");
11
11
  const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
12
12
  const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
13
13
  const pluginInstallCommand = "claude plugin add arndtgold/ai-native-governance-delivery-framework";
14
- const allowedTargets = new Set(["codex", "copilot", "both", "init", "doctor", "gate-check"]);
14
+ const allowedTargets = new Set(["codex", "copilot", "both", "init", "doctor", "gate-check", "delivery-map"]);
15
15
  const agdfFragmentPath = "AGENTS.agdf.md";
16
16
  const userGateOrder = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
17
17
  const durableGateArtefacts = new Set(["UR", "PRD", "SD", "TP", "QA"]);
18
+ const internalStepArtefacts = new Set(["Brownfield Review"]);
19
+ const deliveryRelationships = [
20
+ { from: "UR", relationship: "approved_by", to: "Approval: UR", requiredBy: "UR" },
21
+ { from: "PRD", relationship: "derived_from", to: "UR", requiredBy: "PRD" },
22
+ { from: "SD", relationship: "derived_from", to: "PRD", requiredBy: "SD" },
23
+ { from: "TP", relationship: "derived_from", to: "SD", requiredBy: "TP" },
24
+ { from: "QA_REPORT", relationship: "tests", to: "TP", requiredBy: "QA" },
25
+ ];
18
26
  const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
19
27
  const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
20
28
  const codexPluginFiles = [
@@ -27,10 +35,12 @@ const codexPluginFiles = [
27
35
  join("plugins", "agdf", "control", "templates", "CONTEXT_GRAPH.md"),
28
36
  join("plugins", "agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
29
37
  join("plugins", "agdf", "control", "templates", "artefacts", "UR.md"),
38
+ join("plugins", "agdf", "control", "templates", "artefacts", "BROWNFIELD_REVIEW.md"),
30
39
  join("plugins", "agdf", "control", "templates", "artefacts", "PRD.md"),
31
40
  join("plugins", "agdf", "control", "templates", "artefacts", "SD.md"),
32
41
  join("plugins", "agdf", "control", "templates", "artefacts", "TP.md"),
33
42
  join("plugins", "agdf", "control", "templates", "artefacts", "QA_REPORT.md"),
43
+ join("plugins", "agdf", "control", "templates", "artefacts", "OR.md"),
34
44
  join("plugins", "agdf", "hooks", "hooks.json"),
35
45
  join("plugins", "agdf", "hooks", "session-start.sh"),
36
46
  join("plugins", "agdf", "meta", "agdf-agent-router.md"),
@@ -48,10 +58,12 @@ const controlFiles = [
48
58
  join(".agdf", "control", "templates", "CONTEXT_GRAPH.md"),
49
59
  join(".agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
50
60
  join(".agdf", "control", "templates", "artefacts", "UR.md"),
61
+ join(".agdf", "control", "templates", "artefacts", "BROWNFIELD_REVIEW.md"),
51
62
  join(".agdf", "control", "templates", "artefacts", "PRD.md"),
52
63
  join(".agdf", "control", "templates", "artefacts", "SD.md"),
53
64
  join(".agdf", "control", "templates", "artefacts", "TP.md"),
54
65
  join(".agdf", "control", "templates", "artefacts", "QA_REPORT.md"),
66
+ join(".agdf", "control", "templates", "artefacts", "OR.md"),
55
67
  ];
56
68
  const liveControlFiles = [
57
69
  {
@@ -77,10 +89,12 @@ const liveControlFiles = [
77
89
  ];
78
90
  const artefactTemplateFiles = [
79
91
  join(".agdf", "control", "templates", "artefacts", "UR.md"),
92
+ join(".agdf", "control", "templates", "artefacts", "BROWNFIELD_REVIEW.md"),
80
93
  join(".agdf", "control", "templates", "artefacts", "PRD.md"),
81
94
  join(".agdf", "control", "templates", "artefacts", "SD.md"),
82
95
  join(".agdf", "control", "templates", "artefacts", "TP.md"),
83
96
  join(".agdf", "control", "templates", "artefacts", "QA_REPORT.md"),
97
+ join(".agdf", "control", "templates", "artefacts", "OR.md"),
84
98
  ];
85
99
  const doctorRequiredFiles = [
86
100
  join(".agdf", "control", "AGDF_RUN.md"),
@@ -109,11 +123,12 @@ Usage:
109
123
  npm create agdf@latest init
110
124
  npm create agdf@latest doctor
111
125
  npm create agdf@latest gate-check
126
+ npm create agdf@latest delivery-map
112
127
 
113
128
  Options:
114
129
  --dir <path> Write files into a specific directory
115
130
  --force Overwrite existing generated files
116
- --json Print doctor or gate-check output as JSON
131
+ --json Print doctor, gate-check or delivery-map output as JSON
117
132
  --help Show this help
118
133
  `);
119
134
  }
@@ -176,7 +191,7 @@ function parseArgs(argv) {
176
191
  }
177
192
 
178
193
  if (!target || !allowedTargets.has(target)) {
179
- console.error("Please choose one target: codex, copilot, both, init, doctor or gate-check.");
194
+ console.error("Please choose one target: codex, copilot, both, init, doctor, gate-check or delivery-map.");
180
195
  printUsage();
181
196
  process.exit(1);
182
197
  }
@@ -361,6 +376,21 @@ function hasFilledEvidenceRow(content) {
361
376
  });
362
377
  }
363
378
 
379
+ function markdownSection(content, heading) {
380
+ const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
381
+ return content.match(new RegExp(`(?:^|\\n)## ${escaped}\\s*\\n([\\s\\S]*?)(?:\\n## |\\n# |$)`))?.[1] ?? "";
382
+ }
383
+
384
+ function filled(value) {
385
+ return Boolean(value && !isPlaceholderValue(value) && value.trim() !== "");
386
+ }
387
+
388
+ function nonTemplateRows(section, headerCell) {
389
+ return tableRows(section)
390
+ .filter((cells) => cells[0] !== headerCell)
391
+ .filter((cells) => cells.some((cell) => filled(cell)));
392
+ }
393
+
364
394
  function parseQualityContracts(content) {
365
395
  const parsed = JSON.parse(content);
366
396
  if (!Array.isArray(parsed.contracts) || parsed.contracts.length === 0) {
@@ -504,6 +534,11 @@ function evaluateDoctor(targetDir) {
504
534
  "Restore the generated contracts or fix the JSON contract schema.",
505
535
  );
506
536
  }
537
+
538
+ const runState = readRunState(targetDir);
539
+ for (const finding of analyzeDeliveryMap(runState).findings) {
540
+ addFinding(findings, finding.severity, finding.code, finding.message, finding.path, finding.next_step);
541
+ }
507
542
  }
508
543
 
509
544
  const severityRank = { block: 3, revise: 2, warn: 1 };
@@ -549,6 +584,11 @@ function extractField(content, field) {
549
584
  return content.match(pattern)?.[1]?.trim() ?? "";
550
585
  }
551
586
 
587
+ function extractSectionField(section, field) {
588
+ const pattern = new RegExp(`^- ${field}:[^\\S\\r\\n]*(.*)$`, "m");
589
+ return section.match(pattern)?.[1]?.trim() ?? "";
590
+ }
591
+
552
592
  function cleanStatusCell(value) {
553
593
  return value.replace(/^`|`$/g, "").trim();
554
594
  }
@@ -575,6 +615,11 @@ function readRunState(targetDir) {
575
615
  approvals: new Map(),
576
616
  artefacts: new Map(),
577
617
  evidence_refs: [],
618
+ artefact_chain: [],
619
+ mode_slice_decision: {},
620
+ missing_evidence: [],
621
+ risks: [],
622
+ context_graph: {},
578
623
  };
579
624
  }
580
625
 
@@ -584,10 +629,10 @@ function readRunState(targetDir) {
584
629
  addApprovalRows(approvals, content.match(/## Gate Checklist([\s\S]*?)(?:\n## |\n# |$)/)?.[1] ?? "");
585
630
 
586
631
  const artefacts = new Map();
587
- const artefactsSection = content.match(/## Artefacts([\s\S]*?)(?:\n## |\n# |$)/)?.[1] ?? "";
632
+ const artefactsSection = markdownSection(content, "Artefacts");
588
633
  for (const cells of tableRows(artefactsSection)) {
589
634
  const [type, path, status, notes] = cells;
590
- if (!userGateOrder.includes(type)) continue;
635
+ if (!userGateOrder.includes(type) && !internalStepArtefacts.has(type)) continue;
591
636
  artefacts.set(type, {
592
637
  path: path ?? "",
593
638
  status: cleanStatusCell(status ?? ""),
@@ -595,10 +640,17 @@ function readRunState(targetDir) {
595
640
  });
596
641
  }
597
642
 
598
- const evidenceSection = content.match(/## Evidence([\s\S]*?)(?:\n## |\n# |$)/)?.[1] ?? "";
599
- const evidence_refs = tableRows(evidenceSection)
643
+ const artefactChain = nonTemplateRows(markdownSection(content, "Artefact Chain"), "From")
644
+ .map((cells) => ({
645
+ from: cells[0] ?? "",
646
+ relationship: cleanStatusCell(cells[1] ?? ""),
647
+ to: cleanStatusCell(cells[2] ?? ""),
648
+ evidence: cells[3] ?? "",
649
+ }));
650
+
651
+ const evidence_refs = tableRows(markdownSection(content, "Evidence"))
600
652
  .filter((cells) => cells[0] !== "Evidence")
601
- .filter((cells) => Boolean(cells[0] || cells[1] || cells[2]))
653
+ .filter((cells) => filled(cells[0]) || filled(cells[1]) || filled(cells[2]))
602
654
  .map((cells) => ({
603
655
  evidence: cells[0] ?? "",
604
656
  source: cells[1] ?? "",
@@ -606,6 +658,40 @@ function readRunState(targetDir) {
606
658
  strength: cleanStatusCell(cells[3] ?? ""),
607
659
  }));
608
660
 
661
+ const missingEvidence = tableRows(markdownSection(content, "Missing Evidence"))
662
+ .filter((cells) => cells[0] !== "Missing evidence")
663
+ .filter((cells) => filled(cells[0]))
664
+ .map((cells) => ({
665
+ missing_evidence: cells[0] ?? "",
666
+ impact: cleanStatusCell(cells[1] ?? ""),
667
+ required_next_step: cells[2] ?? "",
668
+ }));
669
+
670
+ const risks = tableRows(markdownSection(content, "Risks"))
671
+ .filter((cells) => cells[0] !== "Risk")
672
+ .filter((cells) => filled(cells[0]))
673
+ .map((cells) => ({
674
+ risk: cells[0] ?? "",
675
+ impact: cleanStatusCell(cells[1] ?? ""),
676
+ mitigation_or_owner: cells[2] ?? "",
677
+ }));
678
+
679
+ const contextGraph = {
680
+ impact: cleanStatusCell(extractField(content, "context_graph_impact")),
681
+ refs: extractField(content, "context_graph_refs"),
682
+ required_action: cleanStatusCell(extractField(content, "context_graph_required_action")),
683
+ gate_effect: cleanStatusCell(extractField(content, "context_graph_gate_effect")),
684
+ evidence: extractField(content, "context_graph_evidence"),
685
+ };
686
+
687
+ const modeSliceSection = markdownSection(content, "Mode / Slice Decision");
688
+ const modeSliceDecision = {
689
+ decision: cleanStatusCell(extractSectionField(modeSliceSection, "decision")),
690
+ required_next_gate: cleanStatusCell(extractSectionField(modeSliceSection, "required_next_gate")),
691
+ scope_reason: extractSectionField(modeSliceSection, "scope_reason"),
692
+ evidence: extractSectionField(modeSliceSection, "evidence"),
693
+ };
694
+
609
695
  return {
610
696
  path: runPath,
611
697
  content,
@@ -614,6 +700,11 @@ function readRunState(targetDir) {
614
700
  approvals,
615
701
  artefacts,
616
702
  evidence_refs,
703
+ artefact_chain: artefactChain,
704
+ mode_slice_decision: modeSliceDecision,
705
+ missing_evidence: missingEvidence,
706
+ risks,
707
+ context_graph: contextGraph,
617
708
  };
618
709
  }
619
710
 
@@ -649,6 +740,118 @@ function isDurableGateArtefactSatisfied(runState, gate) {
649
740
  return artefact.status === "approved";
650
741
  }
651
742
 
743
+ function isInternalStepSatisfied(runState, step) {
744
+ const artefact = runState.artefacts.get(step);
745
+ if (!artefact) return false;
746
+ return artefact.status === "done" || artefact.status === "not_applicable";
747
+ }
748
+
749
+ function modeSliceDecision(runState) {
750
+ const decision = runState.mode_slice_decision?.decision ?? "";
751
+ const scopeReason = runState.mode_slice_decision?.scope_reason ?? "";
752
+ const evidence = runState.mode_slice_decision?.evidence ?? "";
753
+ if (!decision || isPlaceholderValue(decision) || !filled(scopeReason) || !filled(evidence)) return "undecided";
754
+ return decision;
755
+ }
756
+
757
+ function relationshipRequired(runState, requiredBy) {
758
+ if (gateApprovalStatus(runState, requiredBy) === "not_applicable") return false;
759
+ if (requiredBy === "QA") {
760
+ return isGateSatisfied(runState, "QA");
761
+ }
762
+
763
+ return isGateSatisfied(runState, requiredBy);
764
+ }
765
+
766
+ function findRelationship(runState, expected) {
767
+ return runState.artefact_chain.find((row) =>
768
+ row.from === expected.from
769
+ && row.relationship === expected.relationship
770
+ && row.to === expected.to
771
+ );
772
+ }
773
+
774
+ function severityFromImpact(value) {
775
+ if (value === "block") return "block";
776
+ if (value === "revise") return "revise";
777
+ if (value === "warning" || value === "warn") return "warn";
778
+ return null;
779
+ }
780
+
781
+ function analyzeDeliveryMap(runState) {
782
+ const findings = [];
783
+ const relationships = deliveryRelationships.map((expected) => {
784
+ const row = findRelationship(runState, expected);
785
+ const required = relationshipRequired(runState, expected.requiredBy);
786
+ const evidence = row?.evidence ?? "";
787
+ const status = !row ? "missing" : filled(evidence) ? "pass" : required ? "missing_evidence" : "template";
788
+
789
+ if (required && status !== "pass") {
790
+ findings.push({
791
+ severity: "revise",
792
+ code: status === "missing" ? "AGDF_DELIVERY_RELATIONSHIP_MISSING" : "AGDF_DELIVERY_RELATIONSHIP_EVIDENCE_MISSING",
793
+ message: `${expected.from} must be traceable via ${expected.relationship} ${expected.to}.`,
794
+ path: runState.path,
795
+ next_step: "Fill the Artefact Chain row with concrete evidence before treating the delivery map as complete.",
796
+ });
797
+ }
798
+
799
+ return {
800
+ from: expected.from,
801
+ relationship: expected.relationship,
802
+ to: expected.to,
803
+ required,
804
+ status,
805
+ evidence,
806
+ };
807
+ });
808
+
809
+ for (const item of runState.missing_evidence) {
810
+ const severity = severityFromImpact(item.impact);
811
+ if (!severity) continue;
812
+ findings.push({
813
+ severity,
814
+ code: "AGDF_MISSING_EVIDENCE_DECLARED",
815
+ message: item.missing_evidence,
816
+ path: runState.path,
817
+ next_step: item.required_next_step || "Resolve or explicitly accept the missing evidence before advancing the gate.",
818
+ });
819
+ }
820
+
821
+ for (const item of runState.risks) {
822
+ const severity = severityFromImpact(item.impact);
823
+ if (!severity) continue;
824
+ findings.push({
825
+ severity,
826
+ code: "AGDF_RISK_DECLARED",
827
+ message: item.risk,
828
+ path: runState.path,
829
+ next_step: item.mitigation_or_owner || "Assign mitigation or ownership before advancing the gate.",
830
+ });
831
+ }
832
+
833
+ const contextSeverity = severityFromImpact(runState.context_graph?.gate_effect);
834
+ if (contextSeverity) {
835
+ findings.push({
836
+ severity: contextSeverity,
837
+ code: "AGDF_CONTEXT_GRAPH_GATE_EFFECT",
838
+ message: `Context Graph impact is ${runState.context_graph.impact || "unspecified"} with gate effect ${runState.context_graph.gate_effect}.`,
839
+ path: runState.path,
840
+ next_step: runState.context_graph.required_action && runState.context_graph.required_action !== "none"
841
+ ? `Resolve Context Graph action: ${runState.context_graph.required_action}.`
842
+ : "Clarify the Context Graph impact before advancing the gate.",
843
+ });
844
+ }
845
+
846
+ return {
847
+ relationships,
848
+ missing_evidence: runState.missing_evidence,
849
+ risks: runState.risks,
850
+ context_graph: runState.context_graph,
851
+ findings,
852
+ };
853
+ }
854
+
652
855
  function durableArtefactBlock(gate, nextGate) {
653
856
  const label = gate === "QA" ? "QA report" : `${gate} artefact`;
654
857
  const stablePath = gate === "QA" ? ".agdf/control/artefacts/<key>/QA_REPORT.md" : `.agdf/control/artefacts/<key>/${gate}.md`;
@@ -694,6 +897,63 @@ function transitionDecisionForRunState(runState) {
694
897
  if (gateApprovalStatus(runState, "PRD") === "approved" && !isGateSatisfied(runState, "PRD")) return durableArtefactBlock("PRD", "SD");
695
898
 
696
899
  if (!isGateSatisfied(runState, "PRD")) {
900
+ if (!isInternalStepSatisfied(runState, "Brownfield Review")) {
901
+ return {
902
+ status: "open",
903
+ current_gate: "Brownfield Review",
904
+ blocking_reason: "none",
905
+ missing_approval: "none",
906
+ allowed: [
907
+ "run Brownfield Review after G-00",
908
+ "identify existing workstream, owners, SoT, reuse risks and open PRD/SD questions",
909
+ "mark Brownfield Review as done or not_applicable in AGDF_RUN.md",
910
+ ],
911
+ forbidden: ["create PRD before Brownfield Review is resolved", "create SD", "create TP", "implement code", "claim QA or release readiness"],
912
+ next_allowed_action: "Run Brownfield Review after G-00 before drafting PRD, or mark Brownfield Review not_applicable with evidence.",
913
+ };
914
+ }
915
+
916
+ const modeDecision = modeSliceDecision(runState);
917
+ if (modeDecision === "undecided") {
918
+ return {
919
+ status: "open",
920
+ current_gate: "Mode/Slice Decision",
921
+ blocking_reason: "none",
922
+ missing_approval: "none",
923
+ allowed: [
924
+ "decide whether the approved UR is quick_task, structured_slice, structured_delivery or block",
925
+ "record scope reason, evidence and required next gate depth in AGDF_RUN.md",
926
+ "choose the next required gate depth before drafting PRD or implementing",
927
+ ],
928
+ forbidden: ["create PRD before process size is decided", "create SD", "create TP", "implement code", "claim QA or release readiness"],
929
+ next_allowed_action: "Record the Mode/Slice Decision from Brownfield Review with scope reason and evidence before choosing PRD depth or Quick Task execution.",
930
+ };
931
+ }
932
+
933
+ if (modeDecision === "block") {
934
+ return {
935
+ status: "blocked",
936
+ current_gate: "Mode/Slice Decision",
937
+ blocking_reason: "mode_slice_decision_blocked",
938
+ missing_approval: "none",
939
+ allowed: ["resolve ownership, SoT, evidence, impact or product-direction uncertainty", "run gate-check again"],
940
+ forbidden: ["create PRD", "create SD", "create TP", "implement code", "claim QA or release readiness"],
941
+ next_allowed_action: "Resolve the Brownfield Review blocker before choosing a delivery path.",
942
+ };
943
+ }
944
+
945
+ if (modeDecision === "quick_task") {
946
+ return {
947
+ status: "open",
948
+ current_gate: "Quick Task Execution",
949
+ blocking_reason: "none",
950
+ missing_approval: "none",
951
+ allowed: ["implement the narrow approved UR scope", "run relevant checks", "record evidence and close with OR-lite"],
952
+ forbidden: ["expand scope beyond the Brownfield Review decision", "create broad PRD/SD/TP artefacts by ritual", "claim QA or release readiness without evidence"],
953
+ next_allowed_action: "Proceed as a Quick Task within the Brownfield Review scope and record verification evidence.",
954
+ };
955
+ }
956
+
697
957
  return {
698
958
  status: "open",
699
959
  current_gate: "PRD",
@@ -701,7 +961,9 @@ function transitionDecisionForRunState(runState) {
701
961
  missing_approval: "Approval: PRD",
702
962
  allowed: ["draft or refine PRD", "define scope", "define acceptance criteria", "define non-goals", "request exact PRD approval"],
703
963
  forbidden: ["create SD", "create TP", "run Brownfield Analysis as implementation preparation", "implement code", "claim QA or release readiness"],
704
- next_allowed_action: "Draft or refine the PRD; do not implement before PRD, SD and TP are approved.",
964
+ next_allowed_action: modeDecision === "structured_slice"
965
+ ? "Draft or refine the smallest PRD slice justified by Brownfield Review; do not implement before required artefacts are approved."
966
+ : "Draft or refine the PRD; do not implement before PRD, SD and TP are approved.",
705
967
  };
706
968
  }
707
969
 
@@ -750,6 +1012,7 @@ function evaluateGateCheck(targetDir) {
750
1012
  const doctorReport = evaluateDoctor(targetDir);
751
1013
  const runState = readRunState(targetDir);
752
1014
  const transitionDecision = transitionDecisionForRunState(runState);
1015
+ const deliveryMap = analyzeDeliveryMap(runState);
753
1016
  const doctorBlocker = doctorReport.findings.find((finding) => finding.severity === "block");
754
1017
  const doctorRevise = doctorReport.findings.find((finding) => finding.severity === "revise");
755
1018
 
@@ -789,6 +1052,12 @@ function evaluateGateCheck(targetDir) {
789
1052
  doctor_status: doctorReport.status,
790
1053
  doctor_summary: doctorReport.summary,
791
1054
  evidence_refs: runState.evidence_refs,
1055
+ delivery_map: {
1056
+ relationships: deliveryMap.relationships,
1057
+ mode_slice_decision: runState.mode_slice_decision,
1058
+ context_graph: deliveryMap.context_graph,
1059
+ findings: deliveryMap.findings,
1060
+ },
792
1061
  doctor_report: doctorReport,
793
1062
  };
794
1063
  }
@@ -814,6 +1083,85 @@ function printGateCheckReport(report, json) {
814
1083
  console.log(`Next allowed action: ${report.next_allowed_action}`);
815
1084
  }
816
1085
 
1086
+ function readBacklogPointers(targetDir) {
1087
+ const backlogPath = join(".agdf", "control", "MASTER_BACKLOG.md");
1088
+ if (!existsSync(join(targetDir, backlogPath))) return [];
1089
+
1090
+ const backlog = readTargetFile(targetDir, backlogPath);
1091
+ const activeSection = markdownSection(backlog, "Active Backlog");
1092
+ return nonTemplateRows(activeSection, "Prio")
1093
+ .map((cells) => ({
1094
+ prio: cells[0] ?? "",
1095
+ key: cells[1] ?? "",
1096
+ title: cells[2] ?? "",
1097
+ status: cleanStatusCell(cells[3] ?? ""),
1098
+ ur: cells[4] ?? "",
1099
+ brownfield_review: cells[5] ?? "",
1100
+ prd: cells[6] ?? "",
1101
+ sd: cells[7] ?? "",
1102
+ tp: cells[8] ?? "",
1103
+ qa: cells[9] ?? "",
1104
+ or: cells[10] ?? "",
1105
+ current_spec: cells[11] ?? "",
1106
+ notes: cells[12] ?? "",
1107
+ }));
1108
+ }
1109
+
1110
+ function evaluateDeliveryMap(targetDir) {
1111
+ const doctorReport = evaluateDoctor(targetDir);
1112
+ const runState = readRunState(targetDir);
1113
+ const map = analyzeDeliveryMap(runState);
1114
+ const gateDecision = transitionDecisionForRunState(runState);
1115
+
1116
+ const severityRank = { block: 3, revise: 2, warn: 1 };
1117
+ const deliverySeverity = map.findings.reduce((max, finding) => Math.max(max, severityRank[finding.severity] ?? 0), 0);
1118
+ const doctorSeverity = severityRank[doctorReport.status] ?? 0;
1119
+ const maxSeverity = Math.max(deliverySeverity, doctorSeverity);
1120
+ const status = maxSeverity >= 3 ? "block" : maxSeverity === 2 ? "revise" : maxSeverity === 1 ? "warn" : "pass";
1121
+
1122
+ return {
1123
+ schema_version: "1",
1124
+ status,
1125
+ checked_at: new Date().toISOString(),
1126
+ target_dir: targetDir,
1127
+ current_gate: gateDecision.current_gate,
1128
+ next_allowed_action: isPlaceholderValue(runState.next_allowed_action) ? gateDecision.next_allowed_action : runState.next_allowed_action,
1129
+ backlog_pointers: readBacklogPointers(targetDir),
1130
+ artefacts: Object.fromEntries([...runState.artefacts.entries()]),
1131
+ approvals: Object.fromEntries([...runState.approvals.entries()]),
1132
+ mode_slice_decision: runState.mode_slice_decision,
1133
+ relationships: map.relationships,
1134
+ evidence_refs: runState.evidence_refs,
1135
+ missing_evidence: map.missing_evidence,
1136
+ risks: map.risks,
1137
+ context_graph: map.context_graph,
1138
+ findings: map.findings,
1139
+ doctor_status: doctorReport.status,
1140
+ doctor_summary: doctorReport.summary,
1141
+ doctor_report: doctorReport,
1142
+ };
1143
+ }
1144
+
1145
+ function printDeliveryMapReport(report, json) {
1146
+ if (json) {
1147
+ console.log(JSON.stringify(report, null, 2));
1148
+ return;
1149
+ }
1150
+
1151
+ console.log(`AGDF delivery-map: ${report.status}`);
1152
+ console.log(`Current gate: ${report.current_gate}`);
1153
+ console.log(`Next allowed action: ${report.next_allowed_action}`);
1154
+ console.log(`Relationships: ${report.relationships.filter((item) => item.status === "pass").length}/${report.relationships.length} evidenced`);
1155
+ console.log(`Findings: ${report.findings.length}`);
1156
+
1157
+ for (const finding of report.findings) {
1158
+ console.log("");
1159
+ console.log(`[${finding.severity}] ${finding.code}`);
1160
+ console.log(finding.message);
1161
+ console.log(`Next step: ${finding.next_step}`);
1162
+ }
1163
+ }
1164
+
817
1165
  function main() {
818
1166
  const options = parseArgs(process.argv.slice(2));
819
1167
 
@@ -829,6 +1177,12 @@ function main() {
829
1177
  process.exit(report.status === "blocked" ? 2 : 0);
830
1178
  }
831
1179
 
1180
+ if (options.target === "delivery-map") {
1181
+ const report = evaluateDeliveryMap(options.dir);
1182
+ printDeliveryMapReport(report, options.json);
1183
+ process.exit(report.status === "block" ? 2 : 0);
1184
+ }
1185
+
832
1186
  const files = generatedFilesForTarget(options.target, options.dir, options.force);
833
1187
  const wroteAgentsFragment = files.some(file => file.path === agdfFragmentPath);
834
1188
 
@@ -9,12 +9,14 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
9
9
  | File | Purpose |
10
10
  |---|---|
11
11
  | `templates/AGDF_RUN.md` | Template for current run state: mode, gate, approvals, evidence, risks, next allowed action |
12
- | `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/PRD/SD/TP artefacts |
12
+ | `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/Brownfield/PRD/SD/TP/QA/OR artefacts |
13
13
  | `templates/artefacts/UR.md` | Template for the durable user requirement artefact of a work item |
14
+ | `templates/artefacts/BROWNFIELD_REVIEW.md` | Template for the durable Brownfield Review and Mode/Slice Decision |
14
15
  | `templates/artefacts/PRD.md` | Template for the durable product requirements artefact |
15
16
  | `templates/artefacts/SD.md` | Template for the durable solution design artefact |
16
17
  | `templates/artefacts/TP.md` | Template for the durable task and test plan artefact |
17
18
  | `templates/artefacts/QA_REPORT.md` | Template for the durable QA decision report |
19
+ | `templates/artefacts/OR.md` | Template for the durable Orchestration Report closeout |
18
20
  | `templates/SOT_REGISTRY.md` | Template for the source-of-truth registry: one primary owner per domain |
19
21
  | `templates/CONTEXT_GRAPH.md` | Template for project memory: durable decisions, Brownfield findings, risks, evidence and exit criteria |
20
22
  | `templates/AGENT_QUALITY_CONTRACTS.json` | Template for machine-readable warning, revise and block contracts for review and QA |
@@ -29,10 +31,12 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
29
31
  artefacts/
30
32
  <work-item>/
31
33
  UR.md
34
+ BROWNFIELD_REVIEW.md
32
35
  PRD.md
33
36
  SD.md
34
37
  TP.md
35
38
  QA_REPORT.md
39
+ OR.md
36
40
  SOT_REGISTRY.md
37
41
  CONTEXT_GRAPH.md
38
42
  AGENT_QUALITY_CONTRACTS.json
@@ -61,7 +65,9 @@ npm create agdf@latest gate-check --json
61
65
 
62
66
  - `AGDF_RUN.md` is the current run dashboard.
63
67
  - `MASTER_BACKLOG.md` points to active delivery work; detailed artefacts live beside the work item.
68
+ - Brownfield Review records the post-UR Mode/Slice Decision before PRD depth or Quick Task execution is chosen.
64
69
  - UR, PRD, SD, TP and QA decisions require durable artefacts or links to the authoritative repository source of truth before the next gate can open.
70
+ - OR records the run closeout and next permissible step; it does not approve later gates.
65
71
  - `SOT_REGISTRY.md` decides which document owns which domain.
66
72
  - `CONTEXT_GRAPH.md` records durable project knowledge only when it has evidence and an exit criterion.
67
73
  - `AGENT_QUALITY_CONTRACTS.json` names reusable block, revise and warning conditions.
@@ -5,7 +5,7 @@
5
5
  - run_id:
6
6
  - started_at:
7
7
  - mode: `quick_task | structured_delivery`
8
- - current_gate: `none | UR | PRD | SD | TP | CD+Tests | CR | QA | UAT | OR`
8
+ - current_gate: `none | UR | Brownfield Review | Mode/Slice Decision | PRD | SD | TP | Quick Task Execution | Brownfield Analysis | CD+Tests | CR | QA | UAT | OR`
9
9
  - decision: `pass | revise | block | in_progress`
10
10
  - owner:
11
11
 
@@ -44,10 +44,34 @@ Valid approval format for new runs: `Approval: <GateName>`.
44
44
  | PRD | | `draft | approved | superseded | not_applicable` | |
45
45
  | SD | | `draft | approved | superseded | not_applicable` | |
46
46
  | TP | | `draft | approved | superseded | not_applicable` | |
47
+ | Brownfield Review | | `missing | draft | done | not_applicable | superseded` | |
47
48
  | Review | | `missing | done | not_applicable` | |
48
49
  | QA | | `missing | pass | revise | block | not_applicable` | |
49
50
  | OR | | `missing | done | not_applicable` | |
50
51
 
52
+ ## Mode / Slice Decision
53
+
54
+ Set this after Brownfield Review. Do not assume the full gate chain before the existing-system impact is understood.
55
+ Quick Task execution or implementation is not allowed until this decision is visible with scope reason and evidence.
56
+
57
+ - decision: `undecided | quick_task | structured_slice | structured_delivery | block`
58
+ - required_next_gate: `none | PRD | SD | TP | Brownfield Analysis`
59
+ - scope_reason:
60
+ - evidence:
61
+ - transparency_note:
62
+
63
+ ## Artefact Chain
64
+
65
+ Keep the active work item traceable. A gate may open only when the previous gate has both exact approval and a durable or linked artefact.
66
+
67
+ | From | Relationship | To | Evidence |
68
+ |---|---|---|---|
69
+ | UR | `approved_by` | `Approval: UR` | |
70
+ | PRD | `derived_from` | UR | |
71
+ | SD | `derived_from` | PRD | |
72
+ | TP | `derived_from` | SD | |
73
+ | QA_REPORT | `tests` | TP | |
74
+
51
75
  ## Evidence
52
76
 
53
77
  | Evidence | Source | Covers | Strength |
@@ -1,30 +1,32 @@
1
1
  # AGDF Master Backlog
2
2
 
3
- This file is the living control pointer for active AGDF delivery work. Detailed UR, PRD, SD, TP, QA and OR artefacts should live in stable paths and be linked from here.
3
+ This file is the living control pointer for active AGDF delivery work. Detailed UR, Brownfield Review, PRD, SD, TP, QA and OR artefacts should live in stable paths and be linked from here.
4
4
 
5
5
  ## Rules
6
6
 
7
7
  1. New product semantics, functional change or user-visible behaviour change starts as a new UR draft in a stable local artefact path, for example `.agdf/control/artefacts/<key>/UR.md`, unless an authoritative repository SoT already exists and is linked here.
8
8
  2. `Approval: UR` adds or updates exactly one steering row with a link to the UR.
9
- 3. PRD, SD, TP and QA report artefacts are created for the same work item after the previous gate is approved.
10
- 4. `Approval: PRD`, `Approval: SD`, `Approval: TP` and `Approval: QA` require the corresponding durable artefact or linked repository SoT before the next gate can open.
11
- 5. Keep only steering-relevant work in `Active Backlog`.
12
- 6. Every active item has exactly one current spec pointer.
13
- 7. Historical artefacts remain linkable but do not override the current pointer.
14
- 8. If an item is superseded, mark the replacement.
15
- 9. If active work grows beyond roughly ten items, triage the backlog.
9
+ 3. Brownfield Review is created for the same work item after UR approval when existing-system impact must be sized before PRD depth or Quick Task execution.
10
+ 4. PRD, SD, TP and QA report artefacts are created for the same work item after the previous gate is approved and persisted or linked.
11
+ 5. `Approval: PRD`, `Approval: SD`, `Approval: TP` and `Approval: QA` require the corresponding durable artefact or linked repository SoT before the next gate can open.
12
+ 6. Generic consent such as "ok", "go ahead", "do it", "continue", "leg los" or "approved" does not update a gate. Only `Approval: <GateName>` does.
13
+ 7. Keep only steering-relevant work in `Active Backlog`.
14
+ 8. Every active item has exactly one current spec pointer and a visible artefact chain.
15
+ 9. Historical artefacts remain linkable but do not override the current pointer.
16
+ 10. If an item is superseded, mark the replacement.
17
+ 11. If active work grows beyond roughly ten items, triage the backlog.
16
18
 
17
19
  ## Active Backlog
18
20
 
19
- | Prio | Key | Title | Status | Current Spec | Notes |
20
- |---:|---|---|---|---|---|
21
- | P1 | | | `in_progress | blocked` | | |
21
+ | Prio | Key | Title | Status | UR | Brownfield Review | PRD | SD | TP | QA | OR | Current Spec | Notes |
22
+ |---:|---|---|---|---|---|---|---|---|---|---|---|---|
23
+ | P1 | | | `in_progress | blocked` | | | | | | | | | |
22
24
 
23
25
  ## Planned / Parking Lot
24
26
 
25
- | Prio | Key | Title | Status | Current Spec | Notes |
26
- |---:|---|---|---|---|---|
27
- | P2 | | | `planned | review_needed` | | |
27
+ | Prio | Key | Title | Status | UR | Brownfield Review | PRD | SD | TP | QA | OR | Current Spec | Notes |
28
+ |---:|---|---|---|---|---|---|---|---|---|---|---|---|
29
+ | P2 | | | `planned | review_needed` | | | | | | | | | |
28
30
 
29
31
  ## Completed / Superseded Pointers
30
32