Make the wiki history check mandatory before stability-classify (fix kotkan/claude-plugin-inference-arbitrage#17)

bin/stability-classify only ever reads the local filesystem snapshot store
(by design, no bin/ script holds wiki credentials), but SKILL.md step 4b
documented seeding it from the wiki as a conditional "if the store is cold"
aside. That made a cold-but-not-actually-empty local cache indistinguishable
from a genuine first audit: both silently emit stability: unchecked and file
unstable candidates, as observed on the 2026-07-30 anxious run.

- bin/stability-classify: add a required --wiki-checked {empty,imported}
  flag; hard-error when the store is empty and the flag is omitted, instead
  of silently degrading to unchecked.
- tests/stability.test.sh: (g) no flag on an empty store errors, (h)
  --wiki-checked=empty behaves as before, (i) --wiki-checked=imported after a
  real `audit-snapshot import` runs the gate normally against the imported
  history.
- skills/offload-audit/SKILL.md: step 4b now fetches the wiki's
  Data/<target>/snapshots.jsonl and runs `audit-snapshot import`
  unconditionally (it dedupes by run_id, so this is safe every run) before
  invoking the gate.
- Bump plugin.json to 0.6.3.
This commit is contained in:
Oleks
2026-07-30 05:40:08 +03:00
parent eb4b945599
commit 69ff443bd2
4 changed files with 128 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "inference-arbitrage", "name": "inference-arbitrage",
"version": "0.6.2", "version": "0.6.3",
"description": "Audits a Claude Code plugin's definitions and usage transcripts to find steps that should be a deterministic script instead of raw LLM inference, and files the well-evidenced ones as issues on the target repo.", "description": "Audits a Claude Code plugin's definitions and usage transcripts to find steps that should be a deterministic script instead of raw LLM inference, and files the well-evidenced ones as issues on the target repo.",
"author": { "author": {
"name": "oleks" "name": "oleks"
+38
View File
@@ -48,6 +48,26 @@ nothing to compare against. It files normally, marked
of history would contradict FR-2.4 — a target with no history stays auditable on of history would contradict FR-2.4 — a target with no history stays auditable on
its own terms — and would make the first audit of every plugin file nothing. its own terms — and would make the first audit of every plugin file nothing.
AN EMPTY LOCAL STORE IS NOT THE SAME CLAIM AS AN EMPTY WIKI
-------------------------------------------------------------
This script only ever reads the local filesystem mirror of the store — by
design, no `bin/` script holds wiki credentials (see `audit-snapshot`'s
docstring). That means an empty `--store` is ambiguous: it might be a genuine
first audit (FR-2.4), or it might just be a cold local cache sitting in front
of real wiki history nobody imported yet (kotkan/claude-plugin-inference-
arbitrage#17). The two look identical to `find_prior` but are not the same
fact about the target, and only the caller — who can read the wiki — knows
which one is true.
So when the store is empty, `--wiki-checked` is mandatory: `empty` asserts the
caller checked the wiki page `Data/<target>/snapshots.jsonl` and it genuinely
has no history (or the target truly is new), so `unchecked` is correct;
`imported` asserts the caller ran `audit-snapshot import` first — in which case
the store would no longer be empty and this path would not be taken at all.
Omitting the flag on an empty store is a hard error: it turns the SKILL.md
step 4b instruction to check the wiki first from a doc-only aside into
something the gate itself refuses to skip past.
The prior window is the most recent snapshot that contains this candidate by The prior window is the most recent snapshot that contains this candidate by
FR-5.2 identity (issue > signature hash > slug), not merely the most recent FR-5.2 identity (issue > signature hash > slug), not merely the most recent
snapshot: a candidate that sat out one window is still comparable against the snapshot: a candidate that sat out one window is still comparable against the
@@ -232,6 +252,13 @@ def main():
ap.add_argument("--signatures", help="JSON {candidate_id: [tool signature, ...]}") ap.add_argument("--signatures", help="JSON {candidate_id: [tool signature, ...]}")
ap.add_argument("--issue-map", help='JSON {candidate_id: "owner/repo#N"}') ap.add_argument("--issue-map", help='JSON {candidate_id: "owner/repo#N"}')
ap.add_argument("--exclude-run", help="run_id to treat as not-yet-recorded (tests, re-runs)") ap.add_argument("--exclude-run", help="run_id to treat as not-yet-recorded (tests, re-runs)")
ap.add_argument("--wiki-checked", choices=["empty", "imported"],
help="required when the local store is empty for this target: 'empty' "
"asserts the wiki was checked and genuinely has no history; "
"'imported' asserts `audit-snapshot import` already ran. Without "
"this, an empty store is ambiguous between a genuine first audit "
"(FR-2.4) and a merely cold local cache in front of real wiki "
"history (kotkan/claude-plugin-inference-arbitrage#17).")
ap.add_argument("--json", action="store_true", help="compact single-line JSON") ap.add_argument("--json", action="store_true", help="compact single-line JSON")
args = ap.parse_args() args = ap.parse_args()
@@ -239,6 +266,17 @@ def main():
history = [s for s in load_snapshots(args.store, args.target) history = [s for s in load_snapshots(args.store, args.target)
if s.get("run_id") != args.exclude_run] if s.get("run_id") != args.exclude_run]
if not history and args.wiki_checked is None:
sys.exit(
"error: the store has no history for this target and --wiki-checked was not "
"given. This is ambiguous: it may be a genuine first audit (FR-2.4), or it may "
"just be a cold local cache in front of real wiki history "
"(kotkan/claude-plugin-inference-arbitrage#17). Check the wiki page "
f"Data/{args.target}/snapshots.jsonl first, then either pass "
"--wiki-checked=empty (the wiki genuinely has no history for this target), or "
"run `audit-snapshot import` to seed the store and re-run with "
"--wiki-checked=imported.")
result = gate(doc, history, result = gate(doc, history,
load_json(args.scan) if args.scan else {}, load_json(args.scan) if args.scan else {},
load_json(args.signatures) if args.signatures else {}, load_json(args.signatures) if args.signatures else {},
+36 -10
View File
@@ -109,27 +109,53 @@ complete including the overrule case) lives in that script.
## 4b. Check the evidence against the previous window ## 4b. Check the evidence against the previous window
The second hard gate (FR-4.5, rubric §5b). It runs on every audit, before The second hard gate (FR-4.5, rubric §5b). It runs on every audit, before
anything is filed, and its output **replaces** `classified.json` downstream: anything is filed, and its output **replaces** `classified.json` downstream.
**First, unconditionally — not just when the store looks cold — fetch the
wiki's copy of this target's history and seed the local store from it.** The
local store this gate reads is a filesystem-only mirror (no `bin/` script
holds wiki credentials); it never talks to the wiki itself. That means a store
that is empty *locally* is not evidence the target has no history — it may
just be a cache nobody has seeded on this machine yet, and treating the two as
the same thing is exactly the bug behind
kotkan/claude-plugin-inference-arbitrage#17: a candidate silently filed as
`unchecked` when real prior-window history existed on the wiki all along.
`import` dedupes by `run_id`, so running this every time is safe and
idempotent — there is no "if cold" branch to reason about:
```bash
Agent(subagent_type="cluster:gitea-agent", prompt=
"wiki_read Data/<name>/snapshots.jsonl on kotkan/claude-plugin-inference-arbitrage
(or the target's own repo, per how this target's store is organized). If the page
exists, save its content to a local file and report the path. If it does not
exist, say so plainly.")
# if the page existed:
$IA/bin/audit-snapshot import --target <name> --snapshots <fetched snapshots.jsonl>
```
Then run the gate:
```bash ```bash
$IA/bin/stability-classify --classified classified.json --target <name> \ $IA/bin/stability-classify --classified classified.json --target <name> \
--scan scan.json > stable.json --scan scan.json --wiki-checked <empty|imported> > stable.json
``` ```
`--wiki-checked` is mandatory whenever the local store turns out empty for
this target: pass `empty` if the wiki fetch above genuinely found no page (or
no history), or `imported` if it did and you ran `audit-snapshot import`. The
script hard-errors if the store is empty and this flag is omitted — the wiki
check is no longer a documentation aside the gate quietly trusts you did.
It matches each `file` candidate against the most recent prior snapshot that It matches each `file` candidate against the most recent prior snapshot that
recorded it (FR-5.2 identity) and downgrades any whose `measurement_strength` recorded it (FR-5.2 identity) and downgrades any whose `measurement_strength`
changed, or whose share crossed the 2% filing threshold, between the two changed, or whose share crossed the 2% filing threshold, between the two
windows. **Use `stable.json` for steps 5 and 6.** Never file from windows. **Use `stable.json` for steps 5 and 6.** Never file from
`classified.json` once this has run. `classified.json` once this has run.
If the store has no history for this target — a first audit — every candidate If the store has no history for this target even after the wiki fetch above —
comes back `stability: unchecked` and files normally. That is the FR-2.4 a genuine first audit — every candidate comes back `stability: unchecked` and
outcome, not a failure. If the store is cold but the wiki has history, seed it files normally. That is the FR-2.4 outcome, not a failure.
first, or the gate has nothing to check against:
```bash
$IA/bin/audit-snapshot import --target <name> --snapshots <fetched snapshots.jsonl>
```
### 4b-i. A downgrade is a finding against *this* plugin ### 4b-i. A downgrade is a finding against *this* plugin
+53 -2
View File
@@ -76,6 +76,8 @@ json.dump({
"candidates": [{ "candidates": [{
"candidate_id": "synth/skill/step", "candidate_id": "synth/skill/step",
"skill": "synth:skill", "skill": "synth:skill",
"position": "llm-over-script-digest",
"boundary_confidence": "high",
"signature_hash": "slugonly", "signature_hash": "slugonly",
"measurement_strength": strength, "measurement_strength": strength,
"measurement": {"invocations": 10, "offload_value": 500000, "measurement": {"invocations": 10, "offload_value": 500000,
@@ -141,9 +143,11 @@ print(' ok stability names the window it was checked against')
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
echo "== (c) no prior snapshot -> files normally, unchecked (FR-2.4) ==" echo "== (c) no prior snapshot -> files normally, unchecked (FR-2.4) =="
# An absence of history is not evidence of instability. A first audit of a # An absence of history is not evidence of instability. A first audit of a
# target must still be able to file. # target must still be able to file. The caller must still assert the wiki
# was checked (kotkan/claude-plugin-inference-arbitrage#17) -- see (g)/(h).
classified "$tmp/c.json" measured 0.12 classified "$tmp/c.json" measured 0.12
$BIN --classified "$tmp/c.json" --target synth --store "$tmp/store-empty" >"$tmp/c.out.json" $BIN --classified "$tmp/c.json" --target synth --store "$tmp/store-empty" \
--wiki-checked=empty >"$tmp/c.out.json"
check "verdict" "$(field "$tmp/c.out.json" synth/skill/step verdict)" "file" check "verdict" "$(field "$tmp/c.out.json" synth/skill/step verdict)" "file"
check "stability" "$(field "$tmp/c.out.json" synth/skill/step stability)" \ check "stability" "$(field "$tmp/c.out.json" synth/skill/step stability)" \
"unchecked — no prior window to compare" "unchecked — no prior window to compare"
@@ -215,4 +219,51 @@ assert d['summary']['to_file']==0, d['summary']
print(' ok nothing is left to file from that window') print(' ok nothing is left to file from that window')
" || fail=1 " || fail=1
# --------------------------------------------------------------------------
echo "== (g) empty store, no --wiki-checked -> hard error (kotkan/claude-plugin-inference-arbitrage#17) =="
# The bug: a cold local cache and a genuinely history-free wiki look identical
# to this script, which only ever reads the filesystem. Without an explicit
# assertion from the caller, refuse rather than silently degrade to unchecked.
classified "$tmp/g.json" measured 0.12
if $BIN --classified "$tmp/g.json" --target synth --store "$tmp/store-empty-g" \
>"$tmp/g.out.json" 2>"$tmp/g.err"; then
echo " FAIL expected non-zero exit, got success" >&2
fail=1
else
echo " ok exits non-zero"
fi
if grep -q "wiki-checked" "$tmp/g.err"; then
echo " ok error names --wiki-checked"
else
echo " FAIL error does not mention --wiki-checked: $(cat "$tmp/g.err")" >&2
fail=1
fi
# --------------------------------------------------------------------------
echo "== (h) empty store, --wiki-checked=empty -> unchecked, as today =="
# The caller checked the wiki and it really is history-free; behavior matches (c).
classified "$tmp/h.json" measured 0.12
$BIN --classified "$tmp/h.json" --target synth --store "$tmp/store-empty-h" \
--wiki-checked=empty >"$tmp/h.out.json"
check "verdict" "$(field "$tmp/h.out.json" synth/skill/step verdict)" "file"
check "stability" "$(field "$tmp/h.out.json" synth/skill/step stability)" \
"unchecked — no prior window to compare"
# --------------------------------------------------------------------------
echo "== (i) empty store seeded via a real import, --wiki-checked=imported -> gate runs normally =="
# After `audit-snapshot import` seeds the store from a wiki-fetched
# snapshots.jsonl, the store is no longer empty, so the gate compares against
# the imported history exactly as if it had been local all along.
store=$tmp/store-import-i
mkdir -p "$store"
prior "$tmp/seed-i" thin 0.0
IMPORT_BIN=../bin/audit-snapshot
$IMPORT_BIN --store "$store" import --target synth \
--snapshots "$tmp/seed-i/Data/synth/snapshots.jsonl" >/dev/null
classified "$tmp/i.json" measured 0.12
$BIN --classified "$tmp/i.json" --target synth --store "$store" \
--wiki-checked=imported >"$tmp/i.out.json"
check "verdict" "$(field "$tmp/i.out.json" synth/skill/step verdict)" "boundary-question"
check "downgraded" "$(gatefield "$tmp/i.out.json" downgraded)" "1"
exit "$fail" exit "$fail"