76 conn: sqlite3.Connection,
79 logical_state_hash: str,
80 published: Optional[str] =
None,
81 note_sections: Optional[list[str]] =
None,
83 """Render the comprehensive V3 ``ROADMAP-EXTENDED.md`` as deterministic bytes.
85 ``note_sections`` are the pre-rendered framing-note sections (Sources /
86 Reconciliation / Execution Order / Out Of Scope / Git Workflow) read from
87 ``source/notes`` by ``render_living_set`` — appended as an EXTENDED-only
88 appendix (the lean view never carries them); store-only ``render`` keeps no
89 source handle, so the caller passes them in.
92 header = build_generated_header(
93 source_hash=source_hash,
94 logical_state_hash=logical_state_hash,
95 renderer=RENDERER_EXTENDED,
97 version = store_read.selected_roadmap_version(conn)
98 body = roadmap_main._render_manifest_sections(conn, FILE_KIND_EXTENDED)
103 body.extend(versioning)
107 body.extend(note_sections)
113 roadmap_main._version_line(version, published),
116 "A complete index of every OC Chat roadmap phase, sub-phase, non-phase "
117 "item, and shipped version — the full historical record (see ROADMAP.md "
118 "for the lean working map).",
122 *roadmap_main._current_block(conn),
126 *roadmap_main.legend_lines(),
128 toc = roadmap_main._toc(body)
130 lines.extend([
"", *toc])
131 lines.extend([
"", *body])
132 lines.extend([
"", *generated_footer(
"roadmap_extended")])
133 _dbg(
"OC_CHAT.MAIN", func, f
"extended rendered version={version}", 2)
134 return "\n".join(lines).rstrip() +
"\n"
138 """Render the EXTENDED-only Versioning Notes table from ``roadmap_versions``."""
139 conn.row_factory = sqlite3.Row
140 rows = guarded_query(
143 "SELECT version_id, era_id, bump_kind, status, released_at, notes "
144 "FROM roadmap_versions ORDER BY version_id",
148 lines = [
"## Versioning Notes",
"", _VERSION_HEADER]
151 "| {version} | {era} | {bump} | {state} | {released} | {notes} |".format(
152 version=section_render.escape(row[
"version_id"]),
153 era=section_render.escape(row[
"era_id"]),
154 bump=section_render.escape(row[
"bump_kind"]),
155 state=section_render.escape(row[
"status"]),
156 released=section_render.escape(row[
"released_at"]),
157 notes=section_render.escape(row[
"notes"]
or ""),