Karpathy gave us vibe coding: "see stuff, say stuff, run stuff, copy and paste stuff, and it mostly works." Since then, the industry has kept tryin...
For further actions, you may consider blocking this person and/or reporting abuse
The two-axis framing really clicked for me—especially the claim that L1 + high operator discipline compounds better than L5 + low discipline over time. That matches something I've been noticing but hadn't been able to articulate clearly: two people using the same tools diverging significantly over months, and the difference not really being about prompting skill at all.
The decision lifecycle (proposed → accepted → locked) is the part I keep thinking about. The relitigation problem you describe—re-explaining the same architectural decision every few sessions—is exactly the kind of invisible tax that makes AI-assisted work feel exhausting without a clear reason why. Making a decision a piece of state instead of something you have to defend live every time is such a simple fix that I'm surprised it isn't talked about more.
Really glad my post connected with this one — yours gives the operational answer to the question I left open. 🌸
"Two people same tools diverging over months" is the empirical pattern the Anthropic paper just measured at population scale — persistent returns to expertise across 400k sessions. Hearing the same shape from your own practice is part of why this is starting to feel like a thing the field is coalescing on, not a take. Your judgment-bottleneck framing and the decision store are the same thesis from opposite ends — yours names what costs, mine names where it accumulates. Glad the pieces meet in the middle.
"Yours names what costs, mine names where it accumulates" — that's a really elegant way to describe how the two pieces fit together. The Anthropic paper measuring it at population scale across 400k sessions is fascinating context too — it moves the whole thing from "two people I've noticed diverging" to something the field can actually study and build on.
Glad the pieces met in the middle — this thread has been one of the more genuinely useful comment exchanges I've had on DEV.
Yeah — once population scale lands, you stop arguing whether the divergence exists and start arguing what the distribution looks like, which is the better argument to be having. Same shift as moving from "I think locks help" to "the locked-vs-unlocked retention curve looks like this."
That's a much more productive place to argue from — once the existence of the pattern is settled at scale, the interesting questions become about the shape of the distribution, not whether it's real. "What does the curve look like" is a question you can actually do something with.
Distribution shape is exactly where I want this to go next. The "actually-workable question" framing is the part I will be using. Glad this one landed too.
This is the clearest articulation of the second axis I have read, and the L1+High beats L5+Low claim matches what I have watched happen. I run almost the same stores (a persona file, decisions with proposed/accepted/locked, append-only) but for non-code work: marketing, sales, product calls, where sessions are days apart instead of minutes. That gap is where I would push on one rule. You say recaps drift and live capture does not, and inside a tight build loop I agree completely, but when the work has no fast feedback loop the thing that drifts is not the recap, it is the operator: nothing in the session pressures me to write anything down, so live capture quietly lapses and I do not notice for a week. What saved it was making capture a hard boundary the task cannot close without, a forced end-of-task step, precisely because there is no compiler or failing test reminding me. So the refinement I would add: live capture is the right default, but it only fires reliably when the work itself punishes you for skipping it. When the loop is slow, what makes your discipline fire on time, the habit or something structural in the workflow?
Turns out the structural-pressure point is what I'd been calling „discipline" — sloppy on my part. Tight build loop, the compiler IS the pressure. Capture lapses when nothing's flashing red. The real variable isn't whether to live-capture; it's how loud your feedback loop is.
What makes mine fire on time depends on what I'm running. In code, the work reminds me — failing tests, drift alarms in the hook, structural review on commit. In ops (vendor work, compliance, sales calls), somebody else's calendar does what tests do for code: JPK_V7M, RAS, contract review windows. The pressure isn't mine, which is the only reason it works. In research, weekly agile retro is the only structural beat that fires; the exploration itself has no internal alarm. Three different mechanisms, same principle: the alarm lives outside the operator, or it doesn't fire.
Forced end-of-task close is the missing piece for slow-loop work. Turning the structure into the close step removes the question of whether to capture at all. Stealing it. The refinement to my original framing: live capture is the right default when the loop punishes skipping. When it doesn't, the workflow has to do the punishing instead.
This is the pushback I joined the platform for. Built the stores in isolation; the only way to know if they generalize or just fit my desk is to put them in front of other operators.
'The alarm lives outside the operator, or it doesn't fire' is the cleanest version of this I have seen, and it survives the failure mode too: even an external alarm only works if the operator cannot quietly silence it, the dismissed calendar reminder and the skipped retro are the slow-loop equivalents of muting the test suite. For the forced close to hold on slow-loop work, I think it has to be load-bearing for the next session, not just a ritual at the end of this one: the Memory Update survives in my setup only because the next task is useless without it, so skipping it punishes me immediately the next time I sit down, which is the one pressure that actually comes from me. That is the closest I have gotten to building the alarm into the work instead of bolting it on. On putting the stores in front of other operators to see if they generalize, that is exactly why I put mine in the open, so here is a second operator's stores to diff against yours: cowork-os, the decision lifecycle and the assumptions lane are the parts most worth comparing. Where did your three mechanisms disagree most with how another operator would close the same task?
The piece worth circling is that the loop pressure has to live somewhere the operator can't dismiss — and "same model in a checker role" is the easiest place for it to silently dissolve. Two passes of the same distribution share whatever the upstream got wrong; the maker/checker pattern only does work when the checker is a genuinely different class (different model family, different lineage of training data, or off the model entirely as a deterministic gate). Otherwise the disagreement that's supposed to surface is statistically suppressed by shared bias.
Three shapes that survive this in setups I've watched: a deterministic check that has to pass for the next action to land (bite-check style — test must fail against pre-change code or it's décor), an external-memory store that's foundation not bolt-on (so context isn't being re-synthesized inside the same loop every turn), and a structural close-step where the next session is useless without the previous one being consolidated (the alarm lives in tomorrow's work, not today's discipline).
The framing that lands for me: engineering with AI is mostly designing where the model is allowed to be wrong and what catches it when it is. Comprehension-debt is what accumulates when nothing structurally catches it.
The different-class requirement is the part I would push on, because two of your three shapes are synchronous checkers and the third is not the same kind of thing. The deterministic gate and the bite-check catch wrongness inside the pass; the external-memory store is not a checker in that moment, it is what gives the next pass a different vantage than the one that made the error. That is the move I lean on in slow-loop work, where a second model family as a live gate is a luxury: the cheapest different-class checker I have is time. The same model reading its own decision file a week later, against what actually happened since, is not shared bias the way same-model-in-a-checker-role is, because the downstream reality changed even though the model did not. The catch is the one that came up on solosre's thread today: that temporal check is only a different class if the later read is anchored to what happened, not to the decision's own wording, or it just re-confirms the original framing. So your maker/checker rule has a time-shifted twin: a past entry is only a real second view if it gets checked against reality, not re-read in the language it was written in. In your stores, does the external-memory store ever act as the checker, a locked decision re-opened against what actually happened, or is checking always left to the gate while the store stays a pure context provider?
The asymmetry catch is right — first two are sync, third was already temporal, and time-as-cheapest-different-class makes the structure visible. The same model reading its own decision file a week later isn't shared-bias the way same-model-in-checker-role is, provided the later read anchors to what happened, not to the decision's wording. That's the constraint your cross-link from solosre's thread surfaces: supersede chains only resolve forward if the rule re-reads itself against reality, not against its own previous text. Read against own wording = re-confirmation.
To your question — yes, the design intent is that the decision store acts as checker, not just context provider. The verifiable_by field on a locked entry is supposed to fire a diagnostic against reality on a cadence (test still passing, world-state matches, downstream metric not contradicting), not a re-read of the decision's wording. Status survives the diagnostic; folklore-status if verifiable_by is empty or hasn't fired. Honest state: roadmap, not shipped — the cron auto-flag for stale verifiable_by is open; the store currently leans context-provider with manual re-verify.
The other thing your framing surfaces is what breaks time-as-different-class: if the "reality" the later read is anchored against is itself authored by the same lineage (a status field the same agent wrote, a session log the same agent narrated), the temporal check collapses into wording-check one floor up. The external anchor has to be something the writer can't reach — a commit hash, an external receipt, a world-state grep — or the time-shift produces correlation, not independence.
On cowork-os: when Memory Update fires at the start of a new session, does it read the previous file against what actually happened since (logs, commits, external state), or against what the previous session said about its own state?
Authz is where "the alarm has to live outside the operator" gets almost too literal, so it might be the cleanest test case for the axis. A model writes an access rule, it clears whatever checks you run, and it clears them precisely because you are the authorized user when you run them. The in-session feedback is blind to the failure by construction. I shipped a Supabase policy once that let any user read every other user's rows, and nothing in the session ever flagged it, because nothing in the session could. That is comprehension debt with no internal alarm available: the only thing that catches it is a check that does not run as you, a second test identity, a deterministic policy diff, someone external. It is the one area where I have never seen high autonomy plus in-session trust survive contact with a real second user, which might be why it makes the operator axis so easy to see.
Authz is the cleanest case because it splits the verifier from the operator at the identity level, where the other axes only split at the timing level. A test that runs as you cannot see the failure no matter how disciplined you are, so discipline alone never closes it. The fix isn't "try harder," it's "the check runs as someone who isn't you."
Your Supabase row is the canonical planted null: the in-session pass was real, it just answered the wrong question. The receipt that catches it is a second-identity read with an expected deny, fired on every policy change. Deterministic verifier, external anchor, exactly the {kind, id, expected, cadence} shape, because authz is the one domain where nothing softer survives a real second user.
Which is why this is where the axis stops being a framing and becomes a requirement. You can run high autonomy on authz, but only if the alarm is wired to an identity the operator doesn't control. Good catch. It's the example I'll reach for when someone argues discipline scales to everything.
Yeah, and what bites in practice is the cadence, not the writing. People write the second-identity deny test once, then a later migration loosens the policy, the assertion goes red, and the easy move is to "fix the failing test" by relaxing the expected result instead of asking why a deny just became an allow. The receipt only holds if expected-deny is load-bearing, the failure IS the finding, not noise to silence. Same way a planted null dies: someone edits it to match current reality instead of treating the mismatch as the signal. The {kind, id, expected, cadence} shape is the bit I didn't have a clean name for, so thanks for that.
The "fix the failing test" pattern is what happens when the assertion is treated as a code artifact rather than a standing decision.
Expected-deny goes red, the migration made it "allow," and the test is now in the way. Someone edits "expected: deny" to "expected: allow" to get green. No decision was made; a signal was silenced. The receipt framing closes it at the cadence check: the expected value has to be authored at policy-decision time, and changing it requires a new policy decision to be logged, not a code edit. That's what makes "failure IS the finding" load-bearing rather than aspirational. Without the standing being explicit somewhere, the assertion has no claim on anyone's attention when it turns red.
That lines up with something I keep running into now that an AI is usually the thing turning the test green. When expected-deny goes red, the fastest path isn't a human rationalizing it anymore. It's pasting the failure into the model and getting back a diff that flips expected to allow, because the only standing it can see is "red should be green." So the policy decision you're describing has no weight in that loop unless it's sitting right at the edit site. What's helped me is naming the deny by what it guards, so the assertion reads expected_other_user_cannot_read_emails instead of expected: deny. Then flipping it shows up in the diff as "now letting other users read emails," which is harder to wave through even at AI speed. It's not a logged policy decision like you said, but it at least forces whoever approves to look at the standing they're overturning.
Naming the deny by what it guards is the cheapest high-leverage move in the whole pattern, and I'd keep it. It works on exactly the mechanism you named: it turns the diff from "flip expected to green" into "now letting other users read emails," which is a sentence a human has to actively endorse rather than skim. But I think it raises the cost of waving through without moving the standing, and at AI speed that gap matters. Two leaks. The model that flips the assertion can also rewrite the name to match the new behavior, because to it the identifier is just more text in the file it was told to make green. Nothing structural stops expected_other_user_cannot_read_emails from becoming expected_other_user_can_read_emails in the same diff. And even when the name survives, the human approving at speed is reading a diff that still resolves to "make the red thing green," which is the standing it can see. So naming buys you a louder tell, not a different authority. The version that holds is the one you half-conceded: the expected value lives somewhere the actor can't author, and name-by-guard is the human-readable surface on top of that, not the load-bearing part. Same tell as the tier-table thread next door: can the thing being gated edit the rule, and does editing it leave a mark. If the AI can rename the guard, the guard is documentation. If it can't, the name was never what was holding.
Mike, first of all: thank you for writing that piece. The autonomy ladder is indeed incomplete, and you're right to call out the missing axis. I've read the post twice and shared it with my team. The framing is sharp and the examples land well.
That said, I want to offer a candid, grounded critique. Not because I think you're wrong—I think you're pointing at something real—but because I suspect the matrix, as stated, is much harder to operationalize than it appears.
You define it as "how much of your work survives the session boundary as inspectable state." That's a great conceptual anchor. But in practice, this is not Low/High—it's a floating spectrum that changes hourly, per project, per deadline.
Is a decision captured in a Notion doc "inspectable state"?
Is a Slack message with a diagram "state"?
Is a code comment "state"?
What if the state exists but hasn't been updated in three sprints?
You can't label a developer "high discipline" or "low discipline" as a stable trait. Discipline is situational. The day before launch, even the most rigorous architect will say "ship now, document later." And "later" often never comes.
If the axis can't be measured reliably, it can't serve as a predictable coordinate.
It sounds right: discipline beats chaos. But if L5 truly means "AI owns the loop," then the AI itself would internalize context management—i.e., discipline is baked into the system. A genuine L5 agent wouldn't be "low discipline" by definition; it would maintain its own state across sessions.
Meanwhile, an L1 developer—even with impeccable discipline—still types slower, reviews slower, and integrates slower. The velocity gap between L1 and L5 is not linear; it's exponential. In a real sprint, the L5 low‑discipline engineer might ship a feature, run an A/B test, and roll out a fix, all while the L1 high‑discipline person is still writing the first unit test.
Speed compounds. Disorder can be fixed. The inequality might hold over a decade, but over a sprint—or even a quarter—the L5 wins hands down.
You describe a system of a persona file, three append‑only stores, and a live capture habit. That is a second job. For a solo developer or a small team, the overhead of maintaining that state often outweighs the cost of re‑explaining decisions.
Every decision needs to be written, classified (proposed/accepted/locked), and updated.
Every session requires loading, reading, and reconciling state.
Every few weeks, the store accumulates dead threads and outdated locks, demanding a cleanup.
In practice, many developers will choose to "just retype" rather than "update the state machine"—because the latter feels like doing paperwork, not building software. Your system is plausible for a large regulated organisation, but for the individual vibe coder, it's a heavy lift that often gets abandoned after a week.
Your example about locking an architecture decision is relatable. But product development is not a set of permanent decisions. Most decisions are conditionally valid.
"Use PostgreSQL" is fine at 10k users, but may be wrong at 1M.
"Keep the free tier" may be correct until a competitor changes the game.
Your state lifecycle (proposed → accepted → locked) has no room for locked_until_condition_X or review_at_metric_Y. If you never revisit, you lose adaptability. If you revisit often, you're back to re‑explaining, and the state machine loses its value.
So where does this leave us?
I think the matrix is a brilliant diagnostic lens, but not a viable operational framework.
It helps you ask the right question: "Am I repeating myself every session?" If yes, you need better context management. That's a useful nudge.
But it falls short because it assumes that "discipline" can be sustainably maintained by individual willpower. Engineering history tells us that any process relying on personal diligence eventually decays. Only processes embedded in tooling—enforced by CI/CD, by project templates, by collaborative norms—have a half‑life longer than a few months.
Your post is thoughtful, and it has already sparked good conversations. I just worry that readers might treat the 2×6 matrix as a blueprint, when in reality it's more of a mirror: useful for self‑reflection, but not something you can install and run.
Thanks again for writing it. I'm genuinely curious if you've tried instrumenting the discipline axis with any automated telemetry—or if you've observed how long these stores survive in teams that adopt them.
Thanks — this is the kind of grounded critique the post needs, and I want to be honest about where the theory actually is: the operator axis isn't engineered yet. It's a working set of observations, refined daily through exactly this kind of confrontation with other operators. So responses in order, with the qualifier that each one is provisional:
On discipline as continuous, not binary. Accept fully. The matrix compresses what's actually a floating spectrum into a coordinate for legibility, and the cost of that compression is real. The honest version is closer to "discipline is something like a rate of state-decay per session" — Notion docs unupdated for three sprints aren't state, they're archaeology. The 2-bucket framing is diagnostic shorthand for thinking out loud, not a stable classifier. You're right that it can't carry weight as a predictable coordinate without measurement, and the measurement isn't there yet.
On L1+High > L5+Low. I'd push back, but provisionally. One empirical case that pushed me toward the inequality in the first place: 65 trades shipped through a system reporting placed=1 / placed_ok=0 / zero error events — monitoring layer authored by the same loop doing the work, audit trail itself lying. -$9.21 in four hours, system overhead ~60% of equity. L5+Low won sprint velocity while losing reality. Whether that generalizes into an inequality I can stand behind in general — I don't know yet. What it did was make me stop assuming "speed compounds, disorder can be fixed" as a default — because the fix requires someone external eventually checking, and the L5 loop in that case didn't produce evidence that let the check happen. That observation might survive scaling up the dataset. It might not.
On locked-store maintenance = second job. Partial accept, with one empirical complication I haven't reconciled yet. The cost depends on whether capture is integrated into the work loop or layered on top. Manual maintenance (open Notion, classify, update) — agree, abandoned after a week. CLI-hook capture in-line with the same turn that produces the decision — surviving daily for months as a solo experiment, but I'm one person, not a sample. The failure mode you're naming is real for the layered-on case. The question that's still open for me: which side of that line a given team is on, and what evidence anyone could accept to know.
On static locks vs dynamic reality. Sharpen rather than accept, but as a hypothesis. The lifecycle as stated (proposed/accepted/locked) is incomplete — you're right that locked_until_condition_X is missing as a named primitive. What the practice does instead is treat locks as defended-by-default-until-externally-challenged, with an amendment mechanism: when the substrate moves, the operator (or a scheduled re-attestation) surfaces a contradiction, and the lock gets re-defended or amended in place. Whether that's actually adequate, or whether it's a half-built version of what locked_until_condition_X would do properly — I genuinely don't know. The shape seems load-bearing; the engineering isn't done.
On "mirror, not blueprint." Accept that framing more than I initially wanted to. The 2x6 is closer to a working diagnostic than a deployable framework, and treating it as a blueprint would be premature on readers' part and on mine. The piece is partly a public confrontation with the model itself — write it, watch how operators from different domains push back, evolve. Comments like yours are the methodology, not adjacent to it.
On your closing question — telemetry + team survival data. Honest stage with a useful complication: telemetry yes, lots of it (session budget, decisions ledger with lock-amendment history, notes audit log, stale-thread counters, capture-event timestamps). But mapping any of that onto a "discipline axis" measurement is not solved. The streams measure capture-rate and state-decay-of-captured-things — proxies adjacent to the axis, not the axis itself. The thing the matrix calls "discipline" includes everything that didn't get captured, and by definition that's not in the telemetry. Same sample-selection bind that hit the reconciliation thread one comment over: you can't measure the missing state from the captured state alone. So: rich event stream, no validated discipline metric, no team survival data. Three honest gaps, in increasing order of how much each would take to close.