Skip to content

Releases: kvdm-co-pilot/create-cmp

v0.24.0 — Rule 0 ships to adopters

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 04 Sep 02:20
cef4037

[0.24.0] - 2026-09-04

The Rule 0 instrument now ships. Four files in every generated project pointed adopters at
scripts/framework-check.mjs — a path that exists only inside the create-cmp repo. The tool it
named has never been in an adopter's tree, so the fast way to calibrate a gate was advertised
and withheld, and the expensive way was the only one available.

Added

  • qa/framework-check.mjs — Rule 0, in your own tree. Proves the lane returns a fast
    deterministic PASS and FAIL through the real machinery: runner, receipt, Stop hook. No Gradle,
    no device, no network. Measured on a fresh scaffold: 7 plants, 1.9 s.
    • Plants are derived from the tree, not hardcoded — a project with no specs, no flows or
      no Kotlin tests still gets the region plants, and every plant it cannot make is reported
      with its reason. It refuses rather than printing PASS over an empty plant list.
    • Restores everything it touched, including the receipt and the README badge — a smoke
      receipt is refused as done-evidence, so leaving one in place would overwrite a real L1/L2
      receipt with one that proves nothing. Empty directories it created are removed too.
    • Refuses to start when a file it plants into has uncommitted changes.
    • --budget-ms (default 5 s/cycle) reports any calibration cycle slower than Rule 1's stated
      "seconds each" — the bound was prose, and prose does not refuse.
  • qa/lib/framework-check.mjs — the plant selection and run assessment as pure functions,
    unit-tested without a scaffold (27 new tests; suite 1306 → 1333).
  • scripts/framework-check.mjs proves the shipped twin. A sixth leg runs
    qa/framework-check.mjs inside the scratch app it already stamps and asserts the tree is
    byte-identical afterwards — the tool we hand adopters is proven on the tree as shipped, not
    merely shipped. (Its first version compared git status in a directory that is not a repo and
    therefore compared nothing; it hashes the tree now, build output excluded.)

Added

  • qa/lib/agent-hold.mjs + qa/plan.mjs --hold/--beat/--release — liveness for a working
    agent.
    Two failures reported from payment-blueprint on 2026-09-04 were the same missing
    fact. (a) There was no cheap way to answer "is the agent working or wedged?", so the question
    was answered by filesystem archaeology — twice with broken instruments (a find that excluded
    build/, the only directory a proof run writes to; then a find -newermt that reported zero
    writes in 45 minutes while ls -lT showed one at 10) — and a healthy agent was killed
    mid-proof. (b) The Stop hook fired ~15 times in one evening while the correct action every
    time was to wait, because it cannot tell a receipt stale from laziness from one stale because
    a subagent is mid-commit on a half-adopted port.
    • A hold changes the ADVICE, never the verdict. The hook still refuses — a file an agent
      writes about itself must never be able to end a turn. It follows the precedent already set
      for a lane in flight: same refusal, different instruction.
    • It explains only the two refusals a working agent legitimately causes — no receipt yet,
      and a tree that moved under a PASSing receipt. A FAIL, a forgery, a skipped device tier or
      an unreadable surface are never explained by a hold, because there the hold is not the cause
      and offering it would send the reader to wait on an agent when a test is red.
    • Heartbeat older than 5 min reads as a crashed writer; a hold older than the 45 min ceiling
      reads as a wedge and the alarm returns — a heartbeat proves a process is alive, never that
      it is progressing.
    • Ephemeral like its siblings: gitignored and excluded from the receipt's hashed input surface,
      so a note about who is typing can never invalidate a receipt.
    • 19 tests, including the whole safety asymmetry (suite 1333 → 1352).
  • The orchestrator agent now claims, beats and releases the hold, and owes a visible line per
    subagent start and finish.

Fixed

  • Signing N artifacts costs one receipt invalidation, not N. A signature changes
    qa/approvals.json's status, and the approvals gate reads status — so a signature
    legitimately moves the receipt's input hash. Signed one at a time after a green lane, that
    means N signatures kill the receipt N times and cost N lane re-runs and N bookkeeping commits.
    Measured in payment-blueprint's log (2026-09-04, 00:12–03:54): 21 commits, of which 7 were
    code, 6 docs and 8 pure bookkeeping ("sign the approval", "bind the green receipt"); every
    code change cost two to three commits and fired the Stop hook after each. It compounds as a
    repo accumulates governed artifacts, which is what makes a session start fast and grind later.
    • node qa/approve.mjs <a> <b> <c> --as "…" signs them in one write — the idiom
      --reopen-feature already established ("one recorded change, not N commands").
    • The CLI states the other half with its reason attached: sign before the final lane run,
      so the receipt you keep already covers the signatures.
    • An unrecognised flag is still refused by name rather than filtered out silently.

Changed

  • GATE-RULES Rule 1 names its instrument at the point of authoring. Rule 1 states a
    property — this gate fails, by name, on its own violation — not a procedure to perform by
    hand, and it now says so where a gate author reads it rather than inside a Rule 0 aside.
    Measured cost of the procedural reading, three occurrences in one adoption: a wave briefed to
    plant → ./gradlew → confirm red → revert → build, at 30–60 s per cycle, ~38 minutes with
    nothing committed. It had violated Rule 1's own "seconds each" from the first cycle, and
    nothing noticed, because a bound in prose cannot refuse. A plant kept in the instrument is run
    by everyone forever in milliseconds; a plant performed by hand is run once and lost.
  • The orchestrator agent has standing to refuse an expensive instruction. It could already
    escalate before changing a number; it now costs a mandated mechanism the same way —
    instances × seconds-per-instance against the stage budget — names a cheaper instrument if one
    exists, and answers "what in this repo already does this, and why is it insufficient?" before
    briefing any mechanism. It also owes visible progress: a line per subagent start and finish, a
    status upward for anything past ~5 minutes with no output, and proof wall-clock as its own
    report line. A silent agent is indistinguishable from a wedged one.
  • The four dangling scripts/framework-check.mjs references in shipped files now name
    qa/framework-check.mjs (verify.mjs, lib/steps-cmp.mjs, lib/evidence-badge.mjs,
    docs/USAGE.md).

v0.23.0

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 03 Sep 22:32

Two spine fixes from payment-blueprint's adoption: the locked region now covers a lane's own
tests and the declarations it reads. No migration — a Compose app has neither qa/test/ nor a
surface declaration by default, so its region, lock and receipts are unchanged.

Changed

  • The lock region covers the lane's own tests. qa/test/** (every .mjs, recursively) is
    part of the machine-owned region when a project has it, so an adopter's suite that proves its
    gates is locked with the gates. Found by payment-blueprint, which could not vendor
    harness-lock.mjs without narrowing its integrity claim. A Compose app has no qa/test; its
    region and lock are unchanged. Pack tests now pin unique step names per profile (an aliasing
    factory passes a null check) and that the smoke profile stays pure-Node.
  • The lock region covers the declarations the lane reads: qa/verified-surface.json and
    qa/harness-manifest.json. payment-blueprint's planted proof: one entry removed from the
    surface declaration un-attested 203 files while every checker stayed intact and the next
    receipt validated over the smaller surface. An edited definition of what the checker looks at
    is the same attack as an edited checker. State a lane writes (ledgers, journal, evidence) stays
    out. The framework check now plants a narrowed declaration and asserts harnessIntegrity
    names it (7 plants).

v0.22.0

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 03 Sep 18:20

The device tier always runs, every Maestro flow runs, a device journey per feature is a lane
verdict, mutation testing is gone, and every skipped-test guard is read by a planted failure
before release. No migration: an app with no emulator attached will now boot one (set
CMP_AVD if the lane cannot choose; CMP_DEVICE=none is the visible opt-out and is never
done-evidence), and a feature with a screen and a spec now needs one clause proven by a flow.

Removed

  • Every mention of mutation testing. Karel, 2026-09-03: overkill; it broke development
    completely and caused the last days' issues; tests are written from the spec and that is the
    guard. Derived before the decision: the step had never returned a verdict, one module measured
    zero against a 60 % threshold, and a run pinned a shared machine at load 70–80 for 25 minutes.
    Nothing of it remains in the pack, the docs of record, the proposals or the adoption example.

Added — every skipped-test guard is read, on a real scaffold

  • scripts/framework-check.mjs is a planted-failure matrix. On a freshly stamped app it
    plants, one at a time, an orphaned citation, an unbound citation (a SPEC: tag on a class
    with no test in the binding window), a [tier: e2e] clause cited only from the JVM, a real
    feature whose flow stops citing its clause, a citation in a nested flow the lane never runs,
    and one edited byte in the machine-owned region — and asserts each FAILs BY NAME, that the
    Stop hook refuses a FAIL receipt, refuses the forgery (verdict flipped to PASS over a failed
    harnessIntegrity row), and refuses a receipt whose device tier was skipped for an
    environmental reason; then reverts everything and asserts PASS. Six plants, under two
    seconds, no Gradle, no device. This is Rule 0 and Rule 1 for every guard that catches a
    skipped or fake test, run before any release.

Changed — the device tier always runs

  • The lane boots its own headless emulator. With no device attached, the first device
    step boots an AVD headless (CMP_AVD, else the doctor's cmp_pixel, else the only one),
    bounded at 4 minutes, and the lane shuts it down on exit (CMP_KEEP_DEVICE=1 keeps it). A
    device that cannot be provisioned is an ERROR row and the lane FAILs. CMP_DEVICE=none is
    the one explicit opt-out; qa/receipt-check.mjs refuses a receipt whose device tier was
    skipped for an environmental reason as done-evidence. Until now every device row SKIPped
    "no device" on every receipt anyone looked at, and 0.21.0 shipped on a fleet check with
    the whole tier skipped.
  • Every Maestro flow runs. e2eSmoke ran smoke.yaml by name while spec coverage counted
    citations from any yaml under qa/e2e — four hand-written per-feature flows on the
    showcase satisfied clauses without ever executing. The directory now runs in one Maestro
    session; the receipt row lists each flow's result; the executed list and the coverage scan
    read the same list, so a citation can only come from a flow that ran.
  • A flow per feature. qa/scaffold-feature.mjs stamps qa/e2e/<feature>.yaml, a passing
    skeleton naming the screen id and clauses to prove; it cites nothing until it is the
    journey. [tier: e2e] clauses fail coverage until a flow cites them.
  • A device journey per feature is a lane verdict. New pure-Node gate e2eCoverage (every
    profile that runs the pure tier): a feature with a screen AND a spec must have at least one
    live clause cited from a flow the lane runs; FAIL names the feature and the flow file to
    write. A screen without a spec is a placeholder (reported, not failed); a screen declared
    { "unrouted": true } in its brief is exempt. Feature-brief doneness gains the same
    conjunct: a screens: true brief is not done until one of its clauses is cited from
    qa/e2e/. The template smoke flow now proves HOME-02 on device (the first item renders), so
    a fresh scaffold passes; a freshly stamped feature FAILs until its flow is the journey —
    that is the point ("is anything forcing e2e tests to be written per feature?" — now yes).
  • The post-run ANR/crash sweep is scoped to the app under test. The first self-booted lane
    went red on an ANR in another app that lived on the emulator. Incidents in other packages
    are not this lane's failure; with no app id known the sweep stays unscoped and says so.

Fixed — from the showcase's 0.21.0 upgrade report

  • The template .gitignore carries the Android signing-key ignores (keystore.properties,
    keystore/, *.jks, *.keystore). Three consecutive upgrades produced a .gitignore
    sidecar without them; an agent taking the sidecar would leave the keystore one git add -A
    from a public repo. The upgrade now also names what taking a sidecar would drop.

  • Receipts name the lane in words. harnessIntegrity prints the region digest beside the
    version (@create-cmp/harness 0.17.0 (region b56cd4f8) — 45 files verified): two lanes with
    the same package version and different content are told apart on the receipt, not only in
    the lock. The harness package is 0.17.0.

  • Stale *.bak-upgrade files from earlier upgrades are removed before a new upgrade writes
    its own; nothing cleaned them and one set accumulated per upgrade.

  • scripts/fleet-check.mjs defaults to --min-level L2; the template CI workflow sets
    CMP_DEVICE=none explicitly on its hosted runner.

v0.21.0

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 03 Sep 17:09

The console follows the project's layout, and four spine defects the first non-Compose
adopter found are closed. No migration: every change is additive or a bug fix, and a Compose
app with no manifest behaves exactly as before.

Fixed

  • --fast fell open to the full suite after the first lane run — in every Compose app.
    qa/flight-recorder.jsonl is appended by every run and committed, so it sat in the
    changed set as a modified file under qa/, which is the "harness itself" escape hatch.
    It is now a lane output (affected-tests.mjs), pinned by a planted test. Derived on a
    fresh scaffold before the fix: the journal in the changed set, filter mode all.
  • A smoke run rewrote the README's evidence badge from a true L1 to "rung unrecorded".
    Smoke and nightly receipts are refused as done-evidence and now leave the badge alone,
    like --fast.
  • The evidence ladder was the Compose pack's step names inside the spine. Vendored into
    a backend it graded the strongest run L0, L1 unreachable by construction. The ladder is now
    the pack's (createCmpSteps returns evidenceLadder; evidenceLevel takes ladder); a
    pack that declares none earns no rung. Compose apps: unchanged rungs.
  • The release gate itself failed on timing. The bundle-boot test slept 700 ms + 1800 ms and
    read whatever had arrived; under npm publish on a loaded machine the bundle answered late
    and prepublishOnly went red on a healthy bundle. It now waits for the response, bounded
    at 20 s — the bound is the assertion, never a fixed sleep.
  • A new top-level directory was silently unattested by the surface allowlist. The
    receipt now carries inputs.undeclared and the lane prints it — a report, never a gate,
    because the Compose default deliberately omits docs/, the README and the wrapper.

Added

  • Project manifest for the consoleqa/harness-manifest.json declares where a project
    keeps its receipt, architecture document, spec directory and citation roots (and which step
    packs it composes). The console read one layout — a create-cmp Compose app's — as constants,
    so the first spine adopter with its own (payment-blueprint: qa/evidence/receipt.json,
    ARCHITECTURE.md at the root, Kotlin under services/) got an Evidence pane, verdict history,
    audit trail, digest and Architecture page that said "not found" about files that existed. The
    layout is now resolved per project exactly like the verified surface: Compose default, manifest
    override, and a present-but-malformed manifest is refused with every problem named rather than
    silently defaulted. --status reports the layout in use; the rail names the manifest.
  • Layer-tagged receipt rows — a step pack may tag a step function with the layer it proves
    (fn.layer = "backend"); the runner stamps it onto the receipt row and the Evidence page
    groups steps per layer with a per-layer tally. Backward compatible: untagged rows and receipts
    render exactly as before. The Compose pack tags spine / compose / device.
  • Specs page bridges to the project's own scanner — when qa/lib/spec-coverage.mjs exports
    scanSpecClauses/scanCitations, the console renders their reading (the project's clause
    grammar and citation-binding rule), the same "bridge, never fork" stance it takes for
    approvals.mjs. The console's own scan remains the fallback.
  • The receipt bridge reads a flat receipt schema (inputsHash/gitSha/timestamp) alongside
    the nested cmp-evidence/1 one.

Changed

  • Approvals-bridge refusals for a library without reopenArtifact/acceptFeature no longer
    assume an "older scaffold": a step pack that does not govern reopen or briefs is the other,
    named, possibility.

v0.20.0 — lane vouching (strict), approver identity, citation binding

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 03 Sep 11:20

Three gates that read as green while holding nothing, closed. Each is breaking by design
— every one closes a hole that currently reports PASS — and each has a one-command migration.
Read the migration before upgrading.

Migration

Do these once, in this order, after upgrading the harness (create-cmp upgrade --harness):

  1. If your app predates harness locks (no qa/harness.lock.json): the upgrade writes one.
    Without it, harnessIntegrity SKIPs, and 0.20.0 refuses a receipt whose lane did not vouch
    for itself — strict, decided 2026-09-03: a lane that could not check its own integrity is not
    trusted. Apps generated since locks existed, and any app already upgraded, are unaffected.
  2. Re-approve each governed artifact with a signer: node qa/approve.mjs <artifact> --as "Name <email>". Every existing approved row lacks approvedBy; the gate FAILs naming each
    until it carries one. Hashes, statuses and the journal are untouched — only the signer is
    added. The studio console asks once per session and signs with what you type.
  3. Move any // SPEC: citation onto the test it claims. A tag now counts only when a test
    declaration follows within five meaningful lines, and never when it sits on a type
    declaration. specCoverage may go red naming clauses that were never really covered — each
    is a gap the old rule hid, not a regression.
  4. Run the full lane once so the receipt carries the new rows.

Added

  • Approvals record who signed (approvedBy). approveArtifact refuses without one and the
    refusal names the flag; approve.mjs requires --as "Name <email>"; the express lane carries
    the signer through to each artifact; the console asks once per session (sessionStorage — a
    signature is a deliberate act by whoever is at the keyboard now, not a name a browser
    remembers). Deliberately NOT defaulted from git config: that is whatever the machine says, and
    an agent on a developer's laptop would sign with that developer's name. --reopen takes no
    signer — it walks a signature back.
  • A citation must sit on a test. scanCitations counts a // SPEC: tag only when a test
    declaration follows within BINDING_WINDOW (5) non-blank lines; block comments are skipped;
    a tag whose first meaningful line declares a type is refused structurally — the real drift
    that motivated this sat on class PaymentWorkerTest above a genuine @Test. Maestro flows
    are exempt (a flow file is its own test). This also closes the hole under 0.19.0's
    [tier: device] gate, where a device-tier citation could be a bare comment. The rule caught
    the template's own ARCH-04 tag, and the fixtures written to prove the tier gate.
  • A PASS must be vouched by the lane's own rows (checkLaneVouching, in
    @create-cmp/receipts). A receipt whose verdict is PASS is refused if any row is FAIL or
    ERROR, if it has no harnessIntegrity row, or if that row is not PASS — the receipt is
    necessarily excluded from its own inputs hash, so steps[] is the only thing between the
    gate and a text editor.

Fixed

  • VERIFIED_SURFACE was hardcoded in the spine. A repo whose code lives outside composeApp/
    that vendored it had its verified surface silently shrink — the published 0.19.0 spine, run on
    a nested project, returned the sha256 of the empty string as a valid-looking digest attesting
    zero files. The surface now resolves per project from qa/verified-surface.json; the CMP
    default is unchanged (the showcase hashes 485 files to the same digest before and after); a
    malformed or empty declaration is refused; a surface matching nothing throws, and the Stop
    hook reports that as a refusal with its reason rather than a stack trace.
  • The lane marker narrated eight steps as null (memoized wrappers and gradleTestStep's
    returned functions had no runtime name), giving each the default deadline. Named.

v0.19.0 — evidence economics

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 03 Sep 09:17

Added

  • Evidence economics — the loop made cheap, visible and honest (docs/EVIDENCE-ECONOMICS-PLAN.md,
    the doc of record across sessions; causes and named practices in
    docs/proposals/evidence-economics.md). Every slice landed with a planted-failure proof.
    • A fourth verdict, ERROR, and a deadline on every step (qa/lib/step-outcomes.mjs).
      "Could not run" — zero tests executed, a deadline passed, a throw — is no longer reported as
      a behaviour failure: it never accuses the change, earns no evidence rung, does not count as
      executed for receipt plausibility, is never cached, wears its own mark (), and still
      FAILs the lane. Every subprocess inherits a per-step deadline derived from the step's own
      measured history (×3, floor 5 min, ceiling 30); a throw inside a step becomes one row
      instead of crashing the lane.
    • A clause can declare the tier that can observe it- **MOTION-13** [tier: device] — ….
      specCoverage FAILs when no citing test comes from a tier that could see the promise; a
      desktop Compose test citing a process-lifecycle claim is the planted red. App/process
      lifecycle joins the platform-behaviour list in the generated CLAUDE.md.
    • Tiers that have never run are named. The lane reads its own journal and prints
      e2eSmoke — skipped in all 37 recorded full runs; a SKIP is non-fatal, "never" is no longer
      invisible.
    • The lane says what it costs. Last, typical and worst full-run cost (measured over ≥3
      runs) replace the single last-run figure that a Gradle cache hit made a lie.
    • A pulse during long steps (qa/lib/lane-narrator.mjs) — a separate process, because the
      steps are synchronous and no in-process timer can fire during a Gradle call. Quiet under
      20 s, one stderr line every 30 s, "longer than usual" past 1.5×.
    • --profile nightly, with the determinism probe forced on; every receipt names its
      stage
      (scaffold / change / merge / nightly / release) and a nightly receipt is refused as
      done-evidence like --fast.
    • The build stage is observed, not merely declared. Files written since the current
      request move the Drive strip and the inject's chain (observed: 12 files written since the request · last 4s ago, or a named stall) — with no declared plan required.
    • The lane is a spine plus a step pack. qa/lib/lane-runner.mjs (marker narration,
      deadlines, the pulse, the catch, the verdict) and qa/lib/steps-cmp.mjs (every CMP step
      behind createCmpSteps(ctx)); qa/verify.mjs 1,835 → 641 lines. A Kotlin backend keeps the
      spine and supplies its own pack — packages/harness/README.md documents the swap with
      payment-blueprint as the worked example.
  • The studio console renews itself (docs/features/studio-self-renewal.md). bin/console.mjs
    supervises a worker; when the console's own sources change and nothing is in flight, the worker
    exits 75 and is respawned with the new code (budgeted, source-mode only), the page reloads once,
    and the registry record carries buildStale so the per-prompt inject and the statusline stop
    reporting a clean bill of health for a console drawing from old code.
  • The studio console opens on qa/ alone. Screens, preview and the live device are a
    capability, not a gate: a repo with no composeApp/ gets Drive, walks, approvals, evidence,
    comments and the chain. Proven live on a Kotlin backend repo.

