{"slug": "bounded-chaos", "title": "Bounded Chaos", "summary": "Fable 5, an AI model capable of building entire games from a single prompt, demonstrates impressive one-shot generation, but the author argues that real feature work requires a containment strategy rather than trust, using deterministic gates and specs to manage the non-deterministic nature of LLMs. The workflow described involves a fixed sequence of phases—specification, threat modeling, task decomposition, and implementation—each run in isolated sessions to avoid context bloat, with human review gates at critical points.", "body_md": "Most \"AI writes your code\" demos end right where the hard part begins: the second hour.\nWhen a new model comes in, it can draft a feature in one shot. Fable 5, for instance, is\ncapable of building whole games from one prompt! You can open it and play right away. Do you\nwant special assets? Music? Just name it. It's really impressive.\n\nBut it's also not the job. Real feature work isn't a cold-start demo; it's the second hour,\nand the tenth, spent extending a system that already has a shape and opinions.\n\nWithout control, boundaries, and validations, a model tends to ignore the\nspec, skip the tests, and quietly ship the thing you didn't ask for. You can't\nfix that by trusting the model more. The trouble is structural: an LLM is\nnon-deterministic by construction, and no amount of prompting makes it otherwise.\n\nMy workflow makes a different bet: contain, don't trust. The spec and the\ngates are a containment vessel. The model does real work\ninside it and can't talk its way past the walls. Every rule I can make\ndeterministic is one less thing riding on the model behaving.\nThe long game is to keep pushing that boundary outward - every gate, every spec, every\npromoted rule is territory reclaimed from chance.\n\nThis post walks the one flow I run for real feature work, end to end. It's a set\nof skills and review agents that turn a loose intent into a reviewed,\nshipped pull request. Each phase is another wall of the vessel; I'll walk through what every phase\nis for and the state machine the work moves through.\n\nFor any work that earns a spec, the whole chain runs in a fixed order. Each phase\nis a command I run explicitly. Nothing auto-advances. Partly that keeps me in\nthe loop, but there's a mechanical reason too: an auto-advancing chain balloons the\ncontext fast (each validation pass dumps its findings into the same session the\nnext phase inherits), and a runaway context means a token blowup, which means a doomed\nrun. So the workflow stops between phases. Continuity lives on disk: every\nphase starts in a fresh, isolated session and picks up the state the previous one\nleft behind. No single context carries the whole feature from start to finish; each\nphase is bounded and resumable.\n\nEach command owns one phase of the flow. Here's what every phase is for:\n\nThis phase runs a relentless \"grill\" interview to pin down intent. It then grounds that intent in the domain: it updates CONTEXT.md - the project's living domain glossary, the canonical vocabulary the model has to speak - and writes ADRs for the hard-to-reverse, surprising calls. Finally it infers the tier and feature config once, up front (the tier dials are spelled out in The spec config below).\n\nHere a Security Engineer writes a threat model before any spec exists. The spec.md that follows carries functional requirements, API contracts, a data model, and BDD scenarios.\nWith that in place, we run specialized agents that attack the step from different angles:\n\nProject Manager decomposes the spec into vertical slices - each a piece of work that delivers a small working element of the whole feature.\n\nTest Strategist designs the cross-task test strategy: which test proves which scenario, and at which level - all before any of it reaches implement.\n\n[Human gate] Spec & tasks review\n\nBefore a line of code gets written, I read the spec, the design, and the task\nbreakdown end to end. This is where I catch a wrong contract or a bad slice while\nit's still cheap - a misread requirement here costs minutes; the same mistake\ncaught after implement costs a rebuild.\n\nThis phase builds exactly one eligible task, on its own branch, through a red-green-refactor loop; the next eligible task is picked off the dependency graph - the build order already set in propose. It runs inline or routes to the implementer agent named in the task, driving the task todo → in-progress → implemented and opening a draft PR.\n\n[Human gate] Draft-PR review\n\nThis is the first place in the implementation phase where I stop and read code. I open the draft PR, pull the diff\ninto context, and make sure I understand what the model actually built. At this point it doesn't have to be deep - just enough to grasp the changes made. That's how I'm ready to rule on the validation findings later instead of trusting them blind.\n\nThis phase runs the deterministic gates and fans out a parallel panel of advisory agents,\nplus a coverage audit that asks whether the diff actually covers the task's acceptance\ncriteria. One rule resolves all of it: every gate has to end pass before a task is done.\nA gate that errors gets re-run. A gate that raises findings sends the task to review. Only\nwhen every gate comes back clean does the task go straight to done - and on that clean path\nit ships inline, no separate step.\n\nreview-and-ship - rule on the findings, then ship#\n\nThe findings from the validate phase get addressed in two ways: automatic and manual. Structural mappings I built into the process route mechanical findings to automatic fixes; everything else is delegated to me for manual approval.\nThe AUTO bucket clears itself first: mechanical findings (formatting, unused import) and coverage gaps are fixed. Everything else is grouped by code region and presented for acceptance or rejection, one region at a time, and a reasoned rejection can be promoted into a reusable knowledge-base (KB) rule on the spot. Then it ships inline: one commit covering the applied fixes, a push, and the draft PR flipped to ready - into the feature integration branch, so the feature accrues as a reviewable whole before it reaches main. Shipping is the tail of this phase now, not a command of its own; the task lands review → done and shipped in one move.\n\nlearn-from-reports - never the same mistake twice#\n\nThis phase mines validation output for recurring findings and repeated rejections, then promotes the patterns into KB rules so the same mistake gets caught earlier next time.\n\nThis phase runs once every task is done. An auditor reads the cumulative diff against the spec's full FR list, checking what was actually built against what the spec claimed and flagging gaps, then asks the end-question: did we build the spec, with no orphan code, nothing missing? A clean verdict ships; a reopen loops the gaps back as follow-up tasks until the verdict is complete.\n\n[Human gate] Feature review before main\n\nOnce the spec audits complete, the feature integration branch gets a full human\nreview before it reaches main. The per-task gates and the coverage audit get the\nwork ready for that review; they don't replace it.\n\nThe thing that actually flows through that chain is the task, one at a time.\nA feature is decomposed into several tasks, and each task moves through\nits own lifecycle independently. That lifecycle is an explicit state machine:\n\nThe state machine isn't decoration. A task can't go in-progress while its\ndependencies are unfinished, and finishing a task drops every task that was\nblocked on it down to todo. The order is enforced, not suggested.\n\nEvery feature carries a config.yml, inferred once in explore and editable by\nhand. It's a small set of dials, and the same machinery runs at every setting -\nthe config only decides how much ceremony and which checks the feature earns. This\npost - built as a feature through the same flow - used this config:\n\nThe dials:\n\ntier {small | medium | large} sets how much ceremony the feature\nearns. small produces task files only; medium adds a full spec.md; large\nadds a design.md and a dedicated test-strategy.md on top. small also skips\nthe advisory review panel and the final spec audit - a one-file change shouldn't\npay for a threat model.\n\ntrack {feature | technical} picks the shape of the work. feature runs\nthe full business-spec flow above. technical is for refactors and debt, where\nthe intent is already clear and there's nothing to discover - so it skips the spec\nand design artifacts and grounds itself in ADRs and CONTEXT.md instead.\n\ngates is the gate ceiling for the feature - the deterministic checks any\ntask is allowed to run. The set that actually runs on a given task is this ceiling\nintersected with that task's languages, so a Rust task never runs the TypeScript\nlinter.\n\nbranch_strategy {per-task | single-branch} chooses between a draft PR\nper task off a feature integration branch, or one branch that accumulates commits\ninto a single PR, shipped at the tail of review-and-ship.\n\nvalidate_scope {per-task | per-spec | both} decides when the gates\nrun: after each task, once over the finished feature, or both.\n\nagents binds an agent to each phase - which lenses run in explore, who\ndecomposes in propose, who reviews in validate.\n\ntier_ceiling can override the default task and file budgets when a feature\ngenuinely needs more room.\n\nvalidate is worth zooming in on, because it's the phase where a single\nperspective stops being enough. Beyond the deterministic gates, it dispatches a\npanel of specialized review agents in parallel, each looking at the diff through\none lens. Their findings, plus the gate results, are what review-and-ship then\nwalks me through:\n\nThe gates are mechanical - lint, type-check, tests, format - and they run before\nany agent weighs in. The advisory agents each read the diff through one lens (security, code\nquality, architecture), and Odium checks it against the task's acceptance\ncriteria. Everything lands in review-and-ship, where I rule on the\ndisagreements instead of grading my own homework.\n\nThe rules the workflow enforces don't live in the prompts. They live in one\nknowledge base, split by topic directory - architecture/, testing/,\nsecurity/, frontend/, languages/, style/, and a few more. One store, so a\nrule has exactly one home and gets cited the same way everywhere.\n\nEvery phase leaves a trail on disk, so the containment is inspectable after the\nfact.\n\nAn event log per feature records what happens across its lifecycle: task\ntransitions, TDD red and green, coverage-audit start and finish, gate skips, the\ninferred tier, and PR lifecycle.\n\nA findings report per task and gate holds what the gate found. Each finding\ncarries a severity, a category, a source (tool or model), a confidence, and a\nreview status - pending, accepted, rejected, or noted.\n\nAn audit record captures the spec-completion verdict: complete, or reopen.\n\nOn top of that sits a learning loop. /learn-from-reports mines those reports\nacross runs for recurring categories, reasoned rejections, and accepted fixes\ngeneral enough to reuse, then promotes them into the knowledge base under the\nmatching topic. The next run starts with the rule already in place, so the same\nmistake gets caught one phase earlier.\n\nThe loop is mechanical and the inputs are files you can read. A finding the model\nraised and I rejected with a reason doesn't vanish; it becomes evidence the next\nmining pass weighs. Over time the perimeter moves on its own: judgment calls I\nmade once turn into rules the system enforces without me.\n\nFour rules are enforced by the workflow itself, not left to per-run discretion:\n\nTest-first is non-negotiable. Red before green - a failing test has to exist\nbefore the implementing code. LLMs are poor at adding coverage after the code\nexists: they tend to write tests that merely pass and chase a coverage number,\nwith behavioral quality all over the map. Test-first forces the behavior to be\nspecified before the code that satisfies it.\n\nPhases run in isolated sessions. Each phase is bounded and scoped, with state\nhanded off on disk. No single runaway context carries the whole feature.\n\nGates hard-block. A failed gate stops the flow. There's no \"assert and warn\"\nescape hatch that lets a known failure slide through to shipping.\n\nThe dependency graph is enforced. A task can't start until the tasks it's\nblocked_by are done. The build order is a property of the system, not a thing\nI have to remember.\n\nEverything above is the version I run daily: a pile of bash and slash commands\nwired to one AI runtime. It works, and it has three problems I can't ignore.\n\nVendor lock-in. The whole thing is married to Anthropic's models. If the\npricing or the product moves the wrong way, my workflow moves with it.\nThin observability. I read the trail after the fact, in YAML. I don't have a\nlive view of what the model is actually doing while it does it.\nNo control over the system prompts. The tool injects its own heavy prompts on\nevery call. I can't see them, can't trim them, and I pay for the tokens.\n\nBondsmith is the answer I'm building. It's a provider-neutral core - a Rust\nbinary, plus a set of target-neutral .flow contracts - that drives\nthis same workflow across swappable runtime adapters. Two adapters are planned: the\nfirst migrates the Claude Code flow I run today; the second is built from\nscratch for Pi, a minimal agent harness. The point is that the\nprocess outlives any one model or vendor: swap the adapter, keep the scaffold. More on Bondsmith soon.\n\nAIWorkflow\n\nThanks for reading\n\nMore like it are on the way - stick around or say hi.", "url": "https://wpnews.pro/news/bounded-chaos", "canonical_source": "https://coldtake.dev/blog/bounded-chaos", "published_at": "2026-08-12 15:48:34+00:00", "updated_at": "2026-08-12 16:15:17.005401+00:00", "lang": "en", "topics": ["artificial-intelligence", "generative-ai", "ai-agents", "developer-tools"], "entities": ["Fable 5"], "alternates": {"html": "https://wpnews.pro/news/bounded-chaos", "markdown": "https://wpnews.pro/news/bounded-chaos.md", "text": "https://wpnews.pro/news/bounded-chaos.txt", "jsonld": "https://wpnews.pro/news/bounded-chaos.jsonld"}}