Skip to content

Commit d7360d4

Browse files
committed
feat: add roadmap deferred ownership records
1 parent 8648f42 commit d7360d4

5 files changed

Lines changed: 190 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
150150

151151
### Changed
152152
- `brigade roadmap audit` now reads documented commands from command snippets instead of prose and normalizes parameterized examples such as `brigade tools show <id>` to their CLI command path.
153+
- `brigade roadmap audit --json` now includes deferred roadmap ownership records with subsystem, owner, reason, source section, status, and suggested phase.
153154
- Roadmap phase headings now distinguish foundations, active work, and the phase queue so stale Current/Next warnings are actionable.
154155
- Public repo contents now keep live dogfood workspace files, internal planning notes, and root memory cards untracked; public templates remain under `src/brigade/templates/`.
155156
- Dogfood handoff defaults now use `.codex/memory-handoffs/` for new Codex-driven local configs while preserving explicit configured inbox paths such as `.claude/memory-handoffs/`.

docs/phase-61-100-plan.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ Goal: make `brigade roadmap audit` accurate enough to drive phases 61-100. Norma
1616

1717
Acceptance: roadmap audit tests cover command normalization, parent-command examples, prose filtering, stale phase behavior, and pattern coverage. README, ROADMAP, CHANGELOG, and this plan document the phase queue.
1818

19+
Status: implemented.
20+
1921
### Phase 62: Roadmap Ownership And Deferred Item Records
2022
Goal: add explicit roadmap ownership records for deferred items so later phases can close or re-defer them without ambiguous status text.
2123

2224
Acceptance: roadmap audit JSON includes owner, subsystem, deferred reason, and suggested next phase for known deferred items.
2325

26+
Status: implemented with `deferred_items` in `brigade roadmap audit --json`.
27+
2428
### Phase 63: Public Command Documentation Contract
2529
Goal: make public docs and CLI command discovery agree through a stable command contract, without relying on fragile prose scans.
2630

docs/roadmap-completion-plan.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ Phase 61 status:
258258
- Tightened `brigade roadmap audit` command discovery so it scans command snippets, ignores prose, and normalizes parent commands and parameterized examples to known CLI command paths.
259259
- Closed the context-engineering pattern registry owner and test-hint gap.
260260

261+
Phase 62 status:
262+
263+
- Added public-safe deferred roadmap ownership records to `brigade roadmap audit --json`.
264+
- Each known deferred item now has an id, title, subsystem, owner, source section, deferred reason, status, and suggested phase when the item remains in scope.
265+
- Text audit output includes the deferred item count, while unresolved ownership or missing phase metadata would become roadmap audit warnings.
266+
261267
### 3. Inspiration Pattern Registry
262268

263269
Deliverable: a bounded local record of external workflow patterns Brigade intends to support.

src/brigade/roadmap_cmd.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,139 @@
170170
},
171171
)
172172

173+
DEFERRED_ROADMAP_ITEMS: tuple[dict[str, Any], ...] = (
174+
{
175+
"id": "deeper-roadmap-ownership-modeling",
176+
"title": "Deeper roadmap ownership modeling",
177+
"subsystem": "roadmap",
178+
"owner": "roadmap",
179+
"source_section": "Roadmap State Audit And Closure Map",
180+
"deferred_reason": "Earlier roadmap audit work prioritized command visibility, JSON output, tests, and daily-loop health before richer ownership state.",
181+
"suggested_phase": 62,
182+
"status": "active",
183+
},
184+
{
185+
"id": "private-pattern-source-aliases",
186+
"title": "Private pattern source aliases from local config",
187+
"subsystem": "roadmap",
188+
"owner": "roadmap",
189+
"source_section": "Inspiration Pattern Registry",
190+
"deferred_reason": "Exact reference source names belong only in gitignored host-local config, while public docs should expose neutral pattern families.",
191+
"suggested_phase": 62,
192+
"status": "active",
193+
},
194+
{
195+
"id": "cross-producer-provenance-audit",
196+
"title": "Cross-producer provenance audits across historical sources",
197+
"subsystem": "work-inbox",
198+
"owner": "work",
199+
"source_section": "Scanner And Inbox Closure",
200+
"deferred_reason": "The scanner closeout phase tightened the common path first and left historical compatibility backfill for a focused pass.",
201+
"suggested_phase": 64,
202+
"status": "planned",
203+
},
204+
{
205+
"id": "expanded-chat-export-parsers",
206+
"title": "Expanded chat export provider aliases and parser fixtures",
207+
"subsystem": "chat-surfaces",
208+
"owner": "chat",
209+
"source_section": "Chat Surface Export Completion",
210+
"deferred_reason": "The no-live-API boundary kept the first implementation focused on local export contracts and privacy gates.",
211+
"suggested_phase": 66,
212+
"status": "planned",
213+
},
214+
{
215+
"id": "outbound-backup-status-messages",
216+
"title": "Outbound backup operator status messages",
217+
"subsystem": "backup-health",
218+
"owner": "backup",
219+
"source_section": "Backup And Recovery Closure",
220+
"deferred_reason": "Outbound notifications require product-specific surfaces and remain outside the local read-only operator loop.",
221+
"suggested_phase": None,
222+
"status": "out-of-scope",
223+
},
224+
{
225+
"id": "tool-projection-parity-closeout",
226+
"title": "Separate tool projection parity closeout receipt",
227+
"subsystem": "tool-catalog",
228+
"owner": "tools",
229+
"source_section": "Shared Tool Catalog Completion",
230+
"deferred_reason": "Projection state is represented in packs and sync plans first, while closeout state needs a focused compatibility pass.",
231+
"suggested_phase": 68,
232+
"status": "planned",
233+
},
234+
{
235+
"id": "context-harness-destination-writes",
236+
"title": "Context pack writes into harness destinations",
237+
"subsystem": "context",
238+
"owner": "context",
239+
"source_section": "Context Engineering Packs",
240+
"deferred_reason": "Context sync planning remains read-only until a future explicit context apply command exists.",
241+
"suggested_phase": 70,
242+
"status": "planned",
243+
},
244+
{
245+
"id": "learning-accepted-risk-quieting",
246+
"title": "Rich accepted-risk quieting across learning sources",
247+
"subsystem": "learning",
248+
"owner": "learn",
249+
"source_section": "Self-Learning Loop Closure",
250+
"deferred_reason": "Candidate import routing exists first, while source-specific quieting policies remain subsystem-owned.",
251+
"suggested_phase": 74,
252+
"status": "planned",
253+
},
254+
{
255+
"id": "security-sarif-output",
256+
"title": "Dependency-free security SARIF output",
257+
"subsystem": "security",
258+
"owner": "security",
259+
"source_section": "Security Plugin Closure",
260+
"deferred_reason": "JSON and Markdown evidence bundles exist, and SARIF needs a focused schema compatibility pass without new dependencies.",
261+
"suggested_phase": 76,
262+
"status": "planned",
263+
},
264+
{
265+
"id": "stale-issue-repair-imports",
266+
"title": "Stale active issue repair imports",
267+
"subsystem": "work",
268+
"owner": "work",
269+
"source_section": "Issue And TDD Loop Closure",
270+
"deferred_reason": "The first acceptance phase completed the local acceptance rollup before repair-import routing.",
271+
"suggested_phase": 80,
272+
"status": "planned",
273+
},
274+
{
275+
"id": "repo-shareable-workflow-rule-templates",
276+
"title": "Repo-shareable workflow rule templates",
277+
"subsystem": "install",
278+
"owner": "templates",
279+
"source_section": "Issue And TDD Loop Closure",
280+
"deferred_reason": "The first acceptance phase avoided mixing public workflow rules with personal preferences.",
281+
"suggested_phase": 79,
282+
"status": "planned",
283+
},
284+
{
285+
"id": "safe-memory-autofix-planning",
286+
"title": "Safe memory-care autofix planning",
287+
"subsystem": "memory-care",
288+
"owner": "memory",
289+
"source_section": "Memory And Handoff Closure",
290+
"deferred_reason": "Memory-care closeouts record review state first, with mutation-free repair planning left for a focused pass.",
291+
"suggested_phase": 83,
292+
"status": "planned",
293+
},
294+
{
295+
"id": "recursive-repo-root-discovery",
296+
"title": "Safe repo root discovery from configured roots",
297+
"subsystem": "repo-fleet",
298+
"owner": "repos",
299+
"source_section": "Repository Fleet Readiness",
300+
"deferred_reason": "Explicit repo config avoids accidentally exposing private repo names or paths; discovery needs a dry-run privacy-safe plan.",
301+
"suggested_phase": 91,
302+
"status": "planned",
303+
},
304+
)
305+
173306

