Skip to content

v7.2 — machine contour, process control, revision conveyor (waves 1–4) - #3

Merged
pavelevgrafov merged 11 commits into
mainfrom
speedup-waves-1-2-3
Aug 6, 2026
Merged

v7.2 — machine contour, process control, revision conveyor (waves 1–4)#3
pavelevgrafov merged 11 commits into
mainfrom
speedup-waves-1-2-3

Conversation

@pavelevgrafov

Copy link
Copy Markdown
Owner

What this changes

The pipeline was slow, and the usual explanation — "too many rules" — was only half right. Reading rules is not a one-time cost: a resident instruction is paid on every turn that follows it, and cost and wall-clock of an agent run are linear in the number of turns. So the work went after turns first, resident context second, and only then the rules themselves.

Everything deterministic now lives behind one entry point, tools/dops, and never enters the model's context.

Measured

Before After
Invocations to verify a build ~25 (one agent turn each) 1
Whole floor, wall-clock 8.7 s, 25 checks, browser lane included
Resident rule set ~12.9k tokens (AGENTS + 4 SKILL.md) ~1.1k (RULES.card.md, generated)
Stage context one context growing all run flat packet per stage, ~2k
Diagnostics screenshots up to 36, resident deduped to a budget (21 → 6 on the reference run)
cost.actual prose ("one session") a number, written by a script
Self-test 69 passing, browser stage skipped 94 passing, 0 failed, 0 skipped

Main additions

  • tools/dops verify (whole floor, one JSON; the agent reads failures[], not the registry), doctor, card, handoff, shots, harvest, hash, announce, checkpoint, control, guard, stage/report/cost.
  • Rule taxonomy (rules-taxonomy.json) — a rule belongs in the prompt only if it changes what the model writes. Rules a checker enforces are deliberately off the card.
  • [E.3] implemented — it had been prose since v5: nothing stored input hashes, so every change request rebuilt everything. dops hash plan now names exactly what must be recomputed and what may be reused.
  • [A.25] gate-overtaking + [A.26] "nothing silently" — shipped as one package. Autonomous needs the owner's explicit grant; every machine gate decision is announced at the moment with a rollback command.
  • Checkpoints and control queue — every intermediate artifact is published with the actions the owner may take on it; commands steer the run and apply only at control points.
  • Sentinels (dops guard) — verified rules are caught before the edit instead of being carried in the prompt.
  • Contrast pairs as data, heavy floor in CI, starter library 3 → 6.

Defects found and fixed on the way

  1. The browser floor had never actually run. run-ui-checks.sh writes its runner into a temp directory where require('playwright') cannot resolve. Masked because playwright was not installed — the checks degraded honestly and the bug could not surface. Every historical ready_with_caveats verdict rested on fs-level checks alone.
  2. check-divergence.py crashed on a string axes instead of reporting — a check must produce a status, never a traceback.
  3. check-packs.py invoked a bare python3, producing phantom resolver errors.
  4. Every walker audited the vendored toolkit and the self-test's deliberate traps as product defects (8 false failures on a real project).
  5. check-reduced-motion.py rejected the stronger prefers-reduced-motion: no-preference pattern, pushing authors toward the weaker one.
  6. dops doctor --fix could not install PyYAML on an externally-managed Python (PEP 668); it now creates a project venv instead of forcing the system one.

Self-test: 94 passed, 0 failed, 0 skipped. CI runs the quick profile on push and the standard profile with Playwright on this PR.

🤖 Generated with Claude Code

pavelevgrafov and others added 10 commits August 5, 2026 21:40
… queue, hash graph, gate overtaking, A.25+A.26, rule card taxonomy, 6 starters, progress.py, direction-drafter pack, self-test 93/0
…tokens.json, compile-tokens.py reads from $meta
…ages)

D23 scanned the project virtualenv and reported six findings from pip's own
vendored SPDX data. A blocking check that cries wolf on every run stops being
read, which is worse than the risk it was guarding against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ming a verdict

The first live CI run failed, and it was right to. The workflow ran
`dops verify` against this repository's own root — asking whether the toolkit
passes the floor it applies to websites. There is no skeleton, no tokens and
no contract here, so D16 failed and half the floor was unavailable (pyyaml was
not installed either).

CI now checks what it should:
- `selftest` job — the toolkit's own acceptance (dops selftest + package
  self-test), with pyyaml installed;
- `end-to-end` job — materialises a real project from the landing-event
  starter, serves it, records the D22 baseline and runs the standard floor
  against THAT. Rehearsed locally: 24 pass, 1 skip, 1 unavailable (D1, no
  build system for static HTML), verdict ready_with_caveats in 8.8 s.

Two defects surfaced by the rehearsal:

1. Every starter's contract.yaml shipped `verdict: ready_with_caveats`, so a
   materialised project claimed a verdict from its first second. The starter's
   own factory verdict belongs in starter.yaml (`floor_verdict`); the
   project's contract starts empty. This is exactly the retro-fitted
   compliance D19 exists to catch — and D19 did catch it.
2. Open doctrine question, noted in the workflow: a UX model INHERITED from a
   Verified Starter currently trips the quick-mode ceiling (AC-23). Producing
   one in quick mode is over-work; receiving one pre-verified is the entire
   point of starter_first. Left for the design side to rule on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…es it

A Verified Starter promised pre-verified structure but shipped no model to
prove it, so every starter_first project lived out its life with D18 and D.38
reporting `unavailable`. All six starters now carry ux/experience-model.yaml,
and inject.py copies it into artifacts/ux (--ux-out) — shipping it without
carrying it would have changed nothing.

