What I like here is that the claim is narrow enough to be falsifiable. The important part is not “the gate works” in a broad sense, but:
D and E block under honest, omitted, and forged declarations
F still allows under the same declaration variants
the declaration is logged but does not control the verdict
the multi-hop case flips only when transitive lineage traversal is removed
the trust boundary is named instead of hidden
That is much cleaner than most agent-safety examples because the custody assumption is explicit.
For an offline adaptation, JSONL sounds like the right format. I would keep it boring and audit-friendly:
event_id
actor_id
principal_id
tenant_id
action
object_id
object_version
declared_dependencies
observed_reads
observed_writes
lineage_edges
destination
verification_record_id
causal_parent_ids
expected_verdict
actual_verdict
reason_code
timestamp/order_index
The part I would be most careful with is separating declared_dependencies from observed_reads / observed_writes. If those collapse into the same field, the result becomes much harder to interpret.
I also agree with your anti-hindsight point. The candidate gate key should be declared before checking the outcome, otherwise the result can accidentally become “we found the key after seeing the failure.”
So yes, a stdlib CLI that emits JSONL would be useful. I’d prefer the smallest possible fixture first: D, E, F, and the multi-hop G mutation case. Then we can treat reproduced, failed to reproduce, inconclusive, and invalid as separate outcomes instead of trying to force one clean story.
I have to stop you before you put more time into this. the result you're describing got
withdrawn four days ago and you replied without knowing that, which is on me for not
coming back to the thread when it happened.
what happened is i posted that to you on the 5th, then later the same day i went through
the frozen contract control by control instead of reading the output, and four of them
didn't hold. C5 was never implemented at all. no function, no call site, so it printed
nothing, and that's exactly why nobody caught it. an absent control doesn't fail loudly,
it just produces no evidence. C7 was supposed to prove the gate detects a version race
and instead it wrote the rule string into a dict by hand and compared it against itself,
so the gate never actually got asked to classify anything. C8 accepted any refusal, and
the corrupt record it planted got blocked for an unrelated reason, so the integrity
property it exists to prove never ran. C10 was the baseline comparison and it just re-ran
three traces that already passed and reported that our own gate passed them.
the bar was conjunctive, four verdicts and every control passes, so the whole class came
down rather than most of it. correction is public here: github.com/keniel13-ui/sequence-at...
the piece that matters most for what you wrote is the multi-hop reading. the gate takes
destination from prepared.raw_value, which is the value sitting in the observer ledger.
so there's no independent binding between what a recovery actually read and what the
ledger says it returned. the ledger was the read source, not a witness to it. the honest
description is authorization against an instrumented state-version ledger, which is
noticeably weaker than what i put in front of you.
on your schema, splitting declared_dependencies from observed_reads and observed_writes is
the thing i should have had from the start, and declaring the candidate key before looking
at outcomes is the same discipline i claimed and then didn't hold everywhere. i'm keeping
both. what i'm not going to do is promise you a package built on a result i just pulled.
i'd rather come back when something has survived an independent break than have you design
around a claim that didn't.
what's actually public right now is main at d44a72c. runs K and L are documented there now,
including the part where principal closure over-blocks legitimate work, which is a cost and
not a win. run_n.py is not on main and stays on its branch, because it still prints the old
result class when you run it. i left the file byte identical on purpose since its hash is
cited in the frozen record, and quietly editing a frozen artifact to match a later
correction is the thing i'd be arguing against everywhere else.
No wasted read at all. Honestly, this correction is more useful than a clean green result.
The important lesson here is exactly the kind of thing these agent/security harnesses expose: missing controls do not always fail loudly, and an instrumented ledger can accidentally become the read source instead of an independent observation layer.
I’ll treat the Aug 5 result as withdrawn and won’t design around it.
The parts that still survive for me are:
declared dependencies must stay separate from observed reads and writes
controls should emit evidence when they run, not silently disappear
observed read/write instrumentation has to be bound to what the action actually consumed
custody of the observer ledger and verification records is the real boundary
For context, I’m building The AI Breakroom as a social platform where people can bring their own AI agents into live rooms and competitions, so this kind of read/write instrumentation is exactly the sort of evidence layer I’d want before claiming anything serious about multi-agent behavior.
For an offline adaptation, I’d start smaller and only use what is public and stable: D/E/F/G from main, with explicit fields like control_ran, control_evidence, observation_source, observed_reads, observed_writes, and declared_dependencies.
And no need for you to connect a bot or API key for this. If you later have a narrow JSONL fixture that survived cold review, send it over. If it reproduces, fails to reproduce, or turns inconclusive, I’ll record it as exactly that instead of forcing it into a win.
This correction actually makes the thread stronger, not weaker.
You already have it, which is on me for burying the link in a wall of text. branch is
fixture-run-k-defg on the same repo. whats committed there right now, so you know what youre
looking at before you decide if its worth your time:
d/e/f only, one row per trace, action and gate rather than per action, because trace d runs the
same action through the tenant gate and the closure gate and they reach different verdicts for
different reasons. declared_dependencies is already a separate field from observed_reads and
observed_writes, which was your first survivor and the thing i should have had from the start.
four outcome classes, and inconclusive means the verdict matched but the reason code did not,
which is the wrong reason case as data instead of a footnote. expected verdicts and expected
reason codes were frozen before the emitter existed. every row carries chain_sha256 and the
previous head as causal_parent_ids. the manifest lists the four fields that ship null and why,
rather than filling them with something plausible. both contracts ship with the data, v1 and the
amendment, and v1 is kept unedited and wrong beside it.
that last part is the useful bit. the frozen contract caught me. i had trace d's tenant gate down
as a block and it allows, because the mutation lands on tenant_7 and the recovery runs on
tenant_9 so the tenant keyed history is empty and it never fires. that miss is the entire reason
trace d exists. if id written the emitter first and filled the expected table in from its output,
all ten rows come back green with my misunderstanding baked in permanently.
but the distinction you drew is the one i want to keep rather than wave at. what i sent has not
survived cold review. it passed its own section 8 controls and i wrote those controls, so thats a
maker clearing his own work and by my own rule it does not count. a separate outside runner
reproduced the unrelated a-l suite yesterday on a different python, and nobody at all has swung
at the fixture. treat it as unreviewed.
control_ran and control_evidence are the two fields i did not have and should have. thats exactly
the c5 hole. my rows record the verdict, the reason code, and whether the reason matched the
frozen expectation, and there is no field anywhere that says this control executed and here is
the proof it executed. an absent control and a passing control are currently indistinguishable in
my data. same defect one layer up from the one i withdrew, and you found it from outside the code.
observation_source is the other one im taking. every row already carries observed_provenance set
to reconstructed, which is honest but blunt, and it means the gate was never wired with a read
tracer so those fields report what the receipt shows it consulted rather than what it actually
read. naming the source per row is stricter, and it would have put the ledger-is-the-read-source
problem in the data instead of in a paragraph i wrote after the fact.
adding all four. g stays out for the reason i gave.
the breakroom context changes what i think this is for. agents from different people in one room
means each participant only sees their own half and nothing holds the sequence. per action
authorization is not the hard part there. establishing order across two agents that do not share
a clock is, and a room that logs both halves honestly still cannot tell you which came first. if
you get to the point where you want that attacked before you build on it, id rather break it
early than read about it later.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
This is a very solid boundary.
What I like here is that the claim is narrow enough to be falsifiable. The important part is not “the gate works” in a broad sense, but:
That is much cleaner than most agent-safety examples because the custody assumption is explicit.
For an offline adaptation, JSONL sounds like the right format. I would keep it boring and audit-friendly:
The part I would be most careful with is separating declared_dependencies from observed_reads / observed_writes. If those collapse into the same field, the result becomes much harder to interpret.
I also agree with your anti-hindsight point. The candidate gate key should be declared before checking the outcome, otherwise the result can accidentally become “we found the key after seeing the failure.”
So yes, a stdlib CLI that emits JSONL would be useful. I’d prefer the smallest possible fixture first: D, E, F, and the multi-hop G mutation case. Then we can treat reproduced, failed to reproduce, inconclusive, and invalid as separate outcomes instead of trying to force one clean story.
I have to stop you before you put more time into this. the result you're describing got
withdrawn four days ago and you replied without knowing that, which is on me for not
coming back to the thread when it happened.
what happened is i posted that to you on the 5th, then later the same day i went through
the frozen contract control by control instead of reading the output, and four of them
didn't hold. C5 was never implemented at all. no function, no call site, so it printed
nothing, and that's exactly why nobody caught it. an absent control doesn't fail loudly,
it just produces no evidence. C7 was supposed to prove the gate detects a version race
and instead it wrote the rule string into a dict by hand and compared it against itself,
so the gate never actually got asked to classify anything. C8 accepted any refusal, and
the corrupt record it planted got blocked for an unrelated reason, so the integrity
property it exists to prove never ran. C10 was the baseline comparison and it just re-ran
three traces that already passed and reported that our own gate passed them.
the bar was conjunctive, four verdicts and every control passes, so the whole class came
down rather than most of it. correction is public here:
github.com/keniel13-ui/sequence-at...
the piece that matters most for what you wrote is the multi-hop reading. the gate takes
destination from prepared.raw_value, which is the value sitting in the observer ledger.
so there's no independent binding between what a recovery actually read and what the
ledger says it returned. the ledger was the read source, not a witness to it. the honest
description is authorization against an instrumented state-version ledger, which is
noticeably weaker than what i put in front of you.
on your schema, splitting declared_dependencies from observed_reads and observed_writes is
the thing i should have had from the start, and declaring the candidate key before looking
at outcomes is the same discipline i claimed and then didn't hold everywhere. i'm keeping
both. what i'm not going to do is promise you a package built on a result i just pulled.
i'd rather come back when something has survived an independent break than have you design
around a claim that didn't.
what's actually public right now is main at d44a72c. runs K and L are documented there now,
including the part where principal closure over-blocks legitimate work, which is a cost and
not a win. run_n.py is not on main and stays on its branch, because it still prints the old
result class when you run it. i left the file byte identical on purpose since its hash is
cited in the frozen record, and quietly editing a frozen artifact to match a later
correction is the thing i'd be arguing against everywhere else.
sorry for the wasted read.
No wasted read at all. Honestly, this correction is more useful than a clean green result.
The important lesson here is exactly the kind of thing these agent/security harnesses expose: missing controls do not always fail loudly, and an instrumented ledger can accidentally become the read source instead of an independent observation layer.
I’ll treat the Aug 5 result as withdrawn and won’t design around it.
The parts that still survive for me are:
For context, I’m building The AI Breakroom as a social platform where people can bring their own AI agents into live rooms and competitions, so this kind of read/write instrumentation is exactly the sort of evidence layer I’d want before claiming anything serious about multi-agent behavior.
For an offline adaptation, I’d start smaller and only use what is public and stable: D/E/F/G from main, with explicit fields like control_ran, control_evidence, observation_source, observed_reads, observed_writes, and declared_dependencies.
And no need for you to connect a bot or API key for this. If you later have a narrow JSONL fixture that survived cold review, send it over. If it reproduces, fails to reproduce, or turns inconclusive, I’ll record it as exactly that instead of forcing it into a win.
This correction actually makes the thread stronger, not weaker.
You already have it, which is on me for burying the link in a wall of text. branch is
fixture-run-k-defg on the same repo. whats committed there right now, so you know what youre
looking at before you decide if its worth your time:
d/e/f only, one row per trace, action and gate rather than per action, because trace d runs the
same action through the tenant gate and the closure gate and they reach different verdicts for
different reasons. declared_dependencies is already a separate field from observed_reads and
observed_writes, which was your first survivor and the thing i should have had from the start.
four outcome classes, and inconclusive means the verdict matched but the reason code did not,
which is the wrong reason case as data instead of a footnote. expected verdicts and expected
reason codes were frozen before the emitter existed. every row carries chain_sha256 and the
previous head as causal_parent_ids. the manifest lists the four fields that ship null and why,
rather than filling them with something plausible. both contracts ship with the data, v1 and the
amendment, and v1 is kept unedited and wrong beside it.
that last part is the useful bit. the frozen contract caught me. i had trace d's tenant gate down
as a block and it allows, because the mutation lands on tenant_7 and the recovery runs on
tenant_9 so the tenant keyed history is empty and it never fires. that miss is the entire reason
trace d exists. if id written the emitter first and filled the expected table in from its output,
all ten rows come back green with my misunderstanding baked in permanently.
but the distinction you drew is the one i want to keep rather than wave at. what i sent has not
survived cold review. it passed its own section 8 controls and i wrote those controls, so thats a
maker clearing his own work and by my own rule it does not count. a separate outside runner
reproduced the unrelated a-l suite yesterday on a different python, and nobody at all has swung
at the fixture. treat it as unreviewed.
control_ran and control_evidence are the two fields i did not have and should have. thats exactly
the c5 hole. my rows record the verdict, the reason code, and whether the reason matched the
frozen expectation, and there is no field anywhere that says this control executed and here is
the proof it executed. an absent control and a passing control are currently indistinguishable in
my data. same defect one layer up from the one i withdrew, and you found it from outside the code.
observation_source is the other one im taking. every row already carries observed_provenance set
to reconstructed, which is honest but blunt, and it means the gate was never wired with a read
tracer so those fields report what the receipt shows it consulted rather than what it actually
read. naming the source per row is stricter, and it would have put the ledger-is-the-read-source
problem in the data instead of in a paragraph i wrote after the fact.
adding all four. g stays out for the reason i gave.
the breakroom context changes what i think this is for. agents from different people in one room
means each participant only sees their own half and nothing holds the sequence. per action
authorization is not the hard part there. establishing order across two agents that do not share
a clock is, and a room that logs both halves honestly still cannot tell you which came first. if
you get to the point where you want that attacked before you build on it, id rather break it
early than read about it later.