174307
def _roadmap_path(target: Path) -> Path:
175308
return target / "ROADMAP.md"
@@ -360,6 +493,29 @@ def _normalize_documented_command(command: str, known_prefixes: set[str]) -> str
360493
return command
361494

362495

496+
def _deferred_items() -> list[dict[str, Any]]:
497+
return [dict(item) for item in DEFERRED_ROADMAP_ITEMS]
498+
499+
500+
def _deferred_item_checks(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
501+
missing_owner = [item["id"] for item in items if not item.get("owner")]
502+
missing_phase = [item["id"] for item in items if item.get("status") != "out-of-scope" and not item.get("suggested_phase")]
503+
return [
504+
{
505+
"status": WARN if missing_owner else OK,
506+
"name": "roadmap_deferred_missing_owner",
507+
"detail": f"{len(missing_owner)} deferred item(s) missing owner" if missing_owner else "none",
508+
"items": missing_owner,
509+
},
510+
{
511+
"status": WARN if missing_phase else OK,
512+
"name": "roadmap_deferred_missing_phase",
513+
"detail": f"{len(missing_phase)} deferred item(s) missing suggested phase" if missing_phase else "none",
514+
"items": missing_phase,
515+
},
516+
]
517+
518+
363519
def audit_payload(target: Path) -> dict[str, Any]:
364520
target = target.expanduser().resolve()
365521
roadmap = _parse_roadmap(target)
@@ -400,10 +556,14 @@ def audit_payload(target: Path) -> dict[str, Any]:
400556
"commands": missing_docs[:20],
401557
}
402558
)
559+
deferred_items = _deferred_items()
560+
checks.extend(_deferred_item_checks(deferred_items))
403561
issues = [check for check in checks if check.get("status") != OK]
404562
return {
405563
"target": str(target),
406564
"roadmap": roadmap,
565+
"deferred_items": deferred_items,
566+
"deferred_item_count": len(deferred_items),
407567
"documented_commands": documented,
408568
"normalized_documented_commands": normalized_documented,
409569
"cli_commands": cli_commands,
@@ -463,6 +623,7 @@ def audit(*, target: Path, json_output: bool = False, import_issues: bool = Fals
463623
print(f"roadmap audit: {payload['target']}")
464624
print(f"roadmap: {payload['roadmap']['path']}")
465625
print(f"sections: {len(payload['roadmap']['sections'])}")
626+
print(f"deferred_items: {payload['deferred_item_count']}")
466627
print(f"issues: {payload['issue_count']}")
467628
for check in payload["checks"]:
468629
print(f"[{check['status']}] {check['name']}: {check['detail']}")

tests/test_roadmap_cmd.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ def test_roadmap_audit_json_and_imports(tmp_path, capsys):
6161
assert all(item["source"] == "roadmap-audit" for item in _read_imports(tmp_path))
6262

6363

64+
def test_roadmap_audit_includes_deferred_ownership_records(tmp_path, capsys):
65+
(tmp_path / "ROADMAP.md").write_text("# Roadmap\n")
66+
payload = roadmap_cmd.audit_payload(tmp_path)
67+
68+
deferred = {item["id"]: item for item in payload["deferred_items"]}
69+
item = deferred["cross-producer-provenance-audit"]
70+
assert item["owner"] == "work"
71+
assert item["subsystem"] == "work-inbox"
72+
assert item["deferred_reason"]
73+
assert item["suggested_phase"] == 64
74+
assert payload["deferred_item_count"] >= 10
75+
assert all(check["status"] == "ok" for check in payload["checks"] if check["name"].startswith("roadmap_deferred_"))
76+
77+
assert roadmap_cmd.audit(target=tmp_path, json_output=False) == 0
78+
out = capsys.readouterr().out
79+
assert "deferred_items:" in out
80+
81+
6482
def test_roadmap_patterns_cover_neutral_families_and_decisions(capsys, tmp_path):
6583
assert roadmap_cmd.patterns(target=tmp_path, json_output=True) == 0
6684
payload = json.loads(capsys.readouterr().out)

0 commit comments

Comments
 (0)