Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{
"name": "audit",
"source": "./audit",
"version": "0.1.4",
"version": "0.2.0",
"description": "Bulk, read-only audits of a QuantEcon repository — issue triage, PR review, technical debt, translation parity — each producing an evidence-cited report bundle"
}
]
Expand Down
2 changes: 1 addition & 1 deletion audit/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "audit",
"description": "Bulk, read-only audits of a QuantEcon repository — issue triage, PR review, technical debt, translation parity — each producing an evidence-cited report bundle",
"version": "0.1.4",
"version": "0.2.0",
"author": { "name": "QuantEcon" }
}
9 changes: 9 additions & 0 deletions audit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ Versions are [semver](https://semver.org) as a user of this plugin experiences i

Repository: [QuantEcon/skills](https://github.com/QuantEcon/skills) ([every commit that touched this plugin](https://github.com/QuantEcon/skills/commits/main/audit)). How a release is made: [developing-skills § Versioning and releases](https://github.com/QuantEcon/skills/blob/main/docs/developing-skills.md#versioning-and-releases).

## 0.2.0 — 2026-08-07

The two severity-1 defects from the first measured run, which are the same defect at different altitudes: an audit's own record claiming more than it can support.

**Changed**

- **`[verified]` now requires evidence reachable from the ref the audit named.** Doctrine §2 is the single statement of it — §1 rule 1 no longer carries its own copy of the accepted-forms list, which is how the two drifted apart in the first place — and it covers every citation form — a commit must be an ancestor of the baseline ref, a `file:line` must be that line *on the ref* rather than in the working tree, a PR must be merged into it — and `/audit:issues` runs `git merge-base --is-ancestor <sha> <ref>` before tagging a commit citation. Run 1's headline finding cited a commit that is real, does touch the file, and exists only on an unmerged branch, while the report's header said it had verified against `main`. A citation that resolves for its author and not for its reader is worse than an untagged claim, because the tag is what invited the trust. Evidence that genuinely lives off-ref stays citable — as the open PR it is, tagged `[stated]` or `[inferred]`.
- **Phase 2 checkpoints both of its passes.** `findings.md` now carries `## Open` and `## Closed` sections, and the resume rule partitions `issues.json` by state and resumes each side independently at the lowest number with no entry. Run 1 wrote only the 56 open issues to the checkpoint and sent the 62 closed ones straight to the catalog, so a run interrupted during the closed pass would have re-verified all 62 from scratch while reporting itself complete — the single-block resume rule shipped in 0.1.2 could not see the difference.

## 0.1.4 — 2026-08-03

Doctrine §4's rule survived the first measured run; its justification did not. The section is re-derived from what that run actually produced, and the cost figures the skill quotes are replaced with measured ones.
Expand Down
16 changes: 14 additions & 2 deletions audit/references/doctrine.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The method every skill in this plugin follows. Skills own their subject matter

## 1. What makes a bulk audit trustworthy

1. **Never trust an artifact's claim about its own state.** Every "fixed in X", "scheduled into Y", "superseded by Z" is a hypothesis until checked against the current default branch, `CHANGELOG.md`, and merged PRs. Cite `file:line`, a PR, or a tag for each verified claim.
1. **Never trust an artifact's claim about its own state.** Every "fixed in X", "scheduled into Y", "superseded by Z" is a hypothesis until checked against the current default branch, `CHANGELOG.md`, and merged PRs. Every verified claim carries a citation that resolves on the ref the audit named — the accepted forms and the reachability rule are [§2](#2-evidence-classes).
2. **Check both directions.** Open items that are actually resolved, *and* closed items whose fix never really landed. An audit that only prunes is half an audit.
3. **Read every thread, closed ones included.** Closed threads carry decisions, deferred remainders, and agreed-but-never-filed work. Skipping the closed side was the one gap in this runbook's first execution, and it is the default failure mode — the snapshot captures closed threads precisely so there is no cost excuse.
4. **Distinguish guarded from fixed.** "Now fails loudly" is not "root cause resolved". Record which kind of remainder each item carries.
Expand All @@ -19,12 +19,24 @@ Findings are tagged so a reader can tell what was actually inspected. This is th

| Tag | Means | Minimum citation |
|---|---|---|
| `[verified]` | Checked against code, a diff, or a build artifact | `file:line`, a merged PR, or a tag |
| `[verified]` | Checked against code, a diff, or a build artifact | `file:line`, a merged PR, a tag, or a commit — each reachable from the baseline ref (below) |
| `[stated]` | Asserted by a human in a thread or a notes file | Comment URL or `file:line` |
| `[inferred]` | The audit's own reasoning across sources | The sources it reasons from |

An unqualified claim is a defect. `[inferred]` is legitimate and often the most valuable class — but it must never be dressed as `[verified]`, and a status change recommended on `[inferred]` alone should say so in the recommendation itself.
Comment on lines 25 to 26

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, and fixed in 27a5db6 — though at the other end than suggested. You are right that the two statements disagreed: §2's table had grown a fourth form and the reachability rule, while §1 rule 1 still read "Cite file:line, a PR, or a tag for each verified claim". A reader meets rule 1 first and gets the stale list.

The fix is to stop §1 enumerating rather than to add a clarification at §2. §2 already states it correctly, so a third statement of the accepted forms would be one more copy to drift — and duplicated lists drifting is exactly what produced this defect. Rule 1 now carries the requirement and points at §2 for the forms, which leaves one place where they are written down. That also matches the repo's single-source-of-truth rule (AGENTS.md), which this plugin's own doctrine is supposed to model.


**Every `[verified]` citation is relative to one named ref, and must be reachable from it.** An audit states the ref it verified against — the default branch at the snapshot commit — and that ref is what makes its citations checkable. A citation the reader cannot resolve there is not a weaker citation; it is a false one, and worse than an untagged claim, because the tag is what invited the trust.

The failure is easy to miss because it resolves for whoever wrote it. Run 1's headline finding cited a commit that is real, does touch the file, and exists only on an unmerged branch — while the report's own header said "verified against `main` @ `2c3d624`" ([defect 1](https://github.com/QuantEcon/skills/issues/21)). A working tree carrying extra branches, or a `gh` call that searches the whole repository rather than one ref, will both produce citations that a reader checking out the stated ref finds nothing at.

So, before tagging anything `[verified]`:

```bash
git merge-base --is-ancestor <sha> <ref> # exit 0 = citable; non-zero = not on that ref
```

The same question applies to the other citation forms, mechanically or by eye: a `file:line` must be that file and that line **on the baseline ref**, not in the working tree; a PR must be *merged into* it; a tag must be an ancestor of it. Where a claim genuinely rests on off-ref work — an open PR's branch, a fork — that is legitimate evidence, but it is cited as the open PR it is and tagged `[stated]` or `[inferred]`, never `[verified]`.

## 3. Read-only boundary

**These skills observe and report. They never mutate what they audit** — no closing, labelling, milestoning, commenting or editing on the tracker, and in the audited repo no commits, no pushes, no branches, and no changes to tracked files.
Expand Down
16 changes: 13 additions & 3 deletions audit/skills/issues/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ State which was used in the report's method section. Everything the run produces
| Path | Written by | Holds |
|---|---|---|
| `snapshot/` | phase 1 | `meta.json`, `issues.json`, `prs.json`, `coverage.json` |
| `findings.md` | phase 2 | one entry per item, appended as each is verified |
| `findings.md` | phase 2 | one entry per item — **both** the open and the closed pass, under `## Open` and `## Closed`, appended as each is verified |
| `links.md` | phase 3 | the cross-link graph |
| `01-…` `02-…` `03-…` `README.md` | phase 4 | the delivered bundle |

**Append to the checkpoint as you go, not when the phase ends** ([doctrine §4](../../references/doctrine.md#4-checkpointing)). Phase 2 carries nearly all the judgement, so it is both the phase an interruption lands inside rather than between, and the phase whose log the catalog is later assembled from. On restart, read `findings.md` and resume at the lowest number in `issues.json` that has no entry there; re-verify the last entry rather than trusting a possibly truncated write.
**Append to the checkpoint as you go, not when the phase ends** ([doctrine §4](../../references/doctrine.md#4-checkpointing)). Phase 2 carries nearly all the judgement, so it is both the phase an interruption lands inside rather than between, and the phase whose log the catalog is later assembled from.

**Both passes are checkpointed, and the resume rule reads `issues.json`.** Phase 2 walks two sets — the open issues and the closed ones — and each has its own section in `findings.md`. On restart, partition `issues.json` by state and, for each partition independently, resume at the lowest number with no entry under the matching heading; re-verify the last entry in each rather than trusting a possibly truncated write. Do not infer progress from the file's length or from a single block: run 1 wrote only the open set to `findings.md` and sent the 62 closed issues straight to the catalog, so a resume would have re-verified all 62 from scratch while reporting itself complete ([defect 2](https://github.com/QuantEcon/skills/issues/21)).

## Phase 1 — snapshot

Expand All @@ -77,7 +79,15 @@ Per [doctrine §1](../../references/doctrine.md#1-what-makes-a-bulk-audit-trustw

Sibling-repo checks belong here too: for QuantEcon, "resolved in a sibling" and "one step of a rollout" are the two most common wrong conclusions a single-repo audit reaches.

Write each item's finding to `findings.md` as it is verified, in the catalog entry format from [deliverables.md](../../references/deliverables.md#the-auditissues-bundle) — so phase 4 assembles the catalog rather than re-deriving it, and an interrupted run loses one item rather than the phase.
**Check every citation against the baseline ref before tagging it `[verified]`** ([doctrine §2](../../references/doctrine.md#2-evidence-classes)):

- **a commit** — run `git merge-base --is-ancestor <sha> <ref>`; exit 0 means citable
- **a `file:line`** — confirm that line says what the finding claims *on the ref*, not in the working tree
- **a pull request** — confirm it is merged into that ref

Evidence that lives only on an unmerged branch is still worth citing — as the open PR it is, tagged `[stated]` or `[inferred]`.

Write each item's finding to `findings.md` as it is verified — the closed pass too, under its own heading, not straight into the catalog — in the catalog entry format from [deliverables.md](../../references/deliverables.md#the-auditissues-bundle), so phase 4 assembles the catalog rather than re-deriving it and an interrupted run loses one item rather than the phase.

## Phase 3 — relate

Expand Down
Loading