target-revenue/scripts/generate_golden_phase.py
tegwick 55a1756f7c Merge spec/ into specs/: one specs directory for the whole repo
Moves TargetRevenueLicenseConcept.md from the separate singular spec/
directory into specs/ (git mv, preserving history) and updates every live
cross-reference (README, CONTRIBUTING, all specs/*.md, workplans, schema
comments, source docstrings, test file) to the new path.

This resolves the spec/ vs specs/ split that history/260728-SWOT-Assessment.md
flagged as a "perpetual footgun" and recommended deciding on. The historical
record of that split and the recommendation itself are left unedited in
history/ (a dated assessment, not a living document) — only README and TSD
now document the merge as resolved, with a pointer back to that history file
for context.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 10:22:14 +02:00

128 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""Regenerate examples/phase-001/ledger.json with a correct hash chain.
The golden Phase package must exercise a real SHA-256 hash chain, not
hand-typed digests. This script builds the entry sequence from
specs/TargetRevenueLicenseConcept.md §23's illustrative example and writes it
out via the same hashing.entry_hash() the library and tests use, so the
fixture and the code that verifies it can never silently drift apart.
Run: python3 scripts/generate_golden_phase.py
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))
from target_revenue import hashing # noqa: E402
PHASE_ID = "trsl:phase:example-001"
def entry(
entry_id: str,
entry_type: str,
amount: float,
recognized_at: str,
extension_id: str,
extension_version: str,
evidence_reference: str,
previous_entry_hash: str,
) -> dict:
return {
"id": entry_id,
"phase": PHASE_ID,
"type": entry_type,
"amount": amount,
"currency": "USD",
"recognized_at": recognized_at,
"extension": {"id": extension_id, "version": extension_version},
"evidence_reference": evidence_reference,
"previous_entry_hash": previous_entry_hash,
}
def main() -> None:
entries: list[dict] = []
previous_hash = hashing.GENESIS
specs = [
# (id, type, amount, recognized_at, extension_id, evidence_reference)
(
"trsl:entry:example0010001",
"development-credit",
25000,
"2026-09-01T09:00:00Z",
"trsl:extension:development-license",
"confidential:evidence:example-001-dc-0001",
),
(
"trsl:entry:example0010002",
"development-credit",
10000,
"2026-09-15T09:00:00Z",
"trsl:extension:phase-sponsorship",
"confidential:evidence:example-001-dc-0002",
),
(
"trsl:entry:example0010003",
"development-credit",
2000,
"2026-10-01T09:00:00Z",
"trsl:extension:service-with-development-allocation",
"confidential:evidence:example-001-dc-0003",
),
(
"trsl:entry:example0010004",
"remission-credit",
18000,
"2026-12-01T00:00:00Z",
"trsl:policy:linear-longstop-v0",
"confidential:evidence:example-001-rc-0001",
),
(
"trsl:entry:example0010005",
"development-credit",
30000,
"2027-03-01T09:00:00Z",
"trsl:extension:development-license",
"confidential:evidence:example-001-dc-0004",
),
(
"trsl:entry:example0010006",
"remission-credit",
15000,
"2027-06-01T00:00:00Z",
"trsl:policy:linear-longstop-v0",
"confidential:evidence:example-001-rc-0002",
),
]
for entry_id, entry_type, amount, recognized_at, ext_id, evidence in specs:
record = entry(
entry_id,
entry_type,
amount,
recognized_at,
ext_id,
"1.0",
evidence,
previous_hash,
)
entries.append(record)
previous_hash = hashing.entry_hash(record)
out_path = REPO_ROOT / "examples" / "phase-001" / "ledger.json"
with open(out_path, "w", encoding="utf-8") as f:
json.dump(entries, f, indent=2)
f.write("\n")
print(f"wrote {len(entries)} entries to {out_path}")
if __name__ == "__main__":
main()