Repository navigation
calls.jsonl records the call site's tag but not the lane.Role it was routed under, so a watched task step and an unwatched one are the same row #928
Description
What is wrong
calllog.Record — the row every model call writes to ~/.aforge/logs/calls.jsonl —
carries a tag (the call site's own word for the errand) and does not carry the
lane.Role the call was actually routed under.
The role is the thing that decides how the call was routed: λ, the quality bar, the
exploration horizon and — the one a person feels — Visible, which is the whole of the
watched/unattended split. It is in the context at the moment of the call
(provider.WithRole), and it is dropped on the floor before the row is written.
So anything that reads the log back has to reconstruct it, and reconstruction is lossy
in a way that cannot be repaired from the file:
RoleLeafAttachedandRoleLeafUnattendedwrite the same tag,task.
internal/session'slaneRoleaskssomeoneIsWatching()at the moment of the call and
nothing records the answer. A watched task step and an unwatched one are
indistinguishable in the log, and they differ in exactly the field that decides whether
a person's seconds were being spent.- The tag vocabularies do not line up.
internal/session/auxiliary.gowrites
string(role)for aninternal/roles.Role;cmd/aforge/chat.go'serrandContext
writes the errand's name (title,distill,quorum,craft-params, …);
internal/session/toolask.gowritestool:<tool>. Three vocabularies, one column,
and thelane.Rolethat all three already had in hand is in none of them.
Replication
A stranger can run this with no private data:
go test ./cmd/aforge-replay/ -run TestEveryTagTheBuildWritesResolvesToARoleSomebodyDeclared -vThat law walks the tree for every tag the build can write and fails on one the replay's
callSiteRoles table does not name — it is the stopgap standing in for the missing
column, and it exists only because the column is missing. Delete a row from
cmd/aforge-replay/request.go's callSiteRoles and it goes red, naming the tag.
The join itself is roleOf in cmd/aforge-replay/request.go, whose doc comment says it
is "the first thing to delete when the role reaches the row".
Acceptance
End-to-end, through the door the product uses:
calllog.Recordgains arolecolumn (json:"role,omitempty"), filled from the call
context the same waytagis (internal/provider/calllog.go'scallTag, beside it).- An untagged test drives a real call through
internal/providerwith
provider.WithRole(ctx, lane.RoleLeafAttached)and asserts the written JSON line
carries"role":"leaf.attached"— notleaf.unattended, which is the reading every
reader of the log is forced into today. cmd/aforge-replay'sroleOfand its wholecallSiteRolestable are deleted, and
TestEveryTagTheBuildWritesResolvesToARoleSomebodyDeclaredwith them; the replay reads
row.Roledirectly. A mixed log (ten days of rows with norole) still replays — the
old rows read asRoleUnknownand the report says how many.
Why it matters now
cmd/aforge-replay (#922) reports mean regret per role class over the real log, and the
watched half of that table is built on this guess. Its task numbers are a floor on
how bad a watched task step was and can never be a ceiling, and the report has to say so
instead of printing a number.
Evidence
PR #922, cmd/aforge-replay/request.go roleOf / callSiteRoles;
internal/calllog/calllog.go:125 (the tag field's own comment);
internal/session/auxiliary.go:196; cmd/aforge/chat.go:5795;
internal/session/toolask.go:121; docs/design/recovery/census-20260910.md §8 finding 9,
which is the last time the missing tag cost somebody an answer.
Drafted with CodeAF · reviewed and owned by the author
Activity
replay: the incident table is keyed on the request, and two laws that…
replay: the incident table is keyed on the request, and two laws that…
replay: the chooser is judged by regret on ten days of log, not by a …
session: the two holding actions name the issue that deletes them
auxiliary inventory: every request says what it is for, a dead role g…
AbirAbbas commentedon Sep 16, 2026
Closing as a duplicate of #1010, which carries this exact change as its section 2 ("the lane role rides on the record"):
lane.Roleon everycalllog.Recordrow, and deletion of replay's hand-kept tag-to-role table.Nothing here is fixed yet. On
devat77293538cthe record still hasTagand no role field (internal/calllog/calllog.go), andcmd/codeaf-replay/request.gostill carriesroleOfandcallSiteRoles. The work survives in #1010, which PR #996 names as the follow-up that holds it.