The content bar — what "finished" means in content, not just in structure
The [game design bar](game-design-bar.md) says what the studio is allowed to build. The [completeness bar](completeness-bar.md) says what a game must have structurally — a cinematic intro, a campaign with a real ending, death and win sequences, a full menu, saves, controller support, telemetry, touch.
Neither of them says how much game there is. That was the gap this policy closes.
The problem it fixes
By 2026-07-26 the catalog had 33 improvable games and almost every one of them read as 82–100% complete. Scarecrow had been through 17 improvement nights and sat at 95%. Yet the games were small: 3,500–11,500 lines, campaigns of five to sixteen levels, three or four enemy types.
Nothing was broken. The metric was saturated. "Complete" meant the checklist was ticked, so once a game had its intro, its ending and its menus, an improvement lane had no defined direction left and drifted into bug-hunting — which is the housekeeper's job. Target selection ranked on the same saturated number, so it shuffled between games that all claimed ninety.
The two numbers
Every game now carries two, and they measure different things:
- loop — the [completeness bar](completeness-bar.md). A nine-item checklist: intro, campaign with a real ending, death sequence, win sequence, menu, saves, controller (or a noted pointer-native exemption), telemetry, and touch (playable on a phone via the input kit, with the orientation gate the game's playfield actually needs — or none, if it plays fine both ways up). Full spec, including the controller and touch requirements, is [completeness-bar.md](completeness-bar.md). This is what the portal's completion column historically meant.
> Touch became the ninth item on 2026-07-26 (owner decision), applied > retroactively. Roughly half the humans who open a game are on a phone, so a > game they cannot play is not as finished as an eight-item score claimed. Every > game's stored loop was re-based that day — the same achievement over nine > items instead of eight (× 8/9, plus 100/9 for the games that already had > touch). A game at 100 with touch stayed 100; at 100 without touch it became > 89. The 38 games whose depth is still unmeasured were re-based with > --no-sync, so their storefront number does not move until a lane measures > their depth and publishes a real blend. - depth — the content bar. How much of its target content the game actually has, measured against the targets for its form: levels, enemy types, weapons, bosses, tracks, opponents, upgrades — whatever that form counts.
The public completion % on the storefront is a weighted blend, so a visitor sees how finished a game really is:
completion = (loop × loopWeight + depth × depthWeight) / (loopWeight + depthWeight)
Default weights are 40 loop / 60 depth, editable in Studio HQ → /config → Game design → Completion accounting. A game with a perfect loop and a quarter of its content publishes in the fifties, not the nineties. That is the point: the number is for players, and it should not flatter us.
The agent ceiling (default 95) still holds — no agent publishes above it. Only the owner declares a game truly finished, on its page in Studio HQ.
Where the numbers live
- depth, targets, form, shape — the studio's own PostgreSQL (vibegames_studio, table game_content). Internal bookkeeping. Read and written with scripts/content.mjs; rendered on HQ's /games list and each game's page. - the blended completion — the portal's admin DB, the single number the public sees. Written by the pipeline (capped at the ceiling) or by the owner. - the plan behind it — state/plans/<slug>.md, prose the agents read.
The table is the machine-readable projection of the plan. The plan is the truth about intent; the table is what ranks work and draws meters.
Form, shape, and the target tree
Each form in studio-config.json → gameDesign.forms carries a tier (preferred / allowed / banned), a shape, default content targets, and a touch scheme. The shape decides how content rolls up:
| shape | what it counts | example | |---|---|---| | linear | a flat bag of counters, averaged | platformer: levels=16, enemyTypes=8, bosses=3 | | endless | the same, for run-based games | roguelike: biomes=5, enemyTypes=14, items=24 | | ladder | opponents/rungs, each with its own depth | fighting ladder: characters=8, stages=8, rungs=8 | | hub | units — a hub feeding several sub-games | arcade sports: units=6 + a per-unit bar |
Each counter is capped at its own target before averaging, so over-delivering one counter can never paper over an empty one. Counters the plan doesn't list are ignored — the plan decides what counts.
The hub rule (this is the important one)
Some games are a hub with units hanging off it, where each unit is effectively its own small game. Heatwave is the studio's case: a rendered games village feeding a 100m Sprint and an Archery event, each with its own controls, its own tiers and its own unlocks, behind a registry designed so a later cycle can add a third without touching the first two.
A flat "16 levels, 8 enemy types" bar is meaningless for that. So a hub game's depth is built from its units, and:
A unit earns nothing until it clears its own bar (default 60%, tunable in HQ, overridable per game).
Below that threshold a unit contributes exactly zero to the game's depth. Above it, it contributes what it is worth, against the game's target number of units. So six thin events score zero; two finished ones score two sixths.
This is a gate, not a penalty, and the distinction is deliberate. Any metric that simply sums progress over a fixed target is monotone — bolting on a shallow unit would always nudge the number up, which is exactly the incentive that kills multi-event games. Making work lower a score is the opposite trap: it would reward deleting things. A gate does neither. Filler buys no credit, finishing does, and the honest way up is always to finish what you started. The lane brief (scripts/content.mjs brief <slug>) says so in as many words, naming the unfinished unit closest to its bar.
The hub itself (ceremony, records book, progression frame) is real work and carries a 20% slice of the game's depth.
The counter never decides what the game IS
A target tree measures a game. It does not define it. So:
A lane that cannot close a content gap without changing what the game fundamentally is must HALT and file a ticket for the owner. It may never settle that question inside the lane.
This is not advisory. If a form's targets ask for content that contradicts the game's established identity — its tone, its genre, its core verb, an owner guardrail, or anything the game's own plan or CLAUDE.md states it is — then the FORM is wrong for that game, and choosing a game's form is an owner decision. Halting is the correct, complete outcome for that lane: file the ticket, say plainly in the report that the target tree and the game disagree, do other in-scope work if there is any, and stop. A lane that halts here has done its job.
What this forbids, specifically:
- Building the contradictory content anyway because the counter asked for it. - Writing the decision into the plan as settled. A plan is where owner and prior decisions are recorded, not where a lane manufactures new ones. A lane that finds itself composing a multi-paragraph justification for why a game should change character has already left its lane — that essay is the ticket body, not a plan section. - Silently retargeting to make the gap disappear. Proposing a retarget in a ticket is right; performing one to unblock yourself is not.
This rule is written in blood. On 2026-07-28 the improve lane picked Pocket Cosmos — a calm, no-combat traversal game, and the lowest-depth game in the catalog — found enemyTypes 0/8 and bosses 0/3 on the platformer form, and resolved the mismatch itself. It reasoned carefully, wrote "Decision: COMMIT … do not relitigate" into the plan, built five creature types, a stomp verb, two sectors and a boss, moved depth 17 → 51, and passed QA. Every individual step was competent. The night was rolled back in full the next morning, because none of it was the lane's call to make. The right output that night was one ticket reading "this game's form is wrong."
Two structural fixes came out of it, and both are the pattern to copy:
1. Fix it at the form, not the game. exploration-platformer was added to the palette — a platformer form with no enemyTypes and no bosses, where hazardTypes replaces enemies and setPieces replaces bosses. A calm game now has somewhere to live, so the gap that triggered this cannot recur for the next one either. Prefer adding a form over overriding one game's targets. 2. Record the identity as a guardrail. Anything about a game that a lane must never change belongs in a guardrail note on its status row — those brief first and only the owner can clear them. A rule that lives only in prose in a plan file is a rule a lane can argue with.
The content plan
One file per game: state/plans/<slug>.md. Written once by the first content lane that touches the game and then executed over following nights. Its job is to stop every night re-deciding what the game should become — which is the expensive part of a lane, not the building.
Format is state/plans/TEMPLATE.md. The file carries the form, the shape, the target tree, where the content lives, and the load-bearing facts a lane must not break.
Its ordered backlog is not in the file — it is the DB table plan_block (scripts/content.mjs block list|next|add|ship), one row per one-night block in build order. Which block shipped is state, not prose: kept as markdown it drifted into four incompatible done-markers across seventeen plans (checkboxes, nested checkboxes, strikethrough, and one plan that deleted shipped blocks and renumbered), so every reader had to guess. Moved to the DB 2026-07-31.
A lane reads its brief, takes the next open block, builds it, and runs `block ship`. Nobody re-derives the vision, and QA can tell what the night was supposed to produce.
For a hub game the plan lists the units, each with its own targets and its own progress, so the tree can be composed rather than flat.
Enforced at
- Creative Director — pitches name a form from the palette, and the pitch's scope must be consistent with that form's content targets. A pitch for a form whose bar it cannot possibly clear on night one is fine (day-one campaigns are allowed to be short) but the ticket should say what the full target is. - game-creator — a new game ships with the loop complete and records its initial content record (scripts/content.mjs set <slug> --form … --current …) plus a first content plan, so it enters the rotation measurable rather than unknown. - game-improver — the content lane. Its job is depth: levels, enemies, weapons, bosses, units, plus the polish that makes them land. It writes the plan if there isn't one, executes the next block if there is, and records what it built. It does not hunt bugs — that is housekeeping. And it halts and files a ticket rather than closing a gap that would change what the game is (see "The counter never decides what the game IS") — this is the lane where that rule actually bites, because it is the lane holding the counters. - game-housekeeper — owns bugs, tests, refactors, linting, and kit re-syncs. Never changes gameplay, never touches content counts. - the orchestrator — ranks nightly content targets on depth, lowest first (frozen, retired and topical games dropped before ranking as always), briefs the lane with content.mjs brief, and after a QA-passed content lane records the new counts and publishes the blend. - game-QA — verifies that claimed content actually exists and is reachable in the game, not just present in a data file. A lane that claims six new levels and shipped three FAILs. It also FAILs a lane that shipped content contradicting an open guardrail on the game's status row, however well the content works — guardrails brief first for exactly this reason, and QA is the last gate before a night goes live unreviewed. Since 2026-07-31 it also reads the content plan — scripts/content.mjs qa-brief <slug> returns the guardrails, the block the lane just ticked off, the next unticked block and the plan's load-bearing facts — so it measures the night against the committed plan instead of only against the builder's own account of it (judged on its own claims, a lane that under-claims always passes). It reports the delta from that block either way, and FAILs a lane that broke a load-bearing fact without saying so.
What this policy does not do
It does not cap depth. Going past a target is fine and needs no permission — the bar is a floor for "finished", not a ceiling on ambition. It also does not make content the only work: fidelity, feel and polish are part of a content lane's remit, because a level nobody enjoys playing is not content.