Prove · Accountability ledger
Trace a defect back to the session that shipped it
The Accountability ledger fuses seven records RepoOps already keeps into one plain sentence per loop: a session shipped a pull request, it introduced a defect, and a lesson now guards it. It captures nothing new, and it makes no model call to do it.
For: the engineer closing out a defect, and the lead who has to show what the team learned from one
What it does, and why it helps
Open the tab and you get one story per accountability loop over the last 90 days. Each story is a sentence built from records that already exist: a session and its tracked cost, the commit it authored, the pull request it shipped, the defect that commit introduced, the production incident that followed, and the lesson that now guards that defect. Press Trace chain and the sentence expands into the chain left to right, each hop carrying the confidence band its producer recorded (exact, strong, weak, likely or unattributed). The page does not draw the whole graph. Most of a real graph is commits, files and pull requests wired to each other, so it renders the accountability signal and puts the raw composition behind a disclosure labelled Raw graph (advanced), where you can draw the focused subgraph on demand.
A loop with no lesson reads open loop, and Save as lesson writes one into the repository's lessons store with the defect pre-filled. Below the stories, Closed loop: did the lesson work? takes each lesson a guard has applied, splits the merged pull requests at the first application, and reports the defect rate before against the defect rate after. Where either side has fewer than two runs the row reads not yet measurable rather than a rate. Recurrences appear in the same panel under the words the fix did not hold, because a lesson whose guard fired again is a fact the ledger owes you as much as a saving is.
The pain. Dollars saved and prevented counts are numbers in RepoOps's own store. Anyone who wants to check one has to walk git, the incident log and the lessons file by hand, and nobody does.
The point of view. A counter is not evidence. Show the loop that produced it, name the confidence band every hop was recorded at, and let the reader decide how far that band carries.
What gets easier. Reading one loop. The story names the session and its cost, the pull request number, the defect file and line, the incident, and the guarding lesson, and the chain behind it is one click away.
When it helps. Closing out a defect, reviewing a week through the Week audit view, or answering a question about what a team learned after an incident.
Its limits. It reads a fixed 90-day window, so an older loop is absent rather than empty. A recorded catch is not proof the defect would have shipped. Dollars saved is priced only when the lesson traces back through its causal link to a session with a tracked cost, and an event that cannot be priced is counted as unpriced, never as zero. The closed-loop number is a defect rate over merged pull requests, not a claim about prevention.
Understand it in 30 seconds
Read the narration
- 0:00 A dashboard shows dollars saved.
- 0:02 Nothing shows the work behind the number.
- 0:06 A counter is not evidence.
- 0:08 The ledger tells each loop as one sentence.
- 0:13 Every hop carries the confidence band its producer recorded.
- 0:17 Dollars saved is the tracked cost of the session that introduced the defect.
- 0:23 Open loops name themselves.
- 0:25 Where the history is thin, it reads not yet measurable.
Synthetic example. Read the guide
Where to find it
Where to find it
- Desktop:
localhost:4000. It has no sidebar row: open it from the palette, or go straight to its address. - Hosted:
repoops.ai/team/accountability, from Attribution in the sidebar, then Accountability ledger under All tools, in the Sessions, transcripts and traces group. - Keyboard: ⌘ K, then type “Accountability ledger”.
When to use it
An open loop nobody has guarded
Situation. A defect was attributed to the commit that introduced it, and the pull request merged weeks ago. No lesson names that defect, so nothing would flag it coming back.
What you do. Set the Show lens to Open (act now). Read the story, press Trace chain to see the hops and their bands, then press Save as lesson.
What you see. A dialog titled Save as lesson with three required fields, two pre-filled from the defect: Trigger: when does this recur?, What went wrong?, and Fix: what to do instead?. A blank required field refuses with All required fields must be filled.
What it establishes. The lesson is written to the repository brain and the page reloads with the loop no longer open. Whether that lesson changes anything is a separate question, answered by the closed-loop panel once there is run history on both sides of it.
Checking whether a lesson changed anything
Situation. A lesson has been applied several times and the summary card carries a dollar figure. Someone asks whether the defect rate moved.
What you do. Read the Closed loop: did the lesson work? panel. Each row carries the lesson trigger, the delta, how many times it was applied and since when, the runs after the boundary, and the graded band across those runs.
What you see. A measurable row reads as a before rate, an after rate and the gap in percentage points. A thin one reads not yet measurable. A rate that rose after application is shown as a rise, not hidden. The band reads agent, human or low-confidence with a percentage, never a yes or no.
What it establishes. Either a measured delta you can cite with its band, or a plain statement that the history is too thin. The panel never reports a rate it could not compute.
Before you start
- Supported versions
- RepoOps desktop v0.3.1, the release this guide was read against. The tab reads the repository brain and git in place, so a repository tracked in repos.config.json is the only prerequisite for the ledger itself.
- Where it runs
- Local: the Accountability ledger tab under Attribution, with the AI share, Knowledge Graph, Outcomes, Decision diff and Accountability leaderboard subtabs beneath it. Hosted: repoops.ai/team/accountability shows the team's last 30 days as two totals plus one entry per day that carried a measured saving. The hosted page never receives the per-loop chain.
- Permissions
- Local: none beyond opening the app on this machine. Hosted: the page is session-authed, the team comes from your membership, and the rollup is narrowed to the repositories you can see through resolveTeamRepoNarrowing. A personal repository never rolls up for anyone, the owner included.
- Connections
- None for the ledger, the week audit or the closed loop; each reads local records and makes no model call. ANTHROPIC_API_KEY on this machine only for the two prose passes at the bottom of the tab. The cross-repo panels need a second tracked repository before they have anything to say.
- Plan
- Free. The capability map lists the full accountability loop (caused-by trail, blast radius) at the solo tier, which is free local. Seeing the rollup on the hosted dashboard follows the hosted dashboard tiers.
Configure it
- Open the tab on a repository.
The page reads the repository from the query string and every endpoint it calls is scoped by it. Without one the API answers unknown repo, which is a 404, not an empty ledger.
- Narrow with the lenses.
Show offers All loops, Saved $ and Open (act now). Beside it, All time, 90d and 30d bound the window further, and the $ impact only checkbox keeps loops that saved money, recorded a catch, or caused an incident. When a filter empties the list the page says No loops match this filter and offers Clear filters, which is a different sentence from the honest empty below it.
- Switch to Week audit to read one ISO week.
The View control flips between Full ledger and Week audit. Week audit takes an ISO week picker with previous and next arrows and calls /api/accountability/audit?week=YYYY-Www over the same fused graph. A malformed week is a 400 naming the format; a week older than the 90-day read window is empty because it was never read, and the empty state says so rather than implying a quiet week.
- Act on an open loop.
Save as lesson opens the three-field dialog and posts to /api/lessons for this repository. View PR opens the pull-request record in the brain, View lesson jumps to the Lessons tab, and Trace chain expands the story in place.
- Read the panels below the stories before quoting a number.
Closed loop says whether an applied lesson moved the defect rate. Can the before-and-after be measured yet? reports the readiness gate and names what is missing. Commit coverage splits every commit in the window four ways, and its fourth bucket, No AI signal found, is what RepoOps cannot see rather than a claim that a person wrote the code.
- Only then, run the two prose passes.
Propose semantic edges and Propose new entities read the brain's prose and hold their output as proposals under .claude/brain/proposed/. Nothing enters the graph until you tick rows and press Approve selected. The edge pass falls back to a grounded co-mention distiller with no Anthropic key; the entity pass has no fallback and proposes nothing without one.
| Setting | Where | A sensible choice | Why it matters |
|---|---|---|---|
View: Full ledger or Week audit | Accountability ledger tab, the View control | Full ledger day to day, Week audit for a dated review | Week audit scopes the same fused graph to one ISO week, so a week with nothing in it is a fact about the week, not about the read. |
Show: All loops, Saved $, Open (act now) | Accountability ledger tab, the Show control | Open (act now) when you are closing defects | Open means a defect with no lesson naming it, which is the one state on this page you can act on directly. |
All time, 90d, 30d | Accountability ledger tab, beside Show | All time, which is already bounded by the 90-day read | The lens narrows what is already loaded; it cannot widen the window the server read. |
$ impact only | Accountability ledger tab, the checkbox on the lens row | off while reviewing, on while reporting | It keeps loops that saved money, recorded a catch, or caused an incident, and drops the rest. |
REPOOPS_ACCOUNTABILITY_ARTIFACT_MAX_AGE_MS | the data directory's .env | unset, which is 600000 (10 minutes) | The backstop age of the cached fused graph. A brain file change invalidates it at once through a stat-only signature; this backstop covers the git and database inputs a file stat cannot see. A value at or below the daemon capture cadence is clamped back above it. |
REPOOPS_EVENTS_RETENTION_DAYS | the data directory's .env | unset, which is 30 | The Partner receipts panel asks for 90 days and is clamped to this, so a receipt older than raw retention is absent rather than silently missing. |
REPOOPS_ATTESTATION | the data directory's .env | unset, which is armed | Signing runs unless you set 0. It gates POST /api/accountability/prevention-receipt, which signs one recorded ledger row and refuses any catch that is not already in the append-only prevention ledger. There is no control for it on the tab. |
ANTHROPIC_API_KEY | the data directory's .env | set only if you want the prose passes to use a model | The semantic edge pass runs without it on a co-mention distiller; the entity pass proposes nothing without it. Neither writes to the ledger. |
What you should see
A repository with loops in the window
Configuration. A tracked repository with causal links, merged pull requests and at least one lesson inside the last 90 days.
Expect. Four summary cards (measured $ saved by lessons, open loops, closed loops, and lessons in the graph, active and retired), a ranked list of stories with open loops carrying an incident first, and the lens row above them.
Verify. Press Trace chain on a story and count the hops against the sentence. Call GET /api/accountability/graph with the repo id and check that measured_saved_usd matches the first card.
A repository with nothing to hold accountable
Configuration. A tracked repository with no causal links, or none with a lesson, inside the window.
Expect. No accountability loops yet for this repo, with a line saying the graph fills in as sessions ship pull requests and defects get attributed to the commit that introduced them. The panel above reads No prevention proof yet, and names how many lessons are armed and guarding a real defect when any are.
Verify. The endpoint returns empty nodes and edges with measured_saved_usd 0. An honest empty is the expected answer here, not a fault.
An applied lesson with thin history
Configuration. A lesson applied at least once, with fewer than two merged pull requests on one side of the first application.
Expect. The closed-loop row reads not yet measurable, with the applied count, the date of first application, the runs after it, and the graded band all still shown.
Verify. lessonOutcomeLoop in the graph response carries defectDelta.measurable false for that lesson. MIN_SIDE_RUNS in lib/lesson-outcome-loop.mjs is 2.
Data and cost
- What is captured
- Nothing new. The graph is a read-side projector over records seven other features already write: causal links, incidents, lessons and prevention events in the repository brain (.claude/brain/causal-links/, incidents/, lessons/, prevention-events.jsonl), intent specs in .claude/brain/intent/, merged pull requests from git, session outcomes from the local database, and partner events under the events/partners/ partition. Each producer read is bounded at 500 rows.
- Who can see it
- Local by default; the page runs against the local aggregator. The hosted team page shows a redacted rollup built from outcome events the desktop already streams: a money-saving outcome count, dollars saved, and one ledger entry per day that carried a saving over the last 30 days, scoped to the repositories the viewer can see. The per-loop chain, the file paths, the session ids and the lesson text stay on the machine.
- How long it is kept
- The ledger reads a fixed 90-day window and the artifact cache holds the fused result for at most 10 minutes. Neither is a retention rule: the underlying JSONL files are append-only and stay on disk after they leave the window. Partner receipts are clamped to raw events retention (REPOOPS_EVENTS_RETENTION_DAYS, default 30). The hosted rollup covers 30 days, and a window holding more than 5,000 events counts the most recent 5,000 and says its totals are a floor.
- What leaves the machine
- None for the ledger, the week audit, the closed loop, the readiness gate, the cross-repo panels or the coverage split. The two prose passes call Anthropic on your own key when one is set, and their spend is recorded in the local metered ledger. The hosted rollup reaches the team through the outcome events the desktop publishes, not through this tab.
- What it costs
- No model call, so no cost, for everything above the Semantic layer heading. The two prose passes are the only priced work on the page; they run on demand, one call per press, on your key.
When the result differs
| Symptom | Likely cause | Next action |
|---|---|---|
| The page shows nothing and the API answers unknown repo. | The tab was opened without a repository, so no producer read is scoped. | Open it from the dashboard nav, or add the repo query parameter to the URL. |
| No accountability loops yet for this repo. | No defect is attributed to a commit in the window, or no lesson names one. | This is the honest empty. Attribute a defect from the Incidents or Security path, or write a lesson, and the loop appears on the next read. |
| A loop you remember is missing. | It falls outside the 90-day read window, or a lens is filtering it out. | Press Clear filters. If it is older than 90 days it is absent by design; no setting widens the window. |
| Every closed-loop row reads not yet measurable. | Fewer than two merged pull requests on one side of each lesson's first application. | Wait for run history. The panel reports a rate only when both sides clear the floor. |
| Can the before-and-after be measured yet? says not yet. | The readiness gate wants 5 incidents before the boundary, 5 after, and 1 catch by a guard the loop itself produced. | Read the blockers it lists; each names what is missing and how many you have. It never computes a partial number. |
| The stories are stale after a lesson was written elsewhere. | Git and database inputs are covered by the 10-minute backstop rather than the file signature. | Reload after the backstop expires, or lower REPOOPS_ACCOUNTABILITY_ARTIFACT_MAX_AGE_MS, which is clamped above the daemon capture cadence. |
| Propose new entities returns nothing at all. | No ANTHROPIC_API_KEY on this machine, and the entity pass has no keyless fallback. | Set the key, or use the edge pass, which falls back to a co-mention distiller. |
| The hosted page says no closed loops measured yet while the desktop shows loops. | The hosted rollup reads outcome events, not this graph, and your repositories may be narrowed or personal. | Check that the desktop is streaming outcome events and that the repository is not personal; a personal repository never rolls up. |
- Disable
- Not applicable as a switch. The tab reads and renders; it starts no schedule and writes nothing on load. To stop the two prose passes from spending, remove ANTHROPIC_API_KEY: the edge pass drops to its keyless distiller and the entity pass proposes nothing.
- Roll back
- Not provided, and nothing to roll back: no read on this page changes state. A lesson you wrote with Save as lesson is deleted or retired from the Lessons tab (DELETE /api/lessons with the lesson id, or POST /api/lessons/retire-guard, which takes a named human). A held proposal is discarded before approval and reports that nothing was written.
- Revoke access
- Not provided here. This tab mints no credential and holds no token. The hosted rollup's reach is the team membership and the repository narrowing on repoops.ai. Signing is turned off by setting REPOOPS_ATTESTATION to 0, which makes a signature honestly absent; it does not retract a receipt already issued.
- Delete
- Not provided. No route deletes a loop, a causal link or a prevention event. The data sits in the repository brain at .claude/brain/causal-links/, .claude/brain/incidents/, .claude/brain/lessons/ and .claude/brain/prevention-events.jsonl. A lesson is the one node with a delete route, from the Lessons tab; deleting it removes its guard from later loops and leaves the prevention rows that explain the count.
Related tasks
Maintenance evidence
- Feature id
accountability-graph(spine leafaccountability-ledger)- Owner
- Compounding Accountability Graph (MOAT M1), with the weekly audit (A3), the lesson-to-outcome closed loop (CNA.16) and the cross-repo panels (PAB.2). Guide: LDG-0717.
- Supported product version
- RepoOps v0.3.1
- Last verified
- 2026-09-15, read against origin/main at 52366bb6d; labels read from the served tab source (public/accountability-graph.html), the route table in lib/routes/accountability.mjs, the defaults in .env.example, and the hosted page at website/app/team/(home)/accountability/page.tsx.
- Example fixtures
- No fixture file; the producer rows are hand-built inline. lib/accountability-graph.test.mjs has 37 cases over the fused graph, the honest empties and the ISO-week filter; lib/lesson-outcome-loop.test.mjs has 10 over the before-and-after delta, the honest null and the graded band; test/lending-panel-direction.test.mjs runs the lending panel's own render over a real payload.
- Source references
lib/accountability-graph.mjs,lib/accountability-graph-cache.mjs,lib/routes/accountability.mjs,lib/lesson-outcome-loop.mjs,lib/continuity/cost-attribution.mjs,lib/lessons.mjs,lib/causal/benchmark-reality.mjs,lib/causal/prevention-receipt.mjs,lib/coverage/attribution-coverage.mjs,lib/partners/read.mjs,public/accountability-graph.html,website/app/team/(home)/accountability/page.tsx- Documentation review
- Independent review requested on the slice pull request; not yet recorded.
- Video review
- Story script written 2026-09-15; render and review pending in the same slice.
Last updated