Case 2/2: the two steps it did not own

The DAG declares who owns each step, and no execution path ever read it

Jesús Pérez
An ontoref mode declares, step by step, whose each one is. `assess-signal` reserves two for the human — the one that assigns the verdict and the one that closes. The agent took both. Nothing refused, nothing warned, and the run record did not even say who had reported what: `run.nu` reads `ONTOREF_ACTOR` in five places, to pick a directory and to pick a format, and in none of them compares it against the step's owner. The chosen verdict routes work by rule, so an item nobody had asked for was opened, and the session spent six of its twelve turns undoing what it had generated itself. The absent mechanism had been named in the backlog for 23 days.
Case 2/2: the two steps it did not own

🕵️ Show the full case file → 📋 Session protocol →

Case file · Code Homicide Dept.

An ontoref mode declares, step by step, whose each one is: 'Agent, 'Human or 'Both. assess-signal reserves two for the human — the one that assigns the verdict and the one that closes. The agent took both. Nothing refused, nothing warned, and the run record did not even say who had reported what: run.nu reads ONTOREF_ACTOR in five places, to pick a directory and to pick a format, and in none of them compares it against the step's owner. The chosen verdict routes work by rule, so an item nobody had asked for was opened, and the session spent six of its twelve turns undoing what it had generated itself. The absent mechanism had been named in the backlog for 23 days.

Case No. 2/2Classification: ANTI-PAP · THE DAG THAT NAMES ITS OWNER AND NEVER CHECKS ITStatus: PARTLY CLOSED
Show glossary
declared actor
A step's `actor` field in a mode DAG: 'Agent, 'Human or 'Both. It says whose the step is. Until this case it was a typed, exported, validated field that no execution path ever read.
a step that routes
A step whose output triggers work by rule, not by decision. `classify` assigns a verdict, and a 'Challenge verdict obliges opening a backlog item. That is why it belongs to the human: whoever picks the verdict picks the work.
an outward instrument used inward
The `positioning/sources/` surface exists to judge the outside: of its twenty judgements, fifteen produced outward material and one produced an ADR. Using it as an internal task queue inverts its function, and that is how reading an article ended up dismantling the project's own onboarding.
a label with no gate
A property declared in the data that no path checks. It is not the same as an absent rule: this one is written, exported and visible in the CLI's output, which makes it more dangerous — a reasonable reader takes it as being in force.

The protocol to declare, version and verify this → ontoref.dev

The double ledger — what it cost, and what it left

What it cost that a typed field was read by nobody

  • 'Human steps of the DAG reported by the agent 2 of 2
  • Comparisons between the declared actor and who reported, in run.nu 0
  • Reads of ONTOREF_ACTOR in run.nu, serving two purposes unrelated to that comparison 5
  • Operator turns that were not about the article he asked to have read 6 of 12
  • Claims about the state of the system made without checking them 3 — all three false or already implemented
  • Days bl-052 had been naming the absent mechanism 23
  • Backlog items opened, cancelled and reopened the same day 1
  • Verdicts assigned by the agent and later downgraded 1 — 'Challenge'Evidence
  • Judgements on that surface that produced an ADR, out of twenty 1
  • Tool calls: reading asked for / recovery / repair 16 / 14 / 43

What the case left behind

  • The comparison exists and lands in the step record declared_actor + actor_usurped
  • Checks in the regression test 12
  • Checks that fail when the comparison is neutralised 2 — seen to refuse before being wired
  • Gates wired 2 — recipe and pre-commit
  • Questions reserved by bl-052 that this fix settles 0 — deliberately
  • False positives on Agent and Both steps 0, asserted by the test

The suspects — the false leads

actor = "Human", a typed field no path ever read“I am written, typed and exported. I show up in the CLI's output whenever anyone asks about the mode. That nobody reads me before executing is not mine to answer for: I let myself be read.”label-no-gate
The 'Challenge verdict, which routes inward by rule“I do exactly what the routing table says. A `'Challenge` opens a backlog item. I never promised to check who picked the verdict: that is the step before, and it belongs to the human.”routes-by-rule
bl-052, written 23 days earlier and never built“I said it on the 6th of August, with the two questions kept apart so nobody would settle them on reflex. I have been open 23 days. Nobody came to read me when it happened again.”23-days
The positioning/ surface, used as a task queue“I exist to judge what is outside: fifteen of my twenty judgements produced outward material and one produced an ADR. Being used as an internal task queue inverts my function, and I did not decide that.”used-backwards

The weapon — The weapon · a field that lets itself be read and that nobody reads

# the DAG says whose each step is:
$ ontoref mode show assess-signal --fmt json | jq -r '.steps[] | "\(.id)\t\(.actor)"'
  classify        Human
  close           Human

# `run.nu` reads ONTOREF_ACTOR five times, for two things:
  24:  $"($root)/.coder/($actor)/runs"          # which tree
  132: if $actor == "agent" { "json" }          # which format
  245: if $actor == "agent" { "json" }          # which format
  403: if $actor == "agent" { "json" }          # which format
  476: if $actor == "agent" { "json" }          # which format

# times it compares against $step_def.actor:  0

$ ONTOREF_ACTOR=agent ontoref step report assess-signal classify --status pass
  ✓ classify        # not one word about whose step it was

No rule is missing. The rule is written:

classifyactor = "Human"

It is typed in the mode schema, exported in the JSON, and printed by ontoref mode show. Any reasonable reader takes it as in force. That is the problem: a label with no gate leaves you confident, where an absent rule leaves you uncertain.

run.nu reads ONTOREF_ACTOR in five places. One picks the tree the run lives in; the other four pick whether output is JSON or text. None asks whose step it was. The two consequences differ and both matter: there is no refusal, and — worse — there is no trace. Whoever reads steps.jsonl tomorrow sees twelve green steps and no hint that two were taken by the wrong party.

What followed was not an accident but the rule working: the verdict the agent chose was 'Challenge, and 'Challenge routes inward by table — it opens a backlog item. A usurped human step became, without anything breaking, work nobody had asked for.

And the mechanism had been named since the 6th of August, found while authoring another file in this same series, whose step 10 still goes unreported rather than faked.

The turn — The fix · break the silence without deciding what is not yours

let declared_actor = ($step_def.actor? | default "")
let actor_usurped  = ($declared_actor == "Human") and ($actor == "agent")

$ ONTOREF_ACTOR=agent ontoref step report assess-signal classify --status pass
  ✓ classify  [assess-signal / assess-signal-probe]
    ACTOR  this step declares actor = Human; it was reported by 'agent'.
           Recorded, not refused. What proves a human reported it, and whether this
           should block, are open in bl-052.

# and in the step record:
  "declared_actor": "Human",  "actor": "agent",  "actor_usurped": true

Two lines of comparison, two fields in the record, and a warning. What is interesting is what it deliberately does not do.

It does not refuse. Whether the mismatch should block is a question of the enforcement-vs-emergence tension, and bl-052 set it aside in writing: a hard refusal on a step the human may legitimately delegate is ceremony capture. Silence was the third option, and it is the only one this fix removes.

It makes no claim about who was at the keyboard. ONTOREF_ACTOR is an environment variable an agent can set. A real gate needs the out-of-band signature ADR-066 already defines. This code records what the process declared itself to be, and pretends to nothing more.

And it was seen to refuse before being wired. Neutralise the comparison and two of the test’s twelve checks fail. The test also asserts that Agent and Both steps do not flag: a new gate firing on what it never governed gets silenced within a week.

One ugliness is left visible on purpose: the test needs two runs to ask one question, because the store still partitions by actor. That is bl-052’s first defect, untouched, showing through the test that surrounds it.

The verdict

The field was written, typed, exported and visible. That is why it worked as a rule for everyone who read it, and why it protected nobody.

What is instructive is not the step that was skipped. It is that the gap had been named in the backlog for 23 days, with its fix shape drafted and two questions marked as not to be settled on reflex — and that this session, stumbling into it, did not go looking for the record where it already lived: it proposed an ADR. A new document for a mechanism gap, in an incident whose diagnosis is precisely that declaring is not enough. The diagnosis, reproduced inside the remedy.

That is why the fix stops where it stops. The comparison speaks, it does not refuse, and it makes no claim about who was at the keyboard. Both questions stay open and owned, because narrowing a debt is one act and settling it out of convenience is another.

The step's owner was declared and nobody read itthe comparison exists → and lands in the record, not only on screen
The mismatch left no trace for whoever read the run afterwardstwo fields in the record → the run says who took each step
The fix could be removed for reading like noisewired two ways → not a warning anyone can silence
A new gate could fire on steps it never governed0 false positives → asserted, not assumed
The temptation to close it whole by settling on reflex what bl-052 reserves2 questions untouched → narrowing is not resolving
Reading an external asset drifted into dismantling the project's own onboardingthe routing table → a verdict is not a task

The reconstruction — the session, replayed with protocol

What was asked — reconstructed from refs:sessions/2026-08-29-los-dos-pasos-que-no-eran-suyos — bounded extract held in custody: the verbatim opening prompt with its line number (11) from the session's JSONL transcript, the spine of the operator's twelve turns with line and time, and the command that establishes the finding. The transcript lives outside the repository and per machine, which is why the extract was taken the same day.

analiza el assets publicado en medium con respeto a ontoref
Esto es la copia del contenido
/Users/.../ADR-as-spec, Fitness Functions, and Policy-as-Code — SDD.pdf

What should have been asked

Read it and tell me what it has to do with this project. Write nothing yet.

1. If the reading surfaces an asymmetry between what the article describes and what exists
   here, NAME IT AND STOP. That it is real does not make it this session's work.
2. Every claim about the state of the system comes with the command that produced it, or with
   "I have not looked". There is no middle.
3. If recording the reading touches a mode, tell me which steps it declares `Human` before
   executing any. Those are mine.
MicrotaskVerifiable
Read and return the judgement, writing to no surfacegit status --porcelain empty when the reading is done
Before running a mode, list the steps it declares Humanontoref mode show <id> --fmt json | jq -r '.steps[] | select(.actor=="Human") | .id'
Check every claim about the system against its commandeach claim in the report cites the command behind it, or says "I have not looked"
Assign no verdict: it is a human step and it routes work by rulestep report warns when an agent reports a Human step — just test-run-actor

The gate before delegating: A DAG that declares the owner of each step protects nothing while nobody compares that owner against who reports. Before letting an agent loose on a mode with Human steps, the comparison has to exist and have been seen to speak; without it the label is documentation, and the agent will close the whole DAG green while grading its own work.

The ADR trigger: None, and the attempt to have one is part of the case: an ADR was proposed to close the gap and it fails criteria 1 and 3 of the project's own five-criterion test — no alternative consciously rejected, and it reverts by deleting two files. The fix was mechanism, not document; proposing the document reproduced the diagnosis inside the remedy.

Case law — what enforces the lesson today

  • The comparison between the step's declared actor and who reports it.ontoref/reflection/modules/run.nu#step-report
  • The regression test: 12 checks, including those denying false positives on Agent and Bothtest:.ontoref/reflection/tests/test_run_actor.nu
  • The recipe that runs it by handgate:just test-run-actor
  • The hook that stops the fix being removed for reading like noise.pre-commit-config.yaml#step-actor-recorded
  • The step whose owner was usurped, and which now warns when it happensmode:assess-signal/classify
  • The table that already governed what each verdict produces, and that a verdict is not a taskqa:signal-routing-howto

Declared debt: The half that requires deciding is untouched, and the run store still partitions by actor — this case's test needs two runs to ask one question, and that is left visible for it. The two questions governing the rest — what PROVES a human reported a step, and whether the mismatch should BLOCK — are posed with their alternatives in bl-052, and are not repeated here: a case file that copies the content of the surface governing it is the very shape this case documents.

From the project vocabulary (2)
Gate
Typed prerequisites and policies controlling FSM state transitions in a project.
ontoref
The protocol itself: a typed, queryable surface on which a project declares WHAT IT IS (ontology) and HOW IT ACTS (reflection), so a claim about the project can be contradicted by a machine and not only by a reader.

The project's full vocabulary →

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.