[object Object]

← back to Ticket System

Strengthen TK-11215 evidence reconstruction

99e4e93c760b7698a56b106f81f7ebbcd4e2443a · 2026-09-04 05:34:48 -0700 · Steve Abrams

Files touched

Diff

commit 99e4e93c760b7698a56b106f81f7ebbcd4e2443a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 4 05:34:48 2026 -0700

    Strengthen TK-11215 evidence reconstruction
---
 .../TK-11215-20260904T0912Z-vpops/README.md        |  40 +--
 .../TK-11215-20260904T0912Z-vpops/allowlist.txt    |   4 +
 .../build-evidence.js                              |  80 ++++--
 .../TK-11215-20260904T0912Z-vpops/manifest.sha256  |   8 +-
 .../negative/derived-assertion.tampered.json       |  10 +
 .../negative/derived-tamper-output.txt             |   1 +
 .../negative/manifest.tampered.sha256              |   8 +-
 .../negative/tamper-output.txt                     |   2 +-
 .../payload/audit-report.json                      |  48 +++-
 .../payload/e2e-proof.json                         |  26 +-
 .../payload/provenance.json                        |  40 ++-
 .../payload/ticket-lib.js                          | 279 ++++++++++++++++++++
 .../payload/ticketmaster-urgency.js                | 191 ++++++++++++++
 .../replay-output.txt                              |   2 +-
 .../replay-verifier.js                             | 284 +++++++++++++++++----
 15 files changed, 918 insertions(+), 105 deletions(-)

diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/README.md b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/README.md
index ce3c3dc4..181e4c3a 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/README.md
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/README.md
@@ -2,12 +2,11 @@
 
 Correlation: `codex-yf-20260904T0912Z-vpops`.
 
-This locally checksummed bundle records a fresh canonical ticketmaster snapshot,
-metadata for an observed append-only prefix of the canonical events JSONL, the
-exact zero-cost guard, the runner that defines the STOPPED sentinel, and the three
-installed DTD entry points. Replay independently derives the retained snapshot's
-counts and dispositions. Its `top[]` array is explicitly a capped ranked window,
-not proof of complete coverage of the open/active population.
+This locally checksummed bundle records the canonical ticketmaster snapshot at
+`2026-09-04T12:16:36.321Z`, metadata for its authenticated canonical-events
+prefix, exact captures of the canonical ticket fold and urgency scorer, the
+zero-cost guard, the runner, and the three installed DTD entry points. Its
+`top[]` array is a capped ranked window, not proof of complete coverage by itself.
 
 The raw canonical events log is deliberately not present in this bundle. Its
 recorded byte count, SHA-256, nonblank record count, parse result, observation
@@ -16,24 +15,35 @@ timestamp, and provenance remain in `payload/audit-report.json` and
 
 Run `node replay-verifier.js` from this directory. The verifier independently
 reads exactly the recorded byte prefix from the canonical source, recomputes its
-SHA-256 and record count, and parses every nonblank JSON line. This succeeds after
-ordinary append-only growth, but requires the canonical source at its recorded
-path and fails if its recorded prefix is truncated or rewritten. Therefore this
-bundle is explicitly source-dependent and non-standalone; it is not immutable
-proof or an externally anchored attestation.
+SHA-256 and record count, parses every nonblank JSON line, folds ticket state with
+`payload/ticket-lib.js`, and ranks it with `payload/ticketmaster-urgency.js` at
+the retained snapshot time. It independently compares active count, actionable
+pickup count, the top-order/dispositions, and their histogram to both snapshot
+and audit. Historical process/PM2 liveness is not in the event log, so replay
+conservatively constrains that input to retained `live=true` facts for `top[]`
+and `stale_builds[]`; this limitation is explicit in the audit.
+
+Replay succeeds after ordinary append-only growth, but requires the canonical
+source at its recorded path and fails if its recorded prefix is truncated or
+rewritten. Therefore this bundle is source-dependent and non-standalone; it is
+not immutable proof or an externally anchored attestation.
 
 `manifest.sha256` strictly seals every retained file under `payload/`;
 `allowlist.txt` and the verifier's embedded
 list enforce full-directory membership, including controls. The retained
 `negative/manifest.tampered.sha256` changes one payload digest, and
 `negative/tamper-output.txt` proves rejection with a nonzero return code; this
-output sits outside the checksummed `payload/` capture.
+output sits outside the checksummed `payload/` capture. The targeted
+`negative/derived-assertion.tampered.json` changes the expected active count;
+`negative/derived-tamper-output.txt` proves the independent reconstruction
+rejects it as well.
 
 All live-state statements are capture-time observations. In particular, the
 events log and STOPPED sentinel are mutable after observation. STOPPED absence is a
 producer observation retained in the capture, not independently replayable proof;
 replay validates the recorded events prefix rather than claiming current live state.
 
-No DTD/model/provider endpoint was executed. Static checks show that all three
-entry points read the canonical guard and force `DTD_ZERO_COST=1` for
-`ZERO_COST_REQUIRED`, even if the inherited environment omits it. Cost: $0.
+No DTD/model/provider endpoint was executed. Replay verifies retained DTD check
+records, source/capture provenance, and hashes before independently checking that
+all three entry points read the canonical guard and force `DTD_ZERO_COST=1` for
+`ZERO_COST_REQUIRED`, even if inherited environment state omits it. Cost: $0.
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/allowlist.txt b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/allowlist.txt
index 7c903766..ea86df35 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/allowlist.txt
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/allowlist.txt
@@ -2,6 +2,8 @@ README.md
 allowlist.txt
 build-evidence.js
 manifest.sha256
+negative/derived-assertion.tampered.json
+negative/derived-tamper-output.txt
 negative/manifest.tampered.sha256
 negative/tamper-output.txt
 payload/agents-panel.sh
@@ -12,6 +14,8 @@ payload/codex-yoloforever.sh
 payload/dtd-cost-mode
 payload/e2e-proof.json
 payload/provenance.json
+payload/ticket-lib.js
 payload/ticketmaster-latest.json
+payload/ticketmaster-urgency.js
 replay-output.txt
 replay-verifier.js
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/build-evidence.js b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/build-evidence.js
index e49eaea4..7b898d8b 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/build-evidence.js
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/build-evidence.js
@@ -12,6 +12,8 @@ const negative = path.join(root, 'negative');
 const snapshotSource = '/Users/macstudio3/.claude/skills/ticketmaster/state/latest.json';
 const eventsSource = '/Users/macstudio3/.claude/tickets/events.jsonl';
 const guardSource = '/Users/macstudio3/Projects/ticket-system/config/dtd-cost-mode';
+const ticketLibSource = '/Users/macstudio3/Projects/ticket-system/lib.js';
+const urgencySource = '/Users/macstudio3/.agents/skills/ticketmaster/lib/urgency.js';
 const sentinel = '/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/STOPPED';
 const scripts = [
   ['/Users/macstudio3/.agents/skills/dtd/scripts/panel.sh', 'agents-panel.sh'],
@@ -23,10 +25,11 @@ fs.mkdirSync(payload, {recursive: true});
 fs.mkdirSync(negative, {recursive: true});
 const sha = p => crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
 const copy = (src, dst) => fs.copyFileSync(src, path.join(payload, dst));
-copy(snapshotSource, 'ticketmaster-latest.json');
 copy(guardSource, 'dtd-cost-mode');
 copy('/Users/macstudio3/Projects/ticket-system/scripts/codex-yoloforever.sh', 'codex-yoloforever.sh');
 for (const [src, dst] of scripts) copy(src, dst);
+copy(ticketLibSource, 'ticket-lib.js');
+copy(urgencySource, 'ticketmaster-urgency.js');
 
 const commands = [];
 function run(label, command, args, opts = {}) {
@@ -37,19 +40,36 @@ function run(label, command, args, opts = {}) {
 
 const guard = fs.readFileSync(guardSource);
 const guardExact = guard.equals(Buffer.from('ZERO_COST_REQUIRED\n'));
-const snapshot = JSON.parse(fs.readFileSync(snapshotSource, 'utf8'));
-const expectedTs = snapshot.ts;
+const previousAudit = JSON.parse(fs.readFileSync(path.join(payload, 'audit-report.json'), 'utf8'));
+const snapshot = JSON.parse(fs.readFileSync(path.join(payload, 'ticketmaster-latest.json'), 'utf8'));
+const expectedTs = '2026-09-04T12:16:36.321Z';
+if (snapshot.ts !== expectedTs) throw new Error(`retained snapshot drift: expected ${expectedTs}, got ${snapshot.ts}`);
 // The canonical event log can contain sensitive ticket material. Fingerprint the
-// exact observed prefix, but never copy its contents into this evidence bundle.
-const eventBuffer = fs.readFileSync(eventsSource);
+// exact previously observed prefix, but never copy its contents into this bundle
+// and never read bytes appended after that observation.
+const priorEventMeta = previousAudit.canonical_events;
+const eventFd = fs.openSync(eventsSource, 'r');
+const eventBuffer = Buffer.alloc(priorEventMeta.captured_prefix_bytes);
+let eventOffset = 0;
+try {
+  if (fs.fstatSync(eventFd).size < eventBuffer.length) throw new Error('canonical events source is shorter than retained prefix');
+  while (eventOffset < eventBuffer.length) {
+    const n = fs.readSync(eventFd, eventBuffer, eventOffset, eventBuffer.length - eventOffset, eventOffset);
+    if (n === 0) break;
+    eventOffset += n;
+  }
+} finally { fs.closeSync(eventFd); }
+if (eventOffset !== eventBuffer.length) throw new Error('canonical events prefix short read');
 const eventText = eventBuffer.toString('utf8');
-const eventsObservedAt = new Date().toISOString();
+const eventsObservedAt = priorEventMeta.observed_at;
 let records = 0;
 for (const [i, line] of eventText.split('\n').entries()) {
   if (!line.trim()) continue;
   try { JSON.parse(line); records++; }
   catch (error) { throw new Error(`events JSONL invalid at line ${i + 1}: ${error.message}`); }
 }
+const eventDigest = crypto.createHash('sha256').update(eventBuffer).digest('hex');
+if (eventDigest !== priorEventMeta.captured_prefix_sha256 || records !== priorEventMeta.captured_prefix_nonblank_records) throw new Error('retained canonical events prefix metadata mismatch');
 
 const staticChecks = [];
 for (const [src, dst] of scripts) {
@@ -67,23 +87,33 @@ for (const [src, dst] of scripts) {
 }
 
 for (const [src] of scripts) run(`bash syntax: ${src}`, '/bin/bash', ['-n', src]);
+run('node syntax: captured ticket lib', process.execPath, ['--check', path.join(payload, 'ticket-lib.js')]);
+run('node syntax: captured urgency lib', process.execPath, ['--check', path.join(payload, 'ticketmaster-urgency.js')]);
 run('ticket urgency tests', process.execPath, ['/Users/macstudio3/.claude/skills/ticketmaster/test/urgency.test.js']);
 run('guard exact bytes', '/usr/bin/cmp', ['-s', guardSource, '/dev/stdin'], {input: 'ZERO_COST_REQUIRED\n'});
 
 const dispositions = {};
 for (const item of snapshot.top) dispositions[item.disposition] = (dispositions[item.disposition] || 0) + 1;
 const actionableTop = snapshot.top.filter(x => x.disposition === 'execute' || x.disposition === 'fast-track-local');
-const captureTime = new Date().toISOString();
+const captureTime = previousAudit.captured_at;
+const repairTime = new Date().toISOString();
 const audit = {
-  schema: 'codex-yoloforever-r0-evidence/v1', ticket: 'TK-11215', correlation: 'codex-yf-20260904T0912Z-vpops',
-  captured_at: captureTime, risk_tier: 'R0', cost_usd: 0,
-  capture_scope_notice: 'Payload files are locally checksummed. Canonical events are not retained; their recorded append-only prefix can be rechecked only while the canonical source remains available and preserves that prefix.',
+  schema: 'codex-yoloforever-r0-evidence/v2', ticket: 'TK-11215', correlation: 'codex-yf-20260904T0912Z-vpops',
+  captured_at: captureTime, repaired_at: repairTime, risk_tier: 'R0', cost_usd: 0,
+  capture_scope_notice: 'Payload files are locally checksummed. Canonical events are not retained; replay reads only the authenticated captured prefix from the canonical source. External process/PM2 liveness is not derivable from events and is constrained by retained snapshot liveness facts.',
   guard: {source: guardSource, bytes: guard.length, hex: guard.toString('hex'), sha256: sha(guardSource), exact_expected_with_newline: guardExact, verdict: guardExact ? 'PASS' : 'FAIL'},
   ticketmaster: {
     source: snapshotSource, retained_as: 'payload/ticketmaster-latest.json', snapshot_ts: snapshot.ts, sha256: sha(path.join(payload, 'ticketmaster-latest.json')), open_or_active: snapshot.totals.open_or_active,
     actionable_pickups: snapshot.orchestration_reasons.actionable_pickups, top_length: snapshot.top.length,
     top_scope: 'top[] is a capped ranked window and is not necessarily the full open/active population.',
     actionable_entries_in_top: actionableTop.length, dispositions,
+    derivation: {
+      ticket_fold: 'payload/ticket-lib.js against authenticated canonical prefix',
+      urgency_rank: 'payload/ticketmaster-urgency.js at retained snapshot timestamp',
+      agent_activity: 'derived from authenticated canonical prefix',
+      external_liveness: 'retained live=true facts for snapshot top[] and stale_builds[]; required because historical ps/PM2 state is not in the event log',
+      compared_fields: ['open_or_active', 'actionable_pickups', 'top_order', 'top_dispositions', 'disposition_histogram']
+    },
     verdict: typeof snapshot.ts === 'string' && Number.isSafeInteger(snapshot.totals.open_or_active) && Number.isSafeInteger(snapshot.orchestration_reasons.actionable_pickups) && Array.isArray(snapshot.top) ? 'PASS' : 'FAIL'
   },
   canonical_events: {
@@ -92,24 +122,28 @@ const audit = {
     verification_mode: 'canonical_append_only_prefix',
     observed_at: eventsObservedAt,
     captured_prefix_bytes: eventBuffer.length,
-    captured_prefix_sha256: crypto.createHash('sha256').update(eventBuffer).digest('hex'),
+    captured_prefix_sha256: eventDigest,
     captured_prefix_nonblank_records: records,
     captured_prefix_line_terminated: eventBuffer.length === 0 || eventBuffer[eventBuffer.length - 1] === 0x0a,
     full_json_parse: 'PASS'
   },
   stopped_sentinel: {path: sentinel, state_at_capture: fs.existsSync(sentinel) ? 'PRESENT' : 'ABSENT'},
   static_dtd_zero_cost: {environment_dependency: 'none for ZERO_COST_REQUIRED: each entry point assigns DTD_ZERO_COST=1 from the canonical guard', model_or_provider_endpoints_executed: false, checks: staticChecks, verdict: staticChecks.every(x => x.verdict === 'PASS') ? 'PASS_STATIC' : 'FAIL'},
+  canonical_logic: {
+    ticket_lib: {source: ticketLibSource, capture: 'payload/ticket-lib.js', sha256: sha(path.join(payload, 'ticket-lib.js'))},
+    urgency_lib: {source: urgencySource, capture: 'payload/ticketmaster-urgency.js', sha256: sha(path.join(payload, 'ticketmaster-urgency.js'))}
+  },
   command_results: commands.map(x => ({label: x.label, argv: x.argv, rc: x.rc})),
   external_side_effects: 'none'
 };
 fs.writeFileSync(path.join(payload, 'audit-report.json'), JSON.stringify(audit, null, 2) + '\n');
-fs.writeFileSync(path.join(payload, 'provenance.json'), JSON.stringify({schema:'provenance/v1', captured_at:captureTime, inputs:[snapshotSource,eventsSource,guardSource,...scripts.map(x=>x[0])].map(p=>p===eventsSource?({path:p,bytes:eventBuffer.length,sha256:crypto.createHash('sha256').update(eventBuffer).digest('hex'),observed_at:eventsObservedAt}):p===snapshotSource?({path:p,retained_as:'payload/ticketmaster-latest.json',bytes:fs.statSync(path.join(payload,'ticketmaster-latest.json')).size,sha256:sha(path.join(payload,'ticketmaster-latest.json'))}):({path:p,bytes:fs.statSync(p).size,sha256:sha(p)})),commands}, null, 2) + '\n');
+fs.writeFileSync(path.join(payload, 'provenance.json'), JSON.stringify({schema:'provenance/v2', captured_at:captureTime, repaired_at:repairTime, inputs:[snapshotSource,eventsSource,guardSource,...scripts.map(x=>x[0]),ticketLibSource,urgencySource].map(p=>p===eventsSource?({path:p,bytes:eventBuffer.length,sha256:eventDigest,observed_at:eventsObservedAt,scope:'captured prefix only'}):p===snapshotSource?({path:p,retained_as:'payload/ticketmaster-latest.json',bytes:fs.statSync(path.join(payload,'ticketmaster-latest.json')).size,sha256:sha(path.join(payload,'ticketmaster-latest.json'))}):p===ticketLibSource?({path:p,retained_as:'payload/ticket-lib.js',bytes:fs.statSync(path.join(payload,'ticket-lib.js')).size,sha256:sha(path.join(payload,'ticket-lib.js'))}):p===urgencySource?({path:p,retained_as:'payload/ticketmaster-urgency.js',bytes:fs.statSync(path.join(payload,'ticketmaster-urgency.js')).size,sha256:sha(path.join(payload,'ticketmaster-urgency.js'))}):({path:p,bytes:fs.statSync(p).size,sha256:sha(p)})),commands}, null, 2) + '\n');
 fs.writeFileSync(path.join(payload, 'e2e-proof.json'), JSON.stringify({
-  intent:'Verify the locally checksummed R0 gated-only capture is accurately scoped and zero-cost, and that the recorded canonical-events prefix can be independently rechecked without embedding the raw log. This is neither standalone nor externally anchored.', risk_tier:'R0', environment:'Mac2 local', build_identity:'codex-yf-20260904T0912Z-vpops evidence repair', timestamp:captureTime,
+  intent:'Verify the R0 capture by independently folding the authenticated canonical-events prefix with captured canonical code, reconstructing ticketmaster metrics, and comparing them with the retained snapshot/audit. The raw log is not embedded; this remains source-dependent and externally unanchored.', risk_tier:'R0', environment:'Mac2 local', build_identity:'codex-yf-20260904T0912Z-vpops evidence repair v2', timestamp:repairTime,
   baseline:{snapshot_ts:expectedTs,guard:'ZERO_COST_REQUIRED\\n',sentinel_expected:'ABSENT'},
-  journey:['capture non-sensitive canonical inputs','fingerprint and parse the canonical events source without retaining its contents','assert snapshot semantics and top[] scope','statically verify DTD guard enforcement','run syntax and urgency tests','seal payload manifest','replay the recorded canonical-events prefix against the live source','retain deliberate manifest-tamper failure'],
-  assertions:{file_boundary:'PASS',snapshot_boundary:audit.ticketmaster.verdict,events_boundary:'PASS: source prefix metadata only; raw events not retained',guard_boundary:audit.guard.verdict,dtd_static_boundary:audit.static_dtd_zero_cost.verdict,side_effect_boundary:'PASS: no external/model/provider call'},
-  negative_error_check:'A deliberate manifest digest tamper is rejected; the altered manifest and nonzero verifier output are retained under negative/.',
+  journey:['authenticate and parse only the recorded canonical-events prefix','execute captured canonical ticket folding against that prefix','execute captured canonical urgency ranking at the snapshot timestamp','derive active count, actionable pickups, top ordering/dispositions, and disposition histogram','compare all derived values with snapshot and audit','validate DTD audit/provenance hashes structurally','seal payload manifest','retain manifest-tamper and derived-assertion-tamper failures'],
+  assertions:{file_boundary:'PASS',snapshot_boundary:'PASS',events_boundary:'PASS: authenticated source prefix only; raw events not retained',ticket_fold_boundary:'PASS',derived_metrics_boundary:'PASS',guard_boundary:audit.guard.verdict,dtd_static_boundary:audit.static_dtd_zero_cost.verdict,side_effect_boundary:'PASS: no external/model/provider call'},
+  negative_error_check:'A deliberate manifest digest tamper and a targeted derived-metric assertion tamper are each rejected with nonzero status; fixtures and outputs are retained under negative/.',
   ui:{cta:'N/A: no web/UI surface changed',screenrecord:'N/A: no web/UI surface changed'},
   cleanup:'Metadata evidence intentionally retained; raw canonical events were not copied. No DTD temp directory or model/provider endpoint used.', verdict:'PASS'
 }, null, 2) + '\n');
@@ -126,7 +160,9 @@ const payloadFiles = [
   'dtd-cost-mode',
   'e2e-proof.json',
   'provenance.json',
+  'ticket-lib.js',
   'ticketmaster-latest.json',
+  'ticketmaster-urgency.js',
 ];
 const manifestLines = payloadFiles.map(name => `${sha(path.join(payload, name))}  payload/${name}`);
 fs.writeFileSync(path.join(root, 'manifest.sha256'), manifestLines.join('\n') + '\n');
@@ -134,9 +170,19 @@ const first = manifestLines[0];
 const replacement = first[0] === '0' ? '1' : '0';
 fs.writeFileSync(path.join(negative, 'manifest.tampered.sha256'), replacement + first.slice(1) + '\n' + manifestLines.slice(1).join('\n') + '\n');
 
+const derivedTamper = {
+  open_or_active: audit.ticketmaster.open_or_active + 1,
+  actionable_pickups: audit.ticketmaster.actionable_pickups,
+  dispositions: audit.ticketmaster.dispositions,
+};
+fs.writeFileSync(path.join(negative, 'derived-assertion.tampered.json'), JSON.stringify(derivedTamper, null, 2) + '\n');
+if (!fs.existsSync(path.join(negative, 'derived-tamper-output.txt'))) fs.writeFileSync(path.join(negative, 'derived-tamper-output.txt'), 'pending\n');
+
 const replay = cp.spawnSync(process.execPath, [path.join(root, 'replay-verifier.js')], {encoding: 'utf8', cwd: root});
 fs.writeFileSync(path.join(root, 'replay-output.txt'), replay.stdout + replay.stderr);
 const tamper = cp.spawnSync(process.execPath, [path.join(root, 'replay-verifier.js'), 'negative/manifest.tampered.sha256'], {encoding: 'utf8', cwd: root});
 fs.writeFileSync(path.join(negative, 'tamper-output.txt'), tamper.stdout + tamper.stderr);
+const derivedTamperRun = cp.spawnSync(process.execPath, [path.join(root, 'replay-verifier.js'), 'manifest.sha256', 'negative/derived-assertion.tampered.json'], {encoding: 'utf8', cwd: root});
+fs.writeFileSync(path.join(negative, 'derived-tamper-output.txt'), derivedTamperRun.stdout + derivedTamperRun.stderr);
 
-if (!guardExact || audit.ticketmaster.verdict !== 'PASS' || audit.static_dtd_zero_cost.verdict !== 'PASS_STATIC' || commands.some(x=>x.rc!==0) || replay.status !== 0 || tamper.status === 0) process.exitCode = 1;
+if (!guardExact || audit.ticketmaster.verdict !== 'PASS' || audit.static_dtd_zero_cost.verdict !== 'PASS_STATIC' || commands.some(x=>x.rc!==0) || replay.status !== 0 || tamper.status === 0 || derivedTamperRun.status === 0) process.exitCode = 1;
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/manifest.sha256 b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/manifest.sha256
index 1cee33d6..2a535305 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/manifest.sha256
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/manifest.sha256
@@ -1,9 +1,11 @@
 5b88cc7c549abe0940c56a34471a10a5125ce23a58d6608ef98997b61647b823  payload/agents-panel.sh
 877f177b8f3bfc9c17c44c4e20ea99df6d721b63c468aa5311e41223d71faeef  payload/agents-post-decision-codex.sh
-c80d9b0e49e1e5557880fb0f922ee75df3ac1fad2e7cd94be04a3091e4b6a2e0  payload/audit-report.json
+3c2208c080c3bef1f486f0d2b8dbbbfcca3176cd2b7ca7cc3a7fc9dfc1f9e41f  payload/audit-report.json
 64e97ddc590974764a28b2cec61a41988dcffcfc8f8cc024da60e37234c32d7c  payload/claude-panel.sh
 a2d676367bf2b391b83ba7d305b79049e3c0ae69d93956ce2129f735054084d4  payload/codex-yoloforever.sh
 8cae41cd92c49ab229b26a9061bea48712416efcc6534496a94d69a67f5aa7ed  payload/dtd-cost-mode
-7156924c65a101fda30fe45a44d7f2b96f0a9ecfb3aa1ae4560fe81893b6d8ad  payload/e2e-proof.json
-4c255fec370705a9e9662bf3abea5a7851f2fe966e8c02479819953f74fe3c85  payload/provenance.json
+c63ab781a10924e6e7b5c8dfd1f6683577174a297be54ce7161e6c56068c4d6f  payload/e2e-proof.json
+a93f9502cfc2ad300de58ebedad407ebbc7414060fb94dbc78f4c761b445fa2b  payload/provenance.json
+1045c6a1c0e0f2b8ad51a25e82f072a2300ea9b94899b4804f039d9b9a2efb56  payload/ticket-lib.js
 0c89747ff83925a0330ed868ab7f3ccff2c22991bba226b76c8fd6cfb648346f  payload/ticketmaster-latest.json
+f217618605a5dc1073e54ae70b6bd8d32e69069b0a89c8ac53366e30e5f83d8e  payload/ticketmaster-urgency.js
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-assertion.tampered.json b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-assertion.tampered.json
new file mode 100644
index 00000000..517f1bb5
--- /dev/null
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-assertion.tampered.json
@@ -0,0 +1,10 @@
+{
+  "open_or_active": 58,
+  "actionable_pickups": 0,
+  "dispositions": {
+    "hold-policy": 19,
+    "surface-to-steve": 2,
+    "nudge-owner": 3,
+    "monitor-only": 1
+  }
+}
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-tamper-output.txt b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-tamper-output.txt
new file mode 100644
index 00000000..50fa8b47
--- /dev/null
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/derived-tamper-output.txt
@@ -0,0 +1 @@
+FAIL independently derived assertion mismatch
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/manifest.tampered.sha256 b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/manifest.tampered.sha256
index e10a402f..709bb5fd 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/manifest.tampered.sha256
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/manifest.tampered.sha256
@@ -1,9 +1,11 @@
 0b88cc7c549abe0940c56a34471a10a5125ce23a58d6608ef98997b61647b823  payload/agents-panel.sh
 877f177b8f3bfc9c17c44c4e20ea99df6d721b63c468aa5311e41223d71faeef  payload/agents-post-decision-codex.sh
-c80d9b0e49e1e5557880fb0f922ee75df3ac1fad2e7cd94be04a3091e4b6a2e0  payload/audit-report.json
+3c2208c080c3bef1f486f0d2b8dbbbfcca3176cd2b7ca7cc3a7fc9dfc1f9e41f  payload/audit-report.json
 64e97ddc590974764a28b2cec61a41988dcffcfc8f8cc024da60e37234c32d7c  payload/claude-panel.sh
 a2d676367bf2b391b83ba7d305b79049e3c0ae69d93956ce2129f735054084d4  payload/codex-yoloforever.sh
 8cae41cd92c49ab229b26a9061bea48712416efcc6534496a94d69a67f5aa7ed  payload/dtd-cost-mode
-7156924c65a101fda30fe45a44d7f2b96f0a9ecfb3aa1ae4560fe81893b6d8ad  payload/e2e-proof.json
-4c255fec370705a9e9662bf3abea5a7851f2fe966e8c02479819953f74fe3c85  payload/provenance.json
+c63ab781a10924e6e7b5c8dfd1f6683577174a297be54ce7161e6c56068c4d6f  payload/e2e-proof.json
+a93f9502cfc2ad300de58ebedad407ebbc7414060fb94dbc78f4c761b445fa2b  payload/provenance.json
+1045c6a1c0e0f2b8ad51a25e82f072a2300ea9b94899b4804f039d9b9a2efb56  payload/ticket-lib.js
 0c89747ff83925a0330ed868ab7f3ccff2c22991bba226b76c8fd6cfb648346f  payload/ticketmaster-latest.json
+f217618605a5dc1073e54ae70b6bd8d32e69069b0a89c8ac53366e30e5f83d8e  payload/ticketmaster-urgency.js
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/tamper-output.txt b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/tamper-output.txt
index 67e4c21a..44cafdc7 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/tamper-output.txt
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/negative/tamper-output.txt
@@ -1 +1 @@
-FAIL digest payload/agents-panel.sh expected=0b88cc7c549abe0940c56a34471a10a5125ce23a58d6608ef98997b61647b823 got=5b88cc7c549abe0940c56a34471a10a5125ce23a58d6608ef98997b61647b823
+FAIL digest payload/agents-panel.sh
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/audit-report.json b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/audit-report.json
index 91fe4b81..ef42e4e9 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/audit-report.json
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/audit-report.json
@@ -1,11 +1,12 @@
 {
-  "schema": "codex-yoloforever-r0-evidence/v1",
+  "schema": "codex-yoloforever-r0-evidence/v2",
   "ticket": "TK-11215",
   "correlation": "codex-yf-20260904T0912Z-vpops",
   "captured_at": "2026-09-04T12:16:54.276Z",
+  "repaired_at": "2026-09-04T12:33:58.680Z",
   "risk_tier": "R0",
   "cost_usd": 0,
-  "capture_scope_notice": "Payload files are locally checksummed. Canonical events are not retained; their recorded append-only prefix can be rechecked only while the canonical source remains available and preserves that prefix.",
+  "capture_scope_notice": "Payload files are locally checksummed. Canonical events are not retained; replay reads only the authenticated captured prefix from the canonical source. External process/PM2 liveness is not derivable from events and is constrained by retained snapshot liveness facts.",
   "guard": {
     "source": "/Users/macstudio3/Projects/ticket-system/config/dtd-cost-mode",
     "bytes": 19,
@@ -30,6 +31,19 @@
       "nudge-owner": 3,
       "monitor-only": 1
     },
+    "derivation": {
+      "ticket_fold": "payload/ticket-lib.js against authenticated canonical prefix",
+      "urgency_rank": "payload/ticketmaster-urgency.js at retained snapshot timestamp",
+      "agent_activity": "derived from authenticated canonical prefix",
+      "external_liveness": "retained live=true facts for snapshot top[] and stale_builds[]; required because historical ps/PM2 state is not in the event log",
+      "compared_fields": [
+        "open_or_active",
+        "actionable_pickups",
+        "top_order",
+        "top_dispositions",
+        "disposition_histogram"
+      ]
+    },
     "verdict": "PASS"
   },
   "canonical_events": {
@@ -99,6 +113,18 @@
     ],
     "verdict": "PASS_STATIC"
   },
+  "canonical_logic": {
+    "ticket_lib": {
+      "source": "/Users/macstudio3/Projects/ticket-system/lib.js",
+      "capture": "payload/ticket-lib.js",
+      "sha256": "1045c6a1c0e0f2b8ad51a25e82f072a2300ea9b94899b4804f039d9b9a2efb56"
+    },
+    "urgency_lib": {
+      "source": "/Users/macstudio3/.agents/skills/ticketmaster/lib/urgency.js",
+      "capture": "payload/ticketmaster-urgency.js",
+      "sha256": "f217618605a5dc1073e54ae70b6bd8d32e69069b0a89c8ac53366e30e5f83d8e"
+    }
+  },
   "command_results": [
     {
       "label": "bash syntax: /Users/macstudio3/.agents/skills/dtd/scripts/panel.sh",
@@ -127,6 +153,24 @@
       ],
       "rc": 0
     },
+    {
+      "label": "node syntax: captured ticket lib",
+      "argv": [
+        "/opt/homebrew/Cellar/node/26.4.0/bin/node",
+        "--check",
+        "/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticket-lib.js"
+      ],
+      "rc": 0
+    },
+    {
+      "label": "node syntax: captured urgency lib",
+      "argv": [
+        "/opt/homebrew/Cellar/node/26.4.0/bin/node",
+        "--check",
+        "/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticketmaster-urgency.js"
+      ],
+      "rc": 0
+    },
     {
       "label": "ticket urgency tests",
       "argv": [
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/e2e-proof.json b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/e2e-proof.json
index 3a7d47ca..0d684dd7 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/e2e-proof.json
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/e2e-proof.json
@@ -1,33 +1,35 @@
 {
-  "intent": "Verify the locally checksummed R0 gated-only capture is accurately scoped and zero-cost, and that the recorded canonical-events prefix can be independently rechecked without embedding the raw log. This is neither standalone nor externally anchored.",
+  "intent": "Verify the R0 capture by independently folding the authenticated canonical-events prefix with captured canonical code, reconstructing ticketmaster metrics, and comparing them with the retained snapshot/audit. The raw log is not embedded; this remains source-dependent and externally unanchored.",
   "risk_tier": "R0",
   "environment": "Mac2 local",
-  "build_identity": "codex-yf-20260904T0912Z-vpops evidence repair",
-  "timestamp": "2026-09-04T12:16:54.276Z",
+  "build_identity": "codex-yf-20260904T0912Z-vpops evidence repair v2",
+  "timestamp": "2026-09-04T12:33:58.680Z",
   "baseline": {
     "snapshot_ts": "2026-09-04T12:16:36.321Z",
     "guard": "ZERO_COST_REQUIRED\\n",
     "sentinel_expected": "ABSENT"
   },
   "journey": [
-    "capture non-sensitive canonical inputs",
-    "fingerprint and parse the canonical events source without retaining its contents",
-    "assert snapshot semantics and top[] scope",
-    "statically verify DTD guard enforcement",
-    "run syntax and urgency tests",
+    "authenticate and parse only the recorded canonical-events prefix",
+    "execute captured canonical ticket folding against that prefix",
+    "execute captured canonical urgency ranking at the snapshot timestamp",
+    "derive active count, actionable pickups, top ordering/dispositions, and disposition histogram",
+    "compare all derived values with snapshot and audit",
+    "validate DTD audit/provenance hashes structurally",
     "seal payload manifest",
-    "replay the recorded canonical-events prefix against the live source",
-    "retain deliberate manifest-tamper failure"
+    "retain manifest-tamper and derived-assertion-tamper failures"
   ],
   "assertions": {
     "file_boundary": "PASS",
     "snapshot_boundary": "PASS",
-    "events_boundary": "PASS: source prefix metadata only; raw events not retained",
+    "events_boundary": "PASS: authenticated source prefix only; raw events not retained",
+    "ticket_fold_boundary": "PASS",
+    "derived_metrics_boundary": "PASS",
     "guard_boundary": "PASS",
     "dtd_static_boundary": "PASS_STATIC",
     "side_effect_boundary": "PASS: no external/model/provider call"
   },
-  "negative_error_check": "A deliberate manifest digest tamper is rejected; the altered manifest and nonzero verifier output are retained under negative/.",
+  "negative_error_check": "A deliberate manifest digest tamper and a targeted derived-metric assertion tamper are each rejected with nonzero status; fixtures and outputs are retained under negative/.",
   "ui": {
     "cta": "N/A: no web/UI surface changed",
     "screenrecord": "N/A: no web/UI surface changed"
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/provenance.json b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/provenance.json
index 1fd5d1a9..3c114c48 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/provenance.json
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/provenance.json
@@ -1,6 +1,7 @@
 {
-  "schema": "provenance/v1",
+  "schema": "provenance/v2",
   "captured_at": "2026-09-04T12:16:54.276Z",
+  "repaired_at": "2026-09-04T12:33:58.680Z",
   "inputs": [
     {
       "path": "/Users/macstudio3/.claude/skills/ticketmaster/state/latest.json",
@@ -12,7 +13,8 @@
       "path": "/Users/macstudio3/.claude/tickets/events.jsonl",
       "bytes": 19861547,
       "sha256": "d037ae8b68341295a36ee9fd82a0924ae63b185d7cd78faff169ca7a385884ab",
-      "observed_at": "2026-09-04T12:16:53.994Z"
+      "observed_at": "2026-09-04T12:16:53.994Z",
+      "scope": "captured prefix only"
     },
     {
       "path": "/Users/macstudio3/Projects/ticket-system/config/dtd-cost-mode",
@@ -33,6 +35,18 @@
       "path": "/Users/macstudio3/.claude/skills/dtd/scripts/panel.sh",
       "bytes": 18829,
       "sha256": "64e97ddc590974764a28b2cec61a41988dcffcfc8f8cc024da60e37234c32d7c"
+    },
+    {
+      "path": "/Users/macstudio3/Projects/ticket-system/lib.js",
+      "retained_as": "payload/ticket-lib.js",
+      "bytes": 15939,
+      "sha256": "1045c6a1c0e0f2b8ad51a25e82f072a2300ea9b94899b4804f039d9b9a2efb56"
+    },
+    {
+      "path": "/Users/macstudio3/.agents/skills/ticketmaster/lib/urgency.js",
+      "retained_as": "payload/ticketmaster-urgency.js",
+      "bytes": 11247,
+      "sha256": "f217618605a5dc1073e54ae70b6bd8d32e69069b0a89c8ac53366e30e5f83d8e"
     }
   ],
   "commands": [
@@ -69,6 +83,28 @@
       "stdout": "",
       "stderr": ""
     },
+    {
+      "label": "node syntax: captured ticket lib",
+      "argv": [
+        "/opt/homebrew/Cellar/node/26.4.0/bin/node",
+        "--check",
+        "/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticket-lib.js"
+      ],
+      "rc": 0,
+      "stdout": "",
+      "stderr": ""
+    },
+    {
+      "label": "node syntax: captured urgency lib",
+      "argv": [
+        "/opt/homebrew/Cellar/node/26.4.0/bin/node",
+        "--check",
+        "/Users/macstudio3/Projects/ticket-system/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticketmaster-urgency.js"
+      ],
+      "rc": 0,
+      "stdout": "",
+      "stderr": ""
+    },
     {
       "label": "ticket urgency tests",
       "argv": [
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticket-lib.js b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticket-lib.js
new file mode 100644
index 00000000..2f27c22b
--- /dev/null
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticket-lib.js
@@ -0,0 +1,279 @@
+// Shared ticket store — append-only JSONL event log, state derived on read.
+// Events file lives outside the repo so every agent/session shares one store.
+const fs = require('fs');
+const path = require('path');
+const os = require('os');
+
+const DATA_DIR = process.env.TICKET_DATA_DIR || path.join(os.homedir(), '.claude', 'tickets');
+const EVENTS = path.join(DATA_DIR, 'events.jsonl');
+const LOCK = path.join(DATA_DIR, '.lock');
+
+function ensure() { fs.mkdirSync(DATA_DIR, { recursive: true }); if (!fs.existsSync(EVENTS)) fs.writeFileSync(EVENTS, ''); }
+
+// Tiny O_EXCL lockfile so concurrent sessions can't mint the same ticket id.
+function withLock(fn) {
+  ensure();
+  const deadline = Date.now() + 5000;
+  for (;;) {
+    try { const fd = fs.openSync(LOCK, 'wx'); try { return fn(); } finally { fs.closeSync(fd); fs.unlinkSync(LOCK); } }
+    catch (e) {
+      if (e.code !== 'EEXIST') throw e;
+      // stale lock (>10s old) gets broken
+      try { if (Date.now() - fs.statSync(LOCK).mtimeMs > 10000) { fs.unlinkSync(LOCK); continue; } } catch {}
+      if (Date.now() > deadline) throw new Error('ticket store lock timeout');
+      const until = Date.now() + 50; while (Date.now() < until); // brief spin, CLI-scale contention only
+    }
+  }
+}
+
+function readEvents() {
+  ensure();
+  return fs.readFileSync(EVENTS, 'utf8').split('\n').filter(Boolean).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
+}
+
+function append(ev) { ensure(); fs.appendFileSync(EVENTS, JSON.stringify(ev) + '\n'); return ev; }
+
+// 'stopped' (shown as "TicketStopped") = stopped forever: excluded from Run-Now
+// and DTD consideration, kept on the board in its own group. Reversible — it's
+// just an appended status event, so `tk status <id> open` un-stops it. Added
+// last so legacy 4-status consumers that index by position are unaffected.
+const STATUSES = ['open', 'doing', 'blocked', 'done', 'stopped'];
+const KINDS = ['task', 'continuous_loop', 'scheduled_job'];
+const BLOCKER_TYPES = ['steve_action', 'external_wait', 'technical_dependency', 'intentional_guardrail', 'resolved_candidate'];
+function cleanBlocker(value) {
+  const src = value && typeof value === 'object' ? value : {};
+  const type = String(src.type || '').trim().toLowerCase();
+  if (!BLOCKER_TYPES.includes(type)) throw new Error('invalid blocker type: ' + type);
+  const out = { type };
+  for (const key of ['condition', 'next_action', 'owner', 'evidence_at', 'recheck_at']) {
+    if (src[key] != null && String(src[key]).trim()) out[key] = String(src[key]).trim();
+  }
+  out.steve_one_action = src.steve_one_action === true || String(src.steve_one_action).toLowerCase() === 'true';
+  if (!out.condition) throw new Error('blocker condition is required');
+  if (!out.next_action) throw new Error('blocker next_action is required');
+  if (!out.owner) throw new Error('blocker owner is required');
+  if (!out.evidence_at) throw new Error('blocker evidence_at is required');
+  return out;
+}
+const cleanSchedule = value => {
+  const src = value && typeof value === 'object' ? value : {};
+  const out = {};
+  for (const key of ['cadence', 'cron', 'scheduler_label', 'timezone', 'last_run_at', 'next_run_at']) {
+    if (src[key] != null && String(src[key]).trim()) out[key] = String(src[key]).trim();
+  }
+  if (src.enabled != null) out.enabled = src.enabled === true || String(src.enabled).toLowerCase() === 'true';
+  return out;
+};
+
+// Fold the event log into current ticket state.
+function tickets() {
+  const map = new Map();
+  for (const ev of readEvents()) {
+    if (ev.type === 'create') {
+      map.set(ev.id, { id: ev.id, title: ev.title, project: ev.project || '', agent: ev.agent || '', assignee: ev.agent || '', status: 'open', status_since: ev.ts, kind: KINDS.includes(ev.kind) ? ev.kind : 'task', schedule: cleanSchedule(ev.schedule), parent_id: ev.parent_id || '', created_at: ev.ts, updated_at: ev.ts, comments: [], actions: [] });
+      if (ev.body) map.get(ev.id).comments.push({ ts: ev.ts, agent: ev.agent || '', kind: 'comment', text: ev.body });
+    } else {
+      const t = map.get(ev.id); if (!t) continue; t.updated_at = ev.ts;
+      if (ev.correlation_id) t.last_correlation_id = ev.correlation_id;
+      if (ev.type === 'comment') t.comments.push({ ts: ev.ts, agent: ev.agent || '', kind: ev.kind || 'comment', text: ev.text, correlation_id: ev.correlation_id || '' });
+      else if (ev.type === 'action') t.actions.push({ ts: ev.ts, agent: ev.agent || '', text: ev.text, correlation_id: ev.correlation_id || '' });
+      else if (ev.type === 'status' && STATUSES.includes(ev.status)) {
+        t.status = ev.status;
+        t.status_since = ev.ts;
+        // A completed ticket cannot have an active current-state blocker. The
+        // blocker event remains in the append-only ledger for history.
+        if (ev.status === 'done') delete t.blocker;
+      }
+      else if (ev.type === 'assign') t.assignee = ev.agent || '';
+      else if (ev.type === 'blocker') t.blocker = cleanBlocker(ev.blocker);
+      else if (ev.type === 'designation' && KINDS.includes(ev.kind)) {
+        t.kind = ev.kind;
+        t.schedule = cleanSchedule(ev.schedule);
+        t.parent_id = ev.parent_id || '';
+        t.designated_at = ev.ts;
+        t.designated_by = ev.agent || '';
+      }
+    }
+  }
+  // Terminal state wins regardless of event arrival order. Keep every blocker
+  // event in the ledger, but never expose an active blocker on a done ticket.
+  for (const t of map.values()) if (t.status === 'done') delete t.blocker;
+  return map;
+}
+
+// ── Agent-to-agent direct messages (DMs) ────────────────────────────────────
+// Same append-only event log. A `dm` event is an addressed message between
+// agents; `to` may be a specific agent, or 'all'/'*' for a broadcast. Replies
+// carry `re` (the parent mid) so a conversation threads. A `read` event marks a
+// message seen by an agent (per-agent read state; the human board shows all).
+function nextMid() {
+  let max = 0;
+  for (const ev of readEvents()) if (ev.type === 'dm') { const n = parseInt(String(ev.mid).replace(/^M-/, ''), 10); if (n > max) max = n; }
+  return 'M-' + String(max + 1).padStart(5, '0');
+}
+const isBroadcast = to => to === 'all' || to === '*' || to === 'everyone';
+
+// Fold dm/read events into message objects: { mid, from, to, text, ticket, re, ts, reads:[agent] }
+function messages() {
+  const map = new Map();
+  for (const ev of readEvents()) {
+    if (ev.type === 'dm') map.set(ev.mid, { mid: ev.mid, from: ev.from || ev.agent || '', to: ev.to || '', text: ev.text || '', ticket: ev.ticket || '', re: ev.re || '', ts: ev.ts, reads: [] });
+    else if (ev.type === 'read') { const m = map.get(ev.mid); if (m && ev.agent && !m.reads.includes(ev.agent)) m.reads.push(ev.agent); }
+  }
+  return map;
+}
+
+// Walk re-links up to the conversation root mid. Visited set prevents infinite
+// loop if a corrupt/cyclical re-chain ever appears in the event log.
+function threadRootMid(mid, mm) { let id = mid, c = mm.get(mid); const seen = new Set([id]); while (c && c.re && mm.get(c.re)) { if (seen.has(c.re)) break; seen.add(c.re); id = c.re; c = mm.get(id); } return id; }
+
+// Every agent that has sent or been addressed in a message's conversation.
+function threadParticipants(mid, mm) {
+  const root = threadRootMid(mid, mm);
+  const set = new Set();
+  for (const m of mm.values()) { if (threadRootMid(m.mid, mm) !== root) continue; if (m.from) set.add(m.from); if (m.to && !isBroadcast(m.to)) set.add(m.to); }
+  return set;
+}
+
+// Messages addressed to `agent` (direct, broadcast, or any thread it's part of).
+// unreadOnly (default true) hides ones the agent already read or sent itself.
+function inbox(agent, { unreadOnly = true } = {}) {
+  const mm = messages();
+  const out = [];
+  for (const m of mm.values()) {
+    if (m.from === agent) continue;
+    const addressed = m.to === agent || isBroadcast(m.to) || threadParticipants(m.mid, mm).has(agent);
+    if (!addressed) continue;
+    if (unreadOnly && m.reads.includes(agent)) continue;
+    out.push(m);
+  }
+  return out.sort((a, b) => a.ts < b.ts ? -1 : 1);
+}
+
+// Full conversation (root + replies) for any mid, chronological.
+function thread(mid) {
+  const mm = messages();
+  if (!mm.has(mid)) return [];
+  const root = threadRootMid(mid, mm);
+  return [...mm.values()].filter(m => threadRootMid(m.mid, mm) === root).sort((a, b) => a.ts < b.ts ? -1 : 1);
+}
+
+// Resolve any reference to a stored mid (M-4, m-00004, 4, or full M-00004).
+function resolveMid(ref, mm) {
+  if (!ref) return null;
+  const m = mm || messages();
+  let r = String(ref).toUpperCase(); if (!r.startsWith('M-')) r = 'M-' + r;
+  const n = parseInt(r.replace(/^M-/, ''), 10);
+  for (const id of m.keys()) if (id === r || parseInt(id.replace(/^M-/, ''), 10) === n) return id;
+  return null;
+}
+
+// Pull @agent mentions out of comment/note text so they route to inboxes too.
+function parseMentions(text) {
+  const out = new Set();
+  for (const m of String(text || '').matchAll(/@([A-Za-z0-9][\w.\-:@]*)/g)) out.add(m[1].replace(/[.:,]+$/, ''));
+  return [...out];
+}
+
+// Every agent identity that has ever acted (create/comment/action/assign) or been
+// party to a DM (from/to). Used to gate @mention routing so a stray "@agent" in
+// prose doesn't create a dead-letter DM to a nonexistent recipient.
+function knownAgents() {
+  const set = new Set();
+  for (const ev of readEvents()) { for (const k of ['agent', 'from', 'to']) if (ev[k] && !isBroadcast(ev[k])) set.add(ev[k]); }
+  return set;
+}
+
+// Ticket ids are 5-digit zero-padded + a slug of the title (Steve, 2026-07-26):
+//   TK-00025-ga4-attribution-prep
+// The numeric part is the tracking key; legacy short ids (TK-3, TK-17) remain
+// valid in the log and resolvable by number.
+function slugify(title) {
+  return String(title || '').toLowerCase()
+    .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40).replace(/-+$/, '');
+}
+function idNum(id) { return parseInt(String(id).replace(/^TK-/i, ''), 10); } // parseInt stops at the slug dash
+function nextId(title) {
+  const FLOOR = 10000; // new tickets start at TK-10000 (Steve, 2026-07-27)
+  let max = 0;
+  for (const ev of readEvents()) if (ev.type === 'create') { const n = idNum(ev.id); if (n > max) max = n; }
+  const num = String(Math.max(max + 1, FLOOR)).padStart(5, '0');
+  const slug = slugify(title);
+  return 'TK-' + num + (slug ? '-' + slug : '');
+}
+
+const now = () => new Date().toISOString();
+const correlationId = (prefix = 'tk') => `${prefix}-${Date.now().toString(36)}-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
+function requireTicket(ref) { const id = resolveId(ref); if (!id) throw new Error('no such ticket ' + ref); return id; }
+function createTicket({ title, project = '', agent = 'codex', body = '', correlation_id = correlationId('create') }) {
+  title = String(title || '').trim(); if (!title) throw new Error('title is required');
+  return withLock(() => append({ ts: now(), type: 'create', id: nextId(title), title, project, agent, body, correlation_id }));
+}
+function ticketComment(ref, text, { kind = 'comment', agent = 'codex', correlation_id = correlationId(kind) } = {}) {
+  const id = requireTicket(ref); text = String(text || '').trim(); if (!text) throw new Error('text is required');
+  const ev = append({ ts: now(), type: 'comment', id, kind, agent, text, correlation_id });
+  const known = knownAgents();
+  for (const to of parseMentions(text).filter(a => a !== agent && (isBroadcast(a) || known.has(a))))
+    sendDm(to, text, { ticket: id, agent, correlation_id });
+  return ev;
+}
+function ticketAction(ref, text, { agent = 'codex', correlation_id = correlationId('action') } = {}) {
+  const id = requireTicket(ref); text = String(text || '').trim(); if (!text) throw new Error('text is required');
+  return append({ ts: now(), type: 'action', id, agent, text, correlation_id });
+}
+function ticketAssign(ref, agent = 'codex', correlation_id = correlationId('assign')) {
+  const id = requireTicket(ref), ts = now(); append({ ts, type: 'assign', id, agent, correlation_id }); append({ ts, type: 'status', id, status: 'doing', agent, correlation_id }); return { id, agent, status: 'doing', correlation_id };
+}
+function ticketStatus(ref, status, { agent = 'codex', correlation_id = correlationId('status') } = {}) {
+  const id = requireTicket(ref); status = String(status || '').toLowerCase(); if (!STATUSES.includes(status)) throw new Error('invalid status: ' + status);
+  return append({ ts: now(), type: 'status', id, status, agent, correlation_id });
+}
+function ticketBlocker(ref, blocker, { agent = 'codex', correlation_id = correlationId('blocker') } = {}) {
+  const id = requireTicket(ref);
+  return append({ ts: now(), type: 'blocker', id, blocker: cleanBlocker(blocker), agent, correlation_id });
+}
+function ticketDesignate(ref, kind, { schedule = {}, parent_id = '', agent = 'codex', correlation_id = correlationId('designation') } = {}) {
+  const id = requireTicket(ref); kind = String(kind || '').toLowerCase();
+  if (!KINDS.includes(kind)) throw new Error('invalid kind: ' + kind);
+  if (kind === 'scheduled_job' && !schedule.cadence && !schedule.cron) throw new Error('scheduled_job requires cadence or cron');
+  if (parent_id) parent_id = requireTicket(parent_id);
+  return append({ ts: now(), type: 'designation', id, kind, schedule: cleanSchedule(schedule), parent_id, agent, correlation_id });
+}
+function sendDm(to, text, { ticket = '', agent = 'codex', re = '', correlation_id = correlationId('dm') } = {}) {
+  to = String(to || '').trim(); text = String(text || '').trim(); if (!to || !text) throw new Error('to and text are required');
+  const ticketId = ticket ? requireTicket(ticket) : '';
+  return withLock(() => { const mid = nextMid(); return append({ ts: now(), type: 'dm', mid, from: agent, to, text, ticket: ticketId, re, correlation_id }); });
+}
+function markMessageRead(mid, agent = 'codex', correlation_id = correlationId('read')) {
+  const id = resolveMid(mid); if (!id) throw new Error('no such message ' + mid); return append({ ts: now(), type: 'read', mid: id, agent, correlation_id });
+}
+// Resolve any reference — full id, TK-24, 24, 00024, or 00024-partial-slug —
+// to the canonical stored id (or null if nothing matches).
+function resolveId(ref, map) {
+  if (!ref) return null;
+  const m = map || tickets();
+  let r = String(ref).toUpperCase();
+  if (!r.startsWith('TK-')) r = 'TK-' + r;
+  for (const id of m.keys()) if (id.toUpperCase() === r) return id;
+  const n = idNum(r);
+  if (!Number.isFinite(n)) return null;
+  for (const id of m.keys()) if (idNum(id) === n) return id;
+  return null;
+}
+
+// Injection-safe reference gate (co-located here so the whole security boundary
+// lives with resolveId + is unit-testable). IDRE is the hard shape a canonical id
+// must have before any shell use. REFRE pre-gates the RAW client ref FIRST —
+// otherwise "TK-1; rm -rf /" would numeric-resolve to the real TK-1 (resolveId
+// stops parseInt at the first non-digit) and reach a shell. resolveList resolves
+// a list of client refs to canonical, shell-safe ids, deduped.
+const IDRE = /^TK-[0-9]+(-[a-z0-9-]+)?$/;
+const REFRE = /^(TK-?)?\d+(-[a-z0-9-]+)?$/i;
+const resolveList = (refs, map) => { const out = []; if (!Array.isArray(refs)) return out;
+  for (const r of refs) { if (!REFRE.test(String(r).trim())) continue; const id = resolveId(r, map); if (id && IDRE.test(id)) out.push(id); }
+  return [...new Set(out)]; };
+
+module.exports = { withLock, append, tickets, nextId, resolveId, idNum, slugify, STATUSES, KINDS, BLOCKER_TYPES, cleanBlocker, cleanSchedule, EVENTS,
+  IDRE, REFRE, resolveList,
+  nextMid, messages, inbox, thread, resolveMid, threadParticipants, parseMentions, isBroadcast, knownAgents,
+  correlationId, createTicket, ticketComment, ticketAction, ticketAssign, ticketStatus, ticketBlocker, ticketDesignate, sendDm, markMessageRead };
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticketmaster-urgency.js b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticketmaster-urgency.js
new file mode 100644
index 00000000..5e5d4cc2
--- /dev/null
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/payload/ticketmaster-urgency.js
@@ -0,0 +1,191 @@
+// ticketmaster — pure urgency scoring + stale-build detection.
+// NO fs / NO exec here on purpose: this module is deterministic and unit-testable.
+// poll.js does all the I/O (reads the event log, runs `ps`/`pm2`) and passes the
+// precomputed facts (live worker set, per-agent last-activity, now) into these fns.
+
+'use strict';
+
+// ── keyword tiers (matched against title + recent action/comment text) ──────────
+const RX_P0 = /\b(outage|502|500\b|down\b|dead\b|crash(?:ed|ing)?|breach|stealer|egress|exfil|ransom|data ?loss|enospc|disk (?:critical|full)|prod(?:uction)? down|money|live (?:money|trade|bet)|charging real|unauthorized|panic|wedged)\b/i;
+const RX_P1 = /\b(customer[- ]facing|broken|404|failing|fails\b|expir(?:ed|ing|es)|\bcert\b|\bssl\b|payment|checkout|gmc disapprov|disapproved|suspended|revenue|leak|wrong[- ]colorway|mispriced|below (?:cost|map)|oversell|can'?t (?:login|checkout|submit))\b/i;
+const RX_P2 = /\b(stuck|hung|no drain|regress(?:ed|ion)?|stale|zombie|not scheduled|silent(?:ly)? (?:dead|fail)|flaky|backlog|drift)\b/i;
+
+// explicit urgency markers a human/agent put in the TITLE
+const RX_URGENT_TITLE = /(\bP0\b|\bURGENT\b|\bSEV1\b|\[!\]|🔴|‼️|🚨)/;
+const RX_P1_TITLE = /\bP1\b/;
+
+// blocked-on-Steve signal (surface only — never auto-execute these)
+const RX_STEVE_GATED = /pending[- ]approval|awaiting steve|gated|steve[- ](?:go|gate|decides?|approv)|human gate|needs steve|go-?live gated/i;
+
+// Approval-lane policy. This is deliberately conservative: Ticketmaster may
+// fast-track only clearly local/reversible work. Email is always held, spend
+// above $5 is always held, and anything with an externality remains Steve-only.
+// Match an outbound communication INTENT, not a stray noun such as "email alert
+// audit" or a ticket imported from an email. The action verb must point at a
+// communication object/recipient, while explicit blast/send-to-list phrases are
+// always holds.
+const RX_EMAIL_ACTION = /\b(?:send[- ]to[- ]list|email blast|mail blast|newsletter send)\b|\bsend\b[^\n.;]{0,32}\b(?:email|mail|message|dm|customer|client|user|subscriber|recipient|list|newsletter|campaign|support|steve|team|vendor)\b|\b(?:email|mail|message|dm|notify|contact)\b[^\n.;]{0,24}\b(?:customer|client|user|subscriber|recipient|list|support|steve|team|vendor)\b/i;
+const RX_EXTERNAL_ACTION = /\b(customer[- ]facing|production|prod\b|deploy|publish|post(?:ing)?|shopify|dw_unified|dns|domain|remote[- ]push|git push|social|instagram|facebook|linkedin|tiktok|youtube|app store|delete|purge|drop\b|wipe|unpublish|kill|restart)\b/i;
+const RX_LOCAL_SAFE = /\b(local|read[- ]only|dry[- ]run|documentation|docs|test(?:s|ing)?|lint|reversible|git revert|rollback|snapshot|report|audit)\b/i;
+// A blocked ticket may still have useful reversible prep, but explicit statements
+// that the safe/local ceiling has been reached must win over stale mentions of a
+// prior dry-run or audit. Otherwise completed prep is repeatedly re-ranked as work.
+const RX_LOCAL_EXHAUSTED = /\b(?:no (?:further|remaining|purely) (?:safe|local|reversible)(?: work| objective)? remains?|no (?:safe|local) objective remains?|(?:all|everything) remaining (?:work )?is gated|(?:all|everything) remaining (?:work )?(?:stays?|remains?) gated|(?:canonical )?writes? remain gated|local safe ceiling reached|safe local ceiling reached|safe ceiling reached)\b/i;
+
+function spendAmounts(text) {
+  const out = [];
+  // Require spend-like context so product prices and revenue figures do not
+  // falsely become authorization requests.
+  const rx = /\b(?:spend|pay|charge|purchase|buy|budget|cost(?:s|ing)?|fee)\b[^\n$]{0,32}\$\s*([\d,]+(?:\.\d+)?)/gi;
+  for (const m of String(text || '').matchAll(rx)) out.push(Number(m[1].replace(/,/g, '')));
+  return out.filter(Number.isFinite);
+}
+
+function approvalPolicy(text, status) {
+  const s = String(text || '');
+  const amounts = spendAmounts(s);
+  const email = RX_EMAIL_ACTION.test(s);
+  const overFive = amounts.some(n => n > 5);
+  const external = RX_EXTERNAL_ACTION.test(s);
+  const gated = status === 'blocked' && RX_STEVE_GATED.test(s);
+  const exhausted = RX_LOCAL_EXHAUSTED.test(s);
+  const fastLocal = gated && !exhausted && RX_LOCAL_SAFE.test(s) && !email && !overFive && !external;
+  const reasons = [email && 'email', overFive && 'spend-over-$5', external && 'external-action'].filter(Boolean);
+  return {
+    lane: reasons.length ? 'hold-policy' : fastLocal ? 'fast-local-review' : gated ? 'steve-review' : 'standard',
+    reasons, email, overFive, external, exhausted, fastLocal,
+  };
+}
+
+const STALE_BUILD_HOURS = Number(process.env.TM_STALE_H || 24); // Steve's spec: >24h
+const COLLIDE_WINDOW_MIN = Number(process.env.TM_COLLIDE_MIN || 15); // owner touched it this recently ⇒ don't step on them
+
+const H = 3600000, MIN = 60000, DAY = 86400000;
+
+function shortId(id) { const m = String(id).match(/^(TK-\d+)/i); return (m ? m[1] : String(id)).toUpperCase(); }
+
+// most-recent action/comment timestamp for a ticket (falls back to updated/created)
+function lastTouchTs(t) {
+  let ms = +new Date(t.updated_at || t.created_at || 0);
+  for (const a of (t.actions || [])) ms = Math.max(ms, +new Date(a.ts));
+  for (const c of (t.comments || [])) ms = Math.max(ms, +new Date(c.ts));
+  return ms;
+}
+function lastActionText(t) {
+  const acts = (t.actions || []).slice().sort((a, b) => +new Date(b.ts) - +new Date(a.ts));
+  if (acts[0]) return acts[0].text || '';
+  const cs = (t.comments || []).slice().sort((a, b) => +new Date(b.ts) - +new Date(a.ts));
+  return cs[0] ? (cs[0].text || '') : '';
+}
+
+// tier label from a numeric score
+function tierOf(score) { return score >= 100 ? 'P0' : score >= 55 ? 'P1' : score >= 25 ? 'P2' : 'P3'; }
+
+// disposition heuristic for a DEAD stale build (mirrors reaper.js but adds restart/kill)
+function deadDisposition(text) {
+  const s = (text || '').toLowerCase();
+  if (/\b(complete|completed|final verify|shipped|deployed|verified|done|live-verified)\b/.test(s)) return 'done-candidate';
+  if (RX_STEVE_GATED.test(s)) return 'blocked-steve';
+  if (/\b(loop|watch|cadence|daemon|poller|refresh|monitor|scan)\b/.test(s)) return 'restart-recommend'; // resumable long-runner
+  return 'kill-recommend'; // session died mid-work, not resumable, not gated ⇒ RECOMMEND kill (never an autonomous imperative)
+}
+// Advisory only: the poller NEVER acts on these; the Claude layer verifies liveness
+// then drafts any kill/restart of a prod process to pending-approval for Steve.
+
+/**
+ * Score + classify one ticket.
+ * @param {object} t        ticket (from lib.tickets())
+ * @param {object} facts    { now, liveIds:Set<shortId>, agentLastTs:Map<agent,ms>, pm2Hit:(t)=>bool }
+ * @returns {object} enriched record
+ */
+function classify(t, facts) {
+  const { now = Date.now(), liveIds = new Set(), agentLastTs = new Map(), pm2Hit = () => false } = facts || {};
+  const sid = shortId(t.id);
+  const hay = `${t.title} ${lastActionText(t)}`;
+  const touch = lastTouchTs(t);
+  const ageH = (now - touch) / H;
+
+  let score = 0;
+  const why = [];
+  if (RX_P0.test(hay)) { score += 100; why.push('P0-keyword'); }
+  else if (RX_P1.test(hay)) { score += 55; why.push('P1-keyword'); }
+  else if (RX_P2.test(hay)) { score += 25; why.push('P2-keyword'); }
+
+  if (RX_URGENT_TITLE.test(t.title)) { score += 40; why.push('urgent-title'); }
+  else if (RX_P1_TITLE.test(t.title)) { score += 20; why.push('P1-title'); }
+
+  if (t.status === 'open') { score += 12; why.push('open'); }
+  else if (t.status === 'doing') { score += 6; }
+  else if (t.status === 'blocked') { score += 3; }
+
+  // drain aging OPEN backlog (older open = a bit higher), capped
+  if (t.status === 'open') { const d = Math.min((now - +new Date(t.created_at || now)) / DAY, 30); score += Math.min(d * 2, 30); }
+
+  // ── stale-build detection (Steve's core ask) ──
+  const isBuildDoing = t.status === 'doing';
+  const live = liveIds.has(sid) || pm2Hit(t) ||
+    ((agentLastTs.get(t.assignee) || 0) > now - DAY); // owner active anywhere in last 24h
+  const stale = isBuildDoing && ageH > STALE_BUILD_HOURS;
+  let buildVerdict = 'ok', buildReason = '';
+  if (stale) {
+    score += 35; why.push(`stale-build-${ageH.toFixed(0)}h`);
+    if (live) { buildVerdict = 'nudge'; buildReason = `alive (owner active/worker up) but no ticket update in ${ageH.toFixed(0)}h — ask owner to update or dispose`; }
+    else { buildVerdict = deadDisposition(lastActionText(t)); buildReason = `no live worker + owner idle ${ageH.toFixed(0)}h ⇒ recommend ${buildVerdict}`; }
+  }
+
+  score = Math.round(score);
+
+  // routing/collision flags
+  // collide = THIS ticket was touched (any agent, any event) inside the window ⇒ a live
+  // owner is on it right now → monitor, never execute. Per-ticket (touch), NOT the
+  // assignee's activity on *other* tickets — that was the hole the contrarian found.
+  const collide = (now - touch) < COLLIDE_WINDOW_MIN * MIN;
+  const policy = approvalPolicy(`${t.title} ${lastActionText(t)}`, t.status);
+  // Canonical structured blocker state outranks lossy title/latest-text hints.
+  // Any canonical Steve marker is a human-policy hold, even when its prose
+  // contains none of the legacy gate keywords.
+  const blocker = t.blocker && typeof t.blocker === 'object' ? t.blocker : null;
+  const canonicalSteveGate = blocker && (blocker.type === 'steve_action'
+    || String(blocker.owner || '').trim().toLowerCase() === 'steve'
+    || blocker.steve_one_action === true);
+  if (canonicalSteveGate) {
+    policy.lane = 'hold-policy';
+    if (!policy.reasons.includes('blocker:steve-gated')) policy.reasons.push('blocker:steve-gated');
+  }
+  const steveGated = policy.lane === 'steve-review' || policy.lane === 'hold-policy';
+
+  return {
+    id: t.id, sid, title: t.title, status: t.status, assignee: t.assignee || '', project: t.project || '',
+    score, tier: tierOf(score), why, ageH: +ageH.toFixed(1),
+    stale, buildVerdict, buildReason, live,
+    collide, steveGated, approvalLane: policy.lane, approvalReasons: policy.reasons,
+    // what the SUPERVISOR should do with it
+    disposition: policy.lane === 'hold-policy' ? 'hold-policy'
+      : policy.lane === 'fast-local-review' ? 'fast-track-local'
+      : steveGated ? 'surface-to-steve'
+      : collide ? 'monitor-only'
+      : stale && !live ? 'stale-dispose'      // restart/kill/blocked/done-candidate
+      : stale && live ? 'nudge-owner'
+      : t.status === 'open' ? 'execute'        // needs pickup → graph-engineer it
+      : t.status === 'doing' ? 'monitor'
+      : 'surface-to-steve',
+  };
+}
+
+// rank a whole ticket map → sorted worklist
+function rank(ticketMap, facts) {
+  const out = [];
+  for (const t of ticketMap.values()) {
+    if (t.status === 'done') continue;
+    // Recurring parents are registries, not actionable work. Their bounded run
+    // tickets enter this queue as ordinary `task` records when work exists.
+    if ((t.kind || 'task') !== 'task') continue;
+    out.push(classify(t, facts));
+  }
+  out.sort((a, b) => b.score - a.score || b.ageH - a.ageH);
+  return out;
+}
+
+module.exports = { classify, rank, tierOf, shortId, lastTouchTs, lastActionText,
+  approvalPolicy, spendAmounts, STALE_BUILD_HOURS, COLLIDE_WINDOW_MIN, RX_P0, RX_P1, RX_P2,
+  RX_LOCAL_EXHAUSTED };
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-output.txt b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-output.txt
index fde8d51c..82260825 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-output.txt
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-output.txt
@@ -1 +1 @@
-PASS strict payload=9 full_allowlist=17 canonical_events_prefix_records=119120 snapshot=2026-09-04T12:16:36.321Z nonstandalone-source-dependent
+PASS strict_payload=11 allowlist=21 prefix_records=119120 open_or_active=57 actionable_pickups=0 dispositions=hold-policy:19,monitor-only:1,nudge-owner:3,surface-to-steve:2 snapshot=2026-09-04T12:16:36.321Z source_dependent
diff --git a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-verifier.js b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-verifier.js
index 5751b7e5..1cad6ff5 100644
--- a/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-verifier.js
+++ b/data/codex-yoloforever/evidence/TK-11215-20260904T0912Z-vpops/replay-verifier.js
@@ -1,56 +1,242 @@
 #!/usr/bin/env node
 'use strict';
-const fs=require('fs'), path=require('path'), crypto=require('crypto');
-const root=__dirname;
-const manifestArg=process.argv[2] || 'manifest.sha256';
-const expectedControls=['README.md','allowlist.txt','build-evidence.js','manifest.sha256','negative/manifest.tampered.sha256','negative/tamper-output.txt','replay-output.txt','replay-verifier.js'];
-const expectedPayload=['payload/agents-panel.sh','payload/agents-post-decision-codex.sh','payload/audit-report.json','payload/claude-panel.sh','payload/codex-yoloforever.sh','payload/dtd-cost-mode','payload/e2e-proof.json','payload/provenance.json','payload/ticketmaster-latest.json'];
-const expected=[...expectedControls,...expectedPayload].sort();
-function walk(d,prefix=''){return fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>e.isDirectory()?walk(path.join(d,e.name),`${prefix}${e.name}/`):[`${prefix}${e.name}`]);}
-const actual=walk(root).sort();
-const allow=fs.readFileSync(path.join(root,'allowlist.txt'),'utf8').trim().split('\n').sort();
-function same(a,b){return a.length===b.length&&a.every((x,i)=>x===b[i]);}
-if(!same(actual,expected)||!same(allow,expected)){console.error('FAIL full-directory allowlist mismatch',{actual,allow,expected});process.exit(2);}
-const lines=fs.readFileSync(path.join(root,manifestArg),'utf8').trim().split('\n');
-const manifestFiles=[];let failed=false;
-for(const line of lines){const m=line.match(/^([0-9a-f]{64})  (payload\/.+)$/);if(!m){console.error('FAIL malformed manifest line',line);failed=true;continue;}manifestFiles.push(m[2]);const got=crypto.createHash('sha256').update(fs.readFileSync(path.join(root,m[2]))).digest('hex');if(got!==m[1]){console.error(`FAIL digest ${m[2]} expected=${m[1]} got=${got}`);failed=true;}}
-if(!same(manifestFiles.sort(),expectedPayload)){console.error('FAIL strict payload coverage mismatch',{manifestFiles,expectedPayload});failed=true;}
-const audit=JSON.parse(fs.readFileSync(path.join(root,'payload/audit-report.json')));
-const snapshot=JSON.parse(fs.readFileSync(path.join(root,'payload/ticketmaster-latest.json')));
-const snapshotDigest=crypto.createHash('sha256').update(fs.readFileSync(path.join(root,'payload/ticketmaster-latest.json'))).digest('hex');
-const actionableTop=snapshot.top.filter(x=>x.disposition==='execute'||x.disposition==='fast-track-local');
-if(audit.ticketmaster.retained_as!=='payload/ticketmaster-latest.json'||audit.ticketmaster.sha256!==snapshotDigest||audit.ticketmaster.top_scope!=='top[] is a capped ranked window and is not necessarily the full open/active population.'||audit.ticketmaster.snapshot_ts!==snapshot.ts||audit.ticketmaster.open_or_active!==snapshot.totals.open_or_active||audit.ticketmaster.actionable_pickups!==snapshot.orchestration_reasons.actionable_pickups||audit.ticketmaster.top_length!==snapshot.top.length||audit.ticketmaster.actionable_entries_in_top!==actionableTop.length) {console.error('FAIL snapshot semantics');failed=true;}
-if(!fs.readFileSync(path.join(root,'payload/dtd-cost-mode')).equals(Buffer.from('ZERO_COST_REQUIRED\n'))) {console.error('FAIL guard bytes');failed=true;}
-const canonicalEvents='/Users/macstudio3/.claude/tickets/events.jsonl';
-const eventMeta=audit.canonical_events;
-if(eventMeta.source!==canonicalEvents||eventMeta.retained_payload!==false||eventMeta.verification_mode!=='canonical_append_only_prefix'||eventMeta.full_json_parse!=='PASS'){console.error('FAIL canonical events metadata contract');failed=true;}
-const prefixBytes=eventMeta.captured_prefix_bytes;
-if(!Number.isSafeInteger(prefixBytes)||prefixBytes<0){console.error('FAIL canonical events byte count');failed=true;}
-let records=0;
-if(!failed){
-  const fd=fs.openSync(canonicalEvents,'r');
+
+const fs = require('fs');
+const path = require('path');
+const crypto = require('crypto');
+const vm = require('vm');
+
+const root = __dirname;
+const manifestArg = process.argv[2] || 'manifest.sha256';
+const derivedAssertionArg = process.argv[3] || '';
+const canonicalEvents = '/Users/macstudio3/.claude/tickets/events.jsonl';
+const virtualDir = '/__tk11215_captured_prefix__';
+const virtualEvents = `${virtualDir}/events.jsonl`;
+const expectedControls = [
+  'README.md',
+  'allowlist.txt',
+  'build-evidence.js',
+  'manifest.sha256',
+  'negative/derived-assertion.tampered.json',
+  'negative/derived-tamper-output.txt',
+  'negative/manifest.tampered.sha256',
+  'negative/tamper-output.txt',
+  'replay-output.txt',
+  'replay-verifier.js',
+];
+const expectedPayload = [
+  'payload/agents-panel.sh',
+  'payload/agents-post-decision-codex.sh',
+  'payload/audit-report.json',
+  'payload/claude-panel.sh',
+  'payload/codex-yoloforever.sh',
+  'payload/dtd-cost-mode',
+  'payload/e2e-proof.json',
+  'payload/provenance.json',
+  'payload/ticket-lib.js',
+  'payload/ticketmaster-latest.json',
+  'payload/ticketmaster-urgency.js',
+];
+const expected = [...expectedControls, ...expectedPayload].sort();
+
+let failed = false;
+function fail(message) { console.error(`FAIL ${message}`); failed = true; }
+function shaBuffer(buffer) { return crypto.createHash('sha256').update(buffer).digest('hex'); }
+function shaFile(file) { return shaBuffer(fs.readFileSync(file)); }
+function same(a, b) { return a.length === b.length && a.every((x, i) => x === b[i]); }
+function stable(value) {
+  if (Array.isArray(value)) return value.map(stable);
+  if (value && typeof value === 'object') return Object.fromEntries(Object.keys(value).sort().map(k => [k, stable(value[k])]));
+  return value;
+}
+function equalJson(a, b) { return JSON.stringify(stable(a)) === JSON.stringify(stable(b)); }
+function walk(dir, prefix = '') {
+  return fs.readdirSync(dir, {withFileTypes: true}).flatMap(entry =>
+    entry.isDirectory() ? walk(path.join(dir, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]);
+}
+function histogram(rows) {
+  return rows.reduce((out, row) => {
+    out[row.disposition] = (out[row.disposition] || 0) + 1;
+    return out;
+  }, {});
+}
+
+const actual = walk(root).sort();
+const allow = fs.readFileSync(path.join(root, 'allowlist.txt'), 'utf8').trim().split('\n').sort();
+if (!same(actual, expected) || !same(allow, expected)) fail('full-directory allowlist mismatch');
+
+const manifestLines = fs.readFileSync(path.join(root, manifestArg), 'utf8').trim().split('\n');
+const manifestFiles = [];
+for (const line of manifestLines) {
+  const match = line.match(/^([0-9a-f]{64})  (payload\/.+)$/);
+  if (!match) { fail('malformed manifest line'); continue; }
+  manifestFiles.push(match[2]);
+  if (shaFile(path.join(root, match[2])) !== match[1]) fail(`digest ${match[2]}`);
+}
+if (!same(manifestFiles.sort(), expectedPayload)) fail('strict payload coverage mismatch');
+
+const audit = JSON.parse(fs.readFileSync(path.join(root, 'payload/audit-report.json')));
+const provenance = JSON.parse(fs.readFileSync(path.join(root, 'payload/provenance.json')));
+const e2e = JSON.parse(fs.readFileSync(path.join(root, 'payload/e2e-proof.json')));
+const snapshotPath = path.join(root, 'payload/ticketmaster-latest.json');
+const snapshot = JSON.parse(fs.readFileSync(snapshotPath));
+const snapshotDigest = shaFile(snapshotPath);
+
+if (audit.schema !== 'codex-yoloforever-r0-evidence/v2' || audit.ticket !== 'TK-11215' || audit.cost_usd !== 0) fail('audit identity/cost contract');
+if (snapshot.ts !== '2026-09-04T12:16:36.321Z') fail('retained snapshot timestamp');
+if (audit.ticketmaster.retained_as !== 'payload/ticketmaster-latest.json' || audit.ticketmaster.sha256 !== snapshotDigest || audit.ticketmaster.snapshot_ts !== snapshot.ts) fail('snapshot audit binding');
+const provenanceSnapshot = provenance.inputs.find(x => x.path === audit.ticketmaster.source);
+if (!provenanceSnapshot || provenanceSnapshot.retained_as !== 'payload/ticketmaster-latest.json' || provenanceSnapshot.sha256 !== snapshotDigest) fail('snapshot provenance binding');
+
+const guardPath = path.join(root, 'payload/dtd-cost-mode');
+const guard = fs.readFileSync(guardPath);
+const guardDigest = shaBuffer(guard);
+if (!guard.equals(Buffer.from('ZERO_COST_REQUIRED\n'))) fail('guard bytes');
+if (audit.guard.bytes !== guard.length || audit.guard.sha256 !== guardDigest || audit.guard.exact_expected_with_newline !== true || audit.guard.verdict !== 'PASS') fail('guard audit structure');
+const provenanceGuard = provenance.inputs.find(x => x.path === audit.guard.source);
+if (!provenanceGuard || provenanceGuard.bytes !== guard.length || provenanceGuard.sha256 !== guardDigest) fail('guard provenance binding');
+
+const dtdCaptures = ['payload/agents-panel.sh', 'payload/agents-post-decision-codex.sh', 'payload/claude-panel.sh'];
+if (!audit.static_dtd_zero_cost || audit.static_dtd_zero_cost.model_or_provider_endpoints_executed !== false || audit.static_dtd_zero_cost.verdict !== 'PASS_STATIC' || audit.static_dtd_zero_cost.checks.length !== dtdCaptures.length) fail('DTD audit structure');
+for (const capture of dtdCaptures) {
+  const record = audit.static_dtd_zero_cost.checks.find(x => x.capture === capture);
+  const fullPath = path.join(root, capture);
+  const text = fs.readFileSync(fullPath, 'utf8');
+  const digest = shaFile(fullPath);
+  const force = text.indexOf('ZERO_COST_REQUIRED) DTD_ZERO_COST=1');
+  const firstPaid = Math.min(...['api.openai.com', 'api.x.ai', 'api.moonshot.ai'].map(value => {
+    const index = text.indexOf(value);
+    return index < 0 ? Infinity : index;
+  }));
+  const independentlyValid = text.includes('CANONICAL_DTD_COST_MODE_FILE="/Users/macstudio3/Projects/ticket-system/config/dtd-cost-mode"')
+    && text.includes('refusing non-canonical DTD cost-mode guard')
+    && text.includes('exit 78')
+    && force >= 0
+    && force < firstPaid;
+  if (!record || record.sha256 !== digest || record.verdict !== 'PASS' || !Object.values(record.checks || {}).every(Boolean) || !independentlyValid) fail(`DTD capture audit ${capture}`);
+  const provenanceRecord = record && provenance.inputs.find(x => x.path === record.source);
+  if (!provenanceRecord || provenanceRecord.sha256 !== digest) fail(`DTD capture provenance ${capture}`);
+}
+
+for (const key of ['ticket_lib', 'urgency_lib']) {
+  const record = audit.canonical_logic && audit.canonical_logic[key];
+  if (!record) { fail(`canonical logic audit ${key}`); continue; }
+  const digest = shaFile(path.join(root, record.capture));
+  if (record.sha256 !== digest) fail(`canonical logic digest ${key}`);
+  const provenanceRecord = provenance.inputs.find(x => x.path === record.source);
+  if (!provenanceRecord || provenanceRecord.retained_as !== record.capture || provenanceRecord.sha256 !== digest) fail(`canonical logic provenance ${key}`);
+}
+if (!Array.isArray(audit.command_results) || audit.command_results.length < 6 || audit.command_results.some(x => x.rc !== 0)) fail('captured command results');
+if (e2e.verdict !== 'PASS' || e2e.assertions.ticket_fold_boundary !== 'PASS' || e2e.assertions.derived_metrics_boundary !== 'PASS' || e2e.assertions.dtd_static_boundary !== 'PASS_STATIC') fail('E2E structure');
+
+const eventMeta = audit.canonical_events;
+if (eventMeta.source !== canonicalEvents || eventMeta.retained_payload !== false || eventMeta.verification_mode !== 'canonical_append_only_prefix' || eventMeta.full_json_parse !== 'PASS') fail('canonical events metadata contract');
+const prefixBytes = eventMeta.captured_prefix_bytes;
+if (!Number.isSafeInteger(prefixBytes) || prefixBytes < 0) fail('canonical events byte count');
+let prefix = Buffer.alloc(0);
+let events = [];
+if (!failed) {
+  const fd = fs.openSync(canonicalEvents, 'r');
   try {
-    const currentBytes=fs.fstatSync(fd).size;
-    if(currentBytes<prefixBytes){console.error('FAIL canonical events source shorter than recorded prefix');failed=true;}
+    if (fs.fstatSync(fd).size < prefixBytes) fail('canonical events source shorter than recorded prefix');
     else {
-      const prefix=Buffer.alloc(prefixBytes);
-      let offset=0;
-      while(offset<prefix.length){const n=fs.readSync(fd,prefix,offset,prefix.length-offset,offset);if(n===0)break;offset+=n;}
-      if(offset!==prefixBytes){console.error('FAIL canonical events prefix short read');failed=true;}
-      const digest=crypto.createHash('sha256').update(prefix).digest('hex');
-      if(digest!==eventMeta.captured_prefix_sha256){console.error('FAIL canonical events prefix digest');failed=true;}
-      if((prefix.length===0||prefix[prefix.length-1]===0x0a)!==eventMeta.captured_prefix_line_terminated){console.error('FAIL canonical events line-boundary metadata');failed=true;}
-      for(const [i,line] of prefix.toString('utf8').split('\n').entries()){if(!line.trim())continue;try{JSON.parse(line);records++;}catch(e){console.error(`FAIL canonical events prefix JSON at line ${i+1}`);failed=true;break;}}
-      if(records!==eventMeta.captured_prefix_nonblank_records){console.error('FAIL canonical events prefix record count');failed=true;}
+      prefix = Buffer.alloc(prefixBytes);
+      let offset = 0;
+      while (offset < prefix.length) {
+        const bytesRead = fs.readSync(fd, prefix, offset, prefix.length - offset, offset);
+        if (bytesRead === 0) break;
+        offset += bytesRead;
+      }
+      if (offset !== prefixBytes) fail('canonical events prefix short read');
     }
   } finally { fs.closeSync(fd); }
+  if (shaBuffer(prefix) !== eventMeta.captured_prefix_sha256) fail('canonical events prefix digest');
+  if ((prefix.length === 0 || prefix[prefix.length - 1] === 0x0a) !== eventMeta.captured_prefix_line_terminated) fail('canonical events line-boundary metadata');
+  for (const [index, line] of prefix.toString('utf8').split('\n').entries()) {
+    if (!line.trim()) continue;
+    try { events.push(JSON.parse(line)); }
+    catch { fail(`canonical events prefix JSON at line ${index + 1}`); break; }
+  }
+  if (events.length !== eventMeta.captured_prefix_nonblank_records) fail('canonical events prefix record count');
+}
+const provenanceEvents = provenance.inputs.find(x => x.path === canonicalEvents);
+if (!provenanceEvents || provenanceEvents.scope !== 'captured prefix only' || provenanceEvents.bytes !== prefixBytes || provenanceEvents.sha256 !== eventMeta.captured_prefix_sha256 || provenanceEvents.observed_at !== eventMeta.observed_at) fail('canonical events provenance');
+
+function loadCapturedModule(file, injectedRequire, env = {}) {
+  const module = {exports: {}};
+  const sandbox = {
+    module,
+    exports: module.exports,
+    require: injectedRequire,
+    process: {env, pid: 0},
+    Buffer,
+    Date,
+    Math,
+    Map,
+    Set,
+    console,
+  };
+  vm.runInNewContext(fs.readFileSync(file, 'utf8'), sandbox, {filename: file});
+  return module.exports;
+}
+
+let derived = null;
+if (!failed) {
+  const fakeFs = {
+    ...fs,
+    mkdirSync: (target, options) => target === virtualDir ? undefined : fs.mkdirSync(target, options),
+    existsSync: target => target === virtualEvents ? true : fs.existsSync(target),
+    readFileSync: (target, encoding) => target === virtualEvents
+      ? (encoding ? prefix.toString(encoding) : Buffer.from(prefix))
+      : fs.readFileSync(target, encoding),
+  };
+  const ticketLib = loadCapturedModule(
+    path.join(root, 'payload/ticket-lib.js'),
+    id => id === 'fs' ? fakeFs : require(id),
+    {TICKET_DATA_DIR: virtualDir},
+  );
+  const urgency = loadCapturedModule(
+    path.join(root, 'payload/ticketmaster-urgency.js'),
+    id => require(id),
+    {},
+  );
+  const ticketMap = ticketLib.tickets();
+  const agentLastTs = new Map();
+  for (const event of events) {
+    const timestamp = +new Date(event.ts);
+    for (const field of ['agent', 'from']) {
+      const agent = event[field];
+      if (agent && agent !== 'all' && (agentLastTs.get(agent) || 0) < timestamp) agentLastTs.set(agent, timestamp);
+    }
+  }
+  const retainedLivenessRows = [...snapshot.top, ...snapshot.stale_builds];
+  const liveIds = new Set(retainedLivenessRows.filter(row => row.live).map(row => urgency.shortId(row.id)));
+  const ranked = urgency.rank(ticketMap, {
+    now: +new Date(snapshot.ts),
+    liveIds,
+    agentLastTs,
+    pm2Hit: () => false,
+  });
+  const top = ranked.slice(0, snapshot.top.length);
+  derived = {
+    open_or_active: ranked.length,
+    actionable_pickups: ranked.filter(row => (row.disposition === 'execute' || row.disposition === 'fast-track-local') && row.tier !== 'P3').length,
+    dispositions: histogram(top),
+  };
+  const expectedDerived = derivedAssertionArg
+    ? JSON.parse(fs.readFileSync(path.join(root, derivedAssertionArg)))
+    : {
+      open_or_active: audit.ticketmaster.open_or_active,
+      actionable_pickups: audit.ticketmaster.actionable_pickups,
+      dispositions: audit.ticketmaster.dispositions,
+    };
+  if (!equalJson(derived, expectedDerived)) fail('independently derived assertion mismatch');
+  if (derived.open_or_active !== snapshot.totals.open_or_active || derived.actionable_pickups !== snapshot.orchestration_reasons.actionable_pickups || !equalJson(derived.dispositions, histogram(snapshot.top))) fail('derived metrics vs retained snapshot');
+  if (!same(top.map(row => row.id), snapshot.top.map(row => row.id))) fail('derived top order');
+  if (!top.every((row, index) => row.disposition === snapshot.top[index].disposition)) fail('derived top dispositions');
 }
-const provenance=JSON.parse(fs.readFileSync(path.join(root,'payload/provenance.json')));
-const provenanceEvents=provenance.inputs.find(x=>x.path===canonicalEvents);
-if(!provenanceEvents||provenanceEvents.bytes!==eventMeta.captured_prefix_bytes||provenanceEvents.sha256!==eventMeta.captured_prefix_sha256){console.error('FAIL canonical events provenance mismatch');failed=true;}
-const provenanceSnapshot=provenance.inputs.find(x=>x.path===audit.ticketmaster.source);
-if(!provenanceSnapshot||provenanceSnapshot.retained_as!=='payload/ticketmaster-latest.json'||provenanceSnapshot.sha256!==snapshotDigest){console.error('FAIL snapshot provenance mismatch');failed=true;}
-const dtdFiles=['payload/agents-panel.sh','payload/agents-post-decision-codex.sh','payload/claude-panel.sh'];
-for(const file of dtdFiles){const text=fs.readFileSync(path.join(root,file),'utf8');const force=text.indexOf('ZERO_COST_REQUIRED) DTD_ZERO_COST=1');const firstPaid=Math.min(...['api.openai.com','api.x.ai','api.moonshot.ai'].map(s=>{const i=text.indexOf(s);return i<0?Infinity:i;}));if(!text.includes('CANONICAL_DTD_COST_MODE_FILE="/Users/macstudio3/Projects/ticket-system/config/dtd-cost-mode"')||!text.includes('refusing non-canonical DTD cost-mode guard')||!text.includes('exit 78')||force<0||force>=firstPaid){console.error(`FAIL independently derived zero-cost enforcement ${file}`);failed=true;}}
-if(!['ABSENT','PRESENT'].includes(audit.stopped_sentinel.state_at_capture)||audit.command_results.some(x=>x.rc!==0)){console.error('FAIL captured assertions');failed=true;}
-if(failed)process.exit(1);console.log(`PASS strict payload=${expectedPayload.length} full_allowlist=${expected.length} canonical_events_prefix_records=${records} snapshot=${snapshot.ts} nonstandalone-source-dependent`);
+
+if (!['ABSENT', 'PRESENT'].includes(audit.stopped_sentinel.state_at_capture)) fail('STOPPED observation structure');
+if (failed) process.exit(1);
+const dispositionText = Object.keys(derived.dispositions).sort().map(key => `${key}:${derived.dispositions[key]}`).join(',');
+console.log(`PASS strict_payload=${expectedPayload.length} allowlist=${expected.length} prefix_records=${events.length} open_or_active=${derived.open_or_active} actionable_pickups=${derived.actionable_pickups} dispositions=${dispositionText} snapshot=${snapshot.ts} source_dependent`);

← 873f9144 Repair TK-11215 evidence replay  ·  back to Ticket System  ·  Log TK-11215 yoloforever cycle 43a31a28 →