Changed

  • releaseBuild runs after the cheap tier (unit, conformance, goldens, a11y) in local, ci
    and release — a red unit test is reported in seconds, not after R8 finishes.
  • The Stop hook says WAIT at a running lane instead of "run the lane" — the refusal stands;
    only the instruction changes, naming the running step from the marker.
  • A feature reopen walks back only what it amends — the brief, its declared spec(s), and its
    design when screens: true. Declared touches stay signed and are reported as still signed;
    the hash demands a fresh signature only if the change actually moves them (twelve-for-zero
    becomes two-for-two).
  • The retrospective's skip grouping keys on the reason's first line — seven near-identical
    approvals rows become one.
  • androidChecks that executed zero tests reports "DID NOT EXECUTE — not accusing it" with
    the rerun command, instead of "an on-device behavior claim is broken".

Fixed

  • Memoized step wrappers and gradleTestStep's returned functions had no runtime name, so the
    lane marker narrated eight steps as null and gave them the default deadline. Both now carry
    explicit names.

Added

  • grill-me skill + the grill step in the workflow — the decide step's opening act
    (docs/features/grill-me.md). Before the intent interview at genesis and before the brief on
    every brief-lane request, the agent reads what the repo already answers (signed briefs and
    specs are closed — cited, never re-asked), then asks the frontier of unsettled decisions in
    numbered rounds of ≤5, each with why it matters and a recommended answer, and waits; it stops
    when no answer would change the work. No new artifact: settled answers become the brief's
    Decisions with their why, the human's own calls its Open decisions, and the signature closes
    them. Never grills the direct lane, a bug fix, or a spike. Stated on every entry surface —
    CHANGE-FLOW-DESIGN.md §3, GENESIS-FLOW-DESIGN.md step 0, the generated CLAUDE.md,
    cmp-new §1 — and pinned to agreement by test/grill-me.test.mjs. The plugin now ships
    11 skills.

