Ticket graphs

Every ticket as the root of its provenance graph — goal, patch, approval, runs and (as the ticket-class build lands) mandate, manifestations, guarantees, journey, artifacts and children. Rendered through the <<<TicketGraphList>>> tag.

← all ticket-graphs

ACTIVE#449 congruency

Forge evolution PART 2 of 2: EVOLUTION TIMELINE (root -> fork-point -> tip dates + fork width, plus omni ingest stamps as a second clock) + mechanical CONTAINMENT retirement gate + the 118-blob orphan/merge-home worklist. Read-only; consumes #445's JSON.

goal

PART 2 OF 2. Part 1 (#445) LANDED on main: tools/forge_family_tree.py clusters 264 bare repos into 109 lineages, classifies each, and emits --json. It deliberately never retires or merges anything. THIS ticket adds the two things Part 1 does not do: the EVOLUTION TIMELINE and the RETIREMENT GATE. DELIVERABLE: checkouts/current/congruency/tools/forge_evolution.py — standalone, stdlib + git only. CONSUME Part 1, do not re-derive it: run `forge_family_tree.py --json -` (or accept --family-json PATH) and build on its lineages/members/tips/classification. Part 1 already solved tip resolution (183 of 264 repos have an UNRESOLVABLE HEAD — a symref to a refs/heads/master that does not exist; `rev-parse HEAD` prints the literal string "HEAD" and EXITS 0). Never re-resolve tips yourself; never trust HEAD. 1. EVOLUTION IN STAGES — the temporal dimension. Part 1 carries NO time data at all (verified: zero ts/date keys in its JSON). Git already has every date for free. For each lineage emit a TIMELINE: * root commit date (`log -1 --format=%ai <root>`) * FORK POINT date per member (`log -1 --format=%ai $(merge-base <canonical-tip> <member-tip>)`) * tip date per member * the fork WIDTH — tip date minus fork-point date — i.e. how long the fork ran alone. Order members by fork-point date so the tree reads as stages, oldest first. WORKED EXAMPLE to reproduce (measured, agent_tools_suite lineage, root 379ac05319): 2026-07-08 20:38 root 379ac05 "agent_tools_suite: crankimg ..." 2026-07-11 02:23 FORK POINT = agent_tools_suite tip 888d3447c6 ("add deploy_test loop") 2026-07-12 14:07 jail tip 38e95ad16d -> jail ran 4 days alone, adding 6 files 2. THE SECOND CLOCK — omni ingest stamps. omni.git's refs are `refs/archives/<TS>/<repo>/heads/<b>`: when a snapshot was OBSERVED, distinct from when code was WRITTEN. Where a member's tip appears under an archive ref, report its ingest ts alongside the git dates — that is what reveals a repo was already stale when captured. TWO HARD RULES: (a) omni is ENRICHMENT ONLY and is INCOMPLETE (measured: it is MISSING agent_tools_suite's tip 888d3447c6) — config/forge/remotes/*.git stays authoritative, a missing omni stamp is simply omitted, never an error; (b) `occ.ts` is SOMETIMES THE LITERAL STRING 'gitlab', not a date — never render it as if it were always a timestamp. 3. RETIREMENT GATE — CONTAINMENT PROOF (mechanical, not a judgement). A fork is SAFE TO OMIT IF AND ONLY IF every file at its tip resolves, by CONTENT IDENTITY, to a blob present in the home repo(s). Use the SAME module-sha the ticketer computes: sha256("raw:" + bytes)[:16] — non-Python, or Python that does not parse sha256("ast:" + codebean._ast_norm(src))[:16] — Python that parses AST-normalized identity means a file that came home with only whitespace/comment drift still counts as CONTAINED (same module), while a semantically changed file correctly FAILS and surfaces as work. * every blob resolves -> report "SAFE TO OMIT (proven)" — proven, never assumed. * any blob unresolved -> emit the exact file list. The fork MUST NOT be dropped while that list is non-empty. THE UNRESOLVED LIST *IS* THE MERGE-HOME WORKLIST; it shrinks to empty exactly when the fork is safe to drop. 4. THE ORPHAN SET. Measured across the forge: 118 blobs (2.1% of 5,741 unique code blobs) exist ONLY in non-canonical tips — content that would be SILENTLY LOST by naively unifying on canonical tips. Emit them as a first-class report: blob sha, path, which member holds it, which lineage. This is small enough to review by hand and is the highest-value output of this tool. 5. DIRECTION IS NOT YOURS TO DECIDE. Part 1 already accepts --override / --override-file for the operator's per-PACKAGE home mapping (a grab-bag fork like jail has packages belonging to SEVERAL different homes). Honour that mapping; PROPOSE only; never infer direction from topology. LINEAR and FORK-CAME-HOME are the same git shape and differ only in intent, which is not in the DAG. NOTE: for LINEAR the direction cannot lose code (canonical supersets the rest) — it is a naming decision. Only DIVERGED/SPLIT-STORE put content at risk. Say so in the report. 6. READ-ONLY, ALWAYS. Never write to config/forge/remotes/*.git — the bare repos are the archive. Use `git show`/`cat-file`/`ls-tree`/`log`/`merge-base` plumbing only. Never write to the governance db. This tool PLANS retirement; it never performs it. 7. --selftest on THROWAWAY git repos in a temp dir: a fork fully contained in home (-> SAFE TO OMIT), a fork with one un-merged file (-> worklist of exactly 1, NOT safe), whitespace/comment-only drift (-> contained via ast identity), a semantic change (-> correctly NOT contained), and a fork-width timeline assertion. No network, no live db, no writes outside the temp dir. ACCEPTANCE: --selftest green; a live read-only run reproduces the measured 118-blob orphan set and prints the agent_tools_suite timeline above (root 2026-07-08 20:38 -> fork point 2026-07-11 02:23 -> jail tip 2026-07-12 14:07, width 4 days, 6 files added); jail reports NOT-safe-to-omit with its 6 files as the worklist (they have not come home yet); no writes anywhere. RUN ON CLAUDE.

patch

none

approval

unapproved

runs

no runs recorded

mandate (clauses)

not yet recorded — lands with the ticket-class build

manifestations

not yet recorded — lands with the ticket-class build

guarantees

not yet recorded — lands with the ticket-class build

journey (blunders & successes)

not yet recorded — lands with the ticket-class build

artifacts (forge)

not yet recorded — lands with the ticket-class build

source (forge tree)

browse congruency source (forge-parked tree)

children

not yet recorded — lands with the ticket-class build