Make plate candidate checks non-destructive and align reference exclusions

Add exact pixel region coordinates and native command guidance. Apply UI exclusions symmetrically after cover alignment while retaining raw asset provenance checks. Verify unchanged selected assets, build state, missing-art rejection, and comp-copy rejection.

AI-assisted implementation and validation by Codex under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-09-17 18:44:27 -07:00
parent 66b996a3eb
commit 37e1757a5d
7 changed files with 168 additions and 10 deletions
+3
View File
@@ -450,11 +450,14 @@ retain their local-development trust behavior. See [bundle signing](BUNDLE-SIGNI
Ported from the former `skill/scripts/{comp-spec,comp-diff,font-match,build-phase}.mjs` (+ `lib/{png,raster,image-metrics,font-fingerprint,font-index,hero-checks}.mjs`) into the engine; invoked as `{{scripts_path}}/impeccable <verb>`. All four resolve paths against the process cwd. Printed commands spell the launcher via `IMPECCABLE_SELF` (default `impeccable`), so they name `{{scripts_path}}/impeccable <verb>`, never `node …mjs`. ISO `createdAt`/`startedAt` timestamps in stdout and written JSON are the only run-dependent output.
- **`comp-spec`** — turns an approved comp into a measured build spec. `--comp <png> --grid` writes `.impeccable/build/comp-grid.png` (10x10 labeled grid) and prints PALETTE/BANDS/NEXT; `--comp <png> --regions <json>` measures regions into `.impeccable/build/spec.json` (region box, sampled palette, medium, aspect, detail energy, plate path for raster kinds) and prints the spec; `--comp <png> --auto` derives band regions; `--print` prints the compact spec; `--crop <id> [--out f] [--scale n] [--raw]` writes a reference crop; `--plate-prompt <id>` prints the regeneration prompt. `--spec <path>` overrides the spec path (default `.impeccable/build/spec.json`). Validation refusals (stderr, exit 1) are the JS strings verbatim: a region with no id / duplicate id / no note, a code-kind region whose note names painted material, a code region over 25% of the comp, a grid span that is not `<colrow>:<colrow>`, uncovered ink cells without `allowUncovered`. spec.json is byte-identical to the JS output.
Region inputs support three coordinate representations: inclusive `grid` cells, normalized `box: {x,y,w,h}`, or `pixelBox: {x,y,w,h}` in whole original-comp pixels. Pixel boxes cannot be combined with the other formats and must be positive-sized and contained in the comp; they avoid snapping an asset boundary to a neighbouring grid cell. Foreground UI excluded from a plate reference is excluded at the same aligned coordinates from the candidate during scoring; unmasked asset bytes still undergo provenance checks.
- **`comp-diff`** — `--comp <png> --build <png> [--spec spec.json] [--out-dir dir] [--align top|stretch|cover] [--label name] [--threshold t] [--json] [--no-files]`. Scores structure / color / detail / bands and per-region verdicts (`match`/`drift`/`missing`/`contradicted`); writes `side-by-side.png`, `heatmap.png`, `regions/<id>.png`, and `report.json` under `--out-dir` (unless `--no-files`); prints the text summary or, with `--json`, the report. Exit 0 measured, 1 usage/unreadable input, 3 below `--threshold`. The JSON report and text summary are byte-identical to the JS.
- **`font-match`** — `--measure <text-region-id>` fingerprints the comp crop of a text region (cap height, width/weight class, shape vector), records it on the region's `type` block in the spec, and prints the MEASURE line (pure; byte-identical to the JS). `--rank <id> [--candidates "Family:700,…"] [--text "…"] [--transform …] [--category …]` additionally renders candidate faces in a headless browser and ranks them by fingerprint distance, writing a stamped `chosen` face onto the region and a proof sheet under `.impeccable/build/font-match/`. **Browser**: an installed Chrome discovered and driven over CDP (the same browser the URL engine uses; the JS used Playwright/Puppeteer). With no browser resolvable, the catalog's nearest face is recorded (source `catalog`, estimated size) or, with no catalog either, the MEASURE line stands — matching the JS fallbacks; the sha1 `chosen` stamp is byte-identical. Screenshots vary by Chrome version, so the rendered ranking is not byte-stable.
- **`font-index` catalog (paid moat)** — resolved at run time, never committed to the engine repo: `IMPECCABLE_CATALOG_DIR/font-index.json` first, then the skill's shipped `IMPECCABLE_SKILL_DIR/scripts/data/font-index.json`; absent → the built-in per-width shortlist stands in (the JS degraded path).
- **`build-phase`** — the comp-led build state machine at `.impeccable/build/state.json`. `start --comp <png> | --direction <key>` (opens the phases; reads comp dimensions for the breakpoint), `status [--json]`, `advance [--force --reason "…"]` (runs the current phase's gate; exit 2 on gate failure, state unchanged), `record hero --build <png>`, `scaffold`, `note "<text>"`, `finish --disposition ship|fix|rebuild|recapture`. Phases and gates (`comps`, `spec`, `plates`, `hero`, `sections`, `motion`, `responsive`, `review`) are unchanged from the JS; the hero/responsive gates call comp-diff in-process (the JS spawned it). The organic-clip-path CSS scan is the engine's own rule (`organic-clip-path`), injected into the gate; `--force` is refused unless `--reason` quotes the user downgrading the comp (the JS `forceAllowed` logic verbatim).
`build-phase check-plate <region-id> --candidate <png> [--json]` runs the normal plate gate on a separate candidate, retaining the full spec for reference exclusions. Exit 0 means pass, 2 means gate failure, 1 means invalid input. It does not write files, select an asset, record an approval, or advance build state. JSON includes `ok`, `region`, `candidate`, `reasons`, `plates`, and `stateChanged: false`.
---
## 2. Context and utility verbs