app-dashboard also carries the state_matrix D.38 reads: three async modules,
seven states each. A dashboard with only its ideal state is precisely the
defect A.12 exists to catch.

Also fixed, mine from an earlier commit: site-portfolio and site-content
declared `evidence-first` and `browse-first`, which are not in the closed
pattern taxonomy the validator enforces. Mapped to answer-first (the
positioning line answers the visitor's question, cases support it) and
object-first (articles are objects the reader scans) rather than widening the
taxonomy unilaterally.

Self-test 94/0/0; starters/recheck.sh green; all six models validate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ation

Every edit cost the same. "Make the button darker" and "add a booking flow"
both ran the full cycle — read context, write contract, route through S0,
apply, re-verify, report — and the big model met both. Two moves from Kimi's
revision-conveyor design fix that.

П-1, pins always-on: gate-annotate.js worked only on gate artifacts. It now
embeds in any artifact for the life of the project, and a pin carries
selector + viewport + kind. A comment is born in the artifact and used to be
expressed in chat ("that blue button on the third screen"); half of every
revision went into working out which element was meant. The v6 field names
are still written, so annotations-log.py keeps reading its own artifacts —
verified in the self-test.

П-2, the sorting station: `dops pins classify` routes each pin before the
model sees anything — A token/copy (script, seconds), B block swap, C
structure (narrow K1 + targeted gate), D taste or ambiguous. The classifier
is a word list, not a model: it has to be cheaper than the work it routes.
Structure rules are checked before token rules, so "add a page about prices"
is not mistaken for a colour edit.

Measured on a realistic 15-pin revision set: **67% never reach the big
model** — the design estimated ~80%, and the measured number is what the
documentation now states. Ambiguous wording routes to D and waits: a wrong
cheap lane costs more than one honest question. Duplicate pins are marked,
never dropped — the owner wrote it twice for a reason.

Self-test: 96 passed, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Revision conveyor, move П-3. A pin is now checked between sorting and
execution — negotiation at the cheapest possible moment, before a second of
work is spent. Four questions in a fixed order: does the selector still
resolve, is the value inside the declared ranges, does it contradict a
decision already made, has the owner said this before.

The ranges are read, never re-typed: the type scale and 8pt ladder come from
the skin's tokens.json, the contrast pairs from $meta.contrastPairs (move 8),
and the WCAG maths is imported from check-contrast.py. A second copy of any of
them in the checker would be the drift [A.10] forbids.

Two rules make a refusal usable. A refusal always carries alternatives, and
annotations-log.py fails a `rejected` verdict without a reason and a way out —
a wall is not a negotiation. A duplicate is questioned, never silently merged.

Measured on the same realistic 15-pin set used for П-2: 15 of 15 decided by
script alone, zero model calls; 4 became instant negotiations instead of work
that would have been built and thrown away. The small-model boundary exists
($DOPS_SMALL_MODEL, one JSON in, one JSON out) and is exercised by the
self-test with a stub; with no model in the environment those pins go to the
owner marked checker_unavailable rather than guessed at [A.6].

AC-23 closed per Kimi's ruling: the quick-mode ceiling limits what a run
PRODUCES, not what a Verified Starter carries in. inject.py stamps
artifacts.ux.origin=inherited, validate-pipeline.py exempts it, and absent or
`produced` still violates the ceiling — silence buys no exemption. The CI
rehearsal moves back to quick mode, which is the real starter_first case.

Found on the way: $meta.contrastPairs declares seven pairs and D3 gates four,
and the gap hides a real one — textTertiary/canvasRaised measures 3.39:1 in
both flagship skins. Whether that pair is normal text or UI chrome is a design
call, so `check-contrast.py --tokens` reports it instead of inventing a
threshold to make it disappear.

Version named v7.2 per Pavel's decision. Contract schema stays 7.0 — no
migration. Self-test 96 → 101, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…uild

The skins declared seven contrast pairs in $meta.contrastPairs and
check-contrast.py gated four of them, hardcoded. Two copies of one geometry,
and they had drifted for two versions — hiding textTertiary/canvasRaised at
3.39:1 in both flagship skins.

Thresholds decided by the owner: the two text tiers are normal text (4.5:1);
the tertiary tier is UI chrome, so it answers to 3:1. It measures 3.39 light /
3.17 dark and clears that floor — it would have failed the text floor, which
is precisely why the gap mattered.

The report added earlier is no longer only a report: the self-test fails when
a skin declares a pair the gate does not measure, so the next new pair has to
be given a floor deliberately. Verified against injected drift — a bogus
focusRing/canvas declaration is caught.

D3 now runs 14 checks per skin (7 pairs x 2 themes), all green.
Self-test 101 -> 102, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pavelevgrafov pavelevgrafov changed the title Waves 1–3: machine contour, process visibility, sentinels v7.2 — machine contour, process control, revision conveyor (waves 1–4) Aug 6, 2026
A skipped job still publishes a check run under its own name. With main about
to require that check, a skip could have satisfied the requirement instead of
a real run — a gate a skip can pass is not a gate.

Costs one extra minute per push and makes 'CI green' mean the browser floor
actually executed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pavelevgrafov
pavelevgrafov merged commit 3dc5355 into main Aug 6, 2026
4 checks passed
@pavelevgrafov
pavelevgrafov deleted the speedup-waves-1-2-3 branch August 6, 2026 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant