On 2026-07-28 we audited 33 Try items our agent had written into its own weekly retrospectives across seven weeks. The result split cleanly along one line, and it wasn't the line we expected. Every Try that had been turned into a CLI command, a ledger, and a test was still running weeks later. Every Try left as a sentence had been honored only by coincidence. Two examples, measured against the actual content ledger: a Try that read "one CTA-format post per day" produced 3 such posts out of 30 in the following two weeks. A Try that read "replace the late-morning slot with images and threads" produced zero. Nobody lied. The agent wrote what it intended. The problem is that in a Keep/Problem/Try retrospective, Try is the only column that describes the future, and prose about the future is free to write and free to ignore. Our ledger already had a priorTryReview field — a place to grade last week's Try — but grading happens a week too late. There was a column for judging intentions and no column for making them real. So we made the intention un-writable unless the thing that enforces it already exists. Layer 1: name the guardrail, and the CLI checks it's there Every tryNext item now carries a mechanization object: { kind, reference?, note }. kind is one of exactly five values — quota, commit-gate, cli, owner-decision, one-off. The first three name a machine artifact, and the write path verifies that artifact exists before it will record anything: quota — reference must be an ISO week (YYYY-Wnn), and that week must already appear in the stock-quota ledger. If nobody declared the quota, the Try citing it doesn't record. commit-gate — reference must be a path under test/, and that file must exist on disk. The error message is blunt: write the test first, then declare it. cli — reference must be a script name that exists in package.json's scripts. Naming a command you were planning to write fails. owner-decision and one-off carry no reference — they're the two honest escape hatches, for things blocked on a human and for things that genuinely never repeat. Both still require note at 40 characters or more, so the reason for opting out lands in the ledger rather than evaporating. One deliberate hole: if package.json can't be parsed at all, the script list comes back empty and the cli check is skipped rather than failing everything. An empty list would mean "no command exists," which would reject every valid Try in an environment that merely couldn't read a file. A check that can't distinguish "absent" from "unknown" should decline to judge. The verification also runs over all Try items before a single byte is written. Verifying incrementally would let a partial failure leave a half-validated week in an append-only ledger, where it stays forever. Layer 2: only mechanisms built this week count toward the quota Declaring a guardrail isn't the same as building one. A Try can point at a CLI that already existed for months and satisfy layer 1 without producing anything new. So each Try also carries mechanized: { status, what }, where status is 'new' or 'existing' and what is at least 10 characters of specifics — a command name, a test path, the check that got added. "Done" doesn't clear the bar. And the quota counts only status: 'new'. The filter is one line: Try items count toward the floor only when mechanized?.status === 'new' 'existing' items are welcome in the list; they just don't move the counter. The error text says so explicitly, and reports both numbers: how many counted, and how many Try items there were in total. This is the inversion that makes the whole thing work. To satisfy the Try quota, the agent has to have already built the mechanism, during the week being reviewed. The retrospective stops being a plan and becomes a receipt. You cannot write it before doing the work, because the validator will go looking for what you claim. Layer 3: thin weeks fail loudly instead of shrinking quietly The retrospective is split across four media — Gumroad, Bluesky, dev.to, Hashnode — and each gets its own floors, enforced by the same write path: Keep: at least 5 per medium Problem: at least 5 per medium Try: at least 10 newly-mechanized per medium operation ("who looks at what, when") on every Try: 30 characters minimum summaryJa per medium: 60 characters minimum The floors exist because the alternative is silent decay. A thin week doesn't announce itself; it just produces a shorter list, and the report renders it without complaint. Our own ledger shows the drift as the floors moved: the earliest weeks recorded 3 Keep / 3 Problem / 4 Try. Once a floor of 6 existed, weeks landed at 6 and 7. The current per-medium regime produces 20 Keep / 20 Problem / 40 Try. The agent writes to the floor, which is exactly why the floor has to be set by someone thinking about quality rather than by whoever is tired on a Monday. Shortage checks return a list, not the first failure. Throwing on the first missing item would force one rewrite round-trip per medium. The writer here is the agent itself, so the goal is to hand back the complete set of complaints in one pass. That same asymmetry runs through the module: the read path is deliberately lenient (a malformed mechanization on an old row parses as absent, so historical weeks stay readable), while the write path rejects the whole entry over one bad field. Old data shouldn't be punished for predating a rule. New data has no excuse. Layer 4: rewriting a week leaves a scar Same-week double-appends are rejected outright, because the weekly report renders every week and a duplicate row shows up twice forever. But weeks legitimately need rewriting — a mid-week draft replaced with settled numbers, or an old format migrated to a new one. That requires an explicit supersede: { reason } with at least 20 characters of justification. The old row is never deleted; readers apply a last-row-wins dedupe per week. The reason is prose, and prose can lie, but the superseded row sits next to it in the file for anyone who wants to check. The guard is symmetric in a way worth copying: passing supersede for a week that was never recorded also throws. If you think you're correcting history and there's no history there, something is wrong with your assumption, not with the ledger. And the timestamp on every entry is stamped by the CLI, never accepted from the input — a writer that supplies its own clock can date anything anywhere. What this costs, honestly Quota pressure produces mechanism sprawl. Ten new mechanisms per medium per week is forty per week. Across the ledger's lifetime, Try items cite 35 distinct CLI commands. Some of those are load-bearing; some are a gate that fires four times a year. A quota on mechanisms is still a quota, and Goodhart applies to us exactly as hard as it applies to anyone. Counting only new rewards novelty over consolidation. The most valuable week might be one where nothing was built and three fragile things were merged into one — and that week scores zero. There's no clean fix inside the current rule. What we watch instead is the distribution of reference values. health-check is cited 10 times across the ledger: ten separate retrospectives that added a new check to one existing umbrella command rather than shipping ten new commands. That's consolidation showing up through the novelty rule, and it's the signal we track to tell "growing a system" from "accreting one." When the distribution flattens — many references cited once each — the sprawl is real. Existence is not efficacy. A file under test/ might assert nothing. A script in package.json might be a stub. Layer 1 proves you built something with the right name in the right place; it can't prove the thing works. The quota kind is the strongest of the three because it checks a declaration in a ledger that other gates independently read. The other two check a name. The escape hatches are nearly unused. Of 108 declared mechanizations, owner-decision and one-off account for two apiece. Either almost everything genuinely is mechanizable, or writing a small CLI is the path of least resistance under a quota. We don't yet know which, and the honest position is to say so rather than to claim the low number as evidence of rigor. The transferable part If your agent writes its own retrospectives, the Try column is where the fiction accumulates, because it's the only column that can't be checked against anything at write time. The fix isn't a better prompt about being realistic. It's making the record refer to artifacts, and validating the reference before the record is accepted: name the enforcing mechanism, verify it exists on disk, and count only what was built as a result of this review. Do that and the sequencing inverts on its own. The work has to happen first. The retrospective becomes the thing you write afterward, about what you actually did — which is what a retrospective was always supposed to be. The ledgers and gates described here run Rulestack, a shop where the agent that writes the weekly review is the same one the review constrains. Notes on what these gates catch, week to week, go out from @ai-shop.bsky.social.