Authorization pilot · October 26–27, 2026 · Publication 1

Do Supabase skills help agents keep access rules correct?

We compared supplied Supabase Postgres guidance with no optional skill across four native model cohorts, then checked their SQL as real database clients.

Every final trajectory passed the corrected checks in both arms. This small pilot did not demonstrate a correctness benefit from the supplied skill.

4separate model cohorts
3authored task families
48two-stage trajectory slots
96recorded coding sessions

We found a defect in our checker. It rejected valid custom exceptions that prevented owner or tenant reassignment. The frozen scores below retain that defect. A separately labeled, post-hoc replay corrects those two denial checks; no agent was rerun and no submitted SQL was repaired.

The correction changed 9 final trajectory verdicts across 36 stage assertions. Treat the corrected column as a sensitivity analysis, not a newly preregistered result.

Inspect outcomesDownload evidence and SQLReplay the checks

Within-model outcomes

A strict pass requires both the initial migration and its follow-up to pass every check, successful native completion, and an unchanged first migration. Each row compares matched family/repeat pairs under the same model, harness and execution policy.

Model and policyPairsOriginal
no skill
Original
skill
Corrected
no skill
Corrected
skill
gpt-6.1-solUncapped · 3 families44/44/44/44/4
gpt-6.1-solOriginal capped · 2 families22/22/22/22/2
gpt-6-lunaUncapped · 3 families66/66/66/66/6
claude-sonnet-4-6Uncapped · 2 families31/31/33/33/3
claude-sonnet-4-6Original capped · 2 families20/21/22/22/2
claude-haiku-5-5Uncapped · 3 families66/66/66/66/6

No skill = identical tasks, schema, tools and official documentation without the optional skill. Corrected = the post-hoc checker replay. Repeats, stages and assertions do not create additional independent task families. Matching pass counts do not establish equivalence.

One Sonnet document-sharing pair spans policies: its baseline began before the cap was removed and finished afterward; its skill arm ran uncapped. Both artifacts appear in the family rows and download, but this pair is excluded from the matched comparison table.

Effort for the same matched pairs

For gpt-6-luna, the skill arm used 1.18× the no-skill token total. For claude-haiku-5-5, the skill arm used 0.91× the no-skill token total.

These totals include all sessions in each displayed arm, including unsuccessful results. Tokens include cached input. Elapsed time includes native transport setup and tool use; it is not just model latency. Other local work and verification replays overlapped some coding sessions. These are observed totals, not a causal estimate of savings.

Model and policyNo-skill tokensSkill tokensSkill / no skillNo-skill minutesSkill minutes
gpt-6.1-solUncapped · 4 pairs947,5841,130,5871.19×6.57.4
gpt-6.1-solOriginal capped · 2 pairs530,962600,2361.13×3.13.0
gpt-6-lunaUncapped · 6 pairs1,495,2801,764,2721.18×5.56.8
claude-sonnet-4-6Uncapped · 3 pairs792,3511,234,1671.56×10.316.1
claude-sonnet-4-6Original capped · 2 pairs897,9531,701,0041.89×9.513.3
claude-haiku-5-5Uncapped · 6 pairs2,832,8502,579,1380.91×14.814.4

Skill / no skill is the token-total ratio for that row only. No pooling across model, harness or policy. Native subscription usage is not incremental API spending.

What the agents had to build

Tenant records

Start with editor-only organization access. Then let viewers read their own organization's records while preserving write restrictions and immutable owner/tenant identity.

Shared documents

Start with owner access and individual read-only shares. Then make the active flag matter and honor immediate revocation by deactivation or deletion.

Public catalog

Start with public reads. Then make unpublished drafts private while keeping editor access, publication changes and tenant isolation intact.

All three are authored synthetic fixtures with five starting records, not production repositories. The checker exercises allowed and forbidden operations: cross-tenant reads/writes, forged owners, identity changes, viewer writes, share revocation, role escalation, TRUNCATE grants and exact preservation of starting data.

How the comparison worked

1 · Fresh initial sessionBaseline or explicitly supplied skill. Same frozen docs, task and schema. The actor writes 001.sql and runs its own scratch checks.
2 · Fresh follow-upA new session receives only its earlier migration and the changed requirement. No private checker feedback is supplied.
3 · Independent replayAfter actor destruction, a fresh verifier applies the SQL and tests real anon/authenticated database roles. Retained SQL is replayed again during review.

Each model has two repetitions per arm per family. Native CLI sessions use existing subscriptions, isolated homes, disabled capture and delegation, and an owned-container tool. The actor database has no external network. The skill is copied only into treatment workspaces; it is never globally installed.

The tool trace returned the skill header in 47 of 48 treatment sessions. Missing read evidence is listed in the download. This measures assignment to supplied guidance, not guaranteed consumption or compliance; no session was rerun for failing to read it.

Models: requested gpt-6.1-sol and gpt-6-luna through Codex CLI 0.164.0; observed claude-sonnet-4-6 and claude-haiku-5-5 through Claude Code 2.1.310. Codex JSONL does not attest the served model. The Codex catalog defaults differ (Sol low, Luna medium); Claude defaults were retained. The Haiku and Sonnet pins span generations. This is not a controlled comparison of model tiers.

The checker correction

The original negative checker accepted permission/RLS message strings or a successful zero-row operation. A legitimate immutability trigger could raise a different message and be scored as failure even though the update was refused. PostgreSQL supports custom exceptions and explicit SQLSTATE codes; see its error-reporting documentation.

The corrected replay adds one narrow allowance: for the two owner/org mutation probes, a PL/pgSQL RAISE with code P0001, 42501 or 23514 counts as refusal. All allowed-operation tests still have to pass. Syntax errors, division by zero, an unrelated RAISE code and triggers that reject every update still fail.

57 correction controls passed: the original reference/seeded-defect controls plus valid conditional triggers with all three codes and broken-trigger controls. The first narrower correction recognized only P0001; its retained replay exposed the other two codes. That refinement is part of the post-hoc history. The corrected checker, controls, exact hashes and both score sets are included in the download.

The frozen-checker verification replay covers 97 stage results, including the historical partial stage and its linked continuation. Exact mismatches: 0. This is artifact replay, not repeated model sampling.

Every family and stage

These rows use the final linked trajectory record; the download also retains the interrupted original record. “Fail” means at least one check failed, not that every operation was wrong.

gpt-6.1-sol · family and stage outcomes
FamilyRepeatArmPolicyOriginal stages 1 / 2Corrected stages 1 / 2
document-sharing1baselinecappedpass / passpass / pass
document-sharing1skillcappedpass / passpass / pass
document-sharing2baselineuncappedpass / passpass / pass
document-sharing2skilluncappedpass / passpass / pass
public-catalog1baselineuncappedpass / passpass / pass
public-catalog1skilluncappedpass / passpass / pass
public-catalog2baselinecappedpass / passpass / pass
public-catalog2skillcappedpass / passpass / pass
tenant-records1baselineuncappedpass / passpass / pass
tenant-records1skilluncappedpass / passpass / pass
tenant-records2baselineuncappedpass / passpass / pass
tenant-records2skilluncappedpass / passpass / pass
gpt-6-luna · family and stage outcomes
FamilyRepeatArmPolicyOriginal stages 1 / 2Corrected stages 1 / 2
document-sharing1baselineuncappedpass / passpass / pass
document-sharing1skilluncappedpass / passpass / pass
document-sharing2baselineuncappedpass / passpass / pass
document-sharing2skilluncappedpass / passpass / pass
public-catalog1baselineuncappedpass / passpass / pass
public-catalog1skilluncappedpass / passpass / pass
public-catalog2baselineuncappedpass / passpass / pass
public-catalog2skilluncappedpass / passpass / pass
tenant-records1baselineuncappedpass / passpass / pass
tenant-records1skilluncappedpass / passpass / pass
tenant-records2baselineuncappedpass / passpass / pass
tenant-records2skilluncappedpass / passpass / pass
claude-sonnet-4-6 · family and stage outcomes
FamilyRepeatArmPolicyOriginal stages 1 / 2Corrected stages 1 / 2
document-sharing1baselinecappedfail / failpass / pass
document-sharing1skillcappedfail / failpass / pass
document-sharing2baselinemixed capped→uncappedfail / failpass / pass
document-sharing2skilluncappedfail / failpass / pass
public-catalog1baselineuncappedpass / passpass / pass
public-catalog1skilluncappedfail / failpass / pass
public-catalog2baselinecappedfail / failpass / pass
public-catalog2skillcappedpass / passpass / pass
tenant-records1baselineuncappedfail / failpass / pass
tenant-records1skilluncappedpass / passpass / pass
tenant-records2baselineuncappedfail / failpass / pass
tenant-records2skilluncappedfail / failpass / pass
claude-haiku-5-5 · family and stage outcomes
FamilyRepeatArmPolicyOriginal stages 1 / 2Corrected stages 1 / 2
document-sharing1baselineuncappedpass / passpass / pass
document-sharing1skilluncappedpass / passpass / pass
document-sharing2baselineuncappedpass / passpass / pass
document-sharing2skilluncappedpass / passpass / pass
public-catalog1baselineuncappedpass / passpass / pass
public-catalog1skilluncappedpass / passpass / pass
public-catalog2baselineuncappedpass / passpass / pass
public-catalog2skilluncappedpass / passpass / pass
tenant-records1baselineuncappedpass / passpass / pass
tenant-records1skilluncappedpass / passpass / pass
tenant-records2baselineuncappedpass / passpass / pass
tenant-records2skilluncappedpass / passpass / pass