v0.18.0 — walk legibility + studio drive mode

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 27 Aug 14:31

Two approved feature waves. Harness → 0.16.0.

Walk legibility

The walk speaks human, the console carries it, and the console is always there.

  • Briefs name their specs"specs": ["catalog", "entry-editing"] in the cmp:feature block, the **Spec:** paragraph as fallback, filename as default. One pairing function feeds the board, coverage, the walk and the console. Closes a real defect: a brief whose promises live in two specs used to put a standing false instruction on the primary surface, inviting a second definition of already-signed behavior.
  • Chat is a walk surface — every reply opens with a machinery-authored header line (the statusline's own string, delivered by the per-prompt hook and pasted verbatim). It cannot drift, and unlike the statusline it persists in the transcript.
  • Plain words at the boundary — stage glosses and artifact translation everywhere a human reads, including the Stop hook, which now opens ■ Prove — not done: …. Ledger ids never change.
  • Time is part of position — the lane's cost is read from its own flight recorder ("98s last full run"), never estimated.
  • The console leads every call to action — your-turn cards point at the studio first; the In-flight card carries the full promise list with per-promise state, the measured lane cost, the signature button on the row, and arrivals as now/after buttons.
  • The console is a residentpreview now spawns a detached console that survives MCP respawns; connecting the MCP inside a create-cmp app ensures one at session start; a crashed console is loud on four surfaces (statusline · console down, doctor's console-liveness finding, the injected prompt, and the tool result).

Studio drive mode

Third report of the same complexity problem, fixed by demotion rather than another aggregation layer.

  • Drive replaces Overview as the driving surface: the live chain, the walk cards, the queue with its buttons — with the page's own digest and history folded away.
  • Pages answer first — every mirror section renders its verdict, with the complete derived corpus behind one "Read the full …" disclosure. A section the queue points at greets open, and "take me there" opens the folds on the way. The spec-mirror principle is untouched; only default expansion changed.
  • The live chainRequest: <the ask> · ✓ 1 → ◉ 2 → ○ 3 · now: step 2 of 3, in the studio, the injected prompt, and qa/walk-status.mjs. Three labeled provenance tiers: the request is recorded mechanically from the human's own prompt; the steps are agent-declared through the new node qa/plan.mjs and always carry their age; the lane/render markers say what is actually running and override. The chain gates nothing — the walk stays the truth — and its ephemeral files are excluded from the receipt's hashed inputs, so a prompt can never invalidate a receipt.

Release evidence

  • Fleet check PASS — a scratch app stamped from this tree and its full lane run; harnessIntegrity: PASS (@create-cmp/harness 0.16.0 — 40 files verified).
  • Engine suite 1148/1148; inspector suite 556/556; plugin bundle rebuilt and verified current.
  • Evidence rung: L1 desktop. No device was attached for this release, so e2eSmoke, androidChecks and tokenDrift SKIPped — v0.17.1 shipped with L2 device proof and this one does not. The changed surface is Node-side (lane libraries and console rendering) and CI's stamp + assembleDebug lane passed on the merge commit, so the risk is low, but the rung is genuinely lower and is recorded rather than glossed.

Full changelog: v0.17.1...v0.18.0

v0.17.1

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 25 Aug 10:13

Fixed

  • The walk can no longer be installed and silently unwired. qa/walk-status.mjs is
    lane code, replaced wholesale on upgrade --harness; its two surfaces are not — the
    statusLine and the UserPromptSubmit hook live in .claude/settings.json, which is
    app-owned and, correctly, never clobbered. So an app that hand-edited its settings could
    take the machinery and lose the wiring, and the failure mode was silence — the exact
    thing the walk exists to end, in the one shape nothing in the system could notice.
    create-cmp doctor now carries a walk-wiring finding: warn when the script is
    installed but settings.json does not invoke it, naming which half is missing, healable
    with --fix from the engine's own template (read at fix time, so the heal cannot drift
    from what a fresh scaffold gets). The heal only ever claims an unclaimed slot — an app
    that set its own status line keeps it, an existing UserPromptSubmit is appended to
    rather than replaced, settings it cannot parse are never written over, and a second run
    is a no-op.

  • Minimal mode no longer ships a status line pointing at a lane it deletes. 0.17.0 added
    a top-level statusLine to the template — a command surface classifyHook never saw,
    because it is not a hook. minimalHookSettings therefore passed it through untouched,
    giving a minimal scaffold a status line reading qa/walk-status.mjs, a file minimal
    removes. The command is guarded (test -f … || true), so it printed nothing rather than
    erroring: dead config that fails silently, which is precisely why it survived review. The
    lane-reference rule now applies to every settings surface that carries a command, not only
    to hooks.

  • The Node 18 lane was red on main across two releases, and it was telling the truth.
    package.json declares engines: ">=18" and the CI matrix tests 18, but
    scripts/check-plugin-sync.mjs used import.meta.dirname (Node 20.11+) — so the
    plugin-drift detector was dead on load for anyone on the declared floor, and its test
    file took the whole Node 18 job down with it. Both sites now resolve the long way
    (fileURLToPath(import.meta.url)). A new test/node-floor.test.mjs scans every shipped
    .mjs for APIs newer than the declared floor, so the next violation fails locally rather
    than becoming background noise in a job nobody reads.

Note

upgrade --harness was not at fault here and needed no change: .claude/settings.json
lands in the sweep's applied bucket, so an app that never touched its settings receives the
walk wiring along with the machinery. Verified against the showcase (0.14.1 → 0.17.0).

No change to @create-cmp/harness (0.15.0) or @create-cmp/inspector (0.8.0) — both
version independently and neither was touched.

v0.17.0 — the walk, and a front door that signs

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 24 Aug 21:06

Ships @create-cmp/inspector 0.8.0 (the console) and @create-cmp/harness 0.15.0
(the walk lands in every generated project's lane).

Added

  • The walk — you always know what it's doing and whose turn it is
    (docs/features/walk-status.md; born from the navigation-ia session: 20+ prompts, three
    interleaved walks, no shared map). Every governed change is now a walk through six
    stages spoken in human vocabulary — Decide · Design · Contract · Build · Prove ·
    Sign-off
    — with spec clauses rendered as promises ("keeping promise 5 of 7", in
    the clause's own words). It is a PROJECTION of the existing feature-board derivation
    (phase + nextStep), never new state. Surfaces, layered by reliability: qa/walk-status.mjs
    (cards · --statusline · --inject · --json, fail-open by contract), the template's
    statusLine (always-visible position, no agent involved), a UserPromptSubmit hook that
    re-anchors the agent with derived position + protocol on EVERY prompt (decay-proof:
    re-told, not remembered), and the contract's walk protocol (upfront itinerary with
    "stops for you: N", quiet one-line transitions, loud stop cards at human gates).
    Work no open walk accounts for renders as ▲ ARRIVED, UNPLANNED with the journal's
    reason — interleaving becomes an explicit choice, never an ambush. Deliberately NOT
    a second Stop hook: Stop stays the receipt gate alone (test-pinned); the statusline
    does the footer's job better.
  • The front door signs. Every row in Overview's "What needs you" queue now carries its
    own control — Approve / Re-approve / Accept — with read it first beside it.
    This supersedes the front door's original "names the act, never signs" rule: what that
    rule protected (never sign what you have not read) is served by the evidence already on
    the row plus one-click read-through, not by a forced round trip. It is not a second
    path — the rows emit the same .approve-btn / .feature-accept-btn contract the owning
    sections do, so one approve endpoint, one accept endpoint, one ledger.

Fixed

  • A refusal now surfaces on the panel the click came from. The approve/accept error
    path had exactly two boxes, on the Approvals and Features panels; a refusal triggered
    anywhere else wrote its reason into a hidden element on a tab the human was not looking
    at — a silent failure. Errors resolve to the clicking panel's .sig-error box, with the
    original ids as fallback.

v0.16.0 — the studio console's front door

Choose a tag to compare

@kvdm-co-pilot kvdm-co-pilot released this 23 Aug 19:12

Ships @create-cmp/inspector 0.7.0 — the console lives in that package, so the
front door is released there and picked up by create-cmp-cli 0.16.0.

Added

  • The studio console has a front door. The console had nine peer sections and no
    hierarchy of attention above them, so the returning owner's three questions were
    answered in four places: the queue as a rail widget pointing at rows scattered across
    other tabs, "what changed since I last looked" behind a tab you had to know to open,
    and the lane verdict behind another. The new Overview section (the default landing
    tab) answers all three in the order they get asked — what needs you (the human queue,
    each act carrying the evidence to judge its urgency: a drifted artifact's
    changed/still-signed file split, a proven feature's clause tally and receipt) · what
    changed
    (the digest, retired as a tab into this page) · is it proven (lane glyph,
    verdict, rung, signing tally). It derives nothing of its own and grows no signature
    control — sign-where-you-read is unchanged, and it jumps you to the section that owns
    each act. The rail strip collapses to a pointer in the same move: it keeps the counts
    (status visible on every tab) and hands off with "N things need you → Overview", so the
    rail says that something waits and the front door says what.
  • Evidence renders the test tally the receipt already carried. qa/verify.mjs writes
    each test step's JUnit summary into details; the receipt bridge was stripping it, so
    the release-readiness report could only say unitTests PASS where
    214 tests · 0 failed · 3 skipped was sitting on disk. The step's own note (which
    affected-test filter ran, when a CACHED verdict was earned) renders too.
  • The digest's commits name their files (--name-status). Non-governed changes — the
    data layer, the version catalog, build files — have no approval row and therefore had no
    console surface at all: proven by the lane, reported to no one.

Fixed

  • @create-cmp/inspector 0.6.2 — the mcpName field the MCP registry's ownership
    check requires.
    The registry verifies that a server's published npm package carries
    "mcpName" equal to the server.json name it is submitted under; that field was
    prepared in the launch runbook's patch but never landed, and 0.6.1 published without
    it. npm versions are immutable, so the field arrives as 0.6.2 rather than a
    re-publish. The package stays independently versioned (GROUND-TRUTH.md's
    "deliberately independent" note is unchanged) — this is the anti-impersonation
    handshake, not a version-policy change.