The Core Loop
Intent becomes real only after it crosses the commit boundary.
Chapter 13 - The Core Loop
Part: IV - The Propose / Validate / Commit Loop
Thesis
Propose, Validate, Commit is not only a vibe-coding technique. It is the shared control loop for building software with a model and for running a model inside software. At build time the loop runs once per session. At runtime it runs once per request, forever. Every failure - in AI-assisted development or in an AI-native application - traces back to the same skipped step: a proposal that crossed a commit boundary before it was validated.
Key Line
Intent becomes real only after it crosses the commit boundary.
The Three Phases
The loop has three phases and no shortcuts.
Propose. The model generates a candidate output - code, schema, migration, documentation, test, plan, or, if the model is running inside a live application, an action, a claim, a move, a piece of narration, a state patch. The proposal is cheap. It costs tokens and time, not judgment. A model that produces a wrong proposal has not caused harm. It has produced a proposal that will not survive validation.
Validate. Automated controls fire first. Tests run. The type checker runs. The linter runs. Schema validators run. What passes automated controls then reaches human review. The human is not reading raw model output. The human is reviewing output that has already survived the machine checks. Judgment lives in validation, not in the proposal. In a runtime system there is usually no human in that second layer - the equivalent controls are schema parsers, permission checks, and legality or domain rules, and they must fire on every request, because no one is standing by to catch what they miss.
Commit. The verified output crosses the boundary and becomes state. A commit is not a checkpoint. It is an explicit act of ownership. The developer who commits is saying: “I accept this output as correct.” That statement has weight. It should feel like weight. The boundary is not always a git commit. It is whatever transition turns a proposal into something persistent, public, executable, or user-visible - a merge, a database write, an executed tool call, a published sentence. The next section names the two boundaries this book returns to most.
The loop does not end. After a commit, the next feature, bug, request, or refactor starts a new iteration. The loop is the workflow, at build time and at runtime alike.
Propose
The proposal phase is the only phase where the model operates without constraint on output.
That is not a flaw. It is the point. The model generates broadly because broad generation is cheap to produce and cheap to filter. A model that generates three candidate implementations allows a developer to pick the best one. A model that generates one cautious implementation has already made a judgment call the developer did not authorize.
Proposals are not decisions. A file full of model-generated code sitting in a branch is not a software change. It is a collection of proposals waiting for validation. Treat them that way.
The failure mode in the proposal phase is not bad output. It is treating proposals as decisions. A developer who reads model output, nods approvingly, and commits without running tests has confused Propose with Commit. The loop collapsed.
Keep proposals small. A proposal that covers one function, one endpoint, one migration, or one behavior unit is verifiable. A proposal that covers thirty files is a project, not a proposal.
Validate
Validation has two layers. Both are required.
The first layer is automated. Tests, type checks, schema validation, lint rules - every engineering control defined in Chapter 10 belongs here. These controls fire before a human reads a line of the diff. They do not get tired. They do not grant exceptions because the deadline is close. They fire, and they either pass or fail.
The second layer is human review. The human reviews what passed automated controls. This is the correct framing. The human is not a backup to automation. The human is a second filter that runs on output automation already approved. That sequence matters. A human reviewing output that has already passed tests, types, and schema validation is doing higher-order work: checking intent, checking architecture, checking whether the code does what the commit message claims.
These two layers are not interchangeable. Running human review without automated controls first means the human is doing automation’s job on top of their own. Running automated controls without human review means intent is never checked. Both are required.
The output of a successful validation is permission to commit. Not confidence, not certainty - permission. The controls passed. The human is satisfied. The output may proceed.
Commit
The commit is not a save point. It is a statement.
When a developer runs git commit, they are declaring that the staged changes are correct, verified, and ready to become part of the project’s permanent record. That is a strong claim. It should be made deliberately.
Commit discipline in AI-assisted development is specific. The commit message explains why this change was made, not just what the diff contains. The message is written for the model that will read git log in the next session and need to understand the constraint that produced the decision.
Small commits are easier to verify, easier to revert, and easier to understand. A commit that covers one logical change allows a future reader to understand one decision. A commit that covers a session’s worth of output requires reconstructing the session from the diff.
The commit is also the point at which the developer accepts liability. Not legal liability. Professional liability. If the change breaks production, the commit author owns the investigation. That ownership is why the commit must follow validation, not precede it.
Two Commit Boundaries
“Commit,” so far, has meant one thing implicitly: a developer accepting output into the repository. That is one instance of a more general idea.
Introduction I names two places a model can stand: the build loop and the runtime loop. The Propose / Validate / Commit loop runs in both places, but the commit boundary means something different in each.
The development commit boundary is where generated code, tests, schemas, migrations, documentation, or configuration stops being a proposal and becomes repository or deployed software. The mechanism is usually a merge, a deploy, or a release. The clock is human-paced. A person decided.
The runtime commit boundary is where generated output stops being a draft and becomes database state, an executed tool action, a published claim, a legal move applied to a board, a rendered event, or any other truth a user can see or a system will act on. The mechanism is a write, an execution, a publish call, a state reducer accepting a patch. The clock is machine-paced. Whatever decides has to already be built into the system, because there is no person in the loop to ask before the next request arrives.
Both boundaries answer the same question: has this proposal earned the right to be treated as real? Neither boundary is git-specific. git commit is one implementation of a development commit boundary. It is not what “commit” means in this book.
Only validated state becomes real.
That line holds at both boundaries. A patch that has not passed tests and review is not code yet, no matter how correct it looks in the diff. A tool call that has not passed its schema, its permission check, and its domain rule is not an action yet, no matter how confident the model sounded producing it. Confidence is not validation. Only validation is validation.
The State-First Role Model
Both boundaries are staffed by the same seven roles, whether the system is a codebase or a running application.
| Role | Job | Build-time instance | Runtime instance |
|---|---|---|---|
| Generator | Produces a candidate | The model drafting a patch, a test, a migration | The model drafting a tool call, a move, a claim, a narration |
| Specification | Shapes the proposal before it exists (ex ante) | Prompt, CLAUDE.md, existing tests, schema in context | Tool description, schema, retrieved state, current permissions |
| Validator | Checks the proposal after it exists (ex post) | Tests, type checker, linter, human review | Schema parser, permission check, legality engine, solver |
| State substrate | Holds what has already been accepted | The repository - Chapter 14 | Database, event log, registry - Chapter 14 |
| Reducer | Applies an accepted proposal to state | Merge, migration runner | Board-state reducer, ledger update, action executor |
| Renderer / exporter | Produces what a person or downstream system sees | Build artifact, deployed release | Rendered UI, spoken narration, exported frame |
| Trace | Records what was proposed, accepted, and rejected | Commit log, CI history, PR thread - Chapter 17 | Tool-call log, rejection log, audit trail |
Nothing in this table is optional in a system that takes model output seriously. A generator without a specification is guessing. A validator without a state substrate has nothing authoritative to check the proposal against. A reducer without a trace makes every accepted change unauditable. The table is not a menu. It is a minimum staff list.
One Loop, Two Boundaries: A Worked Comparison
Put a build-time proposal and a runtime proposal through the same loop, side by side.
| Step | Build-time: a code patch | Runtime: a tool action |
|---|---|---|
| Intent | A developer wants to fix a bug | A user’s request implies an action |
| Specification (ex ante) | Prompt, CLAUDE.md, the failing test, existing code | Tool description, schema, current game or account state, permissions |
| Proposal | The model drafts a diff | The model emits a typed tool call |
| Private event | Commit on a feature branch | Draft tool call, not yet authorized |
| Validation (ex post) | Tests, types, lint, human review of the diff | Schema validation, permission check, domain-rule check |
| Commit | git merge to main | The tool executes; a row is written or a state patch is applied |
| Rejected path | PR blocked; review comments explain why | Call rejected; structured error returned; attempt logged |
| Public / persistent event | Merged, deployed change | Executed action, stored state, user-visible result |
| Trace | Commit message, PR history, CI log | Tool-call log, rejection log, audit trail |
Read the two columns against each other. Every row on the left has a row on the right. The steps do not change. The nouns do.
The private-event row matters most. A branch commit and a draft tool call are the same kind of thing - visible to the process that produced them, absent from anything anyone else depends on, cheap to discard. A merge to main and an executed tool call are also the same kind of thing - visible outside the process, expensive to take back, the difference Chapter 6 calls commit-level rather than generation-level failure when they turn out to be wrong. The discipline in this chapter is keeping proposals in the private lane until validation earns them a place in the public one.
The Inner Loop
Inside every Propose-Validate-Commit cycle, a tighter loop runs.
The developer reads the proposal. They find something wrong. They prompt the model to revise. The model revises. They read again. They accept or revise again. This is the inner loop: Propose -> Review -> Revise -> Accept.
The inner loop is where most of the work happens. The outer loop defines the boundary - what counts as done. The inner loop is where output improves before it reaches the boundary.
Inner loop hygiene: keep the inner loop short. A proposal that requires ten rounds of revision before it is acceptable is a signal that the initial prompt was underspecified. Revising the prompt costs one round. Revising the output ten times costs ten rounds. Spend the investment at the beginning, not throughout.
The inner loop does not substitute for the outer loop. A proposal that has been revised until the developer is satisfied has still only passed the human review layer of the inner loop. It has not passed automated controls. The outer loop’s validation layer still applies.
Runtime systems have an inner loop too, but it cannot lean on a human noticing something is off. The pattern is a bounded repair loop: a validator rejects a proposal, the system returns the precise error to the model - which field, which rule, which constraint - and the model gets one or two chances to produce a proposal that passes. That is different from blind resampling, where the model tries again with no new information and no better odds of passing. A repair loop that never terminates is not a control. It is a slower way of ignoring the validator. Chapter 16 treats this loop directly for schema failures.
Loop Hygiene
Loop hygiene is the discipline of keeping iterations small enough to complete quickly.
A loop that takes days to complete one iteration has broken feedback. The proposal from Monday is validated on Thursday. By Thursday, the developer’s memory of why the proposal was shaped that way has faded. The validation is slower and less sharp.
Aim for iterations that complete in hours. A session that produces a proposal in the morning and validates it before lunch has a tight loop. A session that produces a proposal Monday and validates it after the weekend review has a loose loop. Loose loops accumulate unvalidated output. Accumulated unvalidated output is technical risk.
The loop size discipline is:
| Loop duration | Risk level | Remedy |
|---|---|---|
| Under 2 hours | Low | Normal operations |
| 2 - 8 hours | Medium | Review before the session ends |
| 8 - 24 hours | High | Do not start a new proposal until prior one is committed |
| Over 24 hours | Critical | Stop. Validate everything staged. Commit or discard. |
Unvalidated output left overnight is output that will be validated under different conditions than it was generated. Context has shifted. Memory has degraded. The validation will be weaker.
When To Restart
Restart the session when accumulated unvalidated output exceeds what can be reviewed in a single sitting.
If a session has been running for five hours and the diff touches twelve files, the session has outrun the developer’s capacity for thorough review. Committing that output is not closing the loop. It is abandoning the validation phase and calling it done.
The correct response is to stop generating. Review the accumulated diff. Identify what can be committed now - the work that is complete and verifiable. Commit that. Discard or stash what cannot be verified yet. Start the next session with a clean branch.
This feels slow. It is not. The alternative - committing large unreviewed diffs - produces bugs that cost orders of magnitude more time to diagnose than the review would have taken.
A session restart is not a failure. It is the loop enforcing its own discipline.
Domain Map
The loop is domain-independent. Every AI-assisted change follows the same shape.
| Domain | Proposal | Validator | Commit |
|---|---|---|---|
| Code | Diff | Tests, types, lint, CI | Git merge |
| Database | Migration script | Dry run, schema check, backup | Apply migration |
| API | Contract or schema change | Contract tests, client checks | Release endpoint |
| Content | Draft | Source review, fact check | Publish |
| Calculation | Problem interpretation | Deterministic solver, unit system | Recorded result (ProveCalc) |
| Game move | Proposed action | Rules engine, dice system | Move applied to board or world state (RPG-MCP, LLM-Chess) |
| Civic claim | Narration, briefing draft | Source cards, provenance gates | Public event promotion (Clio) |
| Video edit | State-patch proposal | Base-hash check, import gate | Accepted state pack (Semantic Video Studio) |
| Agent tool call | Tool invocation | Capability policy, output schema | Execute |
The columns are always the same. The contents change by domain. The discipline is constant: nothing in the Commit column until the Validator column passes. The worked comparison above unfolds this table’s Code and Agent tool call rows step by step; every other row follows the same shape.
Practical Artifact - Loop Health Check
Run this check at the end of every session, before closing the branch.
| Question | Green | Red |
|---|---|---|
| Is every proposed change covered by at least one automated validation? | Yes | No - validation gap |
| Did CI pass on the current branch? | Yes | No - do not commit |
| Was the diff read line by line before the PR was opened? | Yes | No - review debt |
| Is the commit message written for the next session, not just for today? | Yes | No - memory gap |
| Does the PR cover one logical change? | Yes | No - split the PR |
| Is the branch up to date with main? | Yes | No - merge conflict risk |
| Is there a handoff note if the session continues tomorrow? | Yes | No - context loss |
| If this system also runs at runtime, does every consequential proposal pass schema, permission, and domain validation before it commits? | Yes | No - runtime validation gap |
A session with all green answers has closed the loop. A session with red answers has open loop items. Do not start the next proposal, and do not open the next runtime capability, until the red items are resolved.
Export
Copy this block into your CLAUDE.md, agent instructions, or project checklist.
Intent becomes real only after it crosses the commit boundary.
vcb_chapter: 13
title: "The Core Loop"
key_line: "Intent becomes real only after it crosses the commit boundary."
thesis: "Propose, Validate, Commit is the shared control loop for building software with a model and for running a model inside software. Only validated state becomes real."
checklist:
- item: "Every proposal is scoped to one commit-boundary-sized unit - one logical change, or one action."
protects: "Diffs or actions too large to validate thoroughly"
- item: "Ex post validation - automated controls, or schema, permission, and domain checks - runs before anything crosses the commit boundary."
protects: "Plausible-but-wrong output reaching state"
- item: "Commit message or trace record explains why, not just what."
protects: "Context loss between sessions or between requests"
- item: "Session is restarted, or the runtime backlog is drained, when accumulated unvalidated output exceeds review capacity."
protects: "Large unreviewed diffs or backlogged proposals crossing the commit boundary"
- item: "Loop health check passes before the session closes, and every runtime validation gap is named and owned."
protects: "Open loop items becoming the next session's, or the next request's, technical debt"
- Is every proposal scoped to one commit-boundary-sized unit - one logical change, or one action? - Protects against diffs or actions too large for thorough validation
- Did ex ante specification - prompt, schema, tool description, retrieved state - exist before the proposal was generated? - Protects against the model guessing at unstated rules
- Did ex post validation - automated controls and review, or schema, permission, and domain checks - run before anything crossed the commit boundary? - Protects against plausible-but-wrong output becoming state
- Does a durable record explain why this became state - a commit message, or a trace log entry? - Protects against context loss for the next session or the next request
- Is there a place rejected proposals go, and would you notice if the rejection rate changed? - Protects against silent validation gaps