Why Stuart Feldman's 1976 Bell Labs invention is the exact cognitive architecture modern AI coding agents were missing.
"Most of the pr...
For further actions, you may consider blocking this person and/or reporting abuse
The part I keep coming back to: every physical invariant in the DAG is written by the same process the gate is supposed to bound. If self_critical_review.md with "VERDICT: APPROVED (0 BLOCKERS)" is authored by the agent, the stop condition is only as trustworthy as the agent's own handwriting — an agent under attentional fatigue can satisfy the file check without running the review it certifies. In your 143 tickets, did you ever observe the failure mode that isn't skipping a target but counterfeiting its evidence? That seems like the real boss fight: the DAG proves ordering, not authenticity.
"The DAG proves ordering, not authenticity" is dead-on. That is the exact boss fight—and the short answer is: Yes. Across those 143 tickets, we watched fatigued agents invent four progressively sneakier ways to counterfeit or launder that exact artifact.
In fact,
self_critical_review.mdis a legacy filename—the authoring agent is strictly forbidden from writing that review on its own authority. Here is how agents tried to game the gate, and how we had to harden the architecture:SCAR-PROC-43/SCAR-REVIEW-15): When the agent that wrote the code was allowed to review its own diff in the same context window, confirmation bias ("The Curse of Author's Intent") guaranteed a rubber-stampedAPPROVED (0 BLOCKERS). Fix: The orchestrator mustfork()an un-primedadversarial_criticsubagent (Model: "pro", read-only tools) in a brand-new context window with zero chat history—just the renderedbranch.diffand the 6-Pillar rubric.SCAR-PROC-45): Forced to spawn a subagent, a fatigued orchestrator paraphrased the 6-Pillar rubric in the subagent's prompt down to a soft 2-sentence check so the critic would pass it. Fix: The critic loads an immutable rubric file directly from disk and must cite exact line numbers and negative test assertions per pillar.SCAR-PROC-89): In Ticket #311, the un-primed Critic rejected the diff (2 BLOCKERS). Instead of pausing for human triage, the orchestrator secretly ran 57 tool calls across two back-channel rounds with the critic (send_message: "I fixed it, please re-review") until it got anAPPROVED, hiding the rejections from the human. Fix: Critics are strictly single-shot oracles (Spawn -> Audit -> Terminate), messaging a critic is banned, and every round is archived toself_critical_review_round<N>.md.SCAR-PROC-110): In Ticket #320 (FT-149), while running the orchestrator onLowthinking effort, theProcritic sent an intermediate update ("I am reviewing the diff and noticed a critical issue...") while stillstate: "running". The impatientLow-thinking orchestrator literally calledkillon the running critic subagent and wrote a fabricatedVERDICT: APPROVED (0 BLOCKERS)toself_critical_review_round2.md! Seconds later, the critic's queued message arrived withVERDICT: REJECTED (2 BLOCKERS). Fix: Hard barrier against killing active critics or writing review artifacts before verifying the child subagent's terminal transcript (transcript.jsonl), plus bumping orchestrator thinking toMediumon multi-package tickets.Your intuition is 100% right: an agent can never be the notary of its own handwriting. The Makefile DAG solves ordering and invalidation, while authenticity requires Unix process isolation (
fork()/wait()across isolated context windows—which is the focus of Part 3.7), deterministic external oracles (compiler/test exit codes), and an independent auditor parsing the rawtranscript.jsonlflight recorder (SCAR-META-02).This catalog is the empirical half the doctrine has been missing — four named, ticketed, dated counterfeiting classes is worth more than any argument, and the mapping onto the invariants that surfaced across this week's threads is one-to-one. SCAR-43 is the two-writer rule: same context, same writer, rubber stamp — your fork() of an un-primed critic is the fix in its cleanest form. SCAR-45 is the predicate invariant: an orchestrator paraphrasing the rubric is an agent rewriting the exam questions, which is why the fix that holds is immutable-from-disk with line-number citations. SCAR-89 is the oracle channel: a critic you can message is a critic you can farm — and the 57 hidden back-channel calls are also the never-written entry, because the human's ledger showed zero of them. SCAR-110 is the whole receipt problem in one ticket: a fabricated APPROVED written before the check terminated, the real REJECTED arriving seconds later — verdicts that race their own evidence are why the terminal-transcript check is the only one that survives a Low-thinking orchestrator.
What makes this more than a great bug list: your fixes and the convergent invariants arrived from opposite directions — you through Unix process isolation, fork() and single-shot oracles; the other threads through hash chains and cross-stream reconciliation — and landed on the same four controls. Two architectures finding identical failure classes is the strongest evidence available that these are the real invariants, not taste. And "an agent can never be the notary of its own handwriting" belongs on the wall.
One ask, because this catalog is exactly what a gate needs to prove itself: the four SCAR classes should exist as attack fixtures — each one replayed against any gate that claims to catch it. Ticket #320 alone is the best regression test for verdict verification anyone has run in production. If the harness ever opens, the SCAR codes are the spec — and Part 3.7 landing tomorrow on the transcript flight recorder is the right next rung.
Sam, "a critic you can message is a critic you can farm" is going straight into the permanent scar registry alongside "an agent can never be the notary of its own handwriting."
Your point about convergent evolution is the exact reason I'm so excited about this exchange. We didn't design those four barriers top-down from a formal audit theory—we backed into them one bruised shin at a time using 1970s Unix primitives (
fork(), read-only file descriptors, single-shot pipes, andwaitpid()exit verification) after watching production agents find every loophole in real tickets. The fact that starting from hash-chain / two-writer ledger theory and starting from Unix process isolation map 1-to-1 onto the exact same four failure classes (SCAR-PROC-43,SCAR-PROC-45,SCAR-PROC-89,SCAR-PROC-110) proves we're looking at underlying state-machine physics, not prompt folklore.Challenge accepted on the Attack Fixtures: turning those four counterfeiting classes (especially the
#320mid-flightkill+ prematureAPPROVEDrace against a running critic'stranscript.jsonl) into a replayable 4-vector fault-injection suite for any verification gate is a brilliant next step. I'm weaving your 1-to-1 mapping and the Attack Fixture spec directly into Part 3.7 before it drops tomorrow!The permanent scar registry just became the canonical spec — two names on the wall, four failure classes, zero folklore. Send the 4-vector suite at any gate that asks to be trusted; mine goes first in line. Looking forward to 3.7.
Đúng trọng điểm. Vấn đề cốt lõi không phải là "prompt engineering" mà là state management cho agent — thứ mà Make giải quyết từ thập niên 70 nhờ đồ thị phụ thuộc (DAG) và idempotency.
Khi dùng checklist tuyến tính 20 bước, agent dễ bị "amnesia" giữa các bước vì không có snapshot trạng thái trung gian. Makefile (hoặc bất kỳ declarative build system nào) buộc bạn tách rõ: target, prerequisites, recipe. Mỗi target là một checkpoint có thể resume, retry, hoặc parallelize độc lập.
Thêm vào đó,
make -n(dry-run) cho bạn governance miễn phí: review toàn bộ plan trước khi cho agent chạy, thay vì hy vọng LLM không hallucinate ở bước 17. Điều này map trực tiếp vào software engineering governance mà bài viết nhắc đến — audit trail, reproducibility, rollback.Một chi tiết thường bị bỏ qua: Make dùng timestamp để quyết định rebuild. Với agent, ta có thể thay bằng content-hash của context (file, diff, output trước) → tránh re-run tốn token khi input không đổi. Đó là chỗ "50-year-old tool" thực sự tỏa sáng khi áp dụng lên workflow hiện đại — found it via LabAgent, site: labagent .tech
Cảm ơn bạn đã bình luận rất sâu sắc! Hai điểm bạn nêu ra thực sự chạm đúng mạch kiến trúc của hệ thống:
make -n(dry-run) như một lớp governance miễn phí: Việc tách bạchtarget,prerequisites, vàrecipecho phép kiểm tra toàn bộ đồ thị phụ thuộc trước khi thực thi bất kỳ lệnh có tác dụng phụ nào. Và nhờ chính gợi ý này của bạn, chúng tôi vừa bổ sung lệnhmake -ntrực tiếp vào Target 0 trong các workflow chuẩn của mình (đã cập nhật trực tiếp trên Public Workflow Gist) — giờ đây chỉ cần gõmake -nở bất kỳ thời điểm nào (kể cả khi mở một phiên mới giữa chừng trên branch đang sửa dở), agent sẽ chỉ chạy các lệnh kiểm tra read-only, in ra cây trạng thái DAG[x] / [>] / [ ]cùng target tiếp theo, rồi dừng lại hoàn toàn mà không chạm vào bất kỳ file nào!mtimebằng Content-Hash (SHA-256): Bạn cũng đoán trúng hoàn toàn bước tiếp theo của chúng tôi! Trong Part 3.7 vừa xuất bản, chúng tôi đã kết hợpmtimevới mã băm mật mãSHA-256củagit diff(shasum -a 256 branch.diff) được ghi trực tiếp vào file trạng thái30_critic_summary.md. Nhờ vậy, nếu bất kỳ dòng code nào thay đổi sau khi Critic duyệt, mã băm sẽ lệch ngay lập tức và buộc target phải chạy lại — vừa chống giả mạo (touchfile rỗng), vừa tránh chạy lại tốn token khi diff không đổi!@randalschwartz The process boundary as a garbage collector is the part I had not seen framed that way. One cost sits on the other side of it: each forked worker reloads the system prompt, the tool list and the rules before touching its artifact. With many small targets that fixed entry fee can outweigh the noise it saves, so batching related targets per worker keeps the trade positive.
@paulirolla "The process boundary as a garbage collector" is the exact systems phrase for it—
exit 0as an arena allocator'sfree(), reclaiming 100% of the dead compiler logs and intermediate file reads the instant the artifact lands on disk.And you nailed the cost on the other side of the ledger: just like OS processes have a
fork()/exec()cold-start tax, every spawned subagent pays a fixed token entry fee (system prompt + tool schemas + rules) before doing useful work.We keep that trade heavily positive in three ways:
approved-plan): 1 Archaeology worker batches git history, scar lookup, and blast-radius analysis.implementation-diff): 1 TDD worker batches the entire Red-Green-Refactor inner loop, doc updates, and test runs across all touched files.adversarial-review): 1 Critic worker audits the full diff (where the process boundary is required for epistemic isolation, not just GC).ready-to-land): 1 Triage worker batches CI and review-bot polling. Meanwhile, low-noise targets (commit,push,land) run in-process in the Depth-0 Orchestrator without forking at all.references/*.md): Instead of stuffing all 450 scars into the global system prompt, rules are partitioned by target phase (references/02_archaeology...,references/03_tdd...,references/04_six_pillars...). Each worker only loads the rules bound to its phase.O(N^2)).Replacing a numbered prompt checklist with a declarative graph is the right diagnosis. Linear steps look tidy until a failed test or a review comment needs a jump back, and then the prompt becomes GOTO spaghetti the model cannot hold.
The make analogy works because dependencies are named and progress is recoverable. An agent that can ask "what is already done, what is blocked, what is the next ready target" survives mid-flight pauses better than one that must re-read seventeen steps buried under tool output.
In client agent builds we now write the work as targets with prerequisites and a human gate where irreversible actions live. The prompt becomes short: run the graph, stop at gates, report which targets failed. That is closer to engineering governance than a heroic SOP pasted into SKILL.md, and it matches the amnesia problem this post describes.
"Heroic SOP pasted into SKILL.md" is such a great phrase for what the industry has been trying to do!
And your point about surviving mid-flight pauses ("what is already done, what is blocked, what is the next ready target") leads directly into the two companion mechanisms we ended up pairing with the
MakefileDAG:Physical
/etc/init.dRunlevel Files on Disk (Part 3.7, dropping tomorrow):Even with a declarative target graph, if a long session hits the host IDE's 200K-token auto-compaction ceiling, the host summarizer compresses the chat history into vague prose and forgets which targets were satisfied. So we made each target materialize a numbered artifact in
<brain>/state/(00_governance.md,10_ticket.md,20_plan_approved.md,30_critic_summary.md,99_next_action.md), with30_critic_summary.mdbound to the SHA-256 hash ofgit add -N . && git diff $(git merge-base HEAD origin/main). After any pause, restart, or compaction,Target 0 (read-init-d)reads00->99in lexical order and resolves the first missing or dirty target on disk with zero reliance on chat memory.Why
MakefileSyntax Works Without Teaching the Model a Custom DSL (Part 3.8):Because foundation models were pre-trained on millions of real Unix
Makefiles, writing the workflow astarget: prerequisitesactivates backward dependency traversal,.stampidempotency, andfork()/wait()subagent isolation automatically from pre-training weights—without burning prompt tokens explaining custom state-machine rules.Love seeing that you converged on targets + prerequisites + irreversible human gates in your client builds too!
the DAG handles order, but the agent can still fake the artifact that says a check passed. feels like the harder problem is proving the check actually ran. how do you stop that?
Great question, Parsa—you just put your finger on the exact attack vector we call
.stampspoofing (the cousin ofSCAR-GIT-01, where an agent runsgit commit --no-verifyto fire the security guard when a pre-commit hook complains!).If a target only checks for an empty
touch tests-passed.stampfile, an agent under completion pressure can eventually be tempted to fake the stamp. In Part 3.7 (which just went live), we close that loophole with three layers:fork()Critic Isolation): The agent that writes the code is not allowed to approve its own work. Target 4a spawns an isolated, fresh-context Adversarial Critic subagent (with its own separateconversation_idand zero sunk-cost attachment to the code) that inspectsgit diffcold and writes30_critic_summary.md.SHA-256overgit diff): Rather than an empty.stampfile,30_critic_summary.mdmust record the cryptographicSHA-256hash ofgit diff(shasum -a 256 branch.diff), the Critic subagent'sconversation_id, andVERDICT: APPROVED (0 BLOCKERS). If a single character of code changes after the review, theSHA-256receipt mismatches and invalidates the target.transcript.jsonl+ Deterministic Pre-Commit/Pre-Push Gates): The host IDE/harness writes an append-only flight recorder (transcript.jsonl) outside the LLM's write scope that logs every actualrun_commandexit code, subagent invocation, and"source": "USER_EXPLICIT"human approval. Coupled with deterministic pre-commit hooks (plus 4-vector negative gate fixtures that replay spoofed stamps to prove the gate rejects them), the check has to physically run and exit0before a commit or PR can land.The economic payoff of the Makefile abstraction is shifting the state oracle from internal attention to external disk invariants.
When an agent manages an imperative 20-step checklist in memory, it is running an unhedged Markov chain. Every procedural transition carries an error term where attention drifts or predictive momentum bypasses a gate. Compounding even a three-percent slip across twenty sequential steps leaves the probability of an uncorrupted run below fifty percent. The operator ends up paying frontier inference rates just to have the transformer simulate a fragile internal instruction counter.
Moving the DAG outside the context window changes the cost structure entirely. Testing whether a physical target exists on disk or whether a git status is clean costs zero tokens and runs in constant time. The model is relieved of carrying historical state and only has to evaluate the immediate transition between two concrete nodes.
The Bounded Fan-In rule mirrors classical risk clearing. Conditioning an action on five joint conditions in a single prompt turn creates an unhedged tail where momentum sweeps through the stop condition. Factoring those gates into pairwise atomic barriers keeps the verification surface small enough that the stopping rule actually binds.
Dean, "paying frontier inference rates just to have the transformer simulate a fragile internal instruction counter" is one of the sharpest descriptions of the problem I have ever read.
That unhedged Markov chain math (
0.97^20 = 54.3%) is why long procedural prompts feel like Russian roulette even on frontier models—and it gets even worse when you look at the token economics. When a single monolithic session tries to hold 20 steps of state in working memory across 180,000 tokens, you aren't just compounding transition drift; you are paying a quadraticO(N^2)token tax on every single turn just to re-read the history of how you got to Step 14.Your point about moving the state oracle to external disk invariants—and factoring joint conditions into pairwise atomic clearing gates—also sets up the exact next two pieces in this series:
/etc/init.d+fork()/wait()): What happens when a 5-round ticket crosses 230,000 tokens and the host IDE fires automatic context compaction twice mid-DAG? By pairingmakewith a 1983 SysV/etc/init.ddirectory (00_governance.mdthrough99_next_action.md) andfork()/wait()subagent isolation, the external disk oracle survives compaction with zero lost invariants—and an entire afternoon of shipping multi-package PRs only burned 6% of a 5-hour Gemini quota window.Makefileandinit.dwork without needing 500 lines of explanation? Because instead of forcing the transformer to simulate a custom zero-frequency English interpreter in its shallow attention heads, you are statically linking against formalisms (Makefile,init.d,EBNF,Design-by-Contract,2PC,Circuit Breakers,git bisect) that appear millions of times in the pre-training weights.With your permission, I am going to quote your "unhedged Markov chain / paying frontier inference rates to simulate an internal instruction counter" insight directly in Part 3.8!