Skip to content

feat: agent skills for usage, receipts, distillation, and backtesting - #11

Merged
mstrathman merged 11 commits into
mainfrom
feat/agent-skills
Jul 30, 2026
Merged

feat: agent skills for usage, receipts, distillation, and backtesting#11
mstrathman merged 11 commits into
mainfrom
feat/agent-skills

Conversation

@mstrathman

@mstrathman mstrathman commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What

Four agentskills.io-format skills in skills/, plus a README pointer. Skills carry judgment, not wrappers, since the SQL surface is already the whole API for an agent:

  • sqlite-predict - core usage: which operation for which question, the aggregate calling convention, degraded statuses vs errors, the defaults (auto, conformal, candidates).
  • prediction-receipts - agent-owned provenance. Defines a _predict_receipts table convention: record the input SQL, options, serving model id and its registry content_hash, extension version, and a SHA-256 of the exact result document; replay by re-running and comparing hashes. This is the receipts design living at the layer it always belonged: serving determinism and content-addressed models make it verifiable with zero support from the C core.
  • distill-lifecycle - verify holdout_metric before serving, the measured shape of distillation loss (regression tails are worse than classification), drift and versioned re-distillation, and license discipline (orientation only; points at the docs' not-legal-advice stance).
  • interpret-backtest - MASE against the naive floor, interval coverage honesty, conformal judgment, when to narrow auto's candidate pool.

Why now

Main is locked at the release state; this lands as follow-on activity. It also gives the new CodeRabbit setup its first real PR to review.

Test plan

  • Skills are documentation; no code paths change.
  • SQL statements in the skills were checked against the current surface (aggregate forms, option keys, error codes, _predict_models columns).
  • README builds no links to missing paths (skills/ exists in this branch).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added predict_sha256(x) for deterministic hashing of TEXT/BLOB inputs.
    • Introduced new agent skills documentation, including distillation lifecycle workflows and guidance for interpreting backtests.
    • Added prediction receipts capability to record and verify replay-deterministic execution results, including model/version pinning.
  • Documentation
    • Expanded README with an “Agent skills” section outlining the SQL surface and installable prebuilt skills.
    • Added reference documentation for predict_sha256.
  • Tests
    • Added CI coverage to validate skill specification conformance and receipts record/verify/tamper behaviors.

Four agentskills.io-format skills in skills/: sqlite-predict (core
usage: operation selection, the aggregate convention, statuses vs
errors, defaults), prediction-receipts (agent-owned provenance:
a _predict_receipts table convention, hashing the result document,
replay verification; possible because serving is deterministic and
models are content-hashed), distill-lifecycle (verify holdout before
serving, drift and re-distill cadence, license discipline), and
interpret-backtest (MASE against the naive floor, coverage honesty,
conformal judgment, when to narrow auto's pool). README gains an agent
skills pointer. Skills carry judgment, not wrappers: the SQL surface is
already the API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mstrathman, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ef52f9d3-be67-4477-a5e3-5bfb4dd7b1e5

📥 Commits

Reviewing files that changed from the base of the PR and between ef7500c and db6046c.

⛔ Files ignored due to path filters (1)
  • benchmarks/results/scale-arena.jsonl is excluded by !benchmarks/results/*.jsonl
📒 Files selected for processing (11)
  • .gitignore
  • README.md
  • benchmarks/results/scale.md
  • skills/distill-lifecycle/SKILL.md
  • skills/interpret-backtest/SKILL.md
  • skills/prediction-receipts/SKILL.md
  • skills/prediction-receipts/scripts/receipt.py
  • skills/sqlite-predict/SKILL.md
  • sqlite-predict.c
  • tests/test_skills.py
  • website/src/content/docs/reference/functions.md
📝 Walkthrough

Walkthrough

Adds agent skill documentation for sqlite-predict usage, prediction receipts, distillation lifecycle management, and backtest interpretation. Implements a receipt CLI with deterministic result hashing, SQL hash support, model pinning, replay verification, and integration tests.

Changes

Agent skills and operational workflows

Layer / File(s) Summary
Core sqlite-predict usage
skills/sqlite-predict/SKILL.md, README.md
Documents SQL operations, result formats, input rules, errors, defaults, runtime inspection, and the available agent skills.
Prediction receipt contract and CLI
skills/prediction-receipts/SKILL.md, skills/prediction-receipts/scripts/receipt.py, sqlite-predict.c, website/src/content/docs/reference/functions.md
Defines receipt fields and replay limits, implements recording, verification, listing, canonicalization, hashing, and model pinning, and documents predict_sha256(x).
Receipt determinism and skill conformance tests
tests/test_skills.py
Validates skill metadata, deterministic hashes, tamper detection, model pins, student models, canonicalization, and replay restrictions.
Distillation and backtest workflows
skills/distill-lifecycle/SKILL.md, skills/interpret-backtest/SKILL.md
Documents distillation verification, drift-based redistillation, licensing, backtest metrics, interval calibration, and model selection.
Repository support configuration
.gitignore
Ignores Autogluon benchmark working directories.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant receipt_py
  participant SQLite
  participant sqlite_predict
  Agent->>receipt_py: Record prediction SQL
  receipt_py->>sqlite_predict: Load extension and execute SQL
  sqlite_predict->>SQLite: Read inputs and model metadata
  SQLite-->>receipt_py: Return canonical result
  receipt_py->>SQLite: Store result hash receipt
  Agent->>receipt_py: Verify receipt
  receipt_py->>SQLite: Replay recorded SQL
  SQLite-->>receipt_py: Return replayed result
  receipt_py-->>Agent: Return match report
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is conventional-commit formatted and accurately summarizes the PR’s new agent skills and related docs.
Description check ✅ Passed The description covers the required What/Why/Test plan content and is mostly aligned with the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-skills

Comment @coderabbitai help to get the list of available commands.

mstrathman and others added 2 commits July 28, 2026 17:48
All four validate with the agentskills reference validator
(skills-ref). Add the optional license field and quote metadata values
per the spec's string-map recommendation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
skills/prediction-receipts/scripts/receipt.py is the interoperability
anchor: one stdlib-only implementation of the convention (record,
verify with exit-code semantics, list), with canonicalization defined
in one place (aggregate documents hashed verbatim; row results as
compact JSON with shortest round-trip floats). The skill now points at
it as the preferred path, keeping the hand-rolled steps as the spec.

tests/test_skills.py wires both into the normal pytest run: every
SKILL.md is held to the agentskills spec (name/dir match, name charset,
description bounds and when-to-use, line budget, house dash rule), and
the receipt script is proven end to end: record, replay-match,
re-record determinism, tamper detection via exit code 2, and registry
content_hash pinning for bundled models and distilled students.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/distill-lifecycle/SKILL.md`:
- Around line 70-76: Revise the licensing guidance in the distillation section
to state that the teacher’s license may impose obligations depending on the
exact weights, license, distribution method, and jurisdiction. Require recording
the exact teacher license with the student, and clarify that accept_license is
only an opt-in mechanism, not proof of compliance.
- Around line 49-55: Update the soft-label guidance in the distillation
lifecycle documentation to qualify calibration preservation and imbalance
benefits on the teacher continuing to emit meaningful probabilities; avoid
claiming soft labels rescue severely imbalanced datasets that collapse to a
single class, while retaining the existing refusal behavior.
- Around line 16-19: Update the introductory description in the distillation
lifecycle documentation to avoid presenting “a few kilobytes,” “microseconds,”
and “seconds” as guaranteed performance claims. Either add authoritative sources
for each figure or soften the wording to clearly identify them as illustrative,
while preserving the surrounding explanation of the teacher-to-student
lifecycle.

In `@skills/interpret-backtest/SKILL.md`:
- Around line 43-45: Replace the standalone JSON fragment in the conformal
interval example with a complete backtest(...) call, including the required
query and horizon arguments and the interval_method configuration. Keep the
example in the existing SQL block and ensure it clearly shows where the
configuration is passed.
- Around line 47-51: Revise the conformal intervals guidance to avoid
guaranteeing nominal coverage: state that they can improve empirical calibration
based on measured residuals, while retaining the caveat about needing sufficient
folds and the instruction to verify coverage with backtest on the target series.
- Around line 39-40: Update the default Gaussian band discussion in SKILL.md to
either cite the benchmark source and specify the model and dataset scope
supporting the 0.57 coverage figure, or remove the exact figure while preserving
the broader overconfidence statement.

In `@skills/prediction-receipts/scripts/receipt.py`:
- Around line 62-68: Update canonical_document and its callers so
canonicalization depends on the operation type: preserve raw string output only
for operations that require aggregate-document hashing, while predict and
backtest TVF results always serialize as {"columns": ..., "rows": ...},
including one-row, one-TEXT-column results. Pass the operation context through
the affected call sites rather than inferring behavior from result shape.
- Around line 52-59: Update connect so extension loading is disabled immediately
after db.load_extension(extension) completes, including before returning the
connection; preserve the existing failure handling and ensure cmd_verify’s
subsequent input_sql execution uses the connection with extension loading
disabled.

In `@tests/test_skills.py`:
- Around line 76-136: Extend the receipt tests around
test_receipt_record_verify_and_tamper and test_receipt_pins_a_registered_student
with adversarial cases for one-row textual TVF results, malformed options,
unknown options, and verification of a nonexistent receipt. Exercise extension
failure paths and assert stderr or structured errors contain the exact
PREDICT_ERR_* code, not descriptive prose, while preserving existing success and
tamper assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a9484e45-1705-4622-aaa1-e7dba4553ab7

📥 Commits

Reviewing files that changed from the base of the PR and between ef7500c and 7dd6a15.

📒 Files selected for processing (7)
  • README.md
  • skills/distill-lifecycle/SKILL.md
  • skills/interpret-backtest/SKILL.md
  • skills/prediction-receipts/SKILL.md
  • skills/prediction-receipts/scripts/receipt.py
  • skills/sqlite-predict/SKILL.md
  • tests/test_skills.py

Comment thread skills/distill-lifecycle/SKILL.md Outdated
Comment thread skills/distill-lifecycle/SKILL.md Outdated
Comment thread skills/distill-lifecycle/SKILL.md Outdated
Comment thread skills/interpret-backtest/SKILL.md Outdated
Comment thread skills/interpret-backtest/SKILL.md
Comment thread skills/interpret-backtest/SKILL.md Outdated
Comment thread skills/prediction-receipts/scripts/receipt.py Outdated
Comment thread skills/prediction-receipts/scripts/receipt.py Outdated
Comment thread tests/test_skills.py
mstrathman and others added 3 commits July 28, 2026 17:59
Python was the receipt script's only dependency, and the environments
this extension targets (phone, embedded, wasm) may not have it. The
lightest dependency is the extension itself: expose the vendored
SHA-256 (the hash that already pins model weights) as a deterministic,
innocuous predict_sha256(x) scalar (TEXT/BLOB, NULL passthrough), and
rewrite the prediction-receipts skill so record and replay-verify run
in pure SQL. The Python script stays as optional convenience for
row-shaped results (canonical float serialization) and mismatch
diagnostics. CI: hash vectors against hashlib, plus a pure-SQL
record/verify/tamper round trip; functions reference documents the new
scalar. Also gitignores autogluon's local model dumps, which must never
be committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Security (critical): receipt.py locks extension loading immediately
after loading predict0, so a tampered receipt's replayed input_sql can
no longer call load_extension() on an arbitrary library; a regression
test replays exactly that attack and asserts sqlite refuses it.

Interoperability (major): canonicalization now follows the recorded
operation instead of the result shape, so a one-text-cell backtest or
predict result hashes as {"columns","rows"} rather than masquerading
as an aggregate document; verify() reads the stored operation.

Claims discipline (the reviewer enforcing our own path instructions):
size/latency claims in distill-lifecycle now cite the benchmarks and
state measured ranges; the soft-label rescue is scoped and qualified;
the licensing section says obligations 'may' apply, tells users to
record the exact license with each student, and states that
accept_license is an acknowledgment, not compliance; the 0.57 coverage
figure carries its model/dataset scope and source; the conformal
fragment became a complete backtest() call; and conformal coverage is
'substantially improves, reached nominal in our benchmarks, no
finite-sample guarantee' instead of a promise.

Tests: adversarial cases for the one-cell TVF canonicalization, unknown
option keys asserting the exact PREDICT_ERR_OPTIONS code, missing
receipt ids, and the load_extension replay attack. Eight pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/prediction-receipts/SKILL.md`:
- Around line 90-94: Update the fenced command block in the prediction receipts
documentation to include the text language tag, leaving the commands and
surrounding documentation unchanged.
- Around line 71-81: The receipt SQL example must not be presented as full
receipt verification. Label it as manual verification for the specific hardcoded
forecast query, state that it ignores stored operation, input_sql, options,
model_id, and content_hash metadata, and direct users to the reference script
for full replay verification.
- Around line 51-67: Make the receipt-recording example executable when
_predict_models is absent by separating the registered-model and
unregistered-model SQL paths, or by creating the registry table before the
INSERT. In the unregistered path, set content_hash to NULL while keeping
input_sql identical to the SQL used to compute doc; preserve the existing lookup
for registered models.
- Around line 51-67: Update the receipt example around _predict_receipts so
input_sql follows one consistent replay contract: store the exact SQL used to
compute doc verbatim, or revise the doc query to represent the supplied-row
query, ensuring both expressions match exactly. Also make the content_hash
lookup optional by recording NULL when _predict_models is unavailable, while
preserving the existing model and hash behavior when it exists.
- Around line 47-48: Update the workflow description around predict_sha256() to
distinguish result-document hashing from model-weight pinning: describe
predict_sha256(doc) as hashing the prediction result, and identify the registry
content_hash as the separate provenance value for pinned model weights. Remove
the claim that they are the same hash.

In `@sqlite-predict.c`:
- Around line 423-453: Update predict_sha256_fn to accept only SQLITE_TEXT and
SQLITE_BLOB values; for all other non-NULL types, return the appropriate
existing PREDICT_ERR_* error through the SQLite context instead of converting
with sqlite3_value_text(). Preserve NULL-to-NULL behavior and the current
hashing behavior for TEXT and BLOB inputs.

In `@tests/test_skills.py`:
- Around line 217-220: Replace the prose stderr check in the missing-receipt
test around run_receipt("verify", ...) with an assertion for the appropriate
PREDICT_ERR_* code representing a missing receipt. Preserve the nonzero
return-code assertion and ensure the test validates the CLI’s stable structured
error identifier rather than message wording.

In `@website/src/content/docs/reference/functions.md`:
- Line 126: Update the predict_sha256(x) documentation row after the C
implementation contract is finalized: either document only TEXT/BLOB inputs if
numeric arguments are rejected, or explicitly include INTEGER/REAL inputs and
their defined representation if numeric support is retained. Ensure the
description matches the behavior implemented by the predict_sha256 function and
does not claim a narrower input scope.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e842f56-9b37-4ad3-be51-a24453b9eb00

📥 Commits

Reviewing files that changed from the base of the PR and between 7dd6a15 and 0db3468.

📒 Files selected for processing (8)
  • .gitignore
  • skills/distill-lifecycle/SKILL.md
  • skills/interpret-backtest/SKILL.md
  • skills/prediction-receipts/SKILL.md
  • skills/prediction-receipts/scripts/receipt.py
  • sqlite-predict.c
  • tests/test_skills.py
  • website/src/content/docs/reference/functions.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • skills/distill-lifecycle/SKILL.md
  • skills/interpret-backtest/SKILL.md
  • skills/prediction-receipts/scripts/receipt.py

Comment thread skills/prediction-receipts/SKILL.md Outdated
Comment thread skills/prediction-receipts/SKILL.md Outdated
Comment thread skills/prediction-receipts/SKILL.md Outdated
Comment thread skills/prediction-receipts/SKILL.md Outdated
Comment thread sqlite-predict.c
Comment thread tests/test_skills.py Outdated
Comment thread website/src/content/docs/reference/functions.md Outdated
mstrathman and others added 2 commits July 29, 2026 17:54
predict_sha256 rejects INTEGER/REAL with PREDICT_ERR_SCHEMA instead of
hashing SQLite's 15-digit number-to-text coercion, which could collapse
distinct doubles into one hash; the functions reference documents the
contract. The receipt CLI gains stable RECEIPT_ERR_* failure codes so
agents branch on outcomes the way they do on PREDICT_ERR_* (the test
asserts the code, not prose). The receipts skill now distinguishes
result hashing from weight pinning explicitly, ships an executable
no-registry recording variant, labels the pure-SQL verify as a spot
check of one query's hash and routes full replay to the reference
script, and tags the command block for MD040.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
It lands on main with the scale results.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mstrathman

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

All round-two findings addressed in 18ceff0: predict_sha256 rejects numeric arguments with PREDICT_ERR_SCHEMA, the receipt CLI has stable RECEIPT_ERR_* codes asserted by the tests, the receipts skill distinguishes result hashing from weight pinning, ships the executable no-registry variant, scopes the pure-SQL verify as a spot check, and the command block is tagged. 3aaef19 removes an unrelated file that slipped into the branch.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== PR commits and final changed files ==='
git log --oneline --decorate -12
git diff --name-status HEAD~3..HEAD

printf '%s\n' '=== Updates stated by the author ==='
git show --stat --oneline 18ceff0
git show --stat --oneline 3aaef19
git show --format=fuller --no-ext-diff 18ceff0 -- \
  sqlite-predict.c \
  skills/prediction-receipts/SKILL.md \
  skills/prediction-receipts/scripts/receipt.py \
  tests/test_skills.py

printf '%s\n' '=== Target file outlines ==='
ast-grep outline sqlite-predict.c --items all --match 'predict_sha256|sqlite3_predict_init' || true
ast-grep outline skills/prediction-receipts/scripts/receipt.py --items all
ast-grep outline tests/test_skills.py --items all --match 'receipt|pure_sql|adversarial|sha256' || true

Length of output: 13237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null || true)"
printf '=== merge base: %s ===\n' "${base:-unavailable}"
if [ -n "${base:-}" ]; then
  git diff --stat "$base"..HEAD
  git diff --name-status "$base"..HEAD
fi

printf '%s\n' '=== receipt CLI ==='
nl -ba skills/prediction-receipts/scripts/receipt.py | sed -n '1,270p'

printf '%s\n' '=== hash UDF and registration ==='
nl -ba sqlite-predict.c | sed -n '400,470p'
nl -ba sqlite-predict.c | sed -n '630,700p'

printf '%s\n' '=== receipt skill ==='
nl -ba skills/prediction-receipts/SKILL.md | sed -n '1,180p'

printf '%s\n' '=== receipt tests ==='
nl -ba tests/test_skills.py | sed -n '45,255p'

printf '%s\n' '=== benchmark result references and tracked state ==='
git ls-files benchmarks/results/scale-arena.jsonl benchmarks/results/scale.md benchmarks/scale_arena.py
rg -n -C2 'scale-arena|scale\.md|scale_arena' README.md benchmarks .gitignore 2>/dev/null || true

Length of output: 2609


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered() {
  awk '{printf "%6d\t%s\n", NR, $0}' "$1" | sed -n "${2},${3}p"
}

printf '%s\n' '=== receipt CLI ==='
numbered skills/prediction-receipts/scripts/receipt.py 1 270

printf '%s\n' '=== hash UDF and registration ==='
numbered sqlite-predict.c 400 475
numbered sqlite-predict.c 630 705

printf '%s\n' '=== receipt skill ==='
numbered skills/prediction-receipts/SKILL.md 1 185

printf '%s\n' '=== receipt tests ==='
numbered tests/test_skills.py 45 260

printf '%s\n' '=== all fail() call sites ==='
rg -n -C2 '\bfail\s*\(' skills/prediction-receipts/scripts/receipt.py

printf '%s\n' '=== retained benchmark results ==='
for f in benchmarks/results/scale-arena.jsonl benchmarks/results/scale.md; do
  printf '\n--- %s ---\n' "$f"
  awk '{printf "%6d\t%s\n", NR, $0}' "$f"
done

printf '%s\n' '=== references outside the retained results ==='
rg -n -C2 'scale-arena|scale_arena|scale\.md' \
  -g '!benchmarks/results/scale-arena.jsonl' \
  -g '!benchmarks/results/scale.md' . || true

Length of output: 35001


@mstrathman

  • skills/prediction-receipts/SKILL.md:99 says the reference script performs full replay that re-derives stored fields, but skills/prediction-receipts/scripts/receipt.py:159-183 only replays input_sql and sets match from the result hash. It never uses options and does not derive the replayed model ID to compare it with model_id. Consequently, modifying either receipt field can still produce "match": true as long as the stored SQL yields the original result. Either validate those fields during verification (and include failures in the verification outcome) or narrow the skill’s full-replay/tamper-detection claim. Add adversarial tests for tampered options and model_id.
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The skill claimed the reference script re-derives everything from
stored fields; it only replayed input_sql and compared hashes, so a
tampered model_id or options column still verified. Now verify()
re-derives the serving model from the replayed result and fails the
verification (exit 2, id_matches false) when it contradicts the
recorded model_id; row-form receipts recorded via --model-id report
id_matches null since no model is derivable. The options column is
declared informational in both the report (options_verified: false)
and the skill text: its authoritative copy is the options text inside
input_sql, which the replay executes verbatim, and the receipt row
itself is self-attested. Adversarial tests cover the detected forgery
(model_id) and pin the documented limit (options).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mstrathman

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Round-three finding addressed in 1e49364: verify() now re-derives the serving model from the replayed result and fails verification (exit 2, id_matches false) on a forged model_id; row-form receipts report id_matches null since no model is derivable. The options column is declared informational in the report (options_verified: false) and the skill text, with the receipts row's self-attested nature stated plainly. Adversarial tests cover the detected forgery and pin the documented options limit.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== target commit ==='
git show --stat --oneline 1e49364
git show --format= --no-ext-diff 1e49364 -- \
  skills/prediction-receipts/scripts/receipt.py \
  skills/prediction-receipts/SKILL.md \
  tests/test_skills.py

printf '%s\n' '=== receipt CLI outline ==='
ast-grep outline skills/prediction-receipts/scripts/receipt.py --items all

printf '%s\n' '=== verifier and receipt-related implementation ==='
nl -ba skills/prediction-receipts/scripts/receipt.py | sed -n '1,290p'

printf '%s\n' '=== receipt skill ==='
nl -ba skills/prediction-receipts/SKILL.md | sed -n '1,220p'

printf '%s\n' '=== receipt tests ==='
nl -ba tests/test_skills.py | sed -n '1,330p'

printf '%s\n' '=== all receipt-field references ==='
rg -n -C3 '\b(model_id|options|id_matches|options_verified|result_sha256|content_hash)\b' \
  skills/prediction-receipts/scripts/receipt.py \
  skills/prediction-receipts/SKILL.md \
  tests/test_skills.py

Length of output: 8024


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered() {
  awk '{printf "%6d\t%s\n", NR, $0}' "$1" | sed -n "${2},${3}p"
}

printf '%s\n' '=== PR changed files from merge base ==='
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null || true)"
printf 'merge base: %s\n' "${base:-unavailable}"
if [ -n "${base:-}" ]; then
  git diff --name-status "$base"..HEAD
  git diff --check "$base"..HEAD
fi

printf '%s\n' '=== complete receipt script ==='
numbered skills/prediction-receipts/scripts/receipt.py 1 300

printf '%s\n' '=== complete receipts skill ==='
numbered skills/prediction-receipts/SKILL.md 1 230

printf '%s\n' '=== full receipt-test context ==='
numbered tests/test_skills.py 1 340

printf '%s\n' '=== receipt schema and verification query references ==='
rg -n -C4 'CREATE TABLE|INSERT INTO _predict_receipts|SELECT .*_predict_receipts|UPDATE _predict_receipts|cmd_record|cmd_verify|model_fields|canonical_document' \
  skills/prediction-receipts/scripts/receipt.py \
  tests/test_skills.py

printf '%s\n' '=== current changes to reviewed files ==='
git diff --no-ext-diff "$base"..HEAD -- \
  skills/prediction-receipts/scripts/receipt.py \
  skills/prediction-receipts/SKILL.md \
  tests/test_skills.py

Length of output: 70720


@mstrathman

  • skills/prediction-receipts/scripts/receipt.py:159 executes the mutable input_sql field with unrestricted db.execute(). Disabling extension loading prevents the tested load_extension() path, but a tampered receipt can still run a single destructive or state-changing statement such as DELETE FROM readings, DROP TABLE readings, ATTACH DATABASE, or PRAGMA changes when someone verifies it. Treat replay input as untrusted: enforce a read-only query policy (and test a tampered DELETE/DROP receipt), or perform replay against an immutable/read-only database connection. The current self-attestation note in skills/prediction-receipts/SKILL.md:103-107 does not prevent verification from modifying the verifier’s database.

✏️ Learnings added
Learnt from: mstrathman
URL: https://github.com/PureStorage-OpenConnect/sqlite-predict/pull/11

Timestamp: 2026-07-30T01:20:08.336Z
Learning: In `skills/prediction-receipts/scripts/receipt.py`, aggregate result documents carry a derivable `model` field, whereas row-form `predict` and `backtest` receipts require an explicit `--model-id` and therefore report `id_matches: null` at verification. The separate `options` receipt column is informational; the executable options are the text embedded in `input_sql`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Locking extension loading closed one door and left the write door
open: a tampered receipt's input_sql could DELETE, DROP, ATTACH, or
flip pragmas during verification. verify() and list now open the
database read-only at the file level and install an authorizer that
permits only reads and function calls; every legitimate replay
(aggregates, predict, backtest) is pure and passes, every write shape
is denied at prepare time. Adversarial tests replay DELETE, DROP,
ATTACH, and PRAGMA receipts, assert refusal, and assert the verifier's
data is untouched. The skill states the replay posture explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mstrathman

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Round-four finding addressed: verify() and list now run on a read-only (mode=ro) connection with an allow-list authorizer (reads and function calls only), so a tampered input_sql cannot write, drop, attach, or change pragmas during replay. Adversarial tests replay DELETE/DROP/ATTACH/PRAGMA receipts and assert both refusal and untouched data. The skill documents the untrusted-replay posture.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null || true)"
printf '=== merge base ===\n%s\n' "${base:-unavailable}"
if [ -n "${base:-}" ]; then
  printf '\n=== changed files ===\n'
  git diff --name-status "$base"..HEAD
  printf '\n=== latest commits ===\n'
  git log --oneline "$base"..HEAD
  printf '\n=== whitespace check ===\n'
  git diff --check "$base"..HEAD
fi

printf '\n=== receipt script outline ===\n'
ast-grep outline skills/prediction-receipts/scripts/receipt.py --items all

printf '\n=== receipt script relevant sections ===\n'
nl -ba skills/prediction-receipts/scripts/receipt.py | sed -n '1,360p'

printf '\n=== security-related call sites ===\n'
rg -n -C4 'connect\(|set_authorizer|authorizer|mode=ro|uri=|execute\(|cmd_verify|cmd_list|SQLITE_' \
  skills/prediction-receipts/scripts/receipt.py

printf '\n=== receipt documentation ===\n'
nl -ba skills/prediction-receipts/SKILL.md | sed -n '1,260p'

printf '\n=== receipt-related tests ===\n'
rg -n -C8 'DELETE|DROP|ATTACH|PRAGMA|authoriz|read-only|readonly|cmd_verify|cmd_list|adversarial|receipt' \
  tests/test_skills.py

Length of output: 3530


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered() {
  awk '{printf "%6d\t%s\n", NR, $0}' "$1"
}

printf '%s\n' '=== round-four security commit ==='
git show --format=fuller --stat --no-ext-diff cb0f5c6
git show --format= --no-ext-diff cb0f5c6 -- \
  skills/prediction-receipts/scripts/receipt.py \
  skills/prediction-receipts/SKILL.md \
  tests/test_skills.py

printf '%s\n' '=== complete receipt script ==='
numbered skills/prediction-receipts/scripts/receipt.py

printf '%s\n' '=== receipt skill ==='
numbered skills/prediction-receipts/SKILL.md

printf '%s\n' '=== receipt tests ==='
numbered tests/test_skills.py

printf '%s\n' '=== Python SQLite authorizer constants used by this script ==='
rg -n -C2 '\bsqlite3\.SQLITE_[A-Z_]+\b' skills/prediction-receipts/scripts/receipt.py tests/test_skills.py

printf '%s\n' '=== replay and list invocation sites ==='
rg -n -C5 '\b(cmd_verify|cmd_list|connect)\s*\(|\bset_authorizer\s*\(|\bexecute\s*\(' \
  skills/prediction-receipts/scripts/receipt.py

Length of output: 46758


@mstrathman No further changes requested for the round-four remediation. The replay connection and authorizer enforcement in skills/prediction-receipts/scripts/receipt.py Lines 54-85 and Lines 170-224, together with the mutation-attempt coverage in tests/test_skills.py Lines 276-301, address the prior finding.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Rather than waiting for the next review round to find the next
adjacent gap, this closes the full remaining surface found by an
adversarial self-audit of the receipt tool: a VM-step budget aborts
runaway replays (recursive CTE bombs) instead of hanging the verifier;
BLOB cells canonicalize deterministically as their sha256 instead of
crashing json serialization; --options must parse as JSON before
anything executes; database-open and SQL failures exit with stable
RECEIPT_ERR_* codes instead of tracebacks. Every path has a test:
the bomb aborts under a small step budget, blob receipts round-trip
deterministically, malformed options and missing databases fail clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mstrathman

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

Beyond the round-four fix (read-only replay with an allow-list authorizer, tested against DELETE/DROP/ATTACH/PRAGMA receipts), cb0f5c6 and this push close the rest of the surface from our own adversarial audit: VM-step budget against runaway replays, deterministic BLOB canonicalization, upfront options validation, and stable RECEIPT_ERR_* codes on every failure path instead of tracebacks. Eleven tests cover the attack and hardening set. Requesting a full review rather than incremental so the whole file is judged as it now stands.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

@mstrathman Full review requested for the current PR state, including the receipt replay hardening and adversarial coverage.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 11 minutes.

@mstrathman
mstrathman merged commit 5ad201f into main Jul 30, 2026
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant