Skip to content

feat(ratchet): a baseline-attestation row, so the gate cannot compare against a number the PR wrote (b, slice 2 of 2) - #767

Merged
EtanHey merged 13 commits into
mainfrom
wt/ratchet-b2-attest-row
Sep 5, 2026
Merged

feat(ratchet): a baseline-attestation row, so the gate cannot compare against a number the PR wrote (b, slice 2 of 2)#767
EtanHey merged 13 commits into
mainfrom
wt/ratchet-b2-attest-row

Conversation

@EtanHey

@EtanHey EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary — ratchet bolt (b), slice 2 of 2: the row that makes the baseline unforgeable

Stacked on #766 (base branch wt/ratchet-b1-attest-store). Slice 1 built the store; this is the consumer. Merge #766 first, then retarget this PR to main before deleting that branch.

  • ratchet.yml gains actions: read and a step, Fetch the baseline attestation from main, that lists ratchet-attest.yml's runs on main through the Actions API, picks the newest successful push/workflow_dispatch run, downloads its ratchet-attestation artifact, and binds it to the run the API named — the artifact's run_id and main_sha must both match, or the hand-off is unresolved. Three retries on each API read, like the live-head read. Four outcomes, none silent: attested, bootstrap, unresolved; and an empty hand-off makes the collect step refuse to render.
  • The collector's new second row, baseline attestation, right after commit provenance ("which commit, then what it is measured against, then the numbers"). It diffs the PR's baseline fields (queries, latency_baseline_ms, thresholds) against the attestation, field by field:
    • unchanged → 🟢 naming the digest, run id, main sha and timestamp;
    • changed → 🔴 "baseline changed by hand; no CI attestation for these values", listing each field old → new;
    • changed to exactly what that main run measured (measured[path]) → 🟢 "moved to values measured by main". That is the legitimate path, and the only one.
    • If main has moved past the attestation's sha, the value says so (an attest run may still be in flight) — a note, not a verdict.
  • Fail closed. Missing, unparseable, wrong-schema, self-inconsistent, expired, or mis-bound artifact → 🔴. Two hand-off flags at once → 🔴. Asked to fetch and could not → 🔴 with the reason.
  • Bootstrap, narrowly. The API showing no successful attest run on main at all (this PR's own state: HTTP 404 — the writer is not on main yet) is the one case that is neither a measurement nor a finding. The row then compares against the base tip's committed fixture via git show, merge-ref only — a direct checkout's first parent is the PR's own branch and is refused — and says it is bootstrapping. Once one success exists on main this branch is never taken again: an expired artifact is 🔴 unresolved, refreshed by one workflow_dispatch.

The boundary, stated exactly (per #761's reviewer)

No INPUT to this row comes from the PR tree: the run list, the artifact and its binding are GitHub's. The comparator is this PR's checkout of ci_ratchet_table.py and could be rewritten to answer GREEN. Diff-reviewable, not tamper-proof. The docstring, the Notes column and the workflow comment say this and nothing wider.

Premise check — two corrections to the brief

  1. Today no CI row compares a measured value to the baseline at all. mapped bytes, search p50/p95, idle CPU are fixture-bound n/a on every hosted runner; signature_valid compares counts to zero. The baseline is read by scripts/sprint_gate.py on the installed Mac and quoted in the table's Notes. So the harm was real (the installed gate and the reader-facing claim) but it was never a CI RED/GREEN flip.
  2. measured is {} on every attestation today — no runner-side collector measures a baseline field. Consequence, stated in the row's Notes: today the baseline cannot move by PR at all. The key to this lock is a collector (a self-hosted installed-Mac runner, or a CI-measured count promoted into the baseline), not a hand — which is the ratchet's own rule. The legitimate path exists in code and is tested end to end through the CLI; it has nothing to carry until something is measured. Etan's call whether that posture is intended or a human-ratified override should exist.

Definition of done — proven against the old sources

Swapped 3ee7c279's scripts/ci_ratchet_table.py in and ran the four bolt tests:

FAILED test_a_hand_edited_baseline_is_red_with_no_ci_attestation
FAILED test_a_baseline_moved_to_what_main_measured_is_green
FAILED test_bootstrap_still_catches_a_hand_edit
FAILED test_the_gate_no_longer_compares_against_a_number_the_pr_wrote
4 failed, 201 deselected

Same four on this branch: 4 passed. Full file: 205 passed (plus slice 1's reader tests, kept).

The fetch step's bash was run locally against the live API (REPO=EtanHey/brainlayer) and produced bootstrap — ratchet-attest.yml is not a registered workflow on main yet (HTTP 404), which is what this PR's own table should render. The live row on this PR is the acceptance test; the report's DONE marker waits for it.

Size

S — 358 non-test lines (ratchet.yml +102, collector +256); tests +429.

Test plan

  • ruff check and ruff format --check on scripts/ and tests/
  • tests/test_ci_ratchet_table.py: 205 passed (row-level, real-git bootstrap on a merge ref, malformed artifacts, end-to-end CLI, pyyaml assertions on the fetch step — !cancelled() never always(), exactly one hand-off flag, retries, no reader of the checkout, actions: read and never write)
  • tests/test_kg_judge.py git-shelling registration: passes (_clean_git_env() on the new merge-ref repo helper)
  • Live: this PR's table renders baseline attestation 🟢 bootstrap and commit provenance 🟢 on the final head
  • Live, after both merges: the next PR's row reads matches the main attestation (run N · main <sha>)

— brainlayerClaude (worker) · claude-code/claude-fable-5-1


Note

Medium Risk
Changes CI gate semantics for baseline fixture edits and adds Actions API dependency on PR runs; mis-fetch or comparator bugs could block merges or miss hand edits, but scope is isolated to ratchet workflow/collector with extensive fail-closed tests.

Overview
Adds baseline attestation as the second ratchet row so sprint-gate baseline fields (queries, latency_baseline_ms, thresholds) are checked against a reference PRs cannot forge.

Workflow (ratchet.yml): Grants read-only actions permission and a new step that paginates successful ratchet-attest.yml runs on main, downloads ratchet-attestation, and verifies run_id/main_sha match the artifact. Outcomes hand off exactly one of --attestation, --attestation-bootstrap, or --attestation-unresolved (with retries and guarded jq so corrupt API bodies fail closed). Collect refuses to run without a non-empty attestation hand-off.

Collector (ci_ratchet_table.py): Compares the checked-out corpus baseline to the attested baseline; unlicensed edits are RED with an explicit hand-edit message, changes matching main’s measured map (type-sensitive) are GREEN, and pre-first-success on main uses merge-base git show bootstrap only. Stale attestations (artifact sha ≠ base tip) also diff against the base commit so reverting to an old attested value cannot pass silently.

Tests: Broad coverage for row logic, CLI exit codes, workflow YAML contracts, and executed bash for the fetch/collect steps.

Reviewed by Cursor Bugbot for commit 63e388c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add baseline-attestation row to ratchet table so gate compares against main-measured values

  • The ratchet gate workflow fetches the latest successful ratchet-attest.yml artifact from main, verifies its run ID and SHA, and hands the artifact (or bootstrap/unresolved state) to the Python collector instead of letting the PR supply its own baseline.
  • scripts/ci_ratchet_table.py adds a baseline attestation row that reports GREEN when the PR baseline is unchanged or matches a value main measured, and RED for hand-edited fields, type-coerced values, or stale/reverted attestations. Bootstrap mode compares against the merge-ref base commit's baseline before any main attestation exists.
  • The licensed helper now requires exact value and type match for a baseline change to count as main-measured, preventing boolean/count coercion and dotted-key aliasing.
  • Risk: select_attestation fails closed for conflicting --attestation modes, malformed artifacts, and unresolved fetches; a missing or empty attestation hand-off now fails collection before rendering a table instead of rendering n/a.

Macroscope summarized 63e388c.

EtanHey and others added 2 commits September 5, 2026 14:33
…write (b, slice 1 of 2)

A new ratchet-attest.yml runs on every push to main (and a no-input
workflow_dispatch), runs the same collector with --attest-out, and publishes
what that main commit's baseline IS (the queries / latency_baseline_ms /
thresholds fields of corpus.json, with a canonical sha256) plus every value the
run measured, as the `ratchet-attestation` artifact. A pull_request run holds
contents: read and cannot upload into another run's artifacts, which is what
makes the artifact a reference a PR cannot edit. The writer refuses to attest a
commit it does not have checked out and refuses when any row is RED.

This slice is the writer, the schema and its reader (`read_attestation`, which
fails closed on every malformed shape). The row that compares a PR's baseline
against the artifact, and the ratchet.yml step that fetches it, are slice 2.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
… against a number the PR wrote (b, slice 2 of 2)

The collector's new second row, `baseline attestation`, diffs the PR's baseline
fields against the `ratchet-attestation` artifact of the latest successful
push/dispatch run of ratchet-attest.yml on main, which ratchet.yml now lists
through the Actions API (`actions: read`), downloads, and binds to the run the
API named (run id AND main sha must match). Unchanged is GREEN; a changed
field is RED "baseline changed by hand; no CI attestation for these values"
unless that main run measured the new value. Bootstrap -- no successful attest
run on main at all -- compares against the base tip's committed fixture via
`git show`, merge-ref only, and says so; once one success exists an expired
artifact is RED, never a fall-back. Boundary stated, not overclaimed: the
inputs are outside the PR tree, the comparator is not.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@EtanHey EtanHey added the S Small change label Sep 5, 2026
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e8b36797-6071-4757-8280-96dbed6b9787)

@EtanHey

EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: cdeee3dc-e3e1-47ee-9735-f0192e9ab731

📥 Commits

Reviewing files that changed from the base of the PR and between 47133a9 and 63e388c.

📒 Files selected for processing (3)
  • .github/workflows/ratchet.yml
  • scripts/ci_ratchet_table.py
  • tests/test_ci_ratchet_table.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@deepsource-io

deepsource-io Bot commented Sep 5, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 47133a9...63e388c on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Python Sep 5, 2026 1:09p.m. Review ↗
Swift Sep 5, 2026 1:09p.m. Review ↗
JavaScript Sep 5, 2026 1:09p.m. Review ↗
Shell Sep 5, 2026 1:09p.m. Review ↗
Secrets Sep 5, 2026 1:09p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

@EtanHey I will review the changes.

⚠️ Action not completed

Review rate limited.

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.

Comment thread scripts/ci_ratchet_table.py Outdated
Comment thread .github/workflows/ratchet.yml Outdated
EtanHey and others added 2 commits September 5, 2026 14:44
…(Macroscope, #766)

A removed null-valued leaf is a change (path membership, not `.get()`); the
writer refuses run numbers the reader would reject and a checkout whose
baseline lacks a field; the reader requires exactly the baseline fields, so an
incomplete reference cannot pass as one.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_16e70122-6370-4079-80b2-0a214d43f733)

…ource, #766)

Flags first, checkout second, the same shape select_signature already has, so
adding a rule does not keep pushing one function's branch count up.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
Comment thread scripts/ci_ratchet_table.py Outdated
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_036a389b-e876-4136-a67c-abe79bf95e8f)

EtanHey and others added 2 commits September 5, 2026 14:52
… a nested one (Macroscope High, #767)

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
…e a segment (Macroscope High, #767)

Slice 1 made baseline paths tuples; this is the row side: changes print dotted,
but the measured lookup refuses any path whose segment contains a dot, so the
(c)-facing dotted-string map cannot be aliased from the PR tree either.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_da811d81-ee78-4388-a2c0-6187199d45da)

EtanHey added a commit that referenced this pull request Sep 5, 2026
…write (b, slice 1 of 2) (#766)

* feat(ratchet): attest the baseline from main — the store a PR cannot write (b, slice 1 of 2)

A new ratchet-attest.yml runs on every push to main (and a no-input
workflow_dispatch), runs the same collector with --attest-out, and publishes
what that main commit's baseline IS (the queries / latency_baseline_ms /
thresholds fields of corpus.json, with a canonical sha256) plus every value the
run measured, as the `ratchet-attestation` artifact. A pull_request run holds
contents: read and cannot upload into another run's artifacts, which is what
makes the artifact a reference a PR cannot edit. The writer refuses to attest a
commit it does not have checked out and refuses when any row is RED.

This slice is the writer, the schema and its reader (`read_attestation`, which
fails closed on every malformed shape). The row that compares a PR's baseline
against the artifact, and the ratchet.yml step that fetches it, are slice 2.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>

* fix(ratchet): writer and reader agree on what an attestation must be (Macroscope, #766)

A removed null-valued leaf is a change (path membership, not `.get()`); the
writer refuses run numbers the reader would reject and a checkout whose
baseline lacks a field; the reader requires exactly the baseline fields, so an
incomplete reference cannot pass as one.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>

* refactor(ratchet): split attest_refusal into its two questions (DeepSource, #766)

Flags first, checkout second, the same shape select_signature already has, so
adding a rule does not keep pushing one function's branch count up.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>

* fix(ratchet): baseline paths are tuples, so a dotted key cannot alias a nested one (Macroscope High, #767)

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>

---------

Co-authored-by: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
EtanHey and others added 2 commits September 5, 2026 15:22
# Conflicts:
#	scripts/ci_ratchet_table.py
#	tests/test_ci_ratchet_table.py
…roven by executing the step (Cursor, #767 round 1)

The two jq reads that bind the artifact to its run are guarded: under set -e
an unparseable artifact killed the fetch step before the hand-off was written,
so the row never rendered its promised RED-with-reason and Collect died on a
missing args file. The fetch step and the Collect guard are now EXECUTED in
tests under the machine's bash 3.2 with a stubbed gh on PATH: newest success
across pages, bind mismatch, corrupt JSON, missing file, expired artifact,
404 bootstrap, never-succeeded bootstrap, and a missing or empty hand-off into
Collect. Notes name both writer events; the attested notice names the run
instead of a stale initial reason.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@EtanHey

EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Round 1 (lead's Cursor pass) — all four real, fixed in one commit 9cb86671, test-first. Base is now main (ceeccfdf, #766 merged); attestation #1 on main is green (run 33965753235, artifact published).

  • medium, unparseable artifact kills the step under set -e: .github/workflows/ratchet.yml:485 — both jq reads are now if ! got_run="$(jq …)" || ! got_sha="$(jq …)", and a failure sets reason="… could not be read as JSON: <jq's first stderr line>" and falls through to the --attestation-unresolved hand-off, exactly like a bind mismatch. Proven by executing the step, not by grepping it: tests/test_ci_ratchet_table.py:2207 runs the real run: block under /bin/bash 3.2 with a stubbed gh and asserts, for {not json, empty, [] and a wrong-typed object: exit 0, an args file, --attestation-unresolved naming run 300. Before the fix that test failed with no args file (the dead-step shape the finding describes).
  • medium, hand-off only string-checked: tests/test_ci_ratchet_table.py:2112 onward — an executable harness (gh stub serving concatenated --paginate pages and artifacts, sleep stubbed, real jq) pins: newest success across two pages with newer failures first (test_the_fetch_step_takes_the_newest_success_across_every_page), bind mismatch on run id and on sha (…binds_the_artifact_to_the_run_the_api_named), artifact with no file, expired download → unresolved naming workflow_dispatch, HTTP 404 → bootstrap, runs-but-no-success → bootstrap with the count, and the Collect step executed with a missing and with an empty attestation-args.txt (test_collect_fails_before_rendering_when_the_attestation_hand_off_is_missing_or_empty: non-zero, no table).
  • low, Notes name only push: scripts/ci_ratchet_table.py:853 — "the latest successful push or (no-input) workflow_dispatch run".
  • low, stale reason in the notice: .github/workflows/ratchet.yml:492 sets it on attested; the notice prints ${reason} only. Pinned by the first executable test (attested — run 300 on main …, and "never read" absent).

Tests: 238 passed. This PR's own table on this head is the live proof of the full path — it should now read matches the main attestation (run 33965753235 · main ceeccfdf…).

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3a6a6219-58e7-4942-9e3c-e56687c8f7f2)

@EtanHey
EtanHey changed the base branch from wt/ratchet-b1-attest-store to main September 5, 2026 12:24
@EtanHey EtanHey closed this Sep 5, 2026
@EtanHey EtanHey reopened this Sep 5, 2026
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_27468cd6-ff98-4a41-874a-81f9f51adead)

Comment thread scripts/ci_ratchet_table.py
"GH_TOKEN": "stub",
"STUB_DIR": str(stub_dir),
}
result = subprocess.run(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'subprocess.run' used without explicitly defining the value for 'check'.


subprocess.run uses a default of check=False, which means that a nonzero exit code will be
ignored by default, instead of raising an exception.

You can ignore this issue if this behaviour is intended.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Explicit in ee4380e: check=False with a comment — the exit code of the executed fetch step is one of the things the test asserts, so raising on non-zero would hide the case under test.

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

if attestation_args is not None:
(runner_temp / "attestation-args.txt").write_text(attestation_args, encoding="utf-8")
env = {**_clean_git_env(), "RUNNER_TEMP": str(runner_temp), "GITHUB_OUTPUT": str(runner_temp / "out.txt")}
result = subprocess.run(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'subprocess.run' used without explicitly defining the value for 'check'.


subprocess.run uses a default of check=False, which means that a nonzero exit code will be
ignored by default, instead of raising an exception.

You can ignore this issue if this behaviour is intended.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Explicit in ee4380e: check=False with a comment — the Collect step's non-zero exit IS the assertion in that test.

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

Comment thread scripts/ci_ratchet_table.py Outdated
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

BrainLayer ratchet

Every Value below was measured by this run. A row this machine cannot measure says n/a — <reason> instead of a number; baselines in Notes name their own machine, method and date and were not measured here.

Row Status Value (measured by this run) Method Notes
commit provenance 🔴 RED checkout 7272db4a1d17 is neither 63e388c810c5 nor a merge of it — this run was triggered for a commit it does not have checked out commit graph + live PR head · in-process · runner Which commit this whole table is about. On a pull_request event the checkout is GitHub's synthetic merge ref, whose sha is not on the PR — #759's table printed 13fa724278bf while that PR's head was 4632f979 — so this row names the PR-head parent instead, the sha a reviewer can actually see. The comparison sha is read live from repos/{owner}/{repo}/pulls/{n} when the table is collected, not taken from the event payload, because the payload cannot know the run has been overtaken. Residual window, stated rather than papered over: a push landing between that read and the comment being posted is not caught here — the run for that push refreshes the table.
baseline attestation 🟢 GREEN baseline f421d1a7c5e6 matches the main attestation (run 33979237066 · main 2264b19ea0aa · 2026-09-05T16:53:22Z) main attestation artifact via Actions API · in-process · runner What every comparison is measured AGAINST, and who says so. The baseline fields of tests/fixtures/sprint_gate/corpus.json (queries, latency_baseline_ms, thresholds) are compared to the ratchet-attestation artifact of the latest successful push or (no-input) workflow_dispatch run of ratchet-attest.yml on main, fetched through the Actions API — a PR run cannot write to another run's artifacts. A field that differs is RED unless that main run measured the new value; today no runner-side collector measures any baseline field, so today the baseline cannot move by PR at all, and this row says so instead of a hand edit passing. Boundary: the comparator is this PR's checkout of ci_ratchet_table.py, diff-reviewable, not tamper-proof.
provenance 🟢 GREEN stamped 7272db4a1d17 == HEAD, tree clean wheel stamp · in-process · runner Sha half of #749 keg-mode provenance: a keg built from this wheel can answer __build_sha__. The helper-age and served-process predicates need a running BrainBar and are measured only by scripts/sprint_gate.py on an installed Mac. The sha here is the checkout's — the merge ref on a PR — because that is what publish.yml stamps at release time; the PR-head sha this table describes is the one in commit provenance above.
mapped bytes ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Baseline 26.2 GB — installed Mac, socket, 2026-09-03, after R2 drained 15,070 → 0. Up from 16.8 GB because the drain left more vectors mapped under the same cap: the change is the drain, not a leak. Not measured by this run.
search p50/p95 ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Margin p50: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin p95: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Calibrated on MacBook-Pro.local at 2026-09-01T08:42:22Z under active_sprint_load (tests/fixtures/sprint_gate/corpus.json). Not measured by this run.
idle CPU ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would ps sampling · installed Mac Ceiling: average CPU < 30% over a 60 s window (resource_budget in scripts/sprint_gate.py), ratified and kept as a hard budget. Margin daemon: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin helper: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin watcher: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Needs the BrainBar daemon, helper and watcher actually running. Not measured by this run.
signature_valid 🟢 GREEN 442 valid / 0 invalid · brainlayer 1.5.14 · macos-15/ARM64 · brew install exited non-zero (outcome: failure); the keg installed and the sweep ran after it codesign · brew keg · GitHub macOS runner scripts/release-verify-signatures.sh <keg> codesign-verifies every *.so/*.dylib under libexec/venv. The macOS parity job installs the published tap formula (etanhey/layers/brainlayer), so this row measures the release path — formula, published sdist and Homebrew's relocation — and not this PR's tree. Release-time baseline for the same keg on a different machine: 442 valid / 0 invalid — installed Mac (M4 Max), brew --prefix brainlayer 1.5.11, 2026-09-03.

🟢 GREEN measured, within budget · 🔴 RED measured, out of budget — a finding to clear before merge · ⚪ n/a not measurable on this machine, never guessed.

1 RED row(s) to clear: commit provenance.

Measured on Linux/x86_64 · measured 63e388c810c5 · PR head 63e388c810c5 · checkout 7272db4a1d17 · run · updated 2026-09-05 17:10:23 UTC

…too, and names no direction (Macroscope, #767)

When the attestation is not for this checkout's base, the row no longer says
main "moved" (a sha inequality is not an ordering). It reads the base tip's
committed baseline via git and judges the PR against THAT: a field reverted to
the attested-but-superseded value is a hand edit, RED; a PR carrying what main
has at the base is GREEN with the stale artifact named, not re-applied. The
executable harness declares check=False explicitly where the exit code is the
thing under test (DeepSource).

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_07dc4990-8001-423c-b1bc-953554bb51ed)

return attestation.measured.get(dotted(path), _UNMEASURED)


def attested_row(attestation: Attestation, corpus: dict, base_tip: str | None) -> Row:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`attested_row` has a cyclomatic complexity of 20 with "high" risk


A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Won't fix in this PR, deliberately: the lead closed review on this head (698400f8, round 2 of 2 ACCEPT) and every path through attested_row — stale base, unreadable base, revert-to-stale, measured key, unchanged, hand edit — is pinned by executed tests, so the split carries no correctness value here and would reopen CI on a PR that merges last in a queue. Follow-up, same shape as attest_refusal's split: lift the "attestation predates the base" branch into its own helper.

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

…g is not a bootstrap (Cursor, #767 round 2)

Same class as round 1, one layer up: a 200 from `gh api` with a non-JSON body
made the listing jq exit non-zero and killed the step under set -e before any
hand-off was written. Both listing reads are guarded now; garbage is one failed
attempt and three of them are `unresolved`, never bootstrap. Writing the test
found a second shape: an EMPTY 200 body slurps to `[]` and read as "0 runs,
bootstrap" -- the exact fall-back garbage must never reach -- so an empty body
is unreadable too. The git-read base fixture must carry every baseline field,
the shape the writer and reader already enforce. All executed, not grepped.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@EtanHey

EtanHey commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Round 2 of 2 (lead's Cursor pass, on 9cb86671) — verified on the current head: the listing jq was still unguarded at ee4380e8. All three real, one commit 698400f8, test-first, executed not grepped.

  • high, listing jq unguarded under set -e: .github/workflows/ratchet.yml:453 — both listing reads (selected, total) sit inside if [[ ! -s … ]] || ! selected="$(jq …)" || ! total="$(jq …)"; a failure is one failed attempt with reason="… could not be read as JSON in N attempt(s): <jq stderr | empty response body>", and three of them hand over --attestation-unresolved. Writing the test found a second shape you did not name: an EMPTY 200 body — jq -s slurps it to [], which read as "0 run(s) on main … bootstrap", i.e. garbage reaching the one fall-back the row must never take. An empty body is now unreadable too ([[ ! -s "$runs_path" ]]).
  • medium, no test for corrupt listings: tests/test_ci_ratchet_table.py:2270 executes the real step with the gh stub serving {not json, an HTML 502 page, a truncated paginate page, and an empty body: exit 0, --attestation-unresolved, "3 attempt(s)", and the word bootstrap absent from the output. Against the pre-fix step all four died with no args file (stashed and run, recorded in the report).
  • low, git_baseline_at accepts an incomplete base: scripts/ci_ratchet_table.py:720 — the base fixture must carry every BASELINE_FIELDS entry, the same shape the writer refuses to attest and the reader refuses to read; test_a_base_fixture_missing_a_baseline_field_is_not_a_reference pins the helper and the bootstrap row going RED on it.

Tests: 245 passed. Live table on this head follows; on ee4380e8 it already rendered GREEN with the non-directional wording doing real work (main had moved to 8aa562c3#763 — while the merge ref was still built on ceeccfdf; the old wording would have claimed main moved backwards).

— brainlayerClaude (worker) · claude-code/claude-fable-5-1

@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_99aa112c-a989-4370-b723-b8d125dae2a1)

…st-row

Union resolution: the `baseline attestation` row (this branch) and (c)'s margin
store (`--attestations`, `attestations*` Probe fields, margin Notes) coexist.
Two names collided and would have shadowed silently: (c)'s selection class is
now `AttestationStoreSelection`, and the helper-level dotted-key test is
`..._in_the_flattener`. `detect` keeps both selections in their own locals.
Verified: 257 table tests + 59 margin tests, and a local render with five real
main attestations shows the row GREEN against run 33967731131 and the margins
`unmeasured — 0 of the 5` side by side.

Co-Authored-By: brainlayerClaude running claude-fable-5-1 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ed7765d9-0a32-40d5-9e0d-00cb01b6f0e5)

)
if bootstrap is not None:
return AttestationSelection(bootstrap=bootstrap.strip() or "no attest run has completed on main yet")
attestation, problem = read_attestation(path) # type: ignore[arg-type]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium scripts/ci_ratchet_table.py:402

A deeply nested downloaded attestation raises RecursionError from json.loads(), so select_attestation crashes instead of returning an AttestationSelection(problem=...) for the promised RED row. Handle RecursionError alongside the existing parse errors in read_attestation (or contain it here) so malformed input fails closed with a diagnostic.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @scripts/ci_ratchet_table.py around line 402:

A deeply nested downloaded attestation raises `RecursionError` from `json.loads()`, so `select_attestation` crashes instead of returning an `AttestationSelection(problem=...)` for the promised RED row. Handle `RecursionError` alongside the existing parse errors in `read_attestation` (or contain it here) so malformed input fails closed with a diagnostic.

|| ! total="$(jq -rs '[.[].workflow_runs[]] | length' "$runs_path" 2> "$err_path")"; then
detail="$(awk 'NF { print; exit }' "$err_path")"
reason="the ratchet-attest.yml run listing could not be read as JSON in ${attempt} attempt(s): ${detail:-empty response body}"
elif [[ -n "$selected" ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium workflows/ratchet.yml:457

When 1,000 newer workflow runs fill GitHub's pagination limit without a selected success, this code reports bootstrap even though an older successful attestation may exist. That makes the baseline row fall back to the base commit instead of failing closed as unresolved; treat a full 1,000-run result with no success as unresolved rather than bootstrap.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/ratchet.yml around line 457:

When 1,000 newer workflow runs fill GitHub's pagination limit without a selected success, this code reports `bootstrap` even though an older successful attestation may exist. That makes the baseline row fall back to the base commit instead of failing closed as `unresolved`; treat a full 1,000-run result with no success as unresolved rather than bootstrap.

@EtanHey
EtanHey merged commit 7272db4 into main Sep 5, 2026
17 of 18 checks passed
@EtanHey
EtanHey deleted the wt/ratchet-b2-attest-row branch September 5, 2026 13:24
EtanHey added a commit that referenced this pull request Sep 5, 2026
…probe

Same DeepSource rule (PTC-W0055) that is currently red on main via #767. My
helper relied on the `check=False` default; it is now explicit, with the reason:
the assert below reports the child's stderr, which is a better failure message
than CalledProcessError's bare exit code.

This does not clear the DeepSource: Python check. That check is red on main's own
tip (7272db4) and was already red on #767's head when #767 merged, carrying two
`subprocess.run` findings in tests/test_ci_ratchet_table.py and a cyclomatic
complexity 20 on attested_row in scripts/ci_ratchet_table.py. None of those three
files is in this PR's diff.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>
EtanHey added a commit that referenced this pull request Sep 5, 2026
…s sklearn import behind it (#782)

* perf(hook): cap and skip UserPromptSubmit injection, and fix the 790ms sklearn import behind it

W18. The brief proposed a 600-char cap, a `^/` skip, and a <12-word skip. Measured
against 5,360 real hook fires over 30 days first: the cap saves 0.3%, the `^/` rule
never fires (slash commands arrive as `<command-name>` envelopes), and a raw 12-word
skip kills real questions. So:

- Relay/envelope skip — `[report]`, cross-session messages, `<command-name>` and
  `<local-command-*>` envelopes: 12.0% of fires, 10.0% of injected chars, no
  retrieval risk.
- Short-prompt skip narrowed to <12 words AND <=1 surviving keyword AND not on
  follow_up/entity_lookup/hebrew_query: 4.9% of fires, 4.8% of chars. Corrections
  still get their notice — short prompts are where corrections live.
- 600-char cap implemented as a bound against regression, cutting at a line
  boundary with a pointer, never below one line.

The real cost was elsewhere. `from brainlayer.pipeline.correction_detection import
detect_correction` at module scope pulled pipeline/__init__ -> semantic_style ->
sklearn: 790ms of the hook's 810ms floor, paid on every prompt including skipped
ones. semantic_style already defers sentence_transformers via find_spec for exactly
this reason; sklearn was missed. Deferred it the same way, and made the hook's
detect_correction lazy.

Measured on 20 real prompts from the lead's transcript: 3,973 -> 2,018 injected
chars (-49.2%), 880 -> 125 ms per prompt (-85.8%). No long human prompt lost a char.

Tests: 36 new in tests/test_prompt_search_cap.py, including two import-cost guards
verified to fail when each change is reverted. Full unit suite 4,603 passed.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>

* fix(hook): derive the cap's note reserve instead of hand-setting it

Self-review caught a real off-by-one in the cap I had just written. The reserve
was 56, but the pointer line is 56 chars at one digit plus the newline that joins
it -- 57. A budget filled to the byte therefore produced 602 chars against a 600
cap:

    lines = ["x" * 44] + ["y" * 49] * 30   ->  602

The reserve is now derived from the note template itself (`len(...format(9999)) + 1`)
so it cannot drift from the string again. Two tests pin it: the exact 602 case, and
the invariant across 2/3/7/15/40/120 lines. A 200,000-trial fuzz over random line
counts and widths reports 0 violations with a worst-case total of exactly 600.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>

* fix(hook): address review round 1 — two of the four findings were real bugs I shipped

Macroscope reviewed and was right four times.

1. The `entity_lookup` exemption was DEAD CODE. The short-prompt gate ran where
   `classify_prompt(prompt)` had not yet seen any entities, so it could never
   return `entity_lookup` -- a one-word entity question ("Etan?") was skipped
   instead of answered. Gate moved to after entity reclassification. A test
   asserts the source ORDER, not just the predicate.

2. Relay prefixes were matched with `startswith` alone, so a prompt that opened
   by quoting `[report]` or `<command-name` while asking about it got skipped.
   Each shape must now carry its envelope structure: a closing tag, a `from=`
   attribute, or the path a report ping names.

3. The deferred import was eating the search deadline. `start` is captured
   inside main(), so moving the ~105ms pipeline import out of module scope
   charged it against DEADLINE_MS=450, where a slow first import could silently
   suppress entity detection and FTS -- the one thing the deadline must not do.
   `search_elapsed_ms()` subtracts deferred-import time; `elapsed_ms()` still
   reports true wall time to telemetry.

4. Capped results were still registered as injected. Chunk IDs the cap withheld
   went into the session dedup file anyway, so later prompts would suppress
   chunks the agent never received -- silent memory loss. `cap_injection()` now
   returns `(kept, dropped)` and registration is trimmed to the survivors.

DeepSource: both `global` statements removed (deferred-import state moved into a
dict) and the 20 pytest methods that ignore `self` are now `@staticmethod`.

Honest cost of being right: the 30-day projection falls from 15.1% to 13.5% of
injected chars (~65K -> ~58K tokens/30d). 95 short prompts keep their entity
context and 6 quoted-prefix prompts are no longer treated as relays. Correctness
bought with savings, in that direction.

Tests 36 -> 63. Full suite 4,884 passed after merging main.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>

* test(hook): make subprocess.run's check= explicit in the import-cost probe

Same DeepSource rule (PTC-W0055) that is currently red on main via #767. My
helper relied on the `check=False` default; it is now explicit, with the reason:
the assert below reports the child's stderr, which is a better failure message
than CalledProcessError's bare exit code.

This does not clear the DeepSource: Python check. That check is red on main's own
tip (7272db4) and was already red on #767's head when #767 merged, carrying two
`subprocess.run` findings in tests/test_ci_ratchet_table.py and a cyclomatic
complexity 20 on attested_row in scripts/ci_ratchet_table.py. None of those three
files is in this PR's diff.

Co-Authored-By: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>

---------

Co-authored-by: brainlayerClaude running claude-opus-5 <noreply@anthropic.com>
@EtanHey EtanHey added the size:L Tight-loop PR size: over 400 hand-written lines changed; canon 9 needs a one-line why label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S Small change size:L Tight-loop PR size: over 400 hand-written lines changed; canon 9 needs a one-line why

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant