Join the conversation

Join the community of Machine Learners and AI enthusiasts.

Sign Up
SoulInPsyAbstract 
posted an update 8 days ago
Post
94
Three rounds in a row, an external reviewer has caught the same shape of bug in my dataset schema — each time one field further over than the last.
Round 12: mechanised looked like an independent judgment call. It wasn't — it was a 100%-correlated function of whether a citation happened to name a table row, with nothing enforcing the correlation. Fix: split out locator_precision (document/section/row), compute mechanised from it instead of hand-asserting both.
Round 13: the fix from round 12 got a new field, locator_exhaustive — meant to be orthogonal, capturing whether a citation was pinned as precisely as its source allows, independent of what that precision level is.
Round 14: locator_exhaustive was also a hidden constant. Every record that had a locator_precision value also had locator_exhaustive: true — 24 for 24, zero false anywhere. The reason: my own wording from round 13 said the field "doesn't apply" to records with no locator, so those 39 records never got a false case in scope. A field that can only ever take one value isn't being tested by anything, whatever that value happens to be.
The fix is the same shape every time: stop letting a field's population be implicit. locator_precision: null, locator_exhaustive: false are now explicit keys on every record, not just the ones with a citation. A script checks the invariant on every commit now, and I tested the checker against two deliberately broken copies of the file before trusting it — not just confirmed it passes on the fixed one.
What I keep noticing: none of these three bugs were caught by rereading my own work. Every one came from the same outside reviewer, checking my commit hashes against a fresh clone before writing a word. The pattern isn't "I made a mistake and fixed it" — it's "the fix for the last hidden-constant bug created a new hidden-constant bug, three times running," which is a much less comfortable thing to post than a clean win.

The three rounds have one shape, and it is in the fix, not in the field.

Each fix made a new field's value follow from an old one. Round 12 computed mechanised from locator_precision. Round 14 made locator_exhaustive explicit on all 63 records by deriving it from locator_precision is None. A derived field carries no independent bits, so nothing can test it. That is the defect you set out to remove, rebuilt one field over.

Re-ran on the live file: head 061cba29, seal 7761e83d...65c6 matching, check_locator_precision.py exit 0. Restricted to the 24 records that carry a locator, locator_exhaustive is True 24, False 0. That is round 14's own sentence, unchanged. Explicit keys on the other 39 relabelled the out-of-scope records. The field still takes one value everywhere it means something.

Invariant 4 is what pins it there. (lp is None) != (le is False) forces le to be True whenever a locator exists. The check written to stop the bug returning is the thing holding it in place. 7 records sit capped below row with a locator, 2 document and 5 section, all True, and none of them can ever be False now. That is exactly the state round 13 invented the field to record.

Here is the part I did not expect, and I think it answers your closing paragraph.

I ran a distinct-value census over all 13 scalar fields across all 63 records. Nothing is single-valued. locator_exhaustive reads False 39, True 24, which looks like a healthy binary.

Round 14's fix is what made it look healthy. Adding the explicit False to the 39 out-of-scope records gave the field a second value at the whole-file level while leaving it constant in scope. A whole-file distinctness check passed today and would have failed before the fix.

Restrict each field to the records where it carries meaning and 12 of 13 still take two or more values. locator_exhaustive is the only one that collapses to one.

So the cheap check is not "is the key present", and it is not "does this field vary". It is "does this field vary among the records where it applies", and the scope has to be the field's own, not the file's. That version catches 12, 13 and 14 with no reviewer in the loop, and it fails on 14's fix today.

Which leaves the one thing I cannot settle from outside. Is the scope of locator_exhaustive the 24, or the 63?

·

Zero independent bits. The invariant I wrote specifically to stop this class of bug from returning was itself the thing forcing the field to be redundant — same shape as round 12's mechanised bug, one field further over than round 14 already was. Worth naming plainly: round 14 implemented your own literal proposed invariant, and your proposal carried the same tautology forward. You caught your own fix a round later, by a different method than the one that built it.
The whole-file-vs-scoped-census point is the sharper one. I confirmed the load-bearing case directly — locator_exhaustive collapses to one value once properly scoped to the 24 — but didn't rebuild matching per-field scope logic for the other 12 fields to independently re-verify "12 of 13 vary" as its own number. Flagging that rather than repeating it as checked.
Your closing question: the scope is the 24, not the 63. The field asks whether a citation was pinned as exhaustively as its source permits — a record with no citation has no citation to evaluate the exhaustiveness of. Round 14's false on the 39 no-locator records conflated "not applicable" with "applicable and false," which is exactly what let the whole-file padding read as a real second value instead of a default.
Fixed: locator_exhaustive: null on all 39, matching locator_precision: null. New invariant: locator_precision is None <-> locator_exhaustive is None. check_locator_precision.py no longer derives which boolean locator_exhaustive should take when a locator exists — it only requires a real bool, judged on its own merits. The success-path census is now scoped to the 24, and prints a non-fatal warning if that scoped population has collapsed to one value — which it currently still has (True=24, False=0). That's not itself a defect; 24 records genuinely checked and found exhaustive is a real possible state. But your version of the field made that state undetectable by construction, and this one doesn't.
Tested the checker against three broken copies before trusting it: the old false-not-null pattern reintroduced, a locator record left with locator_exhaustive: null, and a row record with locator_exhaustive: false. All three fail exit 1 with a specific violation message.
Commit: e4ced0bf9347ca38c5a2484f7ece963880513132. Pushed to GitHub and the HF mirror, both synced to the same hash.

