Skip to content

feat: authors() - the write history as attribution reads it - #49

Merged
vreshch merged 1 commit into
masterfrom
feature/log-view
Aug 23, 2026
Merged

feat: authors() - the write history as attribution reads it#49
vreshch merged 1 commit into
masterfrom
feature/log-view

Conversation

@vreshch

@vreshch vreshch commented Aug 23, 2026

Copy link
Copy Markdown
Member

Adds ONE read-only verb to VaultStore: authors(): Promise<AuthorStat[]> - who has written in this vault, how often, and when last. It is the read side of the attribution write/edit already record, and it is what an account-level memory overview needs to answer "which AIs write here".

Why this shape, and not a commit log

The alternative was log(opts?: { limit? }) -> CommitInfo[] with the host aggregating. authors() won on four counts:

  • The in-memory store can implement it honestly. A commit log means an in-memory store retains one record per write forever - a store whose whole point is being a light fixture would grow without bound. A tally is one row per client, so both stores keep the history the contract asks them for and nothing more.
  • The counts are exact. A limit makes writes a count over a truncated window, which is a lie on a busy vault. There is no window here.
  • The signature has no options, so there is no cache-by-limit, no cursor question, and the version cache is a single slot beside describe()'s.
  • No product policy enters the engine. Active windows, initials, badges and display order stay in the host - the engine answers who wrote, how often, when.

The spawn budget is the same either way: one git log.

The contract (pinned by the conformance kit)

  • Attributed changes only. A write with no author, a delete, and a commit that arrived out of band (a push from a person) carry no client and appear in no row.
  • A change is what the store recorded. A no-op write makes no commit, so it counts for nobody.
  • Order is pinned: writes desc, then author.id asc - a total order that never reads a clock, so two stores holding the same history agree. Both stores date to the second, so a clock-ordered contract would be untestable across them.
  • lastAt is a strict ISO 8601 instant. writes/lastAt cover the history the store retains (git: every commit; in-memory: what the instance has seen - capabilities().versioned says which).
  • Never provisions, never mutates, never emits. Hands out a copy, so a caller cannot poison the cache.

How the bare store answers it

gitAuthorOf already stamps the connected client as the git author (<id>@clients.agentage.io) and leaves the committer to the system. clientAuthorOf is the exact inverse, and both directions now sit in commit.ts, so there is no second bookkeeping: authors() is one git log --reverse pass, and a restored clone answers exactly like the store that wrote it (tested). A pushed commit carries a human's identity and belongs to no client (tested).

--reverse is not cosmetic: both stores feed the shared tally chronologically, which is what makes the same-second tie rule ("latest wins") mean the same thing for a live tally and for a log.

Cost

One git log per version, cached in the slot beside the vault card, so a page of memory cards pays for it once.

Verb Warm spawns How
authors() 0 one git log pass per version, then cached like the card

Verified

npm run verify green: type-check, lint, format, 301 tests, coverage 97.5 / 88.4 / 98.4 / 99.1 (floors 70), build, dist smoke (extended to exercise the new verb through dist/).

New perf row on the commit-count axis, where this verb actually lives - it is indifferent to note count. The churn fixture now attributes two of every three commits to a client, so the pass has something to aggregate:

metric measured budget
churned authors (cold) 5.9ms 2000ms
churned authors warm avg 0.2ms 2ms

Notes for review

  • authors() is on VaultReader, so it is a required method - same shape of change as readMany in 1.1.0, and a minor bump for the same reason.
  • The Router is untouched: nothing routes by ref here, and the host composes over container.open exactly as it does for describe().
  • Do not bump the version - the coordinator releases 1.3.0.

One read-only verb on VaultStore: who has written in this vault, how often,
and when last. Conformance-first, both stores.
@vreshch
vreshch marked this pull request as ready for review August 23, 2026 10:00
@vreshch
vreshch merged commit 0085c49 into master Aug 23, 2026
1 check passed
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.

1 participant