7Renderer for per-worktree ``.PLAN_STATUS.md`` files.
11Render the registry's current plan assignment into the per-worktree status
12file used by workers and the legacy plan-status helper.
16- Map registry lifecycle statuses to the legacy `.PLAN_STATUS.md` enum.
17- Render valid schema-v1.0 YAML frontmatter for a worktree.
18- Write status files through the shared atomic artifact helper.
24 L2 - plan-status render lifecycle events
25 L3 - artifact drift details
26 L4 - per-field projection tracing
30- Output validates with `oc_chat.scripts.plan_status.read`.
31- No wall-clock values are invented by the renderer.
35- oc_diagnostics (structured debug logging via _dbg)
36- yaml (frontmatter emission)
37- oc_chat.registry.render._common (projection and write helpers)
38- oc_chat.registry.api (Registry facade the plan row is read from)
40from __future__
import annotations
42from pathlib
import Path
44from oc_diagnostics
import _dbg
56_dbg(
"OC_CHAT.MAIN",
"module",
"loaded", 4)
58STATUS_FILENAME =
".PLAN_STATUS.md"
63 "implementing":
"Implementing",
64 "ready_for_merge":
"Completed",
65 "integrating":
"Completed",
66 "completed":
"Completed",
67 "partial":
"Partially Completed",
69 "superseded":
"Failed",
74 """Render the status file for the plan assigned to ``worktree``."""
76 row = plan_for_worktree(registry, worktree)
79 status = _STATUS_TO_LEGACY.get(str(row[
"status"]),
"Queued")
80 data: dict[str, object] = {
81 "schema_version":
"1.0",
82 "plan_id": row[
"plan_id"],
83 "branch": row.get(
"branch")
or "",
84 "worktree": row.get(
"worktree")
or str(worktree),
85 "agent": agent_letter(row.get(
"assigned_slot")),
86 "model": row.get(
"model_override")
or "gpt-5.5",
87 "thinking":
_thinking(row.get(
"thinking_override")),
88 "session":
_session(row.get(
"session_override")),
96 if row.get(
"created_at"):
97 data[
"queued_at"] = str(row[
"created_at"])
98 if status ==
"Implementing" and row.get(
"updated_at"):
99 data[
"started_at"] = str(row[
"updated_at"])
100 if status
in {
"Completed",
"Partially Completed",
"Failed"}:
101 data[
"finished_at"] = row.get(
"body_observed_at")
or row.get(
"updated_at")
102 body = f
"# {row['plan_id']}\n\nRegistry-rendered status snapshot.\n"
110 prefer_local: bool =
False,
111 dry_run: bool =
False,
113 """Write ``.PLAN_STATUS.md`` for ``worktree``."""
115 return write_text_artifact(
116 worktree / STATUS_FILENAME,
118 artifact_kind=
"plan_status",
119 prefer_local=prefer_local,
125 data: dict[str, object] = {
126 "schema_version":
"1.0",
129 "worktree": str(worktree),
138 "current_step":
"No assigned registry plan",
141 return _frontmatter(data,
"# No Assigned Plan\n\nRegistry has no plan for this worktree.\n")
145 yaml_text = yaml.safe_dump(
149 default_flow_style=
False,
151 return f
"---\n{yaml_text}\n---\n\n{body.rstrip()}\n"
155 text =
"high" if value
is None else str(value)
156 return text
if text
in {
"off",
"low",
"medium",
"high",
"max"}
else "high"
160 text =
"either" if value
is None else str(value)
161 return text
if text
in {
"fresh",
"continue",
"either"}
else "either"
165 if status ==
"Implementing":
166 return "Implementing"
167 if status ==
"Queued":
169 return "Completed - ready to merge"
str _current_step(str status)
RenderResult write_plan_status(Registry registry, *, Path worktree, bool prefer_local=False, bool dry_run=False)
str render_plan_status(Registry registry, *, Path worktree)
str _session(object value)
str _thinking(object value)
str _render_empty(Path worktree)
str _frontmatter(dict[str, object] data, str body)