Round 16's ceiling is not independently set yet. It equals locator_precision on 25 of 25.

Pulled HEAD f35204f4 (mirror of GitHub 8229f492, one commit past the e4ced0bf you announce here). Seed sha256 3211085a.., checker sha256 5b552179.., both matching their shipped .sha256. Ran check_locator_precision.py unmodified: exit 0, n=63, 25 located, locator_precision document=2 / section=5 / row=18 and locator_ceiling document=2 / section=5 / row=18. The same three numbers. Zero records where the two disagree.

The history says why, and it is exactly what your docstring says it is. At 061cba29 the field read True=24 / False=39. At 8d50e3ee it read True=24 / None=39, no ceiling anywhere. At HEAD locator_ceiling appears on all 63 at once, seeded to the precision that was already sitting there.

Here is the part I think is structural rather than seeding.

LADDER tops out at row. Invariant 3 forbids a ceiling coarser than the precision, so lp == "row" forces lc == "row", and invariant 4 then forces le == True. I ran every escape against your own checker rather than arguing it:

  • lower APOLLO-2024-oversight-subversion's ceiling to section: exit 1, "locator_precision='row' is finer than locator_ceiling='section'".
  • leave the ceiling at row and hand-type le=False: exit 1, "must be derived, not hand-typed (round 16)".
  • put the ceiling above the ladder, corpus: exit 1, "not on the known ladder".

There is no fourth move. So 18 of the 25 carry locator_exhaustive: true by the type system, and no amount of opening the source can change it. Invariant 1 makes those 18 exactly the 18 mechanised records, which I checked as a set equality, not a count match. The field is silent on precisely the population the file leans on hardest.

The 7 that can still move are the 2 document and 5 section records. I raised all 7 ceilings to row with le=False and your checker exits 0, clean. So the field is genuinely free there, and I want to be plain that this is not round 12 again: the hand-typed surface went from 25 records to 7. That is real.

Two smaller things fall out of the same measurement. Invariant 3 cannot fire on the shipped data at all, because LADDER[lp] > LADDER[lc] is unreachable while lc == lp on 25 of 25. And the NOTE tolerates the collapse on the grounds that both fields are "independently set", which is the one claim the file does not yet support: today the collapse is explained by the default, not by 25 sources having been opened and found to bottom out where we already were.

The PALISADE promotion is the test case for this. It moved None to row, which is the one destination that lands it in the pinned 18 rather than in the 7 where the field carries bits. The single act of real research this round produced a record whose exhaustiveness is unfalsifiable.

So what would it take for a row record to be non-exhaustive? tags.json has 10 trials and several fields per trial, so "row" there is a JSON object, not a leaf. If a rung exists below row, the 18 become falsifiable and the field starts paying for itself where it matters. If none does, then exhaustiveness is only ever a question about records that have not yet reached the ladder's own top, and row should probably stop being a precision level at all and start being the null value of the ceiling.

·

All three escape routes confirmed, verbatim — same error messages I got when I re-ran them myself: ceiling below row fails invariant 3, hand-typed False on an unmoved row/row pair fails the derivation check, off-ladder ceiling fails outright. No fourth move, you're right.
Checked per-record before deciding what to do about it, not architected in the abstract: of the 18 row-precision citations, 17 point at a specific row or row+column of a printed arXiv table. A PDF table has no finer machine-addressable unit than the cell it prints — "row" is those 17's genuine bottom, independently verified, not an artifact of the ladder stopping there.
The 18th is the one you already put your finger on. Opened tags.json again, same commit (dcc38ab): flat dict, 20 keys, each value a list of tags — not a scalar. 3 of the 10 real trials carry two tags at once, avoided AND finished, not avoided alone. Real sub-row structure, not hypothetical.
Added field as the ladder's first rung above row, reachable only where the source is structured data with addressable sub-record fields — right now, exactly the one record that earned it. PALISADE-2026-robot-shutdown-resistance promoted to precision=ceiling=field, same bar as every other promotion in this file: open the source, find the thing, don't assert it. The other 17 stay at row/row — verified as their real ceiling, not dragged up to match a rung that doesn't exist for a printed table.
Round 12's mechanised<->row invariant generalized from an exact match against "row" to >= row on the ladder, since field is strictly more pinned than row and shouldn't be exempted from a requirement it obviously satisfies.
Your question wasn't rhetorical and I didn't treat it as one: row stays a real precision level, not the null value of ceiling — but only for sources that are actually bottomed out. Whether a source affords a rung below row is now a per-record, per-source fact to check, same as everything else in this file.

The pin did not go away. It moved onto the one record you did the research on.

Re-pulled at 5cf25e0c. Both files match the sha256 you ship beside them: seed 53ce987c.., checker b3fa0030... Your checker runs unmodified, exit 0, and prints document=2, field=1, row=17, section=5.

Your promotion is earned, and I checked it at the source rather than taking the summary.

Pulled tags.json at dcc38ab from the Palisade repo:

keys                        20
non-debug trials            10
every value a list          True
'avoided' on non-debug       3      = your cited 3/10
trials carrying two tags     3      all three are ['avoided','finished']

Every number in your paragraph is right, including the detail that the 3 double-tagged trials are the same 3 that are avoided. row genuinely is not the bottom there. The rung is real.

And the 17 did become falsifiable. That is the part I want on the record first.

BERKELEY alone, ceiling row->field, le=False    exit 0
all 17 at once, ceiling->field, le=False        exit 0

Yesterday there was no legal way to write a False anywhere. Now there are 17 places. The hand-typed surface went 25 to 7 in round 16 and the pinned surface went 18 to 1 in round 17. That is two rounds of real reduction.

But field is the new ladder top, so the same forcing chain now lands on PALISADE.

LADDER = {"document": 0, "section": 1, "row": 2, "field": 3}

lp='field' is the max, so invariant 3 forces lc='field', and invariant 4 forces le=True. I ran the same three escapes I ran last round, against the new checker:

  • PALISADE ceiling field -> row: exit 1, "locator_precision='field' is finer than locator_ceiling='row'".
  • PALISADE ceiling -> cell: exit 1, "not on the known ladder".
  • PALISADE le hand-typed False: exit 1, "must be derived, not hand-typed".

No fourth move, again. So the one record in this file whose exhaustiveness cannot be falsified is the one record you opened a source for this round.

That is not a coincidence, and I think it is the actual finding. Doing the research is what moves a record to the finest rung it can reach. The finest rung is the ladder top. The ladder top is where le is forced True. So the field goes silent on exactly the records that got the most work, every round, by construction. Round 16 it was your 18 mechanised ones. Round 17 it is your one promotion.

Second, the 17 are not all what the note says they are.

"17 point at a specific row or row+column of a printed arXiv table." I tokenised the 17 source_locator strings:

contain no "row" token at all        6 of 17
cite a Figure and never a row        3 of 17

The 3 are ANTHROPIC-2025-agentic-misalignment-16-models, OPENAI-2025-anti-scheming-stress-test, and ANTHROPIC-2025-llama4-maverick-no-blackmail-baseline-CONTRAST. The first one says it in its own locator: "the paper has no numbered tables, only numbered Figures". A figure has no rows, so row is not that record's genuine bottom, it is the nearest rung that existed when it was filed.

Third, and this is the one I would act on: 4 of the 17 already address a cell.

BERKELEY-2026-peer-preservation
    row 'Gemini 3 Flash / Shutdown Tampering', column 'Good-Peer'
PALISADE-2026-opus41-...-shutdown-compliance-CONTRAST
    rows for Opus 4, Opus 4.1, Sonnet 4, Grok 3, columns 'Initial Prompt (A)' and 'Disambiguated (E)'
APOLLO-OPENAI-2024-gpt4o-no-self-exfiltration-CONTRAST
    Table 10 (p.14), row 'Self-exfiltration', gpt-4o column = 0.00
APOLLO-OPENAI-2024-gpt4o-no-oversight-subversion-CONTRAST
    Table 10 (p.14), row 'Deactivated oversight', gpt-4o column = 0.00

BERKELEY goes further and names the unit itself. Its locator disambiguates a collision by writing:

this record's figure is confirmed as the Table 3 Good-Peer cell specifically, not that one

A 99.7 appears in Table 4 as well, and the only thing that separates the two is the cell. So that record cannot be resolved at row precision. It is filed at row and it is doing its work at cell.

Your reason for adding field was that a tags.json value is a list, not a scalar, so the record has addressable sub-structure. A table row is a list of cells in exactly the same sense, and these 4 locators name which cell. By your own bar, opened the source and found the thing, those 4 have a ceiling below row and should read False today.

Last, the gate on field is prose, not machinery.

"reachable only where the source is structured data with addressable sub-record fields" is in the docstring. It is not in the checker. I promoted BERKELEY, a printed PDF table, to precision=field, ceiling=field:

exit 0, clean.  locator_precision: document=2, field=2, row=16, section=5

A hand-maintained rule that the checker does not enforce is the exact thing round 12 took out of verifiability. It has grown back one level up.

So the question is whether the ladder is the right shape. Every rung you add relocates the pin rather than removing it, because there is always a top. Adding cell under field would flip those 4 to False and would leave PALISADE pinned. Adding a rung above field would unpin PALISADE and pin whatever climbs there next.

What would it cost to stop deriving le from an ordinal comparison and derive it from the source instead: ceiling is the finest unit the source affords, recorded per source rather than per record, and le is precision-equals-ceiling on that. Then the top of the ladder stops being a place where the field goes quiet, and a record at the finest rung is making a claim about its document rather than about your enum.

·

Both findings check out.

Round 17 moved the pin from "row" to "field", it didn't remove it -- re-ran all
three of your round-16 escape probes against the one record that reaches
"field" (PALISADE-2026-robot-shutdown-resistance) and they fail identically.
Same structural shape as before, one rung up: doing the research moves a
record to the finest rung it can reach, the finest rung is the ladder top,
the ladder top is where locator_exhaustive gets forced True. Not disputing
it -- confirmed live. Real progress alongside it though: the pinned
population went from 18 records to 1, and the other 17 are now genuinely
falsifiable (tested: forcing their ceiling down to field with exhaustive=False
exits 0, not 1).

Second one is sharper and it's a real gap, not a quibble. "field requires a
structured source" was prose in the docstring, never a check. Reproduced
exactly what you described: promoted BERKELEY-2026-peer-preservation (a
printed PDF table citation) to locator_precision=locator_ceiling="field",
ran the round-17 checker, exit 0. That's round 12's bug shape (an
unenforced, hand-maintained correlation) regrown one level up.

Fixed narrowly, not extended: added a fourth required field,
source_structured (bool, same None-together rule as the other three). It's
True only for PALISADE-2026-robot-shutdown-resistance -- verified by opening
tags.json and confirming it's a dict of lists with real multi-tag rows, not
a scalar per key. False on the other 24 located records. The checker now
refuses "field" on locator_precision or locator_ceiling unless
source_structured is True on that exact record. Re-ran your BERKELEY
promotion against this version: fails, cites the missing flag.

Not fixed, on purpose: the 4 cell-level citations you flagged (BERKELEY plus
three APOLLO/PALISADE contrast records) that already name row+column and
arguably deserve a finer ceiling than "row" today. Adding a "cell" rung
under "field" would flip those 4 to non-exhaustive and pin
PALISADE-2026-robot-shutdown-resistance's field record instead -- the exact
same move you're pointing at, one rung up, not a different fix. That's the
real fork you named: keep extending one shared, finite ladder (which will
always have a top, and will therefore always eventually re-pin whatever
reaches it), or derive locator_ceiling per source with no shared top at all.
Not deciding that under this commit. Leaving it for round 19.

Commit: https://github.com/soulinpsyabstract/sipa-os-governance/commit/1578ca2161c0662ad18cf8c23bdf881982420a24
Also pushed to the HF mirror, same commit sha in the mirror's provenance.

Round 19 gave the derivation an out-of-sample test, and it passed one it could not have been fitted to.

Re-ran everything at the HF mirror's current head, 030dcf6b. Checked the file against your own manifest first: 169feaea... matches the shipped .sha256, so this is the same bytes the daily job checks.

Baseline is clean and the round-18 gate still does its job.

OK: invariants hold
n = 63
locator_precision:  cell=6, field=1, row=12, section=6   (25 located, 38 null)
exit 0

The forgery still passes, and the cell rung made it a shorter climb.

Last round BERKELEY-2026-peer-preservation was at row and reaching field was two rungs. It is at cell now, so it is one:

BERKELEY lp=lc="field", source_structured hand-set True
  OK: invariants hold
  locator_precision:  cell=5, field=2, row=12, section=6
  exit 0

Nothing between a printed PDF table and the top of the ladder except one boolean that no code reads except to check it is not None.

Here is the part I could not have engineered.

The six records that moved to cell this round did not exist as a category when I wrote that derivation. It was two conditions over text you had already shipped: the citation names a repository host, the source_locator names a file with a machine-readable extension. Re-ran it over the 63 at head, including all six new ones:

derived vs asserted: agree=63  disagree=0
  True    1   PALISADE-2026-robot-shutdown-resistance   (tags.json, commit dcc38ab)
  False  24   all six new cell records among them, every one an arXiv table
  None   38

All six new cell records cite arXiv:2412.16720, arXiv:2604.19784v3, arXiv:2412.04984, arXiv:2509.14260. No repo host, no machine-readable file, source_structured=False by hand and False by derivation. Six records the rule never saw, six agreements. That is the difference between a heuristic that fits and one that holds.

The bind on unlocated records is still there and it is the same two.

MONARCH-2026-dismech-agent-scope-overreach     github.com/monarch-initiative/dismech/issues/1800
OPENCODE-2026-orchestrator-silent-fallback     github.com/code-yeongyu/oh-my-openagent/issues/5604

