94 """Attach the ``roadmap`` command group."""
96 parser = subcommands.add_parser(
98 help=
"Import, export, audit, and version ROADMAP registry data.",
100 roadmap_commands = parser.add_subparsers(dest=
"roadmap_command")
102 import_parser = roadmap_commands.add_parser(
"import", help=
"Import ROADMAP markdown.")
103 import_parser.add_argument(
"registry", nargs=
"?")
104 import_parser.add_argument(
"--dir", dest=
"roadmap_dir")
105 import_parser.add_argument(
"--dry-run", action=
"store_true")
106 import_parser.add_argument(
"--actor-slot")
107 import_parser.add_argument(
"--json", action=
"store_true")
108 import_parser.set_defaults(handler=_cmd_import)
110 render_parser = roadmap_commands.add_parser(
113 help=
"Render (or --check) the living ROADMAP GeneratedView set from the "
114 "verified authored projection + source/.",
116 render_parser.add_argument(
"registry", nargs=
"?")
117 render_parser.add_argument(
"--db", dest=
"db", help=
"Authored-projection store (default: workspace).")
118 render_parser.add_argument(
"--source", dest=
"source", help=
"source/ tree (default: workspace).")
120 render_parser.add_argument(
"--out", dest=
"out", help=
"Roadmap dir for ROADMAP*.md (default: workspace).")
122 render_parser.add_argument(
"--root", dest=
"root", help=
"Root dir for CHANGELOG.md (default: workspace root).")
123 render_parser.add_argument(
"--published", help=
"Stamp this 'Updated' date into the header.")
124 render_parser.add_argument(
"--check", action=
"store_true", help=
"Audit on-disk views for drift; do not write.")
125 render_parser.add_argument(
"--json", action=
"store_true")
126 render_parser.set_defaults(handler=_cmd_render)
133 reconcile_parser = roadmap_commands.add_parser(
136 help=
"Check roadmap CLAIMS against roadmap STATE (NOT the drift check).",
138 reconcile_parser.add_argument(
"registry", nargs=
"?")
139 reconcile_parser.add_argument(
"--source", dest=
"source", help=
"source/ tree (default: workspace).")
140 reconcile_parser.add_argument(
"--plans", dest=
"plans", help=
"Completed-plans dir (default: workspace).")
141 reconcile_parser.add_argument(
"--repo", dest=
"repo", help=
"Repository root (default: workspace).")
142 reconcile_parser.add_argument(
143 "--since", default=_DISCIPLINE_LANDED,
144 help=
"Only inspect commits newer than this git date. Defaults to the day "
145 "the round-close discipline landed (%s, plan 205); pre-discipline "
146 "changelog records predate the advances/status-flip rule and are "
147 "grandfathered. Pass an earlier date (or an empty value) to audit "
148 "the full history." % _DISCIPLINE_LANDED,
150 reconcile_parser.add_argument(
151 "--advances-required-from", dest=
"advances_required_from",
152 default=_ADVANCES_REQUIRED_FROM,
154 help=
"Lowest plan id the `advances:` field is REQUIRED on; older plans "
155 "missing it are advisory (the field landed 2026-08-14 with plan 205, "
156 "so this defaults to %s — plans 014-204 predate the mechanism and are "
157 "grandfathered)." % _ADVANCES_REQUIRED_FROM,
159 reconcile_parser.add_argument(
160 "--fail-on-violations",
162 help=
"Exit 1 when violations are present (default: advisory, always exit 0).",
164 reconcile_parser.add_argument(
165 "--all", dest=
"show_all", action=
"store_true",
166 help=
"List advisory findings too, not just violations.",
168 reconcile_parser.add_argument(
169 "--limit", type=int, default=25, help=
"Max findings to list in human output (0 = all).",
171 reconcile_parser.add_argument(
172 "--write-links", action=
"store_true",
173 help=
"Persist the plan->item join into roadmap_plan_links (live store only).",
175 reconcile_parser.add_argument(
"--actor-slot")
176 reconcile_parser.add_argument(
"--json", action=
"store_true")
177 reconcile_parser.set_defaults(handler=_cmd_reconcile)
179 audit_parser = roadmap_commands.add_parser(
"audit", help=
"Audit ROADMAP drift.")
180 audit_parser.add_argument(
"registry", nargs=
"?")
181 audit_parser.add_argument(
"--dir", dest=
"roadmap_dir")
182 audit_parser.add_argument(
"--version")
183 audit_parser.add_argument(
"--json", action=
"store_true")
184 audit_parser.set_defaults(handler=_cmd_audit)
186 bump_parser = roadmap_commands.add_parser(
"bump", help=
"Create a draft roadmap version.")
187 bump_parser.add_argument(
"registry", nargs=
"?")
188 bump_parser.add_argument(
"--from", dest=
"from_version")
189 bump_parser.add_argument(
"--to", dest=
"to_version", required=
True)
190 bump_parser.add_argument(
"--kind", default=
"patch")
191 bump_parser.add_argument(
"--actor-slot")
192 bump_parser.set_defaults(handler=_cmd_bump)
194 status_parser = roadmap_commands.add_parser(
"status", help=
"Show roadmap store status.")
195 status_parser.add_argument(
"registry", nargs=
"?")
196 status_parser.add_argument(
"--json", action=
"store_true")
197 status_parser.set_defaults(handler=_cmd_status)
201 add_source_subcommands(roadmap_commands)
217 """Render (or --check) the living GeneratedView set (§6).
219 Resolves the worktree-local **authored-projection** store + the ``source/``
220 tree — NEVER the shared live registry (the living set renders from the
221 verified projection, not the runtime store).
223 location = discover_registry_location(registry_path=args.registry)
224 workspace = Path(location.workspace_root)
226 Path(args.db)
if args.db
227 else workspace /
".option_c" /
"orchestration" /
"registry_authored.sqlite"
229 source_dir = Path(args.source)
if args.source
else workspace /
"oc_chat" /
"roadmap" /
"source"
230 roadmap_dir = Path(args.out)
if args.out
else workspace /
"oc_chat" /
"roadmap"
231 root_dir = Path(args.root)
if args.root
else workspace
240 results = render_check(db_path, source_dir, roadmap_dir=roadmap_dir, root_dir=root_dir)
241 drift = [result.to_dict()
for result
in results
if result.drift]
242 payload = {
"ok":
not drift,
"checked": len(results),
"drift": drift}
244 return 0
if not drift
else 1
245 written = write_living_set(
246 db_path, source_dir, roadmap_dir=roadmap_dir, root_dir=root_dir,
247 published=args.published,
249 payload = {
"ok":
True,
"files": [str(path)
for path
in written]}
252 except (SourceError, RegenerateError)
as error:
254 return exit_code_for(error)
267 """Compare roadmap CLAIMS against roadmap STATE (Plan 205).
269 Advisory by default: it exits 0 with violations present. That is deliberate.
270 The first full-tree run reports the whole pre-existing backlog, and a check
271 that must be green before it can land is a check that gets weakened until it
272 is. ``--fail-on-violations`` is the opt-in for a gate that has been cleaned.
274 func =
"_cmd_reconcile"
275 location = discover_registry_location(registry_path=args.registry)
276 workspace = Path(location.workspace_root)
277 repo_root = Path(args.repo)
if args.repo
else workspace
279 report = reconcile_workspace(
281 source_dir=args.source,
282 plans_dir=args.plans,
284 advances_required_from=args.advances_required_from,
286 except ReconcileConfigError
as error:
289 print(f
"roadmap reconcile: configuration error\n{error}", file=sys.stderr)
290 print(f
"roadmap reconcile: configuration error\n{error}")
292 _dbg(
"OC_CHAT.MAIN", func, f
"reconciled {repo_root}", 2)
294 payload = report.to_dict()
296 payload[
"write_links"] =
_write_links(args, report).to_dict()
298 print(json.dumps(payload, indent=2, sort_keys=
True))
301 return 1
if (args.fail_on_violations
and report.would_fail)
else 0