Skip to content

feat(telemetry): deterministic claude code token measurement, release 1 - #993

Draft
blafourcade wants to merge 75 commits into
nextfrom
feat/telemetry-deterministic-tokens
Draft

blafourcade wants to merge 75 commits into
nextfrom
feat/telemetry-deterministic-tokens

Conversation

@blafourcade

@blafourcade blafourcade commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

🎯 What & why

Replaces the previous telemetry with a deterministic token count for Claude Code. Every billed call is counted exactly once and stored locally. The report breaks the calls down by person, session, model, day, repository, task and ticket, and every axis sums to the same total. The task comes only from an explicit declaration, and nothing is sent anywhere.

Contract: spec.md. Plan: plan.md. Product contract: usage-contract.md.

🛠️ How it works

  • Count. Ingest reads Claude transcripts incrementally, by byte offset. The key is message.id:requestId and duplicates are folded globally: the largest total wins, then the earliest time, then the lowest session id. Synthetic messages are dropped. Each advisor iteration becomes its own record. Cache writes are summed over the message iterations, and an unknown counter stays null, never 0. (contexts/telemetry/domain)
  • Store. The ledger is local and split by month. Each partition is rewritten only when its content changes, under a lock. Branch bindings are kept as snapshots, so a deleted or reused branch name keeps its past.
  • Declare. aidd telemetry task <name> [--ticket <ref>] | --none binds the session and the working branch; branch bindings live in local git config. The plugin hooks ask once per unbound working branch, only for Claude, only when a person is present, and only where consent is open. A declaration typed as a prompt is parsed by a strict tokenizer and run without a shell, so it never reaches the model. A /clear or /branch keeps the task. (hooks)
  • Attribute. Precedence is the session declaration in force, then the carry, then the branch declaration in force, else unattributed with a reason. The first declaration in a carried session covers that whole session.
  • Consent, per clone. aidd telemetry on writes aidd.telemetry=2:<token> to local git config and opens an interval. A call is stored only if its clone had an open interval at the call's time. A clone is identified by its common dir's dev, ino, birth time and realpath. There is no backfill before on; that is a user decision, because backfill was the source of every consent hole the reviews found. Nothing is committed, so a teammate is never measured without running on.
  • Status. aidd telemetry status shows whether this clone is measured, since when, and its task.
  • First ingest. A transcript last written more than a day before the first on is not read: on a real 6.2 GB history the first ingest goes from over 22 minutes (never finished) to 246 s, the next takes 1.1 s, and the stored calls match an independent count (5 calls, 217,337 tokens).
  • Asking. One line to ask, one line to confirm a declaration, tried in a real session.
  • Tools. Ingest reads one reader per tool (its format and its transcripts). A second tool is its format, its source, one wiring line and its name; storage, attribution and the report stay as they are.
  • Opt out and forget. off closes the interval. forget previews first; with --yes it erases both versions' data and the git keys. The previous version's leftovers are cleaned on on.

🧪 How to verify

  • cd cli && pnpm test (6,448 tests), pnpm test:mutation:telemetry (96.2, floor 96), bash scripts/smoke-tools.sh; node --test 'scripts/__tests__/**/*.test.js' (434).
  • Whole journey on the built binary with the real hooks: telemetry-journey.e2e.test.ts. Consent scenario table: consent-scenarios.integration.test.ts.
  • Every rule has a scripted mutation that turns its test red: mutation-proofs.md.
  • Counting checked against an independent reader on a real history projected into a sandbox: 262,328 calls over 68 days, no day differing (real-history-oracle.md).

