create-agdf 0.2.3 → 0.2.4

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