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

REQUESTED#454 congruency

VM registry: register every VM image as a kind='forge-vm' artifact via the EXISTING artifact.record (ticket_artifacts has the right shape and 0 rows). Report LIVE/ORPHANED-DELTA/STALE-PATH/COPY — all 6 domains are dark from one directory move.

goal

Maintain a REGISTRY of virtual machines, tagged. Use the registry that ALREADY EXISTS — do not invent one. This is a small, honest tool: it records what is actually on disk so the next person (or agent) does not have to guess. USE WHAT IS BUILT. `ticket_artifacts` already has exactly the right shape and has ZERO rows: ticket_artifacts (id, ts, ticket_id, name, version, forge_sha, kind) routes: artifact.record (POST) artifact.list (GET) * kind -> THE TAG. VMs register as kind='forge-vm'. * name -> the domain / image name (e.g. 'workstation', 'noble-arm64-base'). * forge_sha -> the sha256 content address (this is ALREADY the filename in config/forge/large-blobs/<sha256> and the shard key in config/forge/artifacts/blobs/<xx>/...). * version -> the image's identifying version where one exists, else the short sha. Record THROUGH the governed route (artifact.record). NEVER hand-write the db. WHY THIS EXISTS (measured today, all four are the reason): 1. All 6 libvirt domains are 'shut off' and EVERY disk path is DEAD: the xmls point at /Users/stevenpeterson/bin/config/vm/<disk>, but the lab actually lives at <project>/config/vm/. One directory move darkened the whole lab and nothing recorded it. appliance -> appliance-run.qcow2 DISK-EXISTS: NO fabric-root -> fabric-root.qcow2 DISK-EXISTS: NO pi-imaging -> overlay.qcow2 DISK-EXISTS: NO workstation -> workstation.qcow2 DISK-EXISTS: NO 2. QCOW2 backing chains are broken by the same move: large-blobs/ec281818... is a 6.4G delta whose base IS present (config/vm/noble-arm64-base.img, 586M) but is referenced at the pre-move path. 3. 3.46G of large-blobs are BYTE-COPIES of the live lab (verified by sha256: noble-arm64-base.img, raspios-trixie-arm64-lite.img, appliance-run.qcow2 each exist twice). 4. 7.24G are deltas whose bases reference /Users/steve/... — a pre-crash machine/username. Dead. DELIVERABLE: checkouts/current/congruency/tools/vm_registry.py — standalone, stdlib + virsh + qemu-img. 1. SCAN (read-only) and register one artifact per VM image found, kind='forge-vm': * libvirt domains: `virsh -c qemu:///session list --all`, then dumpxml for each disk path. * the image lab: config/vm/*.{qcow2,img} * the blob stores: config/forge/large-blobs/<sha256>, config/forge/artifacts/blobs/<xx>/... Dedup by forge_sha — the SAME bytes in two places is ONE artifact with two locations, not two artifacts. That is the whole point; record every location it was seen at. 2. RECORD, per artifact: name, forge_sha, size, format (qcow2/raw/iso), and — this is the part whose absence caused every problem above — the RESOLVED STATE: * backing_file (from `qemu-img info`), and whether that base EXISTS (by path, and by sha if the base is itself registered) * which libvirt domain(s) reference it, and whether the xml's path resolves * status: LIVE (domain + disk resolve) | ORPHANED-DELTA (base missing) | STALE-PATH (file exists but the referrer points elsewhere) | COPY (byte-identical to another registered artifact) | UNREFERENCED (no domain, no chain) 3. REPORT the lab honestly: a table of every VM, its status, and for STALE-PATH the path it WANTS vs the path where the bytes ACTUALLY ARE. That report alone answers "which VM is which". 4. --json for machines; a readable table by default. 5. READ-ONLY. Do NOT rebase, do NOT edit any libvirt xml, do NOT move or delete a byte, do NOT write to the db except via artifact.record. This tool DESCRIBES the lab; it does not repair it. Repair is a separate, operator-authorized ticket. 6. --selftest against a THROWAWAY temp dir: synthesize a qcow2 with a present base (-> LIVE), one with a missing base (-> ORPHANED-DELTA), two byte-identical files (-> ONE artifact, two locations, COPY), and a file whose referrer points at a moved path (-> STALE-PATH). Skip cleanly with a NAMED reason if qemu-img is absent. No network, no live db, no writes outside the temp dir. ACCEPTANCE: --selftest green; a live read-only run registers every image in config/vm and both blob stores as kind='forge-vm' artifacts via artifact.record; `artifact.list` returns them (the table goes from 0 rows to populated); the report correctly marks all 4 domains STALE-PATH naming ~/bin/config/vm vs config/vm, marks ec281818 ORPHANED-DELTA-with-recoverable-base, marks the 3 verified duplicates COPY, and marks the /Users/steve/ deltas ORPHANED-DELTA (unrecoverable); nothing on disk is modified. 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