⚠️ Heads-up

  • Draft. CI is green on Linux and Windows, every tier including the end-to-end journey (run 38291026139, every mutation scope above its floor). macOS has no CI job: the full suite passes there locally. Windows is tested by CI only: a real session started from an 8.3 short path (RUNNER~1) was not tried, and neither was the cmd /s launch of an npm shim on a real install.
  • Presence. Asked in the terminal and the desktop app. Not in IDE extensions: VS Code shows no hook message. Declare there from a terminal; it binds the branch.
  • Residual limits are listed in the contract:
    • a manual git config off is not seen if no hook or ingest runs before the clone is deleted;
    • inode reuse where the file system keeps no birth time;
    • pid reuse;
    • clock skew;
    • on a file system with no birth time, a clone made again at a deleted one's path is told apart only once ingest has seen it;
    • where Linux refuses statx (seccomp, kernel before 4.11), the birth time Node reports is the change time, so the identity moves at each entry added to the git dir. The clone stops being measured; off also closes the interval its key names at its path, so it fails closed. Simulated (statx made to fail under strace): 0 of 36 rows stored more, 3 runs; before that change one row stored a call made after off.
  • Birth time on Linux. A birth time equal to the change time is kept as a birth. Treating it as no birth made the row "copy at the path" store one call too many on Linux, because the file clock is coarse. Measured in Docker, on btrfs: 3 failures in 150 runs at millisecond resolution, 5 and 8 in 300 at nanosecond resolution, 0 in 400 with the new rule. On ext4, as an unprivileged user: 81 in 200 with the old rule, 0 in 400 with the new (mutation-proofs.md).
  • Performance. At 265k records, ingesting one call takes about 3 s, because the whole month is rewritten. A declaration takes under 1 s, even while an ingest holds the lock.
  • Session id join, probed. The CI job identifier-join runs the installed claude -p against a dead API and checks, through the shipped hook predicates, that the hook's payload, its environment and every transcript line name one session, that CLAUDE_PID is set, and that a headless run never reads as a person present (probe-identifier-join.cjs). It holds on 2.1.295.
  • Bundle budget. Lowered from 734 KB to 667 KB, which is the measured 656 KB plus about 2 % (removing V1 freed the room).
  • Overlap. fix(aidd-telemetry): keep a worktree's sessions in every report, even after the worktree is removed #988 changes V1 telemetry code that this branch removes. A maintainer should decide the merge order.

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp

blafourcade and others added 30 commits October 9, 2026 14:31
The contract for replacing the previous telemetry: every billed Claude Code
call counted once, broken down by person, session, model, period,
repository, task and ticket, the task coming only from a declaration.
Carries the measurements, the common usage record and the prototype
readers with their mutation-proved fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
AIDD-Session-Id: 2c21d903-3a7e-47ac-83f8-d8b7ae3aa579
Removal of the previous telemetry first, then count, store, declare,
ask, attribute and report, opt-in and cleanup, and the end-to-end
proof. Pins the consent key, the binding snapshots, the hook guards
and a mutation per rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
AIDD-Session-Id: 2c21d903-3a7e-47ac-83f8-d8b7ae3aa579
The previous measurement is replaced by a deterministic, declaration-attributed
one in the following commits of this branch. This commit removes the old one so
nothing half-describes the new one.

cli: delete the telemetry context, its wiring, command, displays and tests, and
everything that existed only to serve it: the measurement vocabulary, the
per-tool telemetry declarations and transcript locations, the git adapter that
installed the commit-trailer hook, the identity and sink resolvers, the
FileWriter chmodExecutable method and the run-journal gitignore entry. The
OpenCode hooks bridge no longer names the deleted plugin module in its
generated comments; the framework build golden is re-baselined for that one
line. Architecture guards, biome overrides, mutation scope, smoke steps and the
help golden describe the CLI that remains.

plugins: delete the aidd-telemetry hooks and skills (README reduced to a stub,
manifest description updated). Remove the backlog-link.json step, reference and
template from aidd-pm:04-spec and aidd-dev:01-plan, the backlog-link paragraph
from the SDLC frame, and every aidd:step-end echo with the SDLC, async-dev and
backlog "Say when this orchestration is over" sections.

scripts and CI: delete the telemetry script tests, their fixtures, the two
telemetry scripts, the generated prompts documentation and its lefthook job,
the prepare-commit-msg trailer job, the journal replay, telemetry check and
telemetry e2e exclusion in cli-ci.yml, and the identifier-join probe. Tests
that used the telemetry plugin as a byte fixture read aidd-context instead.

docs: delete the cost-report and metrics contracts and aidd_docs/runs/, rewrite
every memory, README and docs line that claimed the previous telemetry, and mark
the pending telemetry task folders of 2026_09 as superseded.

The previous version's on-disk locations are recorded in
aidd_docs/tasks/2026_10/2026_10_09_deterministic-tokens/context/previous-version-leftovers.md
for the opt-in and forget phases.

BREAKING CHANGE: the aidd telemetry commands, the aidd-telemetry hooks and skills, backlog-link.json and the AIDD-Session-Id commit trailer are removed; measurement returns, for Claude Code first, later on this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Read Claude Code transcripts into one usage record per billed model call.

- key message.id:requestId, or message.id:sessionId:timestamp without a request id
- drop the synthetic model; isSidechain or agentId makes the call a subagent
- cache_write and cache_write_1h are summed over the message iterations; the
  one-hour part is unknown when any iteration lacks its split
