115 """Every NON-product ``version`` string in the scanned source tree.
117 The synthetic band must be disjoint from the roadmap (and any other non-product)
118 version set — colliding there hard-fails at ``SRC_VERSION_METADATA_CONFLICT`` or
119 silently dedup-merges. The product records this seed (re)writes are deliberately
120 EXCLUDED so the band is stable across re-runs (idempotent); product versions are
121 unique within the band by construction.
123 versions: set[str] = set()
124 for scanned
in scan_source_tree(source_dir):
125 if scanned.kind ==
"version":
126 model, _body = load_record(scanned)
127 if model.kind !=
"product":
128 versions.add(model.version)
150def backfill(backup_path: Path, source_dir: Path) -> SeedReport:
151 """Tile ``backup_path`` into ``source/changelog/product/**`` records."""
153 source_dir = Path(source_dir)
154 roadmap_dir = source_dir /
"changelog" /
"roadmap"
155 product_dir = source_dir /
"changelog" /
"product"
158 raw = Path(backup_path).read_text(encoding=
"utf-8")
159 segments = split_segments(raw)
160 line_ranges = segment_line_ranges(raw)
161 canonical = product_changelog_canonicalize(raw)
167 planned: dict[str, str] = {}
168 report =
SeedReport(segments=len(segments), canonical_bytes=len(canonical.encode(
"utf-8")))
169 report.synthetic_band = (band[0], band[-1])
170 for index, (segment, version, (lo, hi))
in enumerate(zip(segments, band, line_ranges), start=1):
173 date = _FALLBACK_DATE
174 report.date_fallback_seqs.append(index)
176 schema_version=rc.SCHEMA_VERSION,
181 extensions={
"changelog_seq": index},
183 text = format_record_text(model, body=segment)
184 filename = f
"{index:03d}-{version}.md"
185 planned[filename] = text
186 body_hash = hashlib.sha256(text.encode(
"utf-8")).hexdigest()
188 "seq": index,
"version": version,
"lines": f
"{lo}-{hi}",
189 "destination": f
"changelog/product/{filename}",
"date": date,
190 "body_sha256": body_hash,
194 if product_dir.is_dir():
195 on_disk = {p.name: p.read_text(encoding=
"utf-8")
for p
in product_dir.glob(
"*.md")}
196 if on_disk
and on_disk != planned:
198 "product changelog dir is non-empty and does not match this seed's expected "
199 f
"record set (on-disk {len(on_disk)} vs planned {len(planned)}); refusing (fail-closed)"
202 product_dir.mkdir(parents=
True, exist_ok=
True)
203 for filename, text
in planned.items():
204 (product_dir / filename).write_text(text, encoding=
"utf-8", newline=
"")
205 report.records_written += 1
209 raise ValueError(
"roadmap changelog records changed during product seed (fail-closed)")
213 with tempfile.TemporaryDirectory()
as tmp:
214 check_db = Path(tmp) /
"seed_fidelity.sqlite"
215 result = regenerate(source_dir, check_db)
217 raise ValueError(f
"regenerate failed after product seed (fail-closed): {result.envelope}")
218 rendered = render_living_set(check_db, source_dir)[
"root_changelog"]
219 body = rendered.split(
"-->", 1)[1].lstrip(
"\n")
220 if body != canonical:
221 raise ValueError(
"render(seed) != canonicalize(backup) — content-faithful proof failed (fail-closed)")
223 _dbg(
"OC_CHAT.MAIN", func, f
"wrote {report.records_written} product records; render==canon", 2)