fix(ledger): count the T3 header as agent, control-board sender as board (#1506)

messageKind knew only the tmux preamble, so a prompt opening with the T3
header [from: role (id) -> to: role (id)] counted as human in Table 2. The
first line now matches either form; anything short of the full header stays
human. Filbert approved R1 against the frozen hashes.

Proof: packages/ledger/tests/ledger.test.mjs, 22/22; against HEAD's
ledger.mjs it fails exactly the two new tests. No suite runs it. Eight
suites green on the staged tree.

The fix changes zero current counts: no Pi log under .pi/state contains a
T3 header, and the ledger does not read T3 transcripts. Gate F waits on a
T3 thread source.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 15:16:55 -05:00
co-authored by Claude Opus 5.5
parent d41f81aafe
commit ef0020ad85
7 changed files with 234 additions and 7 deletions
+6 -2
View File
@@ -77,8 +77,12 @@ export function messageText(content) {
}
export function messageKind(text) {
const firstLine = text.split(/\r?\n/, 1)[0];
const match = firstLine.match(/^\[([^\s:\[\]]+):([^\s\[\]]+) -> ([^\s:\[\]]+):([^\s\[\]]+)(?: class=[a-z-]+)?\](?:\s|$)/);
return !match ? 'human' : match[2] === 'control-board' ? 'board' : 'agent';
// tmux preamble from agent-send.sh: [host:session -> host:session class=x]
const tmux = firstLine.match(/^\[([^\s:\[\]]+):([^\s\[\]]+) -> ([^\s:\[\]]+):([^\s\[\]]+)(?: class=[a-z-]+)?\](?:\s|$)/);
// T3 header (docs/guides/T3-AGENT-COMMS.md): [from: role (id) -> to: role (id) class=x]
const t3 = firstLine.match(/^\[from: ([^\s()\[\]]+) \(([^()\[\]]+)\) -> to: ([^\s()\[\]]+) \(([^()\[\]]+)\)(?: class=[a-z-]+)?\](?:\s|$)/);
const sender = tmux ? tmux[2] : t3 ? t3[1] : null;
return sender === null ? 'human' : sender === 'control-board' ? 'board' : 'agent';
}
async function directories(dir, optional = false) {
try {