Skip to content
Back to skills

Claim Ledger

ASecurity

Before opening a PR, enumerate every behavior it claims — stated, callers- unaffected, invariants-preserved — and tag each with the strongest evidence actually held: RAN, READ, or ASSUMED with a closed-set reason. Ship the ASSUMED residue in the PR description; log harness blockers durably. After review, reconcile each correctness comment against the ledger so misses are classified as harness / context / attention / lying-test with data, not vibes. Use when peers keep finding correctness bugs...

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 19, 2026
ai-agentsgobashgitapi

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add jamestexas/agents --skill claim-ledger --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Claim Ledger?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Claim Ledger
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jamestexas-claim-ledger/badge)](https://www.skillsdirectory.com/skills/jamestexas-claim-ledger)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: claim-ledger
description: >
  Before opening a PR, enumerate every behavior it claims — stated, callers-
  unaffected, invariants-preserved — and tag each with the strongest evidence
  actually held: RAN, READ, or ASSUMED with a closed-set reason. Ship the
  ASSUMED residue in the PR description; log harness blockers durably. After
  review, reconcile each correctness comment against the ledger so misses
  are classified as harness / context / attention / lying-test with data,
  not vibes. Use when peers keep finding correctness bugs you didn't, when
  the test harness is too hard to run so you read instead, or in a monorepo
  where blast radius exceeds what one head holds.
allowed-tools: "Bash,Read,Grep,Glob,Agent,Write,mcp__mache__*"
argument-hint: "build [base-branch] | reconcile <PR number | owner/repo#N>"
---

<!-- Author: jamestexas — drafted by Claude (2026-09-02) from a diagnostic
conversation, NOT a reference run. Every calibration below is a hypothesis
until the first `reconcile` produces a tally; promote or delete on evidence,
and replace this note with real provenance when you do. -->

# claim-ledger — every PR claim, tagged with the evidence you actually hold

The spine, one question:

> **For each behavior this PR claims, what is the strongest evidence I hold
> that it is true — and would I publish that evidence class next to the claim?**

When you wrote code by hand, verification happened in your head while typing.
When an agent writes it, that step has no home: the agent produces, you read,
and the first real execution happens in a peer's head during review. That is
why they find bugs you didn't. This skill gives verification a home *before*
the PR opens, and — the part that matters more — tells you afterward **which
kind** of miss each review comment was.

`self-audit` asks "is this diff clean?" `test-fidelity` asks "do these tests
constrain the code?" This skill asks "what did I actually verify, and what
did I merely believe?" It does not replace either; it wraps them.

## Evidence classes

| Tag | Means | Requires |
|---|---|---|
| `RAN` | Executed against real code, observed the outcome | Command, exit code, output captured under `commands/` |
| `READ` | Traced without executing | `file:line` citations, or a fresh-context adversarial verdict on *this claim* |
| `ASSUMED` | Not verified | Reason from the closed set below + one line naming the blocker |
| `UNLISTED` | *(reconcile only)* A reviewer found a claim you never enumerated | — |

**ASSUMED reasons (closed set):**

- `harness` — could not execute: needs creds / a cluster / 40 minutes / is
  flaky. Name the exact blocker.
- `context` — do not know what a consumer or sibling package assumes. Name
  the consumer.
- `budget` — chose not to. Say so plainly.

## Iron rules

1. **Correlated evidence does not upgrade.** A test written in the same
   session as the code it tests shares that session's misunderstanding. It is
   `READ` until it passes `test-fidelity`'s spine question. Green is not
   `RAN`.
2. **Every claim carries exactly one tag.** Rows start as `ASSUMED` and are
   upgraded by evidence. An untagged claim is a lie of omission; the ledger is
   complete or it is not a ledger.
3. **Reasons are a closed set.** Free-text reasons do not aggregate, and
   aggregation across PRs is the entire point of `reconcile`.
4. **The residue ships.** The `ASSUMED` block goes into the PR description
   verbatim. Discomfort about publishing a row is the signal to go discharge
   it — never to delete it.
5. **`build` without `reconcile` is a checklist.** `reconcile` is what turns it
   into measurement. Skipping it is how you end up guessing "harness vs.
   skill" for another quarter.
6. **Durable directory, never session tmp.**
   `~/claim-ledgers/<org>-<repo>/<branch>/` with `ledger.md`, `residue.md`,
   `commands/`. Session scratch gets garbage-collected mid-run; that failure
   is already on the books in `counterfactual-audit`.

## Where claims come from — three sources, all mandatory

**1. Stated.** PR title, description draft, every commit message. Each verb
phrase is a claim ("retries on 5xx", "no behavior change for existing
callers"). Negative claims count double — "backward compatible" is the claim
most often assumed and least often run.

**2. Callers-unaffected.** Every changed exported symbol implies "existing
callers still behave." Enumerate callers with `mache` (`find_callers`,
`get_impact --max-depth 2`); fall back to `rg -w <Symbol>` with the
unqualified-call discipline from `counterfactual-audit` pass 2. Cluster by
consuming package: **one claim per consuming package**, not per call site.
This is where monorepo breadth becomes finite — a claim list, not a feeling.

**3. Invariants-preserved.** For every touched package read the nearest
`AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, or invariants doc. Each stated
invariant the diff could plausibly violate is a claim. **If a touched package
has no such file, record that as a row** — it is an `UNLISTED` finding
waiting to happen, and `reconcile` will tell you to write it.

**Size calibration.** A reviewable PR yields 5–20 claims. More than 20 → the
PR is too big; stop and run `work-scope`. Fewer than 5 on a 300+ line diff →
you are under-enumerating; go back to source 2.

---

## `build` — before the PR opens

### Step 0 — Resolve and set up

```bash
BASE="${1:-main}"
SHA=$(git rev-parse HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
ORG_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner | tr '/' '-')
LEDGER_DIR="$HOME/claim-ledgers/$ORG_REPO/$BRANCH"
mkdir -p "$LEDGER_DIR/commands"
git diff --stat "$BASE...HEAD"
git log --format='%h %s%n%b' "$BASE..HEAD"
```

### Step 1 — Enumerate

Write `ledger.md` with every row from all three sources, **all tagged
`ASSUMED`**, before discharging any of them. Enumerate first, discharge
second; interleaving means you fix the first row and never finish the list.

```markdown
| # | Claim | Source | Tag | Evidence / reason |
|---|---|---|---|---|
| 1 | Retries on 5xx up to 3× with backoff | stated | ASSUMED | — |
| 2 | pkg/ingest callers of `Fetch` unaffected (14 sites) | callers | ASSUMED | — |
| 3 | `AGENTS.md`: writers never hold the lock across a network call | invariant | ASSUMED | — |
| 4 | pkg/export has no invariants doc | invariant | ASSUMED | context: none exists |
```

### Step 2 — Discharge, highest blast radius first

Sort by caller count descending. For each row:

**Try `RAN`.** Is there a Taskfile target or test that exercises *this
claim*? Run it. Capture stdout/stderr and exit code to
`commands/<row>-<slug>.txt`. If the test was written this session, it stays
`READ` until `test-fidelity` says it constrains the code (rule 1).

If the harness blocks you — needs a cluster, needs creds, takes too long,
flakes — **write the blocker verbatim as the `harness` reason and move on.**
Do not fight the harness during `build`. An hour lost to a flaky integration
suite is an hour not spent on the other 14 rows. The gap log (step 4) is where
that hour gets repaid, as its own PR.

**Else `READ`.** Trace by hand and cite `file:line` for the path that makes
the claim true. Or dispatch a **fresh-context** subagent — never a fork, which
inherits the writer's assumptions — scoped to this one claim:

> Here is a diff and one claim about it: `<claim>`. Find the input, caller,
> or sequence under which the claim is false. Cite file:line. If you find
> nothing, say "holds" — do not manufacture concerns.

The reader is uncorrelated with the writer. That is its only value; a
"holds" from the same context that wrote the code is worth nothing.

**Else `ASSUMED` stays**, with its reason.

### Step 3 — Emit `residue.md`

This block goes into the PR description **verbatim**. Flat tone: it is a map
for the reviewer, not a confession.

```markdown
## Verification

RAN (n): #1 retry/backoff (`task test:pkg/client`), #2 …
READ (n): #3 lock invariant (traced `writer.go:88-114`; adversarial pass: holds)

### Not verified — reviewer attention here
- [harness] #5 export job end-to-end — blocked by: integration suite needs a live GCS bucket
- [context] #7 pkg/billing callers of `Amount` — unknown: whether billing rounds before or after
- [budget] #9 log line format — chose not to; cosmetic
```

### Step 4 — Log harness gaps durably

Every `harness`-reasoned row is appended to
`~/.claude/skills/claim-ledger/harness-gaps.jsonl` — outside any git repo:

```json
{"ts":"2026-09-02","repo":"org/repo","blocker":"integration suite needs a live GCS bucket","claim":"export job end-to-end"}
```

Three hits on the same blocker is a bead. That backlog *is* the platform
work; the fix is almost always `taskfile-ci-parity` on the top entry.

### Step 5 — Stop

`build` produces no fixes. Findings during discharge become new commits
*after* the ledger is complete (`self-audit`'s no-amend rule applies), and
the ledger row is re-tagged when they land.

---

## `reconcile` — after review, mandatory

### Step 1 — Fetch correctness comments

```bash
N=<pr>; OWNER=<org>; REPO=<repo>
gh api "repos/$OWNER/$REPO/pulls/$N/comments" \
  --jq '.[] | {path, line, user: .user.login, body}'
gh api "repos/$OWNER/$REPO/pulls/$N/reviews" \
  --jq '.[] | select(.body != "") | {user: .user.login, state, body}'
```

Keep comments about **behavior** — wrong output, missed case, race, broken
caller, violated invariant. Drop nits, style, naming, and bot output (list bot
logins in the extensions file). When a comment is ambiguous, ask the user
**one** question, not a battery.

### Step 2 — Map each comment to a ledger row, or `UNLISTED`

### Step 3 — Classify and act

| Landed on | What it means | Action |
|---|---|---|
| `RAN` | Your verification lied | Dispatch `test-fidelity` on that test. It is theatre until fixed. |
| `READ` | Reading missed it | Record diff size and whether a fresh-context pass ran on *that row*. This is the attention signal. |
| `ASSUMED` | The system worked — the reviewer looked where you pointed | No fault. Count it. If `harness`-reasoned, the gap-log entry gets a hit. |
| `UNLISTED` | You did not know it was a claim | **Write the invariant** into the nearest `AGENTS.md`/`CLAUDE.md` for that package — in this PR or a follow-up. This is the context loop closing. |

### Step 4 — Tally

Append one line per comment to `~/.claude/skills/claim-ledger/tally.jsonl`:

```json
{"ts":"2026-09-05","repo":"org/repo","pr":412,"landed":"UNLISTED","reason":null,"pkg":"pkg/billing"}
```

Then print the distribution over the last 10 PRs.

### Reading the tally

| Dominant class | Verdict | What to change |
|---|---|---|
| `ASSUMED[harness]` | Harness problem | The gap log is your backlog. `taskfile-ci-parity` on the top blocker, as its own PR. |
| `UNLISTED` | Context problem | Every reconcile writes one invariant down. Six months of this is the monorepo's missing AGENTS.md tree. |
| `READ` | Attention problem | Smaller diffs (`work-scope`), and the fresh-context reader on every row, not just the ones that felt risky. |
| `RAN` | Tests are lying | `test-fidelity` on every test-bearing PR before it opens. |

"Harness" is a valid verdict. So is "skill." So is "both, in this ratio."
The point is to stop guessing.

---

## Calibration

- **Zealotry** — a claim per hunk, a 60-row ledger nobody reads. Claims are
  *behaviors*, not lines. Cluster callers by package. Aim for 5–20.
- **Honesty theatre** — `ASSUMED[budget]` on everything. The ledger is true
  and useless. More than 50% `ASSUMED` → stop; discharge rows or shrink the
  PR. Do not open it.
- **Fighting the harness mid-build** — see step 2. Log the gap, move on.
- **Residue as apology** — hedging language in the residue invites the
  reviewer to skim it. Flat rows, one line each.
- **Reconciling only the bad PRs** — a PR with zero correctness comments is
  a data point too. Record it, or the tally is survivorship-biased.

## Common mistakes *(hypotheses — earn or delete after five reconciles)*

| Mistake | Expected consequence |
|---|---|
| Ledger in session tmp | Lost mid-run; `reconcile` has nothing to map against |
| Treating a same-session test as `RAN` | The row that the reviewer's bug lands on, every time |
| Skipping source 2 because "it's internal" | Monorepo consumers are exactly where `UNLISTED` comes from |
| Free-text `ASSUMED` reasons | Tally cannot aggregate; verdict stays a vibe |
| Deleting an uncomfortable residue row | You just shipped the bug with less reviewer attention on it |

## Project-specific extensions (optional)

If `~/.claude/skills/claim-ledger/extensions.md` exists, read it at the start
of `build` step 2 and `reconcile` step 1. It layers, per repo:

- The **two-minute harness subset** — the fastest Taskfile target that
  exercises each package, so `RAN` is reachable more often.
- Where invariant docs live if not at the conventional paths.
- Bot logins to drop from comment fetches.
- `OWNER`/`REPO` defaults for `gh`.

Absent the file, the procedure is generic and degrades gracefully.

## Why this exists separately

| Skill | Question | Surface |
|---|---|---|
| `self-audit` | Is this diff clean? | The diff |
| `test-fidelity` | Do the tests constrain the code? | The tests |
| `review-prep` | What is the blast radius? | The graph |
| `claim-ledger` | What did I verify vs. believe — and which kind of miss was that? | The claims, across PRs |

`review-prep` feeds source 2. `test-fidelity` gates rule 1. `self-audit` step
7 is one way to discharge a `READ`. `taskfile-ci-parity` is what the gap log
turns into. `work-scope` is where a 30-row ledger sends you.

## Cross-references

- **Evidence tagging lineage:** `counterfactual-audit` (OBSERVED / INFERRED /
  PROPOSED) — same discipline, pointed at a diff instead of an architecture.
- **Callers:** `mache-usage`, `review-prep` steps 6–8.
- **Judgment on `RAN`:** `test-fidelity`.
- **Fresh-context reader:** `self-audit` step 7 prompt, scoped per claim.
- **Where the gap log goes:** `taskfile-ci-parity`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.