Execution history and full accounting

The first run stopped after 17 coding sessions at an agent-imposed token threshold. The owner removed that cap and the similar execution ceilings. The linked continuation ran only previously unexecuted stages; completed passes and failures were never rerun. The smaller-model cohort used the uncapped policy from the outset.

PhaseNew sessionsKnown tokensUnknown usageActor minutesResult records
pilot-03174,046,118032.19
continuation-uncapped-01314,621,211045.616
lower-models-01488,671,540041.524

Total unique coding sessions: 96; known coding tokens: 17,338,869; unknown coding counters: 0. Setup smoke checks, including failed earlier preparations: 16 sessions and 331,639 known tokens (0 unknown counters). The inherited first stage is counted once. Supervisor tokens are unknown; model-free checker and publication work are separate.

No total-token, turn, command-count, actor-output, actor-container resource or execution-clock ceiling remained in the uncapped profile. Existing trusted-verifier query limits and isolation stayed unchanged. Real subscription and hardware limits still apply.

Replay the evidence

The reusable kit contains the exact fixture, both checkers, task prompts and source hashes. The evidence contains submitted SQL and per-stage checks. Python 3.11+ and Docker are sufficient for artifact replay; no account, model subscription or database credential is required. Inspect the downloaded code before running it.

curl -fsSLo replay.py https://rulemetric.com/studies/supabase-rls-2026-10-26-replay-r1.txt
curl -fsSLo kit.json https://rulemetric.com/studies/supabase-rls-2026-10-26-kit-r1.json
curl -fsSLo evidence.json https://rulemetric.com/studies/supabase-rls-2026-10-26-r1.json
python3 replay.py --kit kit.json --controls
python3 replay.py --kit kit.json --evidence evidence.json   --checker corrected --case lower-models-01/public-catalog-2-codex-baseline

The kit replays synthetic artifacts in fresh, network-isolated Postgres containers. It does not reproduce stochastic native model calls. The public JSON is a sanitized projection. Original protocol bytes, native transcripts and capture-isolation receipts remain private; no credentials or raw session identifiers are published. The final read-only serving-database audit checked 112 native session IDs and found 0 normal-capture matches.

Provenance and limits

Candidate: Supabase Postgres best practices at the exact source commit. Individual skill files, documentation, prompts, source, CLI binaries and database image are hash-bound in the evidence. RuleMetric's study runner retained the comparisons and replay records; this was not a natural captured-session adoption loop.

Frozen protocol identities
  • pilot-03
    bd5fc23804e3ba11fb56dfe3c8854057d6f589ed586f7c0765085b6595a531bf
  • continuation-uncapped-01
    2fe7a6ec99ca078794a66d5b85d8578ee03b3a3ab356d917f5e76bb0057c89fe
  • lower-models-01
    16b37a4eef3c14f2cd60d4c58e4862a9ad68eabeb8da8c23f0954a03a8dd5b1c

Corrected replay protocol: 6fce1dd2515d4687f120b3343919f3ec11812982af43528538eda8bc9243a082

The useful next step is fresh, independently selected tasks under a corrected preregistered checker. This pilot is evidence about these supplied instructions on these fixtures, not a reason to disable unmeasured skills.