- each advisor iteration is its own record, keyed <key>#advisor<n>
- an unrecognised shape is reported and never guessed; an unknown counter is
  null, never 0
- global fold across every file: largest total, then earliest time, then
  lowest session id, independent of input order
- source: recursive walk of the projects root including subagents and
  *.jsonl.superseded-* set-asides, byte-offset reads, an unterminated last
  line is left unconsumed, a shrunk or replaced file is re-read whole

Re-adds the telemetry context to the architecture guards (public modules,
biome layer overrides, codebase map, mutation scope, tool-name baseline).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Add `aidd telemetry ingest`: read what every Claude Code transcript gained
and store each billed call of the projects that opted in.

- ledger: <telemetry dir>/ledger/<YYYY-MM>.jsonl by the record's own UTC
  time; a changed partition is rewritten by temp file and rename, so a
  better snapshot of a call replaces the held one even across months and no
  reader meets two live records or a torn line
- idempotent: held records fold first, so an equal record changes nothing;
  the phase 3 fold decides every replacement, in any order
- lock: ledger/.lock holds pid and creation time, created exclusively; a
  dead pid or a lock older than ten minutes is cleared, a live recent one
  is waited for and released only by its owner
- repository: git rev-parse per working directory, id = sha256 of the
  normalised host/owner/repo of origin (https, ssh, scp-like, credentials,
  port and .git dropped), else the lowest root commit; a linked worktree
  resolves to its main repository
- consent: .aidd/config.json telemetry.enabled with version 2; the previous
  bare enabled is not consent; an unparseable file is counted; the main
  working tree answers for a worktree without its own file;
  AIDD_TELEMETRY=0 refuses before anything is read or written
- roots.json remembers each directory seen alive, so lines from a deleted
  one still resolve; one never seen alive is counted, not stored
- bindings/branches.jsonl snapshots branch.<name>.aiddTask|Ticket|DeclaredAt
  with the branch's creation time from its reflog, only when it changed
- write order under the lock: ledger, roots, snapshots, offsets last
- owner-only storage: 0700/0600 on POSIX, icacls on Windows
- coverage counters in the ingest result, by reason not stored

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
aidd telemetry task <name> [--ticket <ref>] | --none binds the running Claude
session from now on and, on a working branch, the branch itself through its
git config, then snapshots the declaration at once. The default branch and a
detached head are left untouched. A project that has not opted in to version 2,
or AIDD_TELEMETRY=0, is refused. With no argument the command shows what the
work is bound to and where that comes from.

The format the CLI writes and the plugin hooks read is pinned by one shared
fixture under scripts/__tests__/fixtures/telemetry-bindings/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Three Claude-only hooks, inert unless the project opted in: a prompt gate that
answers a typed declaration without the model and asks once on an unbound
working branch when a person is present, a session-start that keeps the task
across /clear and /branch, and an async catch-up that runs the ingest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
aidd telemetry report reads new transcripts, then splits what the stored
calls consumed along total, person, session, model, day (UTC), repository,
task or ticket, four counters apart, every axis summing to the same
totals. An unknown counter is left out of its sum and counted, never added
as zero.

