Prepare accepted layer v0.8 publication and preserve immutable ADR history
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
parent
bfef142d4c
commit
5c41564f04
5 changed files with 307 additions and 2 deletions
|
|
@ -111,6 +111,8 @@ def load_manifest(path: Path) -> dict[str, Any]:
|
|||
document["canonical_path"],
|
||||
document["revision_path"].replace("{revision}", "revision"),
|
||||
*document.get("legacy_paths", []),
|
||||
*(document["revision_path"].format(revision=h["revision"])
|
||||
for h in document.get("historical_revisions", [])),
|
||||
):
|
||||
path_value = _safe_path(raw)
|
||||
if path_value in seen:
|
||||
|
|
@ -119,6 +121,44 @@ def load_manifest(path: Path) -> dict[str, Any]:
|
|||
return manifest
|
||||
|
||||
|
||||
def _restore_historical_revisions(
|
||||
document: dict[str, Any], repo: Path, output: Path, current_revision: str,
|
||||
) -> None:
|
||||
"""Retain explicitly pinned served revision bytes even in a clean build."""
|
||||
for historical in document.get("historical_revisions", []):
|
||||
revision = historical["revision"]
|
||||
if revision == current_revision:
|
||||
raise ValueError("historical revision must differ from current revision")
|
||||
source = (repo / historical["source_path"]).resolve()
|
||||
page = (repo / historical["rendered_page_path"]).resolve()
|
||||
for artifact in (source, page):
|
||||
if repo not in artifact.parents or not artifact.is_file():
|
||||
raise ValueError("historical artifact must be a file inside source repository")
|
||||
source_bytes, page_bytes = source.read_bytes(), page.read_bytes()
|
||||
if hashlib.sha256(source_bytes).hexdigest() != historical["source_digest"]:
|
||||
raise RuntimeError("historical source digest mismatch")
|
||||
if hashlib.sha256(page_bytes).hexdigest() != historical["rendered_page_digest"]:
|
||||
raise RuntimeError("historical rendered page digest mismatch")
|
||||
meta, _ = split_frontmatter(source_bytes.decode("utf-8"))
|
||||
if meta.get("id") != document["id"] or meta.get("revision") != revision:
|
||||
raise ValueError("historical source id/revision mismatch")
|
||||
page_text = page_bytes.decode("utf-8")
|
||||
source_revision = SOURCE_REVISION.search(page_text)
|
||||
source_digest = SOURCE_DIGEST.search(page_text)
|
||||
expected_revision = historical["source_revision"]
|
||||
if not CLEAN_GIT_REVISION.fullmatch(expected_revision):
|
||||
raise ValueError("historical source revision must be a clean Git commit")
|
||||
if (not source_revision or not source_digest
|
||||
or html.unescape(source_revision.group(1)) != expected_revision
|
||||
or html.unescape(source_digest.group(1)) != historical["source_digest"]):
|
||||
raise RuntimeError("historical page/source provenance mismatch")
|
||||
target = output / _safe_path(document["revision_path"].format(revision=revision))
|
||||
if target.exists() and target.read_bytes() != page_bytes:
|
||||
raise RuntimeError("immutable historical revision already has different bytes")
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_bytes(page_bytes)
|
||||
|
||||
|
||||
def _redirect(target: str, title: str) -> str:
|
||||
escaped = html.escape(target, quote=True)
|
||||
return (
|
||||
|
|
@ -214,6 +254,7 @@ def build(
|
|||
revision = meta.get("revision") or meta.get("version")
|
||||
if not revision:
|
||||
raise ValueError(f"{source}: revision or version is required")
|
||||
_restore_historical_revisions(document, repo, temporary, revision)
|
||||
source_revision = _source_revision(repo, source)
|
||||
source_digest = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
reviewed = meta.get("last_reviewed") or meta.get("updated")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue