Accents join the sampled record alongside ground and dominant fields,
every recorded color (not only the ground) is compared by number
during the build, and the light-ground-only rationale clauses become
value-neutral so dark and saturated comps get the same protection.
Rule anchor renamed to skill-color-by-number to match its scope.
AI-assisted change (Cursor), prepared under maintainer direction.
Co-authored-by: Cursor <cursoragent@cursor.com>
Style-guide pass: the recording act gets an imperative verb like the
sampling sentence before it, and a generic worked example (a row three
type-heights tall, a gutter a tenth of the width) anchors what a
recorded ratio looks like without bug-specific vocabulary.
AI-assisted change (Cursor), prepared under maintainer direction.
Co-authored-by: Cursor <cursoragent@cursor.com>
Spacing drift toward the genre's stock density runs both ways: an airy
comp ships cramped and a dense comp ships loose. Reword the three air
rules to bind either direction (mirroring GROUND's warmer-or-cooler
form) and drop bug-specific row/cell vocabulary for element heights
and paddings, covering one-off elements like CTAs.
AI-assisted change (Cursor), prepared under maintainer direction.
Co-authored-by: Cursor <cursoragent@cursor.com>
Record the comp's air as ratios in the brief (element height and
padding as multiples of own type size, gaps as width fractions), hold
the build against the record using exact browser boxes in the
comp-is-king comparison, and add AIR as the fourth mandatory
fidelity-matrix row, anchored to the hero-repro capture taken at the
comp's own dimensions.
AI-assisted change (Cursor), prepared under maintainer direction.
Co-authored-by: Cursor <cursoragent@cursor.com>
Sample the approved comp's ground and dominant-field hexes into the
brief (visualize.md), judge the built page's ground by number against
that record including the net value under textures (new-work.md), and
make GROUND a mandatory fidelity-matrix row beside TYPE and MATERIAL
(finish reviewer). Pre-comp palette chips are retired at approval.
AI-assisted change (Cursor), prepared under maintainer direction.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Comp-fidelity review discipline + conciseness pass on core references
Process fixes derived from a real Codex session (Hanasaku landing page)
where a build drifted wholesale from the approved comp and still shipped
under a reviewer pass:
- finish reviewer: new Evidence check (check 0) with a fourth
disposition, recapture, for malformed screenshots; a review on invalid
evidence binds nothing and owes a full re-review, not a verdict pass
- finish reviewer: verdict passes exit scoring mode when recaptures fail
check 0 or when the packet carries user-supplied screenshots that
contradict a prior verdict (those force a fresh full review); a ship
earned in a verdict pass covers the scored fixes, not the whole surface
- new-work: capture-validity rules (settle entrance motion, capture from
document top, comp comparison at comp dimensions, open every file once
before sending); user's actual viewport joins the inspected sizes
- new-work: hero checkpoint now writes .impeccable/review/hero-repro.png
and the reviewer verifies it exists under Persistence
- new-work: comp authority is explicit (only the user can downgrade it);
handoff reports the verdict at its actual scope; user evidence reopens
a full review; documenter re-runs when fixes land after documentation
- craft-floor: Refuse entry for geometric masks approximating organic
photographic contours (the circular-cutout failure)
- editorial conciseness pass over new-work.md, visualize.md, and both
agent files: tighter sentences, no dropped rules, all rule markers and
mechanical tokens preserved
Assisted-by: Claude Code
* fix: define the ship disposition in new-work's action paragraph
Copilot review finding: the paragraph claimed exactly four disposition
words but defined only recapture, rebuild, and fix.
Assisted-by: Claude Code
* fix: rebuild returns get a full review; recapture return shape in preamble
Cursor Bugbot findings:
- a return following a rebuild directive is now a fresh full review on
both sides of the contract, never a verdict pass, so a wholesale
rebuild cannot earn a scoped ship on the directive alone
- the turn-ceiling preamble now names the recapture return shape instead
of contradicting it with "the five sections"
Assisted-by: Claude Code
* fix: absent required captures fail the evidence check
Greptile finding: a packet with no desktop.png/mobile.png (or missing
native device-class captures) routed to the missing-input notice and
could still reach ship. A required capture that is absent now fails
check 0 exactly like a malformed one and forces recapture; the
missing-input allowance in the preamble excludes captures.
Assisted-by: Claude Code
* fix: user-viewport capture is a required, named input to the review
Greptile finding: the evidence gate hard-coded web requirements to
desktop.png and mobile.png, so a reported user viewport could join the
inspected set and still ship uncaptured. The parent now saves it as
user-<width>.png and names every inspected viewport required in the
packet; check 0's required set includes every brief-named capture.
Assisted-by: Claude Code
Two review findings on #583.
"context.mjs reports it" undersold what counts: that directive only fires on an
OPENAI_API_KEY, so a harness with a native image tool and no key generates
images while the boot output says nothing. Read literally, the step would skip
the question exactly where the toggle belongs. It now names both sources and
says a silent boot is not evidence.
The unanswered branch said to state which path the session takes without saying
which one it is. Left implicit, an agent picks its own, which is the failure
this step exists to stop. It now names comp-first, the default new-work applies
when nothing is recorded.
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A live Codex session folded the build path into the stack question as a
trailing recommendation ("I recommend static and code-first"), never said what
either name means, treated its own recommendation as the user's answer, and
wrote `buildPath: code` as a standing default. The user disagreed and flipped
the board to comp-first, but a flip binds one session, so the unasked default
stayed on disk to steer every later round.
Step 5 said to "ask once ... stated as the trade it is", which the run
violated, but the step left the shortcut open: it sits after the interview
ends, it never says a recommendation is not an answer, and unlike the stack
question it offers no way to end without a value, so an agent holding no answer
writes one anyway.
Now: it is its own question, never a clause inside another; the trade is stated
in the question the user reads, because the two names mean nothing on first
contact; only the user's own choice is written; and an unanswered question
records nothing and says so. Unset is a working state, since the page toggle
governs the session and new-work's one-time offer still captures the answer at
the first flip.
The same run also wrote "Code-first build path" into PRODUCT.md's `## Stack`,
so the step now says the config is the only place this lives: a copy in product
truth outlives the setting and steers rounds nobody can trace back to it.
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Round two of review findings, all four valid.
`doctor` builds its own finding list and never called `checkBuildPathUnset`,
so `config-build-path-unset` could not appear in the report even though
doctor.md documents it. That is also the only path left once stalenessCheck is
off, which is exactly when someone is looking for it.
The lookup chain included `process.cwd()`, which lets an ambient invoking
directory decide another project's workflow: run from workspace A with
--target resolving onto workspace B, and B inherited A's buildPath ahead of
the repository default. The chain is now the resolved project then the repo
root, matching `checkBuildPathUnset` exactly; cwd stands in only when no
project resolved at all.
Two prose contradictions, both mine. new-work said to write the value "when
the user says yes" and then to "record the answer either way", which reads as
persist-on-yes-only and leaves the decline to be asked again next session. It
now says the write always happens and the answer picks the value. The README
still pointed existing projects at re-running init, which is the problem this
PR exists to solve; it now names the toggle as the migration path.
The workspace-isolation test earned a correction of its own: the first version
passed a relative --target, which resolves against the caller's cwd and puts
projectRoot back on the calling workspace, so it asserted nothing.
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The build-path preference shipped as a question only `init` asks, written to
a file only `init` writes. Nothing routes an initialized project back through
init, so every existing project took the comp-first default without anyone
choosing it, and the only recourse was a footer toggle that binds one session.
Neither the setting nor the round that preceded it ever reached a release
(skill-v4.0.4 has no `buildPath`, no `comp-led`, no `.impeccable/settings.json`),
so the PRODUCT.md standing-commitment fallback describes an era that never
existed publicly. It is deleted rather than honored: told a field might exist,
models go hunting for it and preserve it.
- `buildPath` moves from `.impeccable/settings.json` into the unified
`.impeccable/config.json`, which already has a known-keys registry, doctor
coverage, and a gitignored `config.local.json` override. Whether a machine
has an image tool is a property of that machine, so the local file wins.
- new-work captures the answer from behavior instead of an interview: a toggle
flip on a project recording nothing asks once, after the round closes,
whether to keep it. The answer is written either way, because a declined
offer nothing writes down is an offer the next session makes again.
- Two findings: `config-invalid-build-path` (an unread value rides the default
rather than the opposite path) and `config-build-path-unset`, gated on a
product record plus evidence of direction work so polish-and-audit projects
never hear about a setting they do not use.
- init treats a recorded value as a confirmed answer, resolving its conflict
with Step 1's "do not reopen confirmed fields".
- The setting was undocumented in the README and doctor.md. Both now cover it.
Also records a measured skill-behavior baseline. Three cells fail on unmodified
main (scenarios 9 and 15, `initialized natural build`), verified against a clean
worktree; the suite README now says so, so the next person does not spend the
hour attributing them to their own branch.
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two failures the trace test found were structural, not model quirks.
critique.md described the report's format and then went straight to writing a
temp file, with no step saying to output the report. gemini-3.6-flash and luna
both responded by bundling heredoc, snapshot write, trend read, and cleanup into
one bash call and stopping, leaving a perfect archive nobody had read. A
"Deliver the Report" step now precedes persistence, and persistence describes
itself as a copy of what was already sent. gemini-3.6-flash failed three
consecutive runs before this and its failures afterward all show the report
reaching chat.
The close is also step 6 of the persistence list rather than a section after it,
since the same shape is what fixed delivery.
Lineup: gpt-5.6-luna and deepseek-v4-flash out, gpt-5.6-terra in at
reasoningEffort high (IMPECCABLE_SKILL_BEHAVIOR_EFFORT overrides), gemini 3.5 to
3.6. Provider options resolve from the model object inside the harness so the 21
runTurn call sites are untouched. Verified the effort actually reaches the API
rather than being silently dropped.
The Gemini bump was not cosmetic: 3.5-flash passed critique closes twice and
3.6-flash then failed three times against identical text. A version bump inside
one family changed the outcome, so the README now treats cross-version carryover
as unmeasured.
Known floor, recorded: critique closes is flaky on gemini-3.6-flash, 1 run in 3.
Two structural attempts moved it from consistently failing to intermittently
passing and then stopped paying. claude-sonnet-5 and gpt-5.6-terra are clean.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The earlier fix in this branch was built on a wrong diagnosis. It assumed a
structured question hides any prose sharing its message, so it split report and
question across two turns. A controlled check showed prose before a question
renders fine; what hides a report is emitting it AFTER the question. The split
therefore fixed nothing and introduced a worse failure: a turn that ends on the
report is a turn that ends, and the questions never arrived at all.
Persistence returns to main's ordering, byte for byte, and the boundary prose is
gone. What replaces it is a position rule: the question is the last thing in the
response.
The trace test added here found two failures beyond the reported one. Critique
can fail to land in three ways, and they are now all asserted:
1. Question emitted before the report, hiding it behind the picker.
2. No close at all: no questions and no skip line, so polish inherits nothing.
3. Report authored into the persistence heredoc and never written to chat,
leaving a perfect snapshot and a user who sees nothing.
Mode 3 predates this branch entirely. Persistence step 1 now says the temp file
is an archive copy, not delivery.
The Codex final-question gate is promoted out of its <codex> fence, where it was
stripped for three of four providers, and the skip branch is now a countable
threshold (fewer than 3 Priority Issues) rather than a judgment call.
Known floor, recorded in the suite README: gpt-5.6-luna passes 1 run in 6 and
deepseek-v4-flash is flaky. claude-sonnet-5 and gemini-3.5-flash are consistent.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review on #576 caught document.md:71 splicing {{ask_instruction}} after
"then", which is the same defect this branch set out to fix. Rendered for
Codex it produced "Show the user the existing file, then STOP and use Codex's
structured user-input/question tool...". The line now starts a new sentence.
The comment added to PROVIDER_PLACEHOLDERS asserted the contract without
enforcing it, which is exactly how four reference files shipped the splice in
the first place. validateAskInstructionSites() in build.js now checks every
call site and fails the build on a mid-sentence interpolation, and the comment
points at the gate instead of asking authors to remember.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The critique report and the AskUserQuestion call shipped in one assistant
message, so the report stayed hidden until the user answered the picker and
the command read as if it had never run.
Reorder critique's persistence steps so the temp-file cleanup runs after the
report and trend line are sent. That cleanup now ends the message carrying the
report, leaving the questions to open a fresh one. Both critique.md and
overdrive.md state the constraint and why it exists, so the ordering is not an
unexplained sequence a model can optimize away. Overdrive additionally moves
its direction descriptions inside the question options, where the user is
actually reading them.
Also fix the ask_instruction splices. The placeholder is a complete sentence,
but five call sites spliced it mid-sentence and shipped text like "stop and
STOP and call the AskUserQuestion tool to clarify. before expanding it". Every
call site is now sentence-initial and the twelve lowercase provider values are
capitalized to match, with a comment in utils.js pinning the contract.
Record a workflow-contract baseline for the current model lineup. The two
failures seen while validating this change are pre-existing: bolder refinement
fails on deepseek-v4-flash identically with bolder.md reverted to HEAD, and
redesign replaces DESIGN is flaky on assertions driven by new-work.md, which
this change does not touch.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The retired execution-contract round and the buildPath payload keep
main's text; the decision-page fallback keeps this branch's gate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- serve-question: payload buildPath { value, toggle } renders a footer
segmented control (comp first / code first) with the trade stated in one
line; the default comes from settings, a flip binds that session only.
Code-led rounds treat declared comp paths as flip reserves: wireframes
render, a flip to comp shimmers the slots and surfaces once through
--wait as BUILD PATH FLIPPED so the agent starts generating mid-round;
the flip back is free and a landed comp stays. The ANSWER carries
buildPath and buildPathFlipped with a session-only directive.
- init Step 5 asks the preference once (only when image generation exists)
and writes .impeccable/settings.json; context.mjs surfaces the recorded
default every session; PRODUCT.md standing commitments stay honored as
the fallback.
- new-work retires the two-card execution-contract round: no round asks a
workflow preference. followup stays as the generic same-table mechanism.
- e2e: new toggle test (14/14 with the wireframe test).
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bugbot's finding: exit 2 is overloaded, and at --wait it means the
question server died, so the unscoped rule would drop a live visual
round onto the text channel after a transient daemon loss. The gate now
names the serving invocation, which also settles Copilot's exit-code
ambiguity, and the display clause reads grammatically.
AI-assisted (Claude Fable 5).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Across every recorded gpt-5.6-sol session, serve-question.mjs was never
invoked once: the rule's prose list of fallback environments (headless,
CI, an eval worker, a remote shell) let the model match itself against
the list and take the structured question tool without running the
script, while claude-opus-5 on the identical harness runs the script
every time and the page works. The direction is then chosen with no
imagery on the table, the catalog challengers are weighed without their
art, and the session's own safest candidate wins: measured end to end
on the eval harness, this is where bland output enters.
The environment list is deleted; the script's own exit 2 is now the
only key to the fallback, and the script already prints the rationale
and the override at runtime to exactly the sessions that hit it. Same
gate on the comp round's approval point: inline image rendering earns
the in-harness path, and a text-only surface is not display.
One adversarial review pass; its two word-level findings are applied.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- concept-seed --scope surface deals three grounded-list indices (dice-picked,
primary leads) instead of one: a single card is not a choice, and the
no-lineup rule stays direction-only, where it was written for worlds
- serve-question renders a new per-card wireframe field as a layout schematic
in the media slot: the code-led channel's visualization, no image
generation needed, no card back, no salience weight
- generate-image gains --ref (repeatable): routes through the edits endpoint
with input images, so an established world's comp inherits identity from a
captured screenshot of a real page instead of a prose paraphrase; tested
against impeccable.style, where the reference-anchored comp reproduced the
live site's chrome and the prose-only comp drifted
- new-work rung two rewritten around the dealt hand: lock-in is the
approval, a locked comp builds comp-led and discharges the visualize.md
three-option round, a locked wireframe builds code-led; visualize.md
records the exemption and the reference-image discipline, including the
reference-leak caveat (chrome carries, the reference page's content
does not)
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The raise block drops the side-tab left border for a quiet patina panel,
and drops the poker jargon: "Improved by Impeccable's worlds" with
per-line "From <world>" donors, on single raises too; tooltip, aria, and
screen-reader copy follow
- The pick-card kicker convention renames MY PICK to IMPECCABLE'S PICK at
every definition site, so users stop reading "my" as themselves
- The footer (steer, registers, canon exit) is a sticky full-bleed bar on
wide viewports, sharing one --page-inset with the content column; portrait
keeps it in flow where the deck scrolls internally
- Short landscape viewports compact the headline and narrow the cards so a
full round fits 1440x800
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cursor's finding was real: gating the density check on a named focal
moment let a busy comp pass whenever the direction named none, which is
the common case on the lane that produced the busy comps. The second leg
reuses the bullet's own distinction: several regions performing the
concept at once is the same shout; regions doing their jobs are not.
AI-assisted (Claude Fable 5).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two independent skeptic passes over the added prose, one hunting
oversteer and example bias, one hunting mode and platform damage. What
they killed, and why:
- The absolute 'never a medium' rule contradicted the file's own
imagery-stance fixity two paragraphs up and stripped legitimate guards
(an illustration-committed world, a native app screen warding off
stock-photo drift). A medium ban now belongs to the committed imagery
stance, never to caution, and the rule appears once per reader context
instead of five times corpus-wide.
- The quoted incident string and the four-example subject list taught
the model the exact framings they existed to prevent. Gone; the
abstract rule plus the point-at-the-subject check carry it.
- 'A first-time visitor learns what this is, why it matters, and what
to do' was Persuade anatomy imposed on all four modes. The guard is
now mode-neutral: a quieted region keeps its information and stops
performing.
- 'Calm is what Operate and Read surfaces are for' contradicted
operate.md's density affordance. Deleted; modes stay defined in one
place.
- The focal-moment count now presupposes nothing: it fires only where
the direction names a focal moment, and only on same-scale rivalry,
so an even, calm field stops reading as a failure.
- The decision-comp clause and the mode bullet no longer restate what
they can reference.
Net: the prose additions drop from roughly 480 words to under 200, with
no quoted strings and no example lists.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Proven necessary by its own demo: the first re-render of the declined
moto-forum comp satisfied subject-present and one-dominant-move by
deleting the value proposition, leaving a members' index that told a
first-time visitor nothing about what this is or why to care. Paul
caught it. Quieting a region means it stops performing, not that it
leaves; empty is quieter, not calmer.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The declined moto-forum comp's prompt read 'no gradients, no rounded SaaS
cards, no photography, no fake member counts, no badges, no testimonials':
the reflex that rightly bans invented claims swallowed the one medium the
subject lives in, and that is exactly how a motorcycle forum got comped
with no motorcycles. The lektor prompt's 'no AI imagery', written by an
image model, is the same fingerprint.
One counterweight, phrased once per authoring surface: the comp
discipline's subject-presence check (which the decision comps already
bind), the asset producer's own prompt rules (a standalone agent that
never reads visualize.md), and new-work's author-assets law (the path a
code-led build takes without the comp round). Truth binds claims, not
demonstrations; a photo of the subject doing its job is a demonstration.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The deliverable died in #545; the word survived as the decision-page
payload's field name, annotated everywhere it appeared with the same
compatibility apology. The page and the skill text ship together and
payloads are per-session, so the compatibility burden is one input alias,
not a frozen name.
serve-question.mjs: the card field, the answer key, the schema docs, the
--schema example, the help text, and every internal identifier (compSrc,
data-comp, .media.comp-pending, img.comp, comp-note) now say comp; a
payload declaring the legacy sketch key still renders and answers
identically. new-work.md and the asset producer drop their wire-name
parentheticals. The unit suite covers the canonical answer key coming
back from a legacy-key payload; the new-work e2e's declined-card stray
comp stays declared as sketch, which doubles as alias coverage.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Factory review evidence (two batches, both lanes): generated comps drift
poster-ward. They render the world's atmosphere at high density, drop the
surface's subject (a motorcycle forum comped with no motorcycles), and stop
reading as screens a product would ship. The existing anti-vignette
self-check catches the fully collapsed case but says nothing about density
or subject presence, and new-work's "committed all the way" reads as a
coverage instruction.
Three sibling self-checks in visualize.md's comp discipline, each phrased
per mode (Persuade/Operate/Read/Experience) and platform-neutral: the
subject appears as the content the regions hold; the mode must be readable
from the image alone; commitment is depth, not coverage, with one dominant
move per viewport. new-work.md's decision-comp rule gains a clause binding
the same checks so the direction round inherits them explicitly.
AI-assisted (Claude Fable 5), prepared for maintainer review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Denoise the design hook and let agents self-serve confident ignores (#497)
The directive footer now emits in full once per session (a one-line
reminder after), the DESIGN.md staleness note is mentioned once per
session, rule descriptions dedupe within an emission, and the per-line
ignore suggestion shrinks to the bare rule/value pair. The footer and
hooks.md replace the confirmation-gated ignore policy with a three-way
triage: fix real problems, self-serve the narrowest ignore for confident
false positives or sanctioned exceptions and disclose it (with an honest
--reason), ask when unsure. Self-serve stops at ignore-value, and the
footer now gives a runnable hook-admin.mjs command instead of a slash
command agents cannot execute.
Measured on a seeded lab session replaying 11 hook events: 33,658 to
14,063 chars of agent-visible output (-58%).
AI-assisted (Cursor agent), directed and reviewed by @abdulwahabone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Preserve the policy footer and honor maxChars under constrained budgets
Greptile's runtime check found two pre-existing clamp gaps that matter
more now that the full policy emits once per session: the last-resort
tail slice cut the footer off an over-budget emission, and the DESIGN.md
staleness note was appended after clamping, pushing past maxChars.
The clamp now gives the footer the budget first, clipping the finding
line and downgrading full to short policy when needed. The staleness
note defers, without consuming its session flag, to a later emission
with room.
AI-assisted (Cursor agent), directed and reviewed by @abdulwahabone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Harden the constrained-budget clamp: keep findings, honest flags, guaranteed note
Review follow-ups from Bugbot and Greptile on the clamp fix:
- The clamp retries with the short policy before dropping finding lines
that fit beside it, and a grouped result that kept only a file header
no longer counts as a fit.
- The full-footer session flag commits only when the full policy
actually survived the clamp, so a downgraded emission does not mark
the session as having seen a policy it never received.
- Render paths reserve room for a pending DESIGN.md staleness note, so
it is delivered inside the budget on the first emission instead of
deferring behind full emissions indefinitely.
AI-assisted (Cursor agent), directed and reviewed by @abdulwahabone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Route the Cursor deny cap through the clamp and match the whole footer
Bugbot follow-up: cursorBlockMessage tail-sliced at 4000 chars after
render, which the default 8000-char budget made reachable, and a cut
that spared the footer's opening words still committed the session
flag. The 4000 cap now feeds through the renderer's footer-preserving
clamp, and commitFooterShown matches the complete footer text instead
of a sentinel.
AI-assisted (Cursor agent), directed and reviewed by @abdulwahabone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Reconcile hook.test.mjs expectations with main's per-platform quoting
Three tests fell out of sync when main's quoteCommandArg change (#533,
building on #476) met this branch's footer/hint rework. Test-only
changes; production logic untouched:
- The full-footer test now accepts either close quote after the
hook-admin.mjs path, since quoteCommandArg single-quotes absolute
paths on POSIX and double-quotes them on Windows. The short-footer
guard rejects `node '` and `node "` alike.
- The #476 hostile-value test asserts the new bare
`ignore-value <rule> '<value>'` hint format. The security property is
unchanged: the value still passes through quoteCommandArg, so
$(touch pwned) stays single-quoted and inert.
- The #533 test previously asserted a concrete quoted `--file` path in
the footer; directiveFooter() now carries only literal placeholders,
so that surface is gone. The per-platform assertion moves to the
per-finding ignore hint, the remaining user-visible surface where
scanned file content flows through quoteCommandArg.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix two Bugbot findings: Cursor prefix budget and footer-cutting tail slice
Both flagged by Cursor Bugbot on PR #508 after the main merge; both real.
1. cursorBlockMessage computed min(maxChars, 4000 - prefix), so a
configured maxChars at or below the Cursor ceiling never charged the
BLOCK_PREFIX against the budget: the final deny text could exceed
maxChars by the prefix length, and appendDesignSystemNoteOnce's size
check lost exactly the room designNoteReserve had held back. The
prefix now comes off whichever limit binds. Default-config behavior
is unchanged (min(8000, 4000) - 60 equals the old 4000 - 60).
2. The note reservation is subtracted after renderTemplate's 500-char
floor, so the clamp can run below the budget clampLastLine assumed
safe, and its last-resort path tail-sliced the rendered text, cutting
the policy footer (the failure mode this PR exists to eliminate) when
a deep file path met a pending DESIGN.md note. The reservation order
stays (the staleness-note delivery guarantee at floor budgets depends
on it); the last resort now drops the finding line and clips the head
instead, so the footer survives every path. New regression test pins
it: 6 findings, 100-char path, maxChars 500, reserveChars 134.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Charge the Cursor deny prefix after the renderer's floor, not before
Greptile's runtime check caught the residual from ead0346d: subtracting
BLOCK_PREFIX from the maxChars passed to renderTemplate does nothing at
floor-tier configs, because the renderer re-raises any budget below its
500-char floor. At maxChars 500 with a stale design sidecar, the
prefixed denial landed at 432 chars and appendDesignSystemNoteOnce
could not fit the staleness note inside 500, deferring it (flag
unconsumed) for every equivalent denial in the session.
The prefix now rides in reserveChars, which comes off after the floor,
so it is charged at every config tier and the final prefixed message
plus a pending note closes exactly at the binding limit (499 chars in
the regression scenario). Default-config output is byte-identical:
max(500, min(8000, 4000)) - prefix equals the old min(8000, 4000) -
prefix. New end-to-end Cursor preToolUse test pins the path with a real
stale sidecar at maxChars 500.
AI-assisted (Cursor agent), directed and reviewed by @abdulwahabone.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
* Map polish's evidence and verify steps per platform
polish.md was the last command reference verifying through web-only
vocabulary after #546 gave the pipeline its native leg. Three targeted
mappings, following the in-file precedent new-work.md set (the
classify-triage-polish-verify flow itself is platform-neutral, so no
polish.native.md):
- Evidence gathering: desktop and mobile sizes on the web; the shipped
device classes on simulator, emulator, or hardware on native, per the
platform reference's Verifying the build section.
- Verify checklist layouts: phone and tablet size classes, both
orientations where supported, on native.
- Verify checklist "supported browsers": native has none, so the
analogues are named (runtime warnings, dropped frames, supported OS
versions).
Assisted-by: Claude Code
* fix: branch the verify checklist web-vs-native explicitly
Copilot follow-up: the parenthetical style could read as both term
sets applying on native. The two bullets now branch explicitly, and
the shared items (console errors, layout shift, latency, image
loading) stay unbranched since they apply everywhere.
Assisted-by: Claude Code
* fix: restore runtime warnings to the native verify branch
greptile follow-up: the explicit-branch restyle dropped the runtime
warnings requirement the parenthetical carried; folding it into
"console errors everywhere" hid it behind web vocabulary. It is back
as its own item in the native branch.
Assisted-by: Claude Code
* Give the verify-and-review pipeline a native leg
The build-verify-review loop assumed a browser end to end while the
comp side of the system was already platform-aware: new-work.md,
visualize.md, and the asset producer all comp a native app portrait at
its device viewport, and then the verification steps asked for desktop
and mobile browser screenshots of it. Concretely:
- new-work.md step 7 ordered detect.mjs on every hookless build with no
platform guard. routing.md declares the detector web-only and the
design hook skips native projects, so a native build was always
hookless and always ordered to run an HTML rule engine over
Swift/Kotlin/RN code. The playbook now guards it: web-only, and on
native the reviewer's floor check is the named slop gate.
- The inspection round and the SKILL.src.md batched-round principle
named desktop and mobile as the only viewports. Both now map per
platform: web keeps desktop and mobile; native inspects the shipped
device classes per OS, captured from the simulator or emulator.
- ios.md and android.md carried no verification guidance at all, so
nothing told a native run how to produce the screenshots the evidence
chain depends on. Each gains a Verifying the build section: simctl /
adb capture commands, dark-appearance and type-scale checks, and the
simulator-vs-hardware honesty line.
- The finish reviewer judged native builds blind: it never runs
context.mjs and its packet carried no platform guidance. On native
the packet now includes the platform reference path(s) and a
no-detector-ran line, and the reviewer's Input Contract says to judge
in the platform's conventions.
Assisted-by: Claude Code
* fix: address PR review bot findings
- greptile: carry the capture's device selector through the
state-changing verification commands (simctl appearance, adb uimode
and font_scale); unqualified forms fail with several targets attached
- Copilot: align new-work.md's cross-reference with the actual heading
(Verifying the build)
- Copilot: give the finish reviewer's Input Contract the native
filename example new-work.md establishes (phone.png / tablet.png,
suffixed per OS on adaptive)
Assisted-by: Claude Code
* fix: identify simulators by UDID, not display name
greptile follow-up: display names can collide across booted simulators,
so the capture and appearance commands now both key on the UDID from
simctl list devices booted.
Assisted-by: Claude Code
* Resolve {{scripts_path}} in the agent bodies Codex ships
Three code paths emit an agent body: the degraded fallback reference, the
.toml nested inside the skill for Codex, and the native agent file. Only the
nested .toml skipped placeholder substitution and rule-marker stripping, so
the codex and .agents dists shipped `node {{scripts_path}}/embed-prompt.mjs`
verbatim in the asset producer, and every caller had to substitute the token
itself at load time.
All three now render through renderAgentBody(), and the new regression test
asserts a runnable embed-prompt command on each emitted surface plus a
synthetic agent proving markers and placeholders resolve in the nested .toml.
Prepared by an AI agent (Claude Code) under pbakaus's instruction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Give the finish reviewer's screenshots one fixed address
The Input Contract asked for "desktop and mobile screenshot paths captured by
the parent" and named none, so each session invented a filename and the
verdict pass went looking for a recapture that was never written there. Two
reviewer passes burned on that in the eval runs.
The parent now captures and recaptures to .impeccable/review/desktop.png and
.impeccable/review/mobile.png, and the reviewer reads those two first,
treating a brief-named path as the fallback for a parent that wrote elsewhere.
Prepared by an AI agent (Claude Code) under pbakaus's instruction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Lead Setup with the base directory the runtime reports
The rendered claude and codex skills opened with
`node .claude/skills/impeccable/scripts/context.mjs`, a project-relative path
that resolves in this repo and in nothing a user installs: a personal or
plugin install puts the scripts outside the project entirely. The working form
was already in the text, parenthesized, after the one that fails.
Setup now leads with `node <skill-base-dir>/scripts/context.mjs` and says once
that the base directory resolves every scripts-path command in the skill and
its references, leaving the project-relative path as the fallback for runtimes
that report no base directory.
Prepared by an AI agent (Claude Code) under pbakaus's instruction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Answer the Copilot review: brittle model assertion, missing review dir
Assert that {{model}} resolved rather than that it resolved to "GPT", which
belongs to PROVIDER_PLACEHOLDERS and can change without touching what the test
guards. And have the parent create .impeccable/review/ when the harness does
not, so a fresh project's first capture has somewhere to land.
Prepared by an AI agent (Claude Code) under pbakaus's instruction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Make the review-screenshot contract directory-based, not web-viewport-named
Two amendments to the recapture contract from review feedback:
1. The canonical location is the directory .impeccable/review/, one file
per captured viewport; desktop.png and mobile.png are the web case,
not the contract. Baking web-viewport names into the reviewer's spec
would have hardened a web assumption into paths that a native
(ios/android/adaptive) build cannot honestly write.
2. Precedence restored to explicit-beats-convention: paths the calling
brief names are authoritative when the files exist; the canonical
directory is where the reviewer looks when the brief names none or a
named path is missing. This avoids stale canonical files from an
earlier run silently winning over fresh explicit paths. The observed
failure (the verdict round inventing a round-stamped filename) stays
fixed: recapture happens over the same files, and invented filenames
are still called out as pointing at nothing.
Assisted-by: Claude Code
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Restore reduced-motion build guidance
Restores the accessibility requirement and verification step to the animation playbook, with a regression test that keeps it on the build path.
Implemented and validated with OpenAI Codex assistance under standing maintainer authorization.
* Harden reduced-motion guidance regression
Normalizes CRLF input and accepts either reduced-motion spelling so the contract stays portable and intent-focused.
Implemented and validated with OpenAI Codex assistance under standing maintainer authorization.
* Anchor skill reference test to its module
Resolve the repository fixture path from the test module so the regression test is independent of the caller's working directory.
This change was prepared with AI assistance under maintainer authorization.
* Clarify reduced-motion guidance
Replace the double negative in the canonical animation guidance and keep the source contract aligned with the clearer wording.
This change was prepared with AI assistance under maintainer authorization.
* Polish the decision page: raise cycler, declined height, canon order, full card anatomy
Field feedback from the first real rolls of the verdict-routed hand:
- Several raises stacked on the assigned card blew it out of proportion.
More than one raise now renders as a compact cycler: one visible, a
counter, click or Enter advances. A single raise stays inline.
- Declined cards inherited the row's stretch alignment, so a narrow card
stood at the tallest contender's height, a strange stilt beside the
hand. They now size to their content.
- Deck order becomes a gradient of standing: contenders, then the canon,
then declined dead last. The canon between full alternates and the
demoted row reads as the familiar door rather than the last resort
after the rejects.
- Root cause of bare-bones challenger and canon cards in the field: the
--schema example only gave the assigned card palette, materials, and
risk, and models author payloads by imitating the example, so the
"same anatomy on every card" instruction lost to it every time. The
example now carries full anatomy on every card and the schema note says
a card with no palette chips is an authoring gap, not a data gap.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Decision cards carry full-fidelity comps instead of sketches
Field verdict on the sketch contract: the sketches came back too simple
to inform the choice, and generation takes the same time at any
fidelity, so the deliberately-unfinished frame paid comp cost for sketch
quality. The decision card's image is now that direction's north-star
comp, produced under visualize.md's comp discipline (structure-led
prompt, real name and content, no invented commercial claims), saved
under .impeccable/mocks/ with its prompt sidecar. Fairness between cards
comes from equal fidelity in each card's own grammar rather than shared
unfinishedness.
The chosen card's comp is never spent by the choice: on a comp-led build
it enters the comp round as compositional option one (visualize.md now
generates two variations beside it; a round arriving with no decision
comp still renders all three), and on a code-led build it returns at the
finish review as the critique reference. Produce order still front-loads
a re-roll's spend onto the cards read first.
serve-question keeps the sketch field's wire name for payload
compatibility; docs, schema paths, shimmer labels, and the answer
directive (CHOSEN COMP) speak comp.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: address PR review bot findings on the comp round
- Producer still forced sketches (cursor, high): the asset producer's
Decision Sketches contract still mandated deliberately unfinished matte
sketches, so the parallel path would keep shipping sketch-era images.
The section is now Decision Comps: full-fidelity north-star comp,
structure-led prompt, equal commitment across siblings, no invented
claims, sidecar written.
- Mocks collided with the approval check (cursor, high): decision comps
now live under .impeccable/mocks/decision/, visualize.md scopes the
no-approval finding to comp-round output, new-work.md states the
unchosen hand implies no approval, and the code-led finish packet names
the chosen decision comp as the critique reference in the approved-comp
slot.
- Raise cycler announces (greptile, both P1s): a visually hidden
aria-live region reads out the newly active raise and its position on
advance; initial render stays quiet.
- Declined width in the vertical deck (cursor, medium): align-self:
flex-start shrank declined cards to content width in the portrait
column layout, where the cross axis is horizontal; they stretch there
and keep content height in the row layout.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: raise cycler tooltip and label name both input modes
Copilot: the tooltip said Click while the control also answers Enter and
Space; the title and a new aria-label now say activate/press Enter.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: finish reviewer exempts decision comps from the approval check
cursor[bot] follow-through: the reviewer's Persistence check still
treated any comps under .impeccable/mocks/ as approval-gated, and the
reviewer never reads visualize.md by design, so code-led and spent-hand
rounds could draw a false skipped-approval finding. The check now scopes
to comp-round comps, exempts .impeccable/mocks/decision/ as the direction
round's dealt hand, and defines how a code-led build's decision comp is
judged in the approved-comp slot: the critique reference, under the
no-approved-comp fidelity rules plus what the image dared that the build
did not.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: the critique reference is its own reviewer input, not the approved-comp slot
cursor[bot]: passing the code-led decision comp through the approved-comp
slot dragged in that slot's obligations (inventory-first reading, the
fidelity matrix, Truth's shipped-asset demand for every image-native
region), which contradicts code-led's premise. The input contract now
names it a separate labeled critique-reference input that nothing binding
"the approved comp" touches, and Fidelity defines its treatment where the
no-approved-comp rules live: provocation, not spec; no matrix, citations,
or asset obligations; its dares enter material_fixes as ordinary fixes.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
* Route the direction hand by verdict, add the pick card, enforce salience parity
The decision round previously rendered every dealt challenger as an equal
full card whatever the weighing said, so a world that fused poorly (an
underwater world dealt to a flower shop) sat at the same visual weight as
the assigned direction, and concept-level fusion had no surviving output.
Three changes, all presentation-layer; the dice, the assignment, and the
two-axis weighing are untouched:
- Verdict routing: the weighing closes with wins / competitive / declined
per challenger, decided before any borrowing. Declined challengers render
demoted (narrow, quiet, catalog art as a labeled thumb, "Adopt anyway"),
reordered to the end of the deck by the page itself, still adoptable,
never silently dropped. Donations return as named "raised by" lines on
the assigned card: a declined challenger donates ambition and system
discipline, never its clothes.
- The pick card: one card for the model's top-ranked grounded candidate
when the dice assigned another, kicker MY PICK, honest familiarity risk
on its face. One card, never a ranked list, never the lead position; the
anti-menu rule survives with exactly this carve-out.
- Salience parity: a card's imagery weight is capped by the assigned
card's. With a text-only assigned card (no image generation in the
harness), full-bleed catalog heroes demote to labeled thumbs, so what
looks important is the verdict's call, never rendering luck.
serve-question payload gains additive fields (verdict, kept, raised); old
payloads render unchanged. concept-seed's rendered instructions carry the
verdict/donation contract and the pick-card carve-out. Covered by two
Playwright tests in the new-work e2e suite (verdict routing + parity).
Design exploration and rationale were worked through with the maintainer;
research grounding is impeccable.style/research lessons 3-5.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add Safer/Bolder re-roll registers to the direction round
The re-roll gains the user's steering wheel on the familiar-to-bold axis.
The decision page renders two register buttons beside the plain re-roll
(payload: reroll: { registers: ["safer", "bolder"] }; booleans still work),
the answer carries the chosen register, and concept-seed gains --register.
The design constraint that shaped the implementation: a register changes
only what a round INSTRUCTS, never what it DEALT. The same key and reroll
count reproduce the same deal whatever the register, so the exclusion chain
never forks and the reproduction contract holds with no API change.
- bolder: the dealt foreign forms become the whole hand, every challenger a
full card; the first-dealt challenger leads (assignment by deal order, so
the dice still choose). The pick card sits out; the canon stays.
- safer: the round's dealt hand is spent unseen and stays excluded; the
model presents its remaining conventional grounded candidates (at most
three) plus the canon executed against named competitors. This is the one
sanctioned lineup of the model's own ranked list, existing only by
explicit user request. Works degraded (needs no catalog); bolder degrades
to a plain grounded round, disclosed.
Registers are user steering, never the model's to pre-select. Covered by a
concept-seed unit test (same-deal invariant, validation) and a Playwright
test (button, answer field, REGISTER directive).
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add the execution-contract round: comp-led or code-led, chosen after the direction
The build previously went comp-led for everyone, silently: a generated comp
led and the build chased it, which produces the boldest compositions and
also the measured worst-of-both-worlds failure (ambitious design landed
poorly, no motion, fix rounds after). Models already defect from it by
quietly skipping comp generation, which is unsanctioned code-led with no
contract to catch it. This makes the fork explicit and both paths
defection-proof:
- Comp-led: the comp is law and non-optional once chosen; visualize.md and
the comp-is-king build phases run as today.
- Code-led: no comp of this page, skipped by contract rather than drift.
The QUALITY BAR boards still calibrate finish, and the ambition moves
into the written direction contract (FIRST VIEWPORT plus a named
signature interaction and motion grammar), audited by the finish
reviewer in behavior. Not a discount on commitment.
Placement: a second round on the same open table, right after the
direction lands. Sketches stay in the direction round (they pick the
world); comps are what code-led skips (they bind the composition). The
chosen world sets the default lead; the user flips freely; a standing
preference recorded in PRODUCT.md skips the round on later surfaces; with
no image generation there is no fork, code-led is the only path.
Mechanism: serve-question gains payload-level followup: true, which keeps
the detached server alive after a pick (exactly like re-roll), swaps the
page to the loading hand instead of goodbye, marks the answer with
followup: true so --wait keeps the table, and prints a FOLLOWUP OPEN
directive telling the agent to deliver the next round via --update.
Covered by a Playwright test driving the full two-round flow.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: address PR review bot findings
- Degraded safer register no longer contradicts itself (greptile,
Copilot, cursor): the degraded template previously said "the assigned
index is suspended; the user picks" and then emitted ASSIGNED INDEX,
the mandatory build instruction, and the restated footer anyway. The
degraded safer path now suppresses the assignment machinery entirely,
matching the non-degraded safer round, and restates the user-picks
behavior for truncated readers instead.
- A declined card's declared sketch no longer renders a full media face
(Copilot): the renderer ignores sketch slots on declined cards
outright, so a stray sketch cannot buy back the salience the verdict
took away.
- Bolder rounds no longer carry the generic weighing instruction
(cursor): it measures against the assigned grounded direction, which
the bolder register suspends; a leader-relative variant weighs the
fused challengers against the first-dealt leader instead.
All three pinned by new assertions in tests/concept-seed.test.mjs and
tests/new-work-e2e.test.mjs.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: followup never arms the loading hand in blocking serve mode
cursor[bot] caught a client/server disagreement: the page interpolated its
FOLLOWUP constant from the payload alone, so a followup: true payload served
in blocking mode (no --start) would leave the browser on a loading hand that
nothing resolves, since a blocking server exits on any pick and has no
update channel. The page constant is now armed only when the server is
detached, blocking rounds get the goodbye screen as before, and new-work.md
states that followup belongs only on a detached round; blocking and
structured-tool channels run the build-path round as its own second
question. Pinned in tests/serve-question.test.mjs.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add card-kind choice telemetry and the bolder routing disambiguation
The choice ping previously fired only when a dealt catalog challenger won,
so pick-share and canon-share had no denominator and the decision page's
new spectrum could not be measured. The ping now fires once per resolved
attended round on API-dealt rolls: --kind names which card class won
(assigned / pick / challenger / canon), --chosen carries the catalog id
only when a dealt challenger won, and --register rides along when the
round came from a steered hand. Grounded candidates' names never leave the
machine (the ping carries the kind alone), the legacy id-only shape stays
valid, and DO_NOT_TRACK / IMPECCABLE_NO_TELEMETRY still disable the ping
entirely. The seed's TELEMETRY block teaches the new invocation.
Also the naming-collision guard: "bolder" said while a direction round is
open routes to the Bolder hand register, never the bolder refinement
command; one line each in bolder.md and new-work.md.
The /api/chosen field additions land in a sister impeccable-site PR; the
API ignores unknown fields meanwhile, so this is safe to ship first.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: ping test survives a DO_NOT_TRACK shell
cursor[bot]: the pingChosen unit test cleared only IMPECCABLE_NO_TELEMETRY,
so a developer shell with DO_NOT_TRACK set failed the success-path
assertions. The test now clears both, restores prior values in finally,
and passes under DO_NOT_TRACK=1.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
A well-made site was audited for what separates it from a competent one, and the
answer was not its ingredients. It runs the default stack, Next and Tailwind and
Geist, with no world and no unusual technique. What it has is attention to the
surfaces a browser renders for you: 29 focus-visible rules, 15 scrollbar rules,
and styled text selection, caret, underline offset and scroll behaviour.
Those are the cheapest signal that a page was built rather than assembled, and
the ones a model skips most reliably, because nobody asks for them and nothing
looks broken without them. The floor already covers contrast, depth, spacing,
measure, motion and states; this is the layer under all of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
probe-compking-sol-4 (evals) executed its staged inventory faithfully and
still lost the comp: the brief had already recorded the comp's materials
down (low-contrast textures, a 70-path lake against the comp's hundreds,
a sculpted plate as flat CSS), and the build thread never loads
visualize.md, so nothing told it the comp wins that disagreement. The
comp-is-king block now says the record gets corrected upward, that the
comparison runs against the freshly reopened comp rather than memory,
and that a texture under a near-opaque wash is not shipped material.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase one is near-pixel-perfect reproduction at the comp's breakpoint,
with exactly three concessions (closest font, icons unless a library
was chosen, genuine comp defects); the overlap comparison is the
authority because models systematically believe their code recreation
succeeded when it did not, and regions that keep losing the comparison
ship as composited rendered assets instead. Phase two brings the
reproduction to life (interaction, motion, responsiveness), and
anything beyond the comp inherits the recorded system, never invented
container chrome.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
context.mjs now probes cwebp/sips/magick/ffmpeg once (which/where per
OS) and prints IMAGE_TOOLS, replacing macOS-specific prose; the
IMAGE_GEN_AVAILABLE directive leads with the harness-native tool so a
present OpenAI key stops reading as an instruction to bill it; and the
sandboxed board-start guidance sheds codex vocabulary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sandboxed shells cannot bind the board's port; every codex session paid
one failed start before retrying escalated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three lessons from the Tortuga containment-map run. The first rebuild
directive now executes immediately, informing the user instead of
asking permission to fix a failure; consultation waits for a second
rebuild verdict or user-approved content at risk. The asset producer
spawns on every subagent-capable run even when produce looks empty,
because its manifest is the independent check on the inventory's media
and the skipped spawn marks every all-CSS failure to date. And the
inventory now opens by reading the comp as a design system (component
grammar, corners, line weights, elevation, type ramp), because the
sections the comp does not show get built from that record, and without
it the fallback is the stock kit: square boxes, 1px grids, bentos, hard
shadows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The condensation pass folded the old textures-are-raster-by-default
sentence into the medium gate's lighting-and-depth clause, and the next
codex run drove straight through the gap: woven cotton as 'layered CSS
textures', a black nylon band as plain CSS, and a physical evidence-tag
CTA as CSS shapes, so the produce bucket stayed empty and the asset
producer was never called. The gate now names textures explicitly,
woven cloth, paper grain, fabric, leather, brushed metal, with no depth
argument owed, and calls 'layered CSS textures' what it is: not a
medium.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Tortuga comp dissolves the Install CTA's edge into the storm's
particles; the build shipped a plain rectangle with four decorative
dots, and neither the builder nor the reviewer's rebuild findings named
it. The inventory now gives the primary action its own row and medium,
naming the shrink-to-border-trick failure as the compliance-token
version of commitment, and the reviewer's fidelity matrix lists the
primary action's treatment among the salient elements, with a
physically-worked CTA rendered as a plain rectangle scored contradicted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Tortuga run showed the finish machinery working end to end, roll,
challengers, approved comp, honest labels, independent reviewer, an
earned rebuild verdict at the user checkpoint, and still cost the user
a full build to learn the hero undersold the comp: a glyph storm at a
tenth of the approved density under type half as compressed. Both
misses were visible the moment the first viewport rendered.
Two cheap gates front-load that discovery. The build section gains a
hero checkpoint: capture the first viewport and set it beside the
comp's before any later section, judging scale and density as
quantities. The inventory gains the same quantitative discipline:
field and texture regions record density and coverage, and TYPE rows
name the compression class and render one headline word against the
comp before anything is built on the face.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The composition pool (stagings) is not ready: too thin to help, and its
draws crowd the decision it rides along with. concept-seed.mjs stops
rendering the staging block by default; IMPECCABLE_COMPOSITIONS=1
re-enables it for catalog development, and the draw machinery,
rating-weighted selection, and mode scoping stay intact and tested for
its return. new-work.md drops the dress-the-staging-challengers
instruction and the FORM contract's staging clauses; the surface-scope
roll still assigns which of the model's own structures gets built.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex's own post-mortem of the second hamster-wheel session: it loaded
the kicker ban, shipped five kickers anyway, and then the reviewer and
documenter 'compounded it by accepting, and even canonizing, the
invented label style'. Nothing downstream of the builder ever re-read
the floor.
The reviewer gains check 6, Floor: read craft-floor.md (now the one
skill reference it may read, passed in its inputs) and hold the
screenshots against the Refuse list; a banned element is a material fix
even when it matches nothing in the comp, because fidelity cannot
authorize what the floor refuses. The documenter gains the mirror rule:
a floor refusal lands in its not-canonized line as a carried defect,
never in DESIGN.md as a rule future surfaces inherit.
Also updates the live-reference contract test to match the applier's
condensed no-server sentence, which still carries the same guarantee.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three subagent audits reviewed the files that grew through the last
rounds of patches. Their honest verdict: dense, not bloated; roughly
430 words of true redundancy came out with no rule lost, and every cut
they flagged as removing compliance pressure was skipped. Highlights:
approval recording now has one owner in visualize.md, the asset
producer's crop ban went from three statements to the deliberate pair,
its two transparency passages carried contradictory defaults (resolved
toward true alpha first), and the 450-word medium-gate wall split into
three paragraphs at zero cost. The producer also gained a mode-seam
sentence so a sketch run cannot return an asset manifest.
The reviewer's verdict is no longer soft: a derived disposition line
(rebuild / fix / ship) opens every return, computed from the matrix
rather than felt, recomputed after the verdict pass, and never
softenable by the parent, who must report it verbatim. The second
hamster-wheel run showed the parent inventing 'PASS WITH FIXES' over a
matrix with MATERIAL contradicted on the focal element.
Two additions from the same session's evidence: hard offset shadows
outside a neobrutalist world join the craft floor's refusals (codex
invents them without fail), and hookless harnesses must run detect.mjs
once before the finish review, because codex has no hooks and the
detector otherwise never sees the build at all.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The second codex hamster-wheel run read the medium gate and still
assigned a shaded, perspectived technical illustration to 'Authored SVG
geometry': the world was an instruction booklet, so the affinity
clause's 'diagrams' blessed the downgrade, and the page shipped as flat
clipart against an illustration-grade comp. The gate now says style
does not move the boundary: perspective, shading, figure drawing, or
dense mechanical detail is illustration however line-drawn it looks,
and authored SVG ends where drawing skill begins. The craft floor's
sketchy-SVG rule carries the same sentence.
The reviewer in that run built an honest matrix, MATERIAL contradicted
on the focal element, and still emitted it as a fixable item the parent
answered with CSS. The rebuild directive now fires when MATERIAL is
contradicted on the focal element, not only when TYPE falls with it,
and every asset-requiring fix must say 'produce: <region>' so it cannot
be answered as a style tweak.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A landscape frame was the silent default at every generation site,
which is a composition error before the build starts for native apps
and mobile-first surfaces. The sketch frame, the asset producer's
single-sketch contract, and the comp instruction now state it: portrait
at device viewport when the surface is a phone screen, landscape for
desktop web. The decision page adapts in kind: portrait art overrides
the 16/10 slot with its own exact ratio so nothing crops, and the deck
narrows so portrait cards line up side by side. The --schema guidance
tells the model the page handles either.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A codex greenfield build produced an excellent approved comp and then an
abysmal page, and the reviewer approved it. The failure chain: the
implementation inventory downgraded a photographic hero to 'silhouette
in SVG' and sculpted panels to 'material finish: CSS'; the builder read
'no photography on hand' as a license to avoid photographic rendering;
QA looked at one full-page thumbnail; the reviewer was spawned with the
builder's forked history and then scored fix claims instead of pixels;
and the output contract had no way to say 'rejected'.
The fixes, stage by stage:
- The inventory's medium column gets a gate: a human figure, product
object, machinery, or lit material is raster whatever the stack, and
such regions are regenerated cleanly at asset resolution with the
comp and its embedded prompt as reference. Never cropped from the
comp, whose effective resolution is reference grade; the asset
producer's direct bucket closes the same hole. Dropping an
image-native region is a user decision at the approval point.
- Generated imagery is a material, not a claim: evidence rules bind
assertions, never render fidelity.
- The build thread's inspection becomes a region-by-region side-by-side
against the comp at legible scale, never one full-page thumbnail.
- The reviewer spawns fresh, never with forked history (fork_turns: 0
in codex), and gains a rejection lane: when TYPE, MATERIAL, and the
focal element are all contradicted, the first material fix is a
rebuild directive the parent surfaces to the user instead of
patching. Verdict passes score recaptures only; the parent's fix
narration is not evidence.
- The verdict-loop ceiling softens: two rounds ends an unattended run,
but an attended session puts the open-items table in front of the
user and lets them fund another round; any round that resolves
nothing stops the loop.
- Comp approval joins the roll as skip-proof: question-tool errors fall
back to the decision page, delegation is recorded in the brief and
the sidecar and disclosed up front, and the reviewer treats comps
with no recorded pick as a material finding.
- Craft floor: system display faces (Impact, Arial Black) as an
own-world display voice and unicode glyphs standing in for icon
systems are named failures.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>