Attribution is one pure function: the session's declaration at the call's
time, else its carry, else the branch's declaration from the snapshots
(from the branch's creation, so declaring late moves earlier work), else
unattributed with the reason. The first declaration in a carried session
applies to the whole session. Sub-agent and advisor calls follow their
session.

aidd telemetry identity <id> writes {person_id} to identity.json in the
telemetry directory, owner-only; --off removes it. Nothing is carried over
from the previous version's file.

Ingest also reports when the oldest transcript still on disk was last
written, for the coverage line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Attribution read only the latest snapshot of a repository and branch name,
so a branch deleted and created again under the same name took the older
generation's calls to the new task, or to none. Snapshots are now read as
generations told apart by branch_created_at: a call belongs to the youngest
generation created strictly before it, and within that generation to the
latest snapshot, so declaring late still moves its earlier work. A snapshot
with no creation time speaks only when no dated generation matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
`on` writes consent at version 2, removes the previous version's commit
hook line with its script, run journal and ignore entry, and resets the
ledger offsets and remembered consent so earlier history is stored once.
`off` switches off and keeps the version. `forget` previews, and with
--yes erases both versions' files and declaration keys under the lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Two thin skills over the CLI: 00-init opts in after consent, sets or
removes the identity and forgets with a preview; 01-usage maps a question
to report flags and reads the JSON without computing a figure. A test
checks every command they name against the help golden.

The usage contract, the plugin README and the CLI memory describe the
record, the version 1 envelope, the stores and the ask and carry rules.
Stale mentions of the replaced measurement go, the smoke harness covers
the telemetry commands, and the bundle budget is set to the measured
build plus 2 %.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Opt in, get asked on an unbound branch, declare by typing it, clear and
keep the task, run a headless session, then check that every report axis
adds up to the total and lands on the declared task and ticket. The real
hooks run through an aidd shim, a .cmd on Windows and a node script
elsewhere, with no AI tool binary on PATH.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The built CLI and the prototype's independent reader counted the same
projected history: 2,746 files, 262,328 records, 68 days, no day
differing. The usage record's branch comment now says what attribution
does with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
C1: partitioning is linear, an ingest rewrites only the months that
changed, declarations and snapshots take a bindings lock and never wait
on the ledger lock.
C2: on lifts a remembered refusal for every directory of the repository.
W1: ordinary prompts that look like a declaration pass the gate.
W2: a branch redeclaration applies from its own time.
W3: consent is the clone's git config aidd.telemetry, never committed.
W4: cmd.exe /s command line, and the hook home matches the CLI's.
W5: mutation proofs recorded.
Minor: stale context docs, superseded old plan, report wording, dead
attribution reasons, V1 config block removal, forget wording, next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
…re remembered as

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
A call is stored only if its directory was seen alive in clone X, X is
the clone answering now (or the remembered X once it is gone), and X's
consent covered the call's time. A clone is its git common dir's
dev, ino, birth time and path; consent is a history of intervals kept
beside the ledger, opened by on, closed by off or by an ingest that
finds the key changed or the clone gone.

roots.json becomes format 2: one entry per directory and clone, no
consented flag. forget names only gone clones that had consented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The identity comment now cites the Node Stats documentation and the
libuv sources it was read from, and drops a claim about FAT and network
shares that no source gave. The proofs file states what was observed:
the damaged-month mutation at its stated scope and without the new
assertion, and row 12 at the old code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
blafourcade and others added 15 commits October 11, 2026 21:17
Where Linux refuses statx, the birth time is the change time, so a
clone's identity moves with each entry added to its git dir, the
key write of `on` included. `off` closed only the interval of the
identity it read, and a call made after it could be stored.

It now also closes the open interval its key names when that interval
was opened at the same path. A copy elsewhere carries the token, not
the path, and is left alone. With statx refused, 0 of 36 consent rows
store more, 3 runs; with statx, 36 of 36 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The identifier-join job lost its probe with the previous telemetry.
This one runs claude -p against a dead API and judges, through the
shipped hook predicates, that the hook's payload, its environment and
every transcript line name one session, that CLAUDE_PID is the hook's
parent, and that a headless run never reads as a person present.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The pending telemetry plans of August are superseded by this one.
The mutation proofs record the off fix and the probe, and the oracle
note names the one guard added to the transcript reader since.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The hook takes CLAUDE_PID and falls back to its parent pid only when
it is unset, so the probe now fails only when CLAUDE_PID is gone, not
when a shell stands between Claude and the hook. Its git init no longer
inherits GIT_* from a git hook, its temp dirs are removed, and the job
runs when the probe or the hook predicates it uses change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The identifier-join probe's first CI run showed a shell between Claude
and its hooks on Ubuntu: CLAUDE_PID 2565, hook parent 2588. The parent
pid only stands in when CLAUDE_PID is unset; the comment now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Removing the previous telemetry's fields from the cursor profile took
killed mutants with them, and the tools-cursor score fell to 96.8,
under its 97 floor. The surviving mutant on the agent name's .md is
real: an agent named read.md-first.md lost its inner .md. Five of the
others are equivalent. Score now 97.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Observed with the maintainer: the terminal and the desktop app set
ATTENDED=1 and show a block's reason; the VS Code extension sets no
ATTENDED and shows neither a reason nor a systemMessage, so a block
there would eat the prompt silently. The presence rule now names the
two surfaces seen to show the reason, cli and claude-desktop, instead
of any entrypoint not starting with sdk, which would block a surface
never seen. Each condition has a mutation that turns its row red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The spec asked every surface where a person can be present, the IDE
extension included. The extension shows no hook message, so it is not
asked: recorded as a deviation in the spec and the plan, and the README
tells a VS Code user to declare from a terminal, which binds the
working branch. Three documents still stated the sdk rule. The presence
matrix now judges every row before failing, so each mutation names all
the rows it turns red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
IDE extensions in general, not VS Code alone: the rule asks only the
terminal and the desktop app, and VS Code is the extension observed.
The README section becomes a table and two bullets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Ingest held Claude's reader directly. A reader is now a tool's
transcripts and its line format, and ingest reads a list of them: a
second tool is its format, its source and one wiring line. Each reader
hands back its own files' positions, laid over the ones held, so no
tool undoes another's and a file no longer listed keeps its place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
`aidd telemetry status` says whether this clone is measured, since
when, and the task its work is bound to; not measured is an answer,
exit 0. `task` with no name used to show that and now refuses,
pointing at status, so each command does one thing. Bare
`aidd telemetry` already prints the group's help.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
With `task` declaring only, a bare `aidd telemetry task` typed as a
prompt would have run the CLI to be refused. The hook now treats it as
a declaration it does not understand and shows the usage, without
running anything. The end-to-end checks of what work is bound to now
go through `status`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Conflicts resolved:
- lefthook.yml: next's one-line catalog job (#998) kept; the telemetry
  prompts-doc job and the prepare-commit-msg trailer job stay removed,
  with the trailer delegate script next added for them.
- cli/tests/e2e/helpers.ts: both sides' imports.
- README.md and architecture-rules.test.js: counts measured on the
  merged tree, 51 skills and 48 skills with actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
…d a tool

The privacy contract and the CLI memory listed the commands without
status. The memory now says what adding a tool takes: its format, its
source, one reader in the wiring and its name in USAGE_TOOLS. The
two-reader ingest test gives the second reader another tool's name,
and the not-measured lines all start the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The smoke script lists every command the binary has and fails on a
drift; status was missing, and is now run after a declaration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
blafourcade and others added 11 commits October 12, 2026 11:08
Tried in a real session: the ask was five lines, and the confirmation
of a declaration showed the CLI's whole output inside Claude's
"blocked by hook" frame, which read as still blocked. The ask is now
one line naming the one way that always works, the declaration typed as
the next prompt: a terminal's `!` runs whatever `aidd` its PATH holds,
not the one the hook found. A declaration is confirmed in one line that
says to send the prompt again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
A first ingest after `on` read the whole Claude history and asked git
the repository of every old call, though none could be stored: over 22
minutes on a 6.2 GB history, never finished. A transcript last written
more than a day before the first consent interval opened is now not
read, and its position is set to its last complete line, so what it
gains later is read. The day absorbs a file clock that lags the call
clock. Same history: 246 s for the first ingest, 1.1 s for the next.

What is stored does not change: a test ingests the same transcripts
with and without the skip and stores the same records, and on a real
session the stored calls match an independent count (5 calls, 217,337
tokens). Pre-consent calls are no longer counted under a reason, and
forget may leave a hand-set key in a clone that never ran `on`; the
contract says both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Conflicts resolved:
- cli-ci.yml: next's Windows architecture step kept; the commit
  trailer end-to-end it named stays removed with the previous telemetry.
- runtime/wiring/framework.ts: next's recipe validation kept; the
  previous telemetry's spread stays removed, telemetry is wired whole.
- bundle budget: measured on the merged tree, 675.2 KB, budget 689 KB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Brings #1003, which restores Stryker's per-test filtering under Vitest 5
(#912): without it, mutants survive with no test run, and the telemetry
and presentation scores fell under their floors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The earliest interval of any clone decides, a damaged consent log
reads everything so each call keeps its reason, and a read that was
not skipped says so. The first interval is now Math.min of every
start, infinity when there is none, with no separate empty case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
The presentation mutation score fell to 94.0 once next's recipe
validation joined this branch's telemetry commands, whose descriptions
no test of that scope read. Each subcommand's help is now compared with
the help golden, and four commands are shown to report a failure and
exit 1. Score 95.1 against a floor of 95.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
With no clone opted in, ingest reads no transcript, so every count is
zero and the usage skill could not say why: it now names that case. A
test chains no consent, `on`, then a grown transcript, and only the
new line is read. The contract states a network file clock lagging by
over a day and transcripts copied from another machine, and the hook's
refusal of unsafe characters says ASCII.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Brings the sharded mutation CI (#1007). Conflict: the telemetry scope
keeps this branch's globs and floor (96) and takes next's 3 shards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants