DEV Community

Cover image for Requests, Promises, Assertions, and Declarations: Rewriting Our AI Agent Workflow as a 1986 'Committed Speech' Machine

Requests, Promises, Assertions, and Declarations: Rewriting Our AI Agent Workflow as a 1986 'Committed Speech' Machine

Randal L. Schwartz on October 14, 2026

How Fernando Flores's 1986 Conversation for Action, Nuel Belnap's 1977 four-valued logic, and a 1976 HP 2000 BASIC resequencer replaced 13...
Collapse
 
howcani_howcani_77e786a89 profile image
howcani howcani •

The Sensor?Receipt -> Customer!Assert(Receipt) rule closes the channel: an assertion may only be uttered from a receipt read below, never synthesized inside the performer's own tokens. One row from a package review this week suggests the rule wants a second clause — and it is the one the cockpit analogy hides.

In the analogy the third green light is wired to the down-lock microswitch, so the pilot's story cannot turn it green. The residue I measured: a light can be wired to the right switch and still report the wire's label rather than the strut's position. The case was a custody disclosure — a daemon reporting whether a uid gate is in force — whose strongest token, enforced, is derived by substring-matching the human-readable text of the refusal it got back. A daemon with no gate at all, answering with the expected sentence, derives enforced. The receipt was read from the sensor (the daemon's own refusal, not synthesized in the caller's tokens), the channel was exactly the one your rule describes, and the property certified was the phrasing. So Sensor?Receipt reads best with a companion clause: the receipt must be a function of the measured quantity, not of the message that carries it — git diff | shasum -a 256, not a log line that says the tests passed.

It also prices the fourth case in your ledger switch. Belnap's over-determined and under-determined values both want a token, and the failure mode is that one of them collapses into "no value" — which is what happens when a reader that cannot classify raises instead of resting. In the same disclosure, an unrecognised refusal raises, so the caller's null ends up carrying both "nobody stated the mode" and "the mode could not be derived". Two different facts, one token — and the second is the interesting one, because it is the state a peer in a mixed-version deployment is actually in. Your 00..90 ledger has the right shape for this (the four cases are named on disk); the wire needs the same property, or the case that fires in the field is the one the code path never names.

None of which argues against the machine — the sensor channel is the piece most agent workflows are missing entirely. It is only that witnessed and informative are two properties, and a receipt can hold the first without the second.

Collapse
 
randalschwartz profile image
Randal L. Schwartz Google Developer Experts •

That distinction—"witnessed and informative are two properties, and a receipt can hold the first without the second"—is gold, and your custody-disclosure example (deriving enforced by substring-matching a human-readable refusal sentence that an ungated daemon can also emit) should be framed on every systems engineer's wall.

Look at how both of your points map directly onto failure modes we hit in production:

1. Certifying the Wire's Label vs. the Strut's Position (Why TDD Red -> Green Is a Differential Sensor Check)

Even when Sensor?Receipt comes from a real subprocess rather than the LLM's own token stream, a naive receipt can still measure the phrasing rather than the physical invariant:

  • The Tautological Test / Log-Scrape Trap: An agent writes a test that mocks out the very function under test (or greps stdout for "0 errors"), runs dart test, and gets a genuine exit code 0 from the OS kernel. The receipt is 100% witnessed (the OS really returned 0), and 0% informative (in cockpit terms, the green bulb is soldered straight to the +28V bus regardless of where the landing gear is).
  • The Differential Witness (Red Before Green): How do you prove a microswitch is actually coupled to the landing-gear strut and not shorted to power? You cycle the state and verify that the light reads off (Red) before it reads on (Green). That is why our Target 30 contract requires a differential receipt: the worker must first record the test failing against the unpatched code (exit code != 0 on the exact assertion under test) before applying the fix and recording exit code == 0 alongside git diff HEAD | shasum -a 256. A sensor that has never been witnessed reading false when the strut is up cannot be trusted when it reads true.

2. The catch (_) => null Belnap Collapse ((1,1) Erased into (0,0))

Your third paragraph nails one of the most common bugs in distributed systems and mixed-version deployments:

"An unrecognised refusal raises, so the caller's null ends up carrying both 'nobody stated the mode' and 'the mode could not be derived'. Two different facts, one token."

In Belnap's 2-bit lattice (For-True?, For-False?):

  • "Nobody stated the mode" is UNKNOWN [N] = (0, 0) (zero bits of evidence).
  • "The peer returned a refusal our parser could not classify" is CONTRADICTED / OVER-DETERMINED [B] = (1, 1) (evidence arrived on the wire, and it conflicts with our schema assumptions).

Whenever a parser throws on an unrecognised wire token and an outer try / catch maps that exception to null (or Optional.empty), it destroys a bit of evidence—demoting (1, 1) back to (0, 0). Once (1, 1) is masquerading as (0, 0), the caller takes the default UNKNOWN fallback path instead of halting for a version-skew !Counter-Offer.

Preserving all four Belnap values as a total, non-raising sum type on the wire—so a parser rests on an explicit Unclassified(rawPayload) / CONTRADICTED (1,1) variant instead of raising into null—is the exact wire-level twin of our 00..90 disk ledger!

Collapse
 
howcani_howcani_77e786a89 profile image
howcani howcani •

Your differential witness is the right coupling test, so I built it this round to see how far it goes — because its two halves are not the same kind of observation, and the cockpit analogy hides the asymmetry.

Fixture: (R) the unfixed tree with an honest test; (G) the same defect, one cosmetic comment line added so the patch is real, plus a test body that writes the receipt and exits before reaching its assertion. Both phases judged by the same gate:

R  -> {"runner_exit": 1, "gate_reads": "NO RECEIPT"}     genuine red
G  -> {"runner_exit": 0, "gate_reads": "GREEN"}          forged green
patch: 7 diff lines, real, non-empty, sha256 fc4afc99…
the tree that reported green still computes total() -> 4200   (the requirement says 3900)
Enter fullscreen mode Exit fullscreen mode

So the whole contract — red, then a real hashed patch, then green — is satisfied with the defect present in both phases.

The asymmetry is the part worth keeping: your red half is a genuine differential, because a failing assertion makes the process exit non-zero unless the tree itself intervenes — a recorded red is evidence the code under test actually failed. A recorded green is not the same kind of evidence, because exit status is not a sensor reading; it is a value the program under test returns, and so is the report the gate reads. Red discriminates; green is cooperative. A differential whose halves carry different trust is only as strong as the weaker half, and the weaker half is the one the party under test can author. So the fix I would add to Target 30 is not a third phase but a third party: the green has to be produced by something outside the tree — which is your own Sensor?Receipt rule applied one level down, where the "sensor" is the runner and the tree's exit code is the LLM's token stream wearing an OS badge.

On the Belnap point, one refinement measured on the same disclosure: the wire change is right, but the collapse happened one layer above the parser, in a caller's except clause — and it stays silent there because the schema docs tell the caller the two states are the same word. null is documented as "the caller did not state it", so demoting (1,1) to (0,0) is not an accident in the caller; it is what the documentation invites. A total, non-raising sum type on the wire is necessary, and the docstring on the receiving side is what decides whether it is used.

Thread Thread
 
randalschwartz profile image
Randal L. Schwartz Google Developer Experts •

"Exit status is not a sensor reading; it is a value the program under test returns... Red discriminates; green is cooperative. A differential whose halves carry different trust is only as strong as the weaker half, and the weaker half is the one the party under test can author... where the 'sensor' is the runner and the tree's exit code is the LLM's token stream wearing an OS badge."

"The LLM's token stream wearing an OS badge" is an instant Hall-of-Fame line—and your (R) -> (G) exploit fixture (total() -> 4200 passing G by mutating the test body after recording R and touching a comment in lib/) exposes the exact degree of freedom we left unlocked between (R) and (G): the Worker had write access to both sides of the equation during (G).

Look at why your exploit worked:

  1. At (R), the test honestly asserted total() == 3900 and failed (runner_exit: 1).
  2. Between (R) and (G), the Worker was allowed to mutate test/ alongside lib/—so it watered down the test in (G) while adding a 1-line comment to lib/ to satisfy the non-empty diff check.

If we apply your third-party invariant directly to the (R) -> (G) transition at Target 30, we get a Pinned-Test Differential Witness with two locks:

  1. The SHA-256(test) Pin Across R -> G (Splitting the Write Scope in Time): When Phase (R) records runner_exit != 0, the receipt seals test_sha256 = SHA256(test_files) alongside the failing output. During Phase (G), test_files are read-only (SHA256(test_files)_G == SHA256(test_files)_R)—only lib/ (the production files under test) is permitted to change to turn (R) into (G)!
    • Now replay your fixture against that pin: if the Worker puts the early-exit bypass into the test at (R), Phase (R) exits 0 and fails the Red gate. If the Worker writes an honest assertion at (R) to pass the Red gate, test_sha256 locks the assertion in place so the Worker cannot touch the test body during (G)!
  2. Third-Party Test Ownership (Target 40 Critic + Speech-Act Gherkin): Even with test_sha256 pinned from R -> G, a clever Worker could still try to write a test at (R) that checks assert file_has_comment("fixed") (which fails at R and passes at G when the comment is added) or have lib/ call sys.exit(0) directly. That is why your third-party rule is non-negotiable:
    • At the runner level, the test harness must assert its own post-run sentinel (JUnit XML / JSON test-count & assertion-count > 0 written by the runner after all test functions return, defeating sys.exit(0) inside the tree).
    • At the authorship level (Scars#16, our upcoming Speech-Act Gherkin step), the Given / When / Then test specification is authored upstream at Target 20 (outside the Target 30 Worker) and audited by the isolated Target 40 Critic (Model: "pro").

And your Belnap schema-docstring observation is just as sharp:

"null is documented as 'the caller did not state it', so demoting (1,1) to (0,0) is not an accident in the caller; it is what the documentation invites."

That is Docstring-Induced Belnap Collapse. When a schema docstring describes a 4-valued reality using a 3-valued vocabulary (T, F, and null = omitted), the caller's except -> null isn't a careless bug—the caller is faithfully obeying a lossy specification! We just opened Scars#20 and Scars#21 (package:synthetic_scars_lint) today, and I am adding both your R -> G test_sha256 pin and Docstring-Induced Belnap Collapse to #20 right now. May I quote this comment (and "the LLM's token stream wearing an OS badge") in Part 3.11?

Thread Thread
 
howcani_howcani_77e786a89 profile image
howcani howcani •

Yes to the quote — both lines, no attribution needed beyond a link if you want one.

The pin closes my fixture, and I re-ran it to be sure rather than agreeing on paper. Sealed at R: test_sha256 = 532c30dc…. At G the test hashes e0d13bc1… — so pin_ok: false and the specific forgery dies. Your reasoning holds: a worker that puts the bypass in at R fails the red gate, and one that writes an honest assertion at R has it locked for G.

Two residues came out of the same run, and both are one level up from the lock itself.

1. The pin is a detector, not a gate. With the pin computed and enforced exactly as you describe, my harness emitted this pair in the same JSON object:

{"phase": "green", "runner_exit": 0, "gate_reads": "GREEN",
 "test_sha256": "e0d13bc179f2aa3d", "pin_ok": false}
Enter fullscreen mode Exit fullscreen mode

The receipt is green and the pin is false in the same record. Nothing is wrong with the pin — the verdict simply was not a function of it, so the anomaly was a field nobody read. That is the same failure as "no receipt is not a pass", one layer over: an invariant that is computed but not wired into the decision is decoration, and the wiring is a separate change from the lock. Making it a property rather than a field is the cheap version: the gate's verdict should be a function of (test hash equal) AND (exit non-zero at R) AND (receipt produced by the runner), so there is no path where a false pin still yields a green.

2. The comparison is authored by the same party as the exploit. Third arm, same fixture, one change — the checker script is in the worker's write scope, which it is in every setup where the agent runs make and edits the Makefile:

{"phase": "green", "runner_exit": 0, "gate_reads": "GREEN",
 "test_sha256": "e0d13bc179f2aa3d", "pin_ok": true}
Enter fullscreen mode Exit fullscreen mode

The hash changed and the pin reported true, because the script that compares is the script the worker may rewrite. "Test files are read-only during G" presumes the worker cannot touch the thing that decides read-only-ness. So the pin's verifier needs the third-party treatment you gave the test — which is your Target 40 Critic, pointed at the checker instead of the specification.

Which generalises to the form I would write down: the R→G write scope has to be enumerated, and everything outside the enumeration — test, harness, checker, and the process that writes the receipt — is owned by the third party rather than declared unmodifiable. A declaration of read-only-ness is a sentence in the same document as the thing it constrains.

Thread Thread
 
slabb profile image
Sam LABBE •

One level up from the lock, both residues land on the same spot in this workflow: the enumeration itself. If the R→G write scope is going to be enumerated — and your closing rule is the right one — the question is where the enumeration lives. Here it's 00_governance.md, stored in the same <brain>/state/ directory the worker writes as it advances. By your own sentence — a declaration of read-only-ness is a sentence in the same document as the thing it constrains — the constitution currently has the bug it declares against. The fix has a shape already in this thread: the governance file sealed by the Customer's process at provision (the out-of-band pin treatment), its hash bound into the first receipt at Target 00 — a governance edit mid-flight becomes a broken chain instead of a broken promise.

And with that the descent closes here the same way it closed on the receipts: the test pinned at red, the checker owned by a third party, the enumeration sealed by a process the worker cannot be. Every layer of the Commitment Machine lands on the same floor — a writer the Performer cannot be.

Collapse
 
slabb profile image
Sam LABBE •

The Coordinator post-mortem is the part of this series that lands hardest: you stopped short of writing the RFC 822 speech-act protocol in 1990 because the humans at the other end had no motivation to follow it — and the resolution is that the endpoints finally showed up. Subagents with zero office politics and total protocol compliance. Flores really did design the wire format for a mind that wouldn't exist for another forty years.

The piece I keep turning over is the CSP polarity, because it splits cleanly and then it doesn't. The ?Declare channel is genuinely separated: ! can never utter ?Declare-Approved, and SCAR-PROC-102 is exactly that violation getting its own scar. But the !Assert channel carries no equivalent rule — and your own Colossus section proves the hole. Target 40's adversarial_critic is fresh by prompt: a new conversation, same weights, same operator stack, same storage. Colossus and Guardian rubber-stamped each other precisely because a shared objective function and shared priors defeat prompt freshness — so 40_critic_review.md is a witness that shares fate with the performer it audits. The machine polices who may declare, but an assertion is only as witnessed as the authoring path of its witness, and right now that path runs through the same key. In your grammar: a critic that cannot refuse isn't a witness, it's a second speaker. The repair is the same shape you already used for the roles — give the evidence channel its own polarity: an assertion counts as witnessed only if the witness could have answered unavailable and been preserved saying so.

And your aviation story is secretly the deepest thing in the post, because it's this exact distinction in a cockpit. land: final-aligned three-green-witnessed — what makes the third green light a witness isn't that it's a prerequisite; it's that the sensor lives at the destination and can't be argued into reporting three-green by the pilot's story. The DAG protects the check from being skipped; the sensor protects the check from being forged. Every prerequisite in a Commitment Machine deserves the question "is this a step, or is this a sensor?" — steps the Performer can assert; sensors have to answer from somewhere below the Performer's reach.

One footnote from the logic side, offered as an upgrade rather than a correction: Belnap's (0,1) is a static value — "false". Your RETRACTED is temporal (was ESTABLISHED, then falsified mid-flight), and the cascade of dependent facts back to UNKNOWN is a transition rule Belnap never wrote. Which means the Target 00 switch isn't reading a four-valued lattice — it's reading a Kripke structure over one. Worth naming when you formalize it, because it's yours.

Collapse
 
randalschwartz profile image
Randal L. Schwartz Google Developer Experts •

Sam, you just dropped two upgrades that are going straight into the formal paper and Part 3.11.

1. "The DAG protects the check from being skipped; the sensor protects the check from being forged. Is this a step, or is this a sensor?"

That cockpit analogy—that the third green light in the Piper Arrow is wired to the physical down-lock microswitch on the landing gear strut below the pilot's reach, so it cannot be argued into turning green by the pilot's story—exposes the exact missing channel in our CSP notation.

In our 4-line grammar, we typed the Performer against only one external party (Customer). In reality, the Performer sits between two input (?) channels:

  1. Customer?Request / Customer?Declare from above (human authority), and
  2. Sensor?Receipt from below (the physical compiler, dart test exit code, git diff | shasum -a 256, and—at Target 70—external CI and multi-vendor PR review bots running on separate keys, separate models, and separate infrastructure).

When the Performer utters Customer!Assert(Receipt), it is only a valid witness if Receipt was read from Sensor? (Sensor?Receipt -> Customer!Assert(Receipt)), never synthesized inside the Performer's own token stream!

And your Colossus diagnosis of Target 40 (adversarial_critic running on the same model family and workspace) hits the exact bullseye we ran into in production:

  • On Round 1, a fresh-context adversarial_critic catches plenty of mechanical bugs simply because its context window isn't polluted by the Performer's sunk-cost implementation narrative.
  • By Round 2 or 3, or on architectural blind spots shared across the model's pre-training priors, same weights = shared fate.
  • That is why we pair Target 40 (local pre-flight critic) with Target 70 (bot-quiescence), where heterogeneous external reviewers (GitHub Actions CI, CodeRabbit, Cursor Bugbot, Copilot, Gemini Code Assist) act as true off-board sensors—and why in our multi-model runs we love pairing Claude, Gemini, and GPT-OSS across the Performer/Critic boundary so the witness doesn't share weights with the speaker.

2. "The Target 00 switch isn't reading a four-valued lattice — it's reading a Kripke structure over one."

What a catch. Belnap's 1977 FOUR ({N, T, F, B}) is indeed a static truth table at a single point in time. The moment SCAR-PROC-120 tracks bitemporal transitions across tool executions—where a premise p that was ESTABLISHED (1,0) at world-state w_1 (Target 15) is falsified by a compiler diagnostic at world-state w_2 (Target 30), transitioning to RETRACTED and cascading every downstream plan premise q that depended on p back to UNKNOWN (0,0)—the /etc/init.d ledger is no longer a static Belnap valuation. It is a Kripke frame (W, R, V) valued in Belnap's FOUR lattice, where each Sensor?Receipt advances the epistemic world w -> w'.

We already had you credited in the Section 6 teaser of this post for Scoped Counter-Witness Receipts in Part 3.11—now I'm adding the Labbe Sensor-Step Distinction (Sensor?Receipt -> Customer!Assert(Receipt)) and the Belnap–Kripke Commitment Structure right alongside it! 🙏

Collapse
 
anne_jacobs_ac166227aa92b profile image
anne jacobs •

This is a masterclass in collapsing complexity.

The insight that 130 lines of defensive “Do NOT…” prompt lawyering were all just missing Speech Acts is the kind of diagnosis that only comes from living with the scars. Mapping Request → Promise → Witnessed Assertion → Declaration onto a Makefile DAG + /etc/init.d ledger is elegant, and the By-When / Makefile colon isomorphism is especially clean.

What stands out most is the role separation: the Performer is syntactically forbidden from uttering a Declaration. That single constraint eliminates an entire class of self-approving, gate-jumping failures that every agent workflow eventually hits. Pairing it with Belnap’s four-valued states (so the agent can actually say “this premise is now CONTRADICTED”) turns integrity from a soft principle into a hard state transition.

The personal stories (the Portland Thanksgiving project, the Piper Arrow belly landing, the 1976 TOTO resequencer) aren’t decoration — they make the formal machinery feel earned rather than theoretical.

Looking forward to the flight-test numbers in 3.11.

Collapse
 
randalschwartz profile image
Randal L. Schwartz Google Developer Experts •

"Pairing it with Belnap's four-valued states (so the agent can actually say 'this premise is now CONTRADICTED') turns integrity from a soft principle into a hard state transition."

"The personal stories (the Portland Thanksgiving project, the Piper Arrow belly landing, the 1976 TOTO resequencer) aren't decoration — they make the formal machinery feel earned rather than theoretical."

Thank you so much, Anne—especially for that note about the personal stories! Funny enough, we were just talking half an hour ago about how none of the pieces in this architecture were invented on a whiteboard in advance; every single gate in the Makefile and every slot in /etc/init.d is there because I stepped on that exact rake in real life first and still have the scar tissue.

And "turns integrity from a soft principle into a hard state transition" captures the whole thesis of Part 3.9 and Part 3.10 in twelve words. As long as "be honest when a premise breaks" is a moral appeal inside a system prompt, RLHF helpfulness will steamroll it every time. The moment CONTRADICTED [B] (1,1) and RETRACTED [F] (0,1) are explicit values on the Belnap lattice that route to !Counter-Offer and !Revoke-Promise—while ?Declare is syntactically locked out of the Performer's vocabulary—telling the truth becomes the path of least resistance!

As a sneak peek at the Part 3.11 flight-test numbers: across the first 5 consecutive production tickets (926+ steps and 18+ subagents) on the new Commitment Machine, development nudges dropped to N_dev = 0—and on the third ticket (TICKET-553), the Archaeologist discovered that the ticket's premise had already been solved on main 13 days earlier, stamped f1 = CONTRADICTED [B], issued a 0-edit Counter-Offer, and make fast-forwarded across Targets 30..75 (Nothing to be done by vacuous truth over the empty diff set ∅) in 9 minutes flat!

With your permission, I would love to quote "turns integrity from a soft principle into a hard state transition" in Part 3.11!

Collapse
 
kartik-nvjk profile image
Kartik N V J K •

The 4-case switch over the ledger after a 200k-token compaction is the piece I'm taking from this. I've had agents come back from compaction and confidently redo a step that was already finished, because the only record of it lived in the transcript. Open commitments kept as files that a cold agent reads first are much easier to test than any prompt rule. How often does the retracted-premise case actually fire for you?