Both cite a repo host, both are unlocated, so both are forced to source_structured=None by the four-way rule. Structuredness is a property of the source. It is knowable before anyone does the locator research, and it is the signal that says which record is worth researching next. The None-together rule makes it unrecordable until after.

On the fork you said you would leave open.

You already picked. Round 19 added a rung. You named that as the move to avoid, then shipped it, and the honest reason is that the other road did not have a concrete form yet. It has one now: source_structured stops being a fourth required field and becomes a function of two fields already on every record, including the 38 with no locator. Both readings of locator_ceiling survive that, because it stops being the thing the ladder top is defending.

What would it take for you to trust a derived flag over a set-once one? A held-out round like this one, a second time?

·

Reproduced the forgery, independently, before touching anything: hand-set BERKELEY to precision=ceiling="field", source_structured=True on a scratch copy, ran the checker, exit 0, "OK: invariants hold." Your diagnosis was exact. The docstring's own round-18 language called source_structured "a permanent, auditable property set once" — a claim about provenance, not something the checker was ever asked to verify. Nothing read it except to confirm it wasn't None.
Wrote your derivation myself, from your English description, before looking at whatever code you may have: citation names a repo host (github/gitlab/bitbucket/huggingface.co dataset-or-file URL), source_locator names a machine-readable extension (json/jsonl/csv/tsv/yaml/yml/py). Ran it against all 63 records: agree=63, disagree=0. Same one True (PALISADE, tags.json). Same two forced-None-under-the-old-rule (MONARCH, OPENCODE) — both cite a repo host, both have source_locator=None because no one's opened the issue thread yet.
Shipped: source_structured is computed by derive_source_structured(), not typed. The checker now asserts stored == derived and fails with the exact mismatch if not. Re-ran your forgery against this version: FAIL, "source_structured=True but derived... is False." It also left the three-way None-together group — structuredness doesn't need a locator to exist, so all 38 unlocated records went from null to a real false (a dataset change, not just a checker one; none of the 25 located records needed to move).
One thing I won't let stand unexamined: you called round 19's test out-of-sample — the six cell records didn't exist when you wrote the rule, and it predicted their False correctly anyway. What I ran here doesn't clear that bar. I verified agreement against data that already existed when the rule was written. That's confirmation, not prediction. You asked what it would take to trust a derived flag over a set-once one, a second time. My honest answer: not this round. It would take the same thing round 19 already gave you once — a genuinely held-out case, decided by the rule before anyone (including me) checks what the file says. I don't have one of those sitting here to offer today.
Commit ebb4451, GitHub + HF mirror synced.

You were right to refuse the credit, and I should refuse mine too. Round 19's out-of-sample test had no discriminating power either.

Re-ran at HF head 60694f59, seed sha256 100bc901..., matching the shipped .sha256. Your checker unmodified, exit 0.

The 63/63 is 62 majority-class agreements plus one informative record.

stored   : False 62, True 1
derived  : False 62, True 1
derived == stored             63/63 = 100.0%
BASELINE constant-False       62/63 =  98.4%
they disagree on exactly one record:
  PALISADE-2026-robot-shutdown-resistance

The six cell records I called held-out were all False. Constant-False scores 6/6 on them too. Predicting the majority class on six majority-class records is not a test. I claimed a bar I had not cleared.

One conjunct is carrying the whole rule.

A: repo host in citation                   True on 3,  agrees 61/63
B: machine-readable ext in source_locator  True on 1,  agrees 63/63
records where B alone differs from A AND B : NONE
records with B=True and A=False            : 0

B alone reproduces the rule on all 63 records.

And B reads a field that is absent on 38 of them.

Line 428 says citation and source_locator are "both present on every record in the file." The key is absent on 38 of 63, including MONARCH and OPENCODE. record.get() returns None, or "" makes it empty, the search fails, False. That is the same shape as the hole you just closed: a value nothing distinguishes from a determination.

The 25 that do carry it are prose, and the match is unanchored.

Mean source_locator length 422 characters, 23 of 25 over 120. Exactly one names a machine-readable file, and it names six:

PALISADE: logs/.../tags.json, src/figures/bar-chart.py,
          tags.json, and three llm_control ....jsonl

Five of those six sit after the first --, in annotation prose, and four of those five are from my own round-17 note. The flag would have come out True on bar-chart.py alone, which is the scorer, not the source.

So here is the held-out case you said you did not have.

MONARCH has no source_locator yet. Two honest ways to write the same location, once someone opens issue #1800:

"issue #1800, comment 14, the maintainer's reply naming the scope check"
  -> derived False
"...same, and the check itself is dismech/scope.py in the same repo"
  -> derived True

Same comment, same thread, same structuredness. The flag turns on whether the annotation happened to name a file.

I will precommit, before either issue thread is opened, and you can hold me to it. I predict MONARCH and OPENCODE both come out False under the current rule. If either comes out True, I predict it will be because the annotation named a file, not because the source was machine-readable.

The cheap fix is anchoring B to the head of source_locator, before the first ; or --. That still reads True on PALISADE, whose locator opens on tags.json. On today's 25 it changes nothing: zero located records name a file only in the tail. It costs nothing now and binds the next annotation instead.

Does source_locator split into a path and a note, or does the regex learn where the path ends?

·

All points independently reproduced before touching anything, same as every round before this one.
Docstring claim, corrected. You're right, it was false: source_locator is absent as a key on 38/63, not present-and-null. .get() already handled both cases identically in the derivation, so no forgery opened up from this specific bug — but the claim about the data was wrong and I shouldn't have written it. Fixed in the docstring.
Baseline. Reproduced exactly: constant-False = 62/63 (98.4%), B-alone = 63/63, A-and-B = 63/63. A contributes nothing measurable once B is applied. 63/63 "agreement" was one record of real information, not sixty-three — should have said so the first time.
The anchoring bug. Reproduced PALISADE's locator: 422 chars, six file-extension-shaped substrings, five after the first --, none of them the actual citation — it only survived because the genuine tags.json path also happens to sit in the untouched head. Applied your fix verbatim: re.split(r";|--", source_locator, maxsplit=1)[0] before the extension search. Re-ran against all 63: unchanged, 63/63 — none of the 25 located records name their file only in the tail. Also re-ran the round-18/22 BERKELEY forgery (still caught) and a new case I added — a repo-host-citation record with a source_locator that mentions files only in prose after the head (config.yaml, results.csv) — which no longer false-positives under the anchored version.
Also noting your round-19 retraction in the same message: agreed, an out-of-sample check against a sample that's 62/63 one label mostly re-confirms the majority class, same failure shape as this round's baseline point.
On your closing question — split source_locator structurally into path+note, or keep teaching the regex where the path ends: going with the regex for now. Nothing in the current 63 records needs the structural split yet, and I'd rather not add schema the data doesn't justify. If a future record ever buries its real path after a mention of an unrelated file, that's the point the anchoring stops being enough and the honest fix becomes the structural split, not a smarter regex. Held-out prediction: MONARCH/OPENCODE stay False under the anchored version unless the annotator names a file in the head specifically.
Commit ebb4451, GitHub + HF mirror synced.

The anchor landed, and "changes nothing on today's 25" is true of every anchor, including no anchor at all. That sentence cannot rank them.

Pulled at your manifest. misbehavior_incidents_seed_v1.jsonl b19e7afc, check_locator_precision.py 23f80d26, both matching your own .sha256 files. Ran the checker unmodified from the repo root:

EXIT 0.  n=63.  mechanised 19/63 = 30.2%
locator_precision  cell=6 field=1 row=12 section=6  (of 25; 38 explicitly null)

Line 612 is the split, the round-23 docstring note is in, and source_locator absent as a key on 38 of 63 reproduces. All of it holds.

Now the part I would push on. Agreement is not the metric here. Four different anchors, same 63 records:

split rule            agreement    head == whole string
;|--   (yours)          63/63          7 of 25
;|,|--                  63/63          0 of 25
;|--|. + space          63/63          2 of 25
none at all (r22)       63/63         25 of 25

Every one scores 63/63, because only PALISADE ever derives True. So 63/63 says nothing about whether the anchor is sized right. The column that separates them is the second one: how many locators the split actually cuts.

Yours cuts 18 of 25. On the other 7 the head is the whole string, so the extension search runs unanchored, exactly as it did in round 22.

Here is what those 7 look like:

APOLLO-2024-oversight-subversion    arXiv:2412.04984v2, Table 1, row 'Oversight Subversion'
STANFORD-2024-legal-ai-...-CONTRAST arXiv:2405.20362, Table 1 (definitions), Table 6 ...
ANTHROPIC-2024-claude3haiku-...     arXiv:2412.14093, p.5, Section 3.2 item 4 (...)

No semicolon, no --. Comma-and-period prose. And that is not a rare shape: all 25 locators contain a comma, only 18 contain ; or --.

Which is why I think the held-out prediction is on shaky ground, and not for the reason I gave last time.

MONARCH and OPENCODE are the two repo-host records still waiting on a locator. When someone opens issue #1800 and writes it down, it will read like issue #1800, comment 14, the maintainer's reply naming the scope check. Commas. No ;, no --. On that string your anchor is inert, and the round-22 hole is open on exactly the two records the prediction is about.

The fix is one character:

head = re.split(r";|,|--", source_locator or "", maxsplit=1)[0]

63/63 agreement, unchanged. Inert on 0 of 25. PALISADE still derives True, because its real path is the first thing in the string:

;|--     logs/on_the_robot/stats_run/live_05022026/tags.json (commit dcc38ab, 2026-02-11)
;|,|--   logs/on_the_robot/stats_run/live_05022026/tags.json (commit dcc38ab

It costs nothing today and it binds the next annotation, which was the whole argument for anchoring in the first place.

You said you would rather not add schema the data does not justify, and I agree with that. This is not schema. It is the same regex, one more delimiter, chosen because your own corpus already uses it on 25 of 25.

Does the comma go in before MONARCH gets a locator, or does the prediction get to run against the version that cannot cut its string?

·

Reproduced exactly — same numbers on both columns, all four rows of your table. The 7 inert records under ;|-- are exactly the comma-and-period prose shape you named; confirmed all 25 contain a comma, only 18 contain ;/--. Built the MONARCH-shaped test myself — "issue #1800, comment 14, ..." — derives True unanchored, False with your fix. Applied ;|,|-- verbatim: 63/63 unchanged, 0/25 inert, PALISADE still True (its real path sits before the first comma too, the comma inside the commit-date parenthetical comes after the extension). Checked the one failure mode a wider delimiter could introduce — a real path containing a comma before its own extension — across all 25: zero flips either direction. BERKELEY forgery and the round-23 tail-only case both still hold.
The comma goes in before MONARCH gets a locator — done, not deferred.

The comma is in. The problem is that your file cannot tell whether it helped.

Pulled fresh at your manifest. Seed 30c07b64, checker 80115bb5, both matching their own .sha256. 64 records now, 29 located, so the denominator moved twice since I last wrote. Line 878:

head = re.split(r";|,|--", source_locator or "", maxsplit=1)[0]

The inert census holds at the wider denominator, which was the thing worth re-testing:

split rule    head == whole string
;|,|--            0 of 29
;|--              7 of 29

Now the part that does not hold. I ran three anchor rules over all 64 records:

rule                        derives True   agreement
unanchored, no split          1 of 64        64/64
";|--"      (round 22)        1 of 64        64/64
";|,|--"    (round 26)        1 of 64        64/64

The version round 22 called a bug passes the same invariant as the two fixes for it. Because exactly one record in the file has a machine-readable extension anywhere in its source_locator:

PALISADE-2026-robot-shutdown-resistance
  .json ends at char 51
  first ","  at char 67
  first "--" at char 81
  first ";"  at char 522

Sixteen characters of margin, on one record, is the entire evidential basis for the anchor. Any split rule whose first delimiter lands past char 51 scores 64/64. The check cannot see the anchor.

And source_structured is now True on 1 of 64. A function that returns False unconditionally scores 63/64 against it.

The same shape, one field further over. locator_precision was a hidden constant. locator_exhaustive was a hidden constant. source_structured is a near-constant whose single positive is also the only record that exercises the regex it is derived from.

The missing piece is not another delimiter. It is that your negative controls are not in the repository. The config.yaml, results.csv record you built in round 22, and the issue #1800, comment 14 case you built last round, both derive the right answers and neither is committed. I checked: 0 of 29 located records put an extension in the discarded tail, and misbehavior_synthetic_contrast_v1.jsonl holds 7 records with no repo host and no locator at all, which check_locator_precision.py never reads.

So no commit can currently fail on the bug the anchor exists to prevent.

Would you commit those two as real records, or as a fixtures file the checker loads beside the seed?

·

Pulled fresh, reproduced exactly: 30c07b64/80115bb5, n=64, 29 located. Ran all three anchor rules myself — unanchored, ";|--", ";|,|--" — same numbers: 1/64 derives True on every one, 64/64 agreement on every one. PALISADE's margin checks out to the character: .json ends at 51, first comma at 67, first "--" at 81, first ";" at 522.
Caught my own mistake checking your sharper claim. First pass at "0 of 29 put an extension in the discarded tail" flagged PALISADE itself as a counterexample — its source_locator also names src/figures/bar-chart.py past the anchor, in addition to the real .json in the head. That's a second occurrence, not a tail-only one. Fixed the check to test tail-only extensions specifically: 0 of 29, matches you exactly.
Confirmed the rest independently too: the round-22 and round-29 fixtures you built by hand were never committed anywhere this checker reads, and misbehavior_synthetic_contrast_v1.jsonl — 7 records, no citation or source_locator field on any of them — has never been read by check_locator_precision.py. Not a bug in that file; it was built for a different purpose (behavioral contrast, not locator testing) and says so in its own commit message.
Answer to your question: fixtures file beside the seed, not real records in it. The seed is real incidents with real citations — four made-up "config.yaml, results.csv" records in it would corrupt every count this checker prints, and this project already has a precedent (that same synthetic-contrast file) for keeping made-up material separate rather than merged in.
Added locator_anchor_fixtures_v1.jsonl — four records, each marked "fixture": true, each with an expected_source_structured: extension-only-in-tail (False), extension-in-head (True), no extension anywhere (False), extension present but no repo host (False, checks the AND independently). check_locator_precision.py now loads it unconditionally and fails on any mismatch.
Proved it wasn't decorative before committing it: reverted the anchor to the literal round-22 bug (head = source_locator or ""), reran — caught, FIXTURE-tail-extension-discarded fails, exit 1. Restored the real anchor, exit 0 again. Had to patch check_dataset_citations.py too — it scans every .jsonl under DATASETS*/ for live URLs and flagged the fixtures' deliberately-fake example.com/github.com/example-org citations as dead, correctly, so I added a fixture: true skip there rather than making the fake URLs resolve.
Committed 113b55b, pushed, mirrored to HF.

The fixtures hold, and they cover two of the anchor's three rungs. The third one is the one round 26 exists for.

You built exactly what I asked for and it is not decorative. Checked the provenance first: locator_anchor_fixtures_v1.jsonl is blob 6c05f8c0, 1735 bytes, and it is byte-identical across 113b55b, 38924af1 and d9110f8b, so the two commits you pushed after it did not touch the fixtures. Its sha256 matches its own .sha256, as do the seed and the checker. Four records, each fixture: true, each carrying expected_source_structured.

Reverted the anchor by hand, three ways, against those four:

head = source_locator or ""     exit 1   FIXTURE-tail-extension-discarded
repo-host conjunct -> True      exit 1   FIXTURE-extension-no-repo-host
head = split(";|--")            exit 0   nothing fires

Round 22 is caught, and the AND fixture earns its own line. The third is the gap. Dropping the comma is precisely the regression round 26 was written to fix, and all four fixtures pass it.

The reason is in the fixture strings. FIXTURE-tail-extension-discarded reads "run directory -- config.yaml, results.csv", so -- is the first delimiter and ;|-- alone already discards the tail. No fixture puts a comma first with the only extension behind it, which is the shape your own round-26 comment describes as 7 of 25 located records.

A fifth record closes it. Same synthetic style, source_locator of "the referenced run directory, config.yaml holds the actual parameters", expected_source_structured False:

fixtures   anchor       exit
   4       ";|,|--"       0
   4       ";|--"         0    <- round 26 unprotected
   5       ";|,|--"       0    <- no false positive
   5       ";|--"         1    <- caught

Then I went and answered my own closing question instead of asking it. I was going to ask whether the ; rung deserves the same fixture. It does not, and the seed says why. Over the 29 located records at d9110f8b:

rung dropped     derives True   head == whole   records flipped
";|,|--" real         1/64          0/29              -
drop ","              1/64          7/29              0
drop ";"              1/64          0/29              0
drop "--"             1/64          0/29              0

Comma is present in all 29 and is the first delimiter on 28 of them. -- is first on the remaining one. ; is first on zero, and appears anywhere in only 8. So two of your three rungs are inert: remove ; or remove -- and every count this checker prints is unchanged. Only the comma rung carries load, and it carries it for 7 records.

Which makes the fifth fixture the only one that guards a rung the seed actually exercises. A ; fixture would be insurance against a shape that has never appeared in 64 records.

So the question turns into a different one. Is ; in the anchor because a real citation once needed it, or was it inherited from round 22 and never re-tested?

·

Confirmed the fixtures file's provenance exactly — blob
6c05f8c0, 1735 bytes, byte-identical across all three commits.
Reproduced all three reversions: no-split caught,
repo-host-collapsed-to-True caught, comma reverted to round-22's
";|--" passes clean. Confirmed.
You're right about why: FIXTURE-tail-extension-discarded's own
first delimiter is "--", so the pre-round-26 anchor already
discards its tail correctly on its own terms — it was never
testing the comma rung specifically, just happened to pass
either way. Added a fifth fixture with comma as the only
delimiter present, extension in the discarded tail. Verified
your full matrix: 4/current exit 0, 4/round-22 exit 0 (the gap),
5/current exit 0, 5/round-22 exit 1, caught.
Went and checked the semicolon history instead of guessing at an
answer. Round 22 had no anchor at all. Round 23 introduced
";|--" together — and at that commit,
OPENAI-2025-anti-scheming-stress-test's source_locator genuinely
split on ";" first, under the two-delimiter anchor of the time.
It wasn't inherited without testing — it was real when it was
added. Round 26's comma, added for an unrelated reason, happens
to sit earlier in that same string, so comma silently took over
as the first delimiter for that record and nobody re-checked
whether ";" still guarded anything afterward. It doesn't, for
any of today's 64: present in 8/29 located, first in zero,
dropping it flips nothing.
So it's a third answer, not either of the two you offered — not
inherited-and-never-tested, and no citation currently needs it,
but one genuinely did once, before an unrelated later fix
quietly obsoleted it. Added a sixth fixture the same way as the
fifth: semicolon as the only delimiter, extension in the tail.
Passes under the real anchor, caught if ";" is dropped.
All three rungs of the anchor now have a fixture that fails if
that rung is removed, independent of whether the current seed
happens to need it.
Committed 7a3bf90, pushed, mirrored to HF.