orchestrata_ultimate.openspec.render
Reference › orchestrata_ultimate › openspec › render
render writes OpenSpec models back to markdown (SPEC-104 FR-004 and FR-007) and is the inverse of parse: parsing the output of render_spec round-trips structurally. render_spec renders an OpenSpecDoc as a capability spec.md (using _render_requirement for each requirement). render_delta renders change-delta blocks. render_proposal produces a change proposal.md with Why, What Changes and Impact sections, and render_tasks produces a tasks.md checklist under a numbered group heading. repo uses all of these when writing to disk. Types come from models.
At a glance
| Source | src/orchestrata_ultimate/openspec/render.py |
| Lines of code | 73 |
| Classes | 0 |
| Functions | 5 |
| Imports (internal) | orchestrata_ultimate.core.traceability, orchestrata_ultimate.openspec.models |
| Imported by | orchestrata_ultimate.openspec, orchestrata_ultimate.openspec.repo |
| Tests that import it | none |
Class diagram
No classes; see Functions.
Dependency diagram
API
Functions
| Function | Signature | Summary |
|---|---|---|
_render_requirement traces |
_render_requirement(req: Requirement) -> str |
|
render_spec traces |
render_spec(doc: OpenSpecDoc) -> str |
Render an OpenSpecDoc to a valid OpenSpec capability spec.md. |
render_delta traces |
render_delta(deltas: list[Delta]) -> str |
Render change-delta blocks (## ADDED/MODIFIED/REMOVED/RENAMED Requirements). |
render_proposal traces |
render_proposal(why: str, what: list[str], impact: str = '') -> str |
Render an OpenSpec change proposal.md (## Why / ## What Changes / ## Impact). |
render_tasks traces |
render_tasks(tasks: list[str], group: str = 'Implementation') -> str |
Render an OpenSpec tasks.md checklist (## 1. |
Source
"""Render OpenSpec models back to OpenSpec markdown (SPEC-104 FR-004/007).
Inverse of :mod:`orchestrata_ultimate.openspec.parse` — ``parse_spec(render_spec(doc))``
round-trips structurally. Also renders change-proposal artifacts (proposal.md,
tasks.md, delta spec.md).
"""
from __future__ import annotations
from orchestrata_ultimate.core.traceability import traces
from orchestrata_ultimate.openspec.models import Delta, OpenSpecDoc, Requirement
@traces(spec="104", story="US-104-001", reqs=["REQ-104-006", "REQ-104-007"])
def _render_requirement(req: Requirement) -> str:
parts = [f"### Requirement: {req.title}"]
if req.text:
parts.append("")
parts.append(req.text)
for scen in req.scenarios:
parts.append("")
parts.append(f"#### Scenario: {scen.name}")
parts.extend(scen.lines)
return "\n".join(parts)
@traces(spec="104", story="US-104-001", reqs=["REQ-104-006"])
def render_spec(doc: OpenSpecDoc) -> str:
"""Render an OpenSpecDoc to a valid OpenSpec capability spec.md."""
title = doc.capability or "Capability"
out = [f"# {title} Specification", "", "## Purpose", "", doc.purpose or "(TBD)", ""]
out.append("## Requirements")
for req in doc.requirements:
out.append("")
out.append(_render_requirement(req))
return "\n".join(out).rstrip() + "\n"
@traces(spec="104", story="US-104-001", reqs=["REQ-104-007"])
def render_delta(deltas: list[Delta]) -> str:
"""Render change-delta blocks (## ADDED/MODIFIED/REMOVED/RENAMED Requirements)."""
out = [
line
for delta in deltas
for line in (
f"## {delta.operation} Requirements",
*(
item
for req in delta.requirements
for item in ("", _render_requirement(req))
),
"",
)
]
return "\n".join(out).rstrip() + "\n"
@traces(spec="104", story="US-104-001", reqs=["REQ-104-007"])
def render_proposal(why: str, what: list[str], impact: str = "") -> str:
"""Render an OpenSpec change proposal.md (## Why / ## What Changes / ## Impact)."""
out = ["## Why", "", why.strip() or "(TBD)", "", "## What Changes", ""]
out.extend(f"- {item}" for item in what)
if impact:
out.extend(["", "## Impact", "", impact.strip()])
return "\n".join(out).rstrip() + "\n"
@traces(spec="104", story="US-104-001", reqs=["REQ-104-007"])
def render_tasks(tasks: list[str], group: str = "Implementation") -> str:
"""Render an OpenSpec tasks.md checklist (## 1. Group, - [ ] 1.n task)."""
out = [f"## 1. {group}", ""]
out.extend(f"- [ ] 1.{i} {task}" for i, task in enumerate(tasks, start=1))
return "\n".join(out).rstrip() + "\n"