From 555174425f3b47725d176f0765b4bffccc40fa00 Mon Sep 17 00:00:00 2001 From: Ralf Anton Beier Date: Sat, 8 Aug 2026 17:28:16 +0200 Subject: [PATCH 1/2] feat(skills): integrate varve, add the red-first oracle rule (plugin 0.20.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the two open skill issues, with every claim tested by execution first (varve 0.13.0, layer 2026.08.2) rather than taken from the issue text. #160 — oracle-gate-a-change 0.4.0 New step 2c "Confirm the oracle is RED — before implementing". 2b proves a gate *runs*; 2c proves it can *fail*. Cites only the instance that could be reproduced: claim-check's `count-max` fails only when n > max, so a pattern matching 0 times stays green — the code's own comment now says so, and `count-min` is the fix. The other two instances in the issue could not be reproduced, so they are not cited as evidence. #161 — varve integration - roster: varve and ordeal added (report-tool-friction already referenced both, but pulseengine-toolchain.md defined neither) - feature-loop 0.3.0: step 0 pins the loop's tools, with the exact copy-pasteable realm setup that was run end-to-end - release-artifact-pipeline 0.3.0: varve layers as a Track B channel, and deposit as an org release-standard enforcer (it excludes tools whose releases lack cosign-signed sums — the workflow records ordeal's exclusion and its rejoin at v0.18.0) - report-tool-friction 0.4.0: report the layer + digest, not just a version - clean-room-verification 0.2.0 + release-execution 0.2.0: independence as a release gate for solo-agent-authored repos (varve REQ-INDEP-001) gate-potency 0.2.0 The varve tamper test lands here, not under #160 — it is a negative control on a shipped check, not a red-first example. Adds the rule that a negative control needs a paired positive one: the same bogus trust root makes `varve verify` exit 1 with no realm and is ignored with one, which isolates the mechanism instead of merely showing something fired. Documents the workflow that works today; the trust-root onboarding gap it works around is filed as pulseengine/varve#34. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01G5qpB7zvxLvdrvn5YRyj4R --- .../.claude-plugin/plugin.json | 2 +- .../memory/pulseengine-toolchain.md | 9 ++++ .../skills/clean-room-verification/SKILL.md | 15 +++++- .../skills/gate-potency/SKILL.md | 20 ++++++- .../skills/oracle-gate-a-change/SKILL.md | 33 +++++++++++- .../skills/pulseengine-feature-loop/SKILL.md | 53 ++++++++++++++++++- .../skills/release-artifact-pipeline/SKILL.md | 30 +++++++++-- .../skills/release-execution/SKILL.md | 18 ++++++- .../skills/report-tool-friction/SKILL.md | 21 +++++++- 9 files changed, 189 insertions(+), 12 deletions(-) diff --git a/claude-tooling/plugins/pulseengine-claude/.claude-plugin/plugin.json b/claude-tooling/plugins/pulseengine-claude/.claude-plugin/plugin.json index bd3b53b..ff05339 100644 --- a/claude-tooling/plugins/pulseengine-claude/.claude-plugin/plugin.json +++ b/claude-tooling/plugins/pulseengine-claude/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "pulseengine-claude", - "version": "0.19.0", + "version": "0.20.0", "description": "PulseEngine methodology as installable Claude Code tooling \u2014 philosophy + toolchain + repo-taxonomy + model-operating-contract memory, memory-persistence hooks (situational awareness at session start, working-context checkpoints across sessions/compaction), plus sixteen procedural skills (clean-room verification, release execution with a V-model traceability gate, oracle-gating, the full feature loop, the standardized release-artifact pipeline, tool-friction reporting, session-learning capture, STPA/STPA-Sec hazard-analysis audit, backend-agnostic proof synthesis, full bidirectional traceability audit across the V, greenfield verification bootstrap, release planning with an issue-driven delivery loop, an incremental issue-hunt loop, a quiesce-gated post-release repo-hygiene sweep, and a gate-potency audit that proves standing CI checks can still fail).", "author": { "name": "PulseEngine", diff --git a/claude-tooling/plugins/pulseengine-claude/memory/pulseengine-toolchain.md b/claude-tooling/plugins/pulseengine-claude/memory/pulseengine-toolchain.md index c15d5b9..8757d13 100644 --- a/claude-tooling/plugins/pulseengine-claude/memory/pulseengine-toolchain.md +++ b/claude-tooling/plugins/pulseengine-claude/memory/pulseengine-toolchain.md @@ -41,6 +41,15 @@ Map of the PulseEngine tools. Each lives in `/Users/r/git/pulseengine/` on **mcp** — Rust framework for building Model Context Protocol servers and clients (the MCP layer rivet/spar expose). Published to crates.io. +**ordeal** — certificate-checked QF_BV SMT. Ships inside the varve layer; a decision procedure whose results carry a checkable certificate rather than being trusted on the solver's word. + +**varve** — toolchain **layer manager**, and the reason "which toolchain produced this artifact?" is answerable. Distributes the whole tool set as one signed, dated, digest-pinned OCI layer (`YYYY.MM.P`) on `ghcr.io/pulseengine/varve/layers`; per-project `varve.toml` pin discovered by walking up from cwd; offline verification against a trust root; anti-rollback counters; content-addressed core so layers coexist and switching is `cd`; PATH shims; `self-update` (old-verifies-new); `deposit` / `export-bazel` for CI. Sits **outside** the layer it installs — it must exist before any layer does. Native Rust CLI, so witness MC/DC and scry are N/A to varve itself (they target the Wasm the layers carry). + +Two properties of varve are load-bearing for the other skills, both verified by execution (2026-08-08, v0.13.0): + +- **No silent fallback.** Outside a pinned project a shim *refuses* — `error: no varve.toml found …`, exit 1 — rather than running whatever is on PATH. Inside one it dispatches and exits 0. +- **Realms beat the ambient environment.** When the pin names a `realm`, a committed `varve-realms.toml` supplies the registry *and* the trust root, and a hostile `VARVE_TRUST_ROOT` cannot substitute a different root. Negative control: the same bogus root makes `varve verify` exit 1 with no realm, and is ignored with one. Prefer the realm path — it needs no environment variable and is the stronger of the two. + ## How they compose The procedure for composing these tools end-to-end (spar → WIT → rivet → code → witness → sigil → smithy) lives in the **`pulseengine-feature-loop` skill** shipped with this plugin, not here. This memory is the directory; the skill is the recipe. diff --git a/claude-tooling/plugins/pulseengine-claude/skills/clean-room-verification/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/clean-room-verification/SKILL.md index fd579e0..b3f749f 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/clean-room-verification/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/clean-room-verification/SKILL.md @@ -3,7 +3,7 @@ name: clean-room-verification description: This skill should be used whenever findings, audits, code-review results, claims, or analysis output need to be validated before reporting — including "verify this", "double-check this", "audit", "is this actually true", "before I report this", "before we merge this", or whenever an agent's summary needs independent confirmation. ALWAYS use this skill before delivering non-trivial inspection results, before claiming a property holds, and whenever agent-produced hashes, digests, versions, file paths, or flag names appear in a report. metadata: author: pulseengine.eu - version: "0.1.0" + version: "0.2.0" --- # Clean-room verification @@ -44,11 +44,24 @@ This is the smithy ritual in PulseEngine vocabulary. The point is to catch hallu - **An agent's summary describes intent, not what landed.** Check the diff. Check the file. Check the symbol. Check the digest. - **"It passed CI" is a statement about the gate's coverage that day, not a timeless guarantee.** Re-verify on the current artifact, not on the historical green check. - **Evidence-backed "blocked" beats forced "done."** If verification surfaces a real blocker, report the blocker — that's the honest path the user explicitly prefers. +- **In a solo-agent-authored repo, this stops being on-demand and becomes a release gate.** Automation + can close almost every gap in such a repo except one: **the authoring agent assigning itself + `verified` status.** No mutation score, coverage number or green board closes that — it is a + structural independence gap, and it is the finding that repeated audits keep returning. The + standing expectation: a release's scope gets a fresh-context reviewer who re-derives every claimed + verdict from evidence (runs the named tests, re-checks the oracles, attempts to refute), with + **reviewer identity, date and outcome recorded on the artifacts** — and the release gate refuses a + scope whose independent review is absent or dissenting. Canonical statement: varve's + `REQ-INDEP-001`, *"No requirement is verified on the author's word alone"* (approved, v0.14.0). + This is the strongest independence achievable without a second human; treat it as the default for + any repo where one agent both writes and blesses the work. ## Anti-patterns - Skipping verification because "the agent ran successfully." The agent's exit code is not evidence the claim is true. - Re-using the verifier's *own* prior context to verify its findings. The whole point is clean-room. +- **Marking a requirement `verified` on the strength of having implemented it.** Authorship and + verification collapsing into one agent is the gap; a stronger mutation score does not fill it. - Burying the verifier's verdict in a footnote. Lead with what was independently confirmed; the rest is suspected. - Verifying with a soft oracle (asking an LLM to read the spec back). See [`oracle-gate-a-change`] — mechanical oracle preferred. diff --git a/claude-tooling/plugins/pulseengine-claude/skills/gate-potency/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/gate-potency/SKILL.md index 21b773a..7f286e9 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/gate-potency/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/gate-potency/SKILL.md @@ -3,7 +3,7 @@ name: gate-potency description: This skill should be used to audit whether a repo's EXISTING required CI checks can still fail — the vacuous-gate class, where a check runs, reports green, and cannot go red. Use it when the user says "audit our gates", "can our CI actually fail", "is this check real", "why did that slip through a green board", when inheriting or taking over a repo, at the campaign self-verify interval, and before a release whose evidence rests on CI being green. Presence is not potency — a non-empty required-checks list proves a gate exists, never that it bites. The method is negative control (inject a violation, confirm red) plus six mechanical audits for the ways a gate goes inert. Composes with oracle-gate-a-change (which covers wiring an oracle you are authoring), release-execution (fire before tagging) and repo-hygiene (same cadence). metadata: author: pulseengine.eu - version: "0.1.0" + version: "0.2.0" --- # Gate potency — can this check still go red? @@ -43,6 +43,24 @@ mutant, a broken trace link, a `sorry` without the exemption, a deleted assertio afterwards. Everything below is a cheap proxy; this is the actual evidence. Do it on a scratch branch and record the run URL — that link *is* the potency evidence. +**Worked example — a supply-chain check, audited in minutes.** To establish that varve's digest +verification actually bites rather than merely existing, append one byte to a tool inside the +content-addressed core and re-run `varve verify`: + +``` +error: tool 'rivet' does not match its signed digest sha256:53af23a… — the binary was altered +``` + +Restore, and it is green again. That is potency evidence; *reading* the verification code is not. + +**Pair the negative control with a positive one.** A control that goes red proves something fired — +not that the *mechanism you think* fired. Show it biting in one configuration and correctly inert in +another. Same audit: pointing `VARVE_TRUST_ROOT` at a bogus key makes `varve verify` exit 1 when the +pin names no realm, and is *ignored* (exit 0) when it names one — which is exactly the claim that a +realm's trust root cannot be substituted by the ambient environment. Either result alone proves +little; the pair isolates the mechanism. Without the red case the test may be vacuous; without the +green case you have not shown the red came from the property rather than the environment. + ### 2. Reads what it writes Assert the gate parses a path the tool actually produces. Compare the parsed path against the real output/artifact layout, not against the docs. Version bumps silently relocate results files. diff --git a/claude-tooling/plugins/pulseengine-claude/skills/oracle-gate-a-change/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/oracle-gate-a-change/SKILL.md index cd072ca..a2c3393 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/oracle-gate-a-change/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/oracle-gate-a-change/SKILL.md @@ -3,7 +3,7 @@ name: oracle-gate-a-change description: This skill should be used whenever proposing, designing, landing, or evaluating a consequential change on a PulseEngine project (rivet, spar, witness, sigil, meld, loom, synth, wohl) — including "propose a change", "add a feature", "fix a bug", "is this safe to land", "what verifies this", "what's the gate", "how do we know this is correct", "before merging this", or whenever a code change needs a mechanical check to back it. ALWAYS use this skill before claiming a property holds and before recommending a change be merged. metadata: author: pulseengine.eu - version: "0.3.0" + version: "0.4.0" --- # Oracle-gate a change @@ -55,6 +55,34 @@ This is the one step where doing it wrong feels identical to doing it right: you Field cases this rule comes from: an oracle behind two headline size claims existed for two releases and was never CI-wired; the next release shipped its central differential oracle referenced by nothing, with a fully green PR board; a later audit found ~70 of ~150 repro scripts undeclared or unwired. +### 2c. Confirm the oracle is RED — before implementing + +Writing the oracle and wiring it still leaves the question the whole method rests on unanswered: +**does it fail when the property is false?** Run it *before* the implementing change and read the +result. **An oracle that passes before the change is not an oracle** — it is measuring something +other than the property, and it will ship as evidence. + +The two commonest causes, both of which look correct in review: + +- **The predicate is satisfied by the initial or default state.** Zero-initialised values, empty + collections, absent files, a fresh entry point. The assertion is true before the feature exists. + Fix by making it position- or state-specific, not merely existential. +- **It is an upper bound where a presence check was needed.** Field case, in this plugin's own gate: + `claim-check`'s `count-max` fails only when `n > max`, so a pattern matching **0** times stays + green — the code's own comment now reads *"greens a 0-match, since 0 > max is false"*. A claim + binding a doc's version string to `count-max` therefore went green precisely when the version + drifted and the string vanished. The `count-min` predicate exists to catch that drift-to-absent + case; pick the polarity that matches what you are asserting. + +**A fixture chosen after the property is written is suspect.** If you picked the input *because* the +test passed, you may have selected around the failing case. Ask what the property claims in general +and whether your fixture is the easy instance. + +This applies to **gates as much as tests**. A CI check whose predicate can silently match nothing is +the same failure with a longer blast radius, because a green check is read as evidence by everyone +downstream. Step 2b proves the gate *runs*; this step proves it can *fail*. Both are required — +see [`gate-potency`] for auditing checks that are already live. + ### 3. Attach a kill-criterion to the claim Per PulseEngine methodology, every claim should carry a falsifiable kill-criterion: "this claim would be wrong if X is observed." This is required for the philosophy to compose — without kill-criteria the falsification stance is empty. @@ -120,6 +148,9 @@ inert. Each of these has cost real time in this org: demonstrably able to fail there**. - **Asserting a gate is non-vacuous by *reading* it rather than by *mutating* it.** Vacuous gates look correct in review — that is exactly why they survive. Break the property and watch for red. +- **Running the oracle for the first time *after* the implementation.** A green result then is + ambiguous — it cannot distinguish "the change works" from "this never measured anything." The + red observation is not a formality; it is the only evidence the oracle discriminates at all. - "Review looks good" as the gate. Review is input; oracle is the gate. - "Tests pass" without saying *which* test exercises the new property. If you can't name it, it doesn't exist. - Skipping the oracle write because "we already have lots of tests." The relevant question is whether *this property* is checked, not whether *anything* is. diff --git a/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md index ecf3aed..0f5b174 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md @@ -3,7 +3,7 @@ name: pulseengine-feature-loop description: This skill should be used when doing a feature end-to-end on a PulseEngine project (rivet, spar, witness, sigil, meld, loom, synth, wohl, kiln) — including "implement a feature", "add a new requirement", "extend the architecture", "write a new pass", "ship a feature end-to-end", "do this properly with traceability", "model-driven implementation", or any feature work that should pass through the full AADL → WIT → typed traceability → oracle-gated code → MC/DC → attestation → verify loop. ALWAYS use this skill when the user authorizes feature work on a PulseEngine project and the work touches more than a single file. metadata: author: pulseengine.eu - version: "0.2.0" + version: "0.3.0" --- # PulseEngine feature loop @@ -22,6 +22,57 @@ This is a long-running explorer (see [`pulseengine-operating-contract`]): self-v ## The compose loop (ordered steps, each producing a concrete artifact) +### 0. Resolve the loop's tools through varve — pin before you build + +Every step below invokes a tool, and by default gets *whatever is on PATH*. That is the +mixed-toolchain hazard: half the pipeline running on one tool version and half on another, producing +an artifact no single toolchain ever built. Pinning a [`varve`] layer closes it by construction and +makes the outputs traceable to an exact toolchain. + +Two committed files — the realm supplies the registry and the trust root, so **no environment +variable is needed**: + +```toml +# varve-realms.toml — the trust universe; travels with the code +[realm.pulseengine] +registry = "oci://ghcr.io/pulseengine/varve/layers" +trust-root = "4e771dc62a08be89e3450f8cd807da58ff70af4a4e124ebf2d2b71684cfd9973" +``` + +```toml +# varve.toml — this project's pin +manifest-version = 1 + +[toolchain] +realm = "pulseengine" +channel = "rolling" +layer = "2026.08.2" +``` + +```sh +varve install # fetch + verify + lay down the layer +varve shim install # shims on PATH; switching projects is `cd` +varve which rivet # which binary runs here — and which layer it came from +``` + +- **State the layer when you report results.** `varve which ` prints the layer and manifest + digest; that identity is what makes "which toolchain produced this?" answerable later. A result + reported without it is not reproducible evidence. +- **A refusal is the feature.** Outside a pinned project a shim exits 1 rather than falling back to + an ambient binary. Do not "fix" that by bypassing varve — fix the pin. +- **Prefer the realm over `VARVE_TRUST_ROOT`.** The realm is authoritative and cannot be overridden + by the ambient environment; the env var can. See the roster entry in + [`pulseengine-toolchain`] for the negative control establishing this. +- If a repo has no pin yet, say so plainly rather than implying the loop ran pinned. Adding + `varve.toml` is a reviewable change like any other — and per [`varve`]'s design, the *only* way a + project ever changes layers. + +**Artifact:** a committed pin, and a layer identity attached to whatever the loop produces. + +> The trust-root value above is the **rolling** channel's provisional root, copied here because +> varve does not yet publish a canonical `varve-realms.toml` (pulseengine/varve#34). When it does, +> reference that file instead of pasting the key. + ### 1. Start in spar — model the architecture If the feature changes architecture (new component, new mode, new interaction, new resource sharing): diff --git a/claude-tooling/plugins/pulseengine-claude/skills/release-artifact-pipeline/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/release-artifact-pipeline/SKILL.md index f289026..c35b87b 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/release-artifact-pipeline/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/release-artifact-pipeline/SKILL.md @@ -3,7 +3,7 @@ name: release-artifact-pipeline description: This skill should be used when setting up, standardizing, auditing, or modifying a release artifact pipeline on a PulseEngine project — including "standardize release artifacts", "set up release workflow", "fix the release pipeline", "add cosign signing", "add SLSA attestation", "add SBOM", "switch to signed SHA256SUMS", "sign the wasm with sigil", "add a witness/scry gate to the release", "publish to crates.io / npm", "add a Pages verification dashboard", "audit release artifacts", "migrate off per-file .sha256 sidecars", or any GitHub Actions release.yml setup/refactor. ALWAYS use this skill when proposing or reviewing changes to a release.yml workflow, when adopting the PulseEngine release-artifact standard for a new repo, or before claiming a release pipeline is "compliant" or "signed". Covers all five tracks — native binaries, distribution channels (crates.io + npm), wasm signing (sigil + cosign) and wasm verification gates (witness MC/DC + scry), the Pages verification dashboard, and rivet verification extraction. metadata: author: pulseengine.eu - version: "0.2.0" + version: "0.3.0" --- # Release artifact pipeline @@ -22,7 +22,8 @@ gets the full supply chain everywhere, while the *wasm* it ships gets weaker sig and no verification gate. Hold wasm to the **same bar** as the binary. - **Track A — native binaries** → the cosign+SBOM+SLSA bundle (canonical: synth). -- **Track B — distribution channels** → crates.io for everything Rust; npm for CLIs/tools. +- **Track B — distribution channels** → crates.io for everything Rust; npm for CLIs/tools; + **varve layers** for the toolchain as a pinned, signed set. - **Track C — wasm artifacts** → sigil + cosign signature, **and** a witness MC/DC gate **and** a scry abstract-interpretation gate. No wasm ships unverified. - **Track D — Pages verification dashboard** → witness-viz / scry-viz (canonical: @@ -88,12 +89,33 @@ mcp a stale unsigned manual script). The rule: wired to a root launcher via `optionalDependencies`), triggered `workflow_run` after the GitHub Release so the binaries exist. This is **not** rivet-only — every user-facing CLI (rivet, spar, …) should ship it. -- **More channels (OCI, editor marketplaces) are in scope later** — sigil's GHCR - `oras push` and rivet/spar's VS Code Marketplace are precedents; not required now. +- **varve layers — the canonical org-internal channel, and now shipping.** A tool's + signed release becomes an entry in a dated OCI layer via `varve deposit` + (`ghcr.io/pulseengine/varve/layers`); consumers pin *one layer* rather than N + independently-drifting tool versions. crates.io and npm remain the public channels — + the layer is how the toolchain is consumed as a set. `varve export-bazel` compiles a + Bazel checksum registry from the verified layer, so every hash Bazel enforces is a + transcription from the signed manifest **instead of TOFU**. +- **Editor marketplaces are in scope later** — rivet/spar's VS Code Marketplace is the + precedent; not required now. A Rust tool is compliant on Track B only when it is on crates.io **and** (if it's a CLI) on npm. crates.io-but-no-npm and npm-but-no-crates.io are both drift. +### The deposit workflow is an org release-standard enforcer + +This is the part worth internalising: `deposit-layer.yml` verifies each tool's release +against **that tool's own repo cosign identity**, and a tool whose release lacks +cosign-signed `SHA256SUMS.txt` is **excluded from the layer** with a notice rather than +deposited unverified. Exclusion is visible and dated — the workflow's own comments record +`ordeal is EXCLUDED until its releases carry cosign-signed sums`, then +`ordeal rejoined at v0.18.0 — its first cosign-signed release`. + +So Track A compliance stopped being advisory the day layers shipped: an unsigned release +no longer merely *fails an audit*, it **drops the tool out of the toolchain everyone +installs**. Treat a tool's absence from the current layer as a release-pipeline defect in +that tool's repo, and file it there per [`report-tool-friction`]. + ## Track C — wasm artifacts (same bar as the binary) Any repo that **ships or emits wasm** (component or module) must sign and verify it diff --git a/claude-tooling/plugins/pulseengine-claude/skills/release-execution/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/release-execution/SKILL.md index f5434cf..a90a3f4 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/release-execution/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/release-execution/SKILL.md @@ -3,7 +3,7 @@ name: release-execution description: This skill should be used when cutting, shipping, or finishing a release — including "ship it", "cut a release", "tag this", "release v0.X.Y", "take this to release", "work the PR queue to green", "finish the release tail", "publish", or any end-to-end release work that involves PRs, reviewers, merging, CI, tagging, GitHub Release, and crates.io publish. ALWAYS use this skill when the user authorizes autonomous release work or asks to "go as long as you can" on a release campaign. metadata: author: pulseengine.eu - version: "0.1.0" + version: "0.2.0" --- # Release execution @@ -72,9 +72,23 @@ The release does not get tagged until the V-model is closed for everything it cl The level-by-level closure rules — every requirement decomposed to architecture/design/code, and verified up through **unit, integration, and requirements-qualification** tests (with passing results), not just "has a `verifies` link" — are defined in [`traceability-audit`]; this gate is that audit run before tagging. It composes [`pulseengine-feature-loop`] (which produces the artifacts this gate audits) and [`clean-room-verification`] (verify the "the V is closed" claim cold, don't infer it from a green dashboard). +### 4b. Independence gate (blocking — solo-agent-authored repos) + +Step 4 checks that the V is *closed*. This checks **who closed it**. Where one agent both authored +the work and marked it `verified`, that status carries no independent evidence — the one gap no +mutation score or green board closes. + +- Every requirement in the release scope needs a **fresh-context clean-room review** + ([`clean-room-verification`]) that re-derives the verdict from evidence rather than reading the + author's summary. +- **Record reviewer identity, date and outcome on the artifacts**, so independence is auditable + later rather than asserted now. +- **Absent or dissenting review blocks the tag**, exactly like a broken trace link. Canonical + statement: varve's `REQ-INDEP-001` — *"No requirement is verified on the author's word alone."* + ### 5. Tag and release - **First assert the campaign invariants** ([`pulseengine-operating-contract`] → "Verify the machinery"): the protected branch's `required_status_checks.contexts` is non-empty (the gate is real), **HEAD's CI completed `success`** — not `cancelled` by a merge-train `cancel-in-progress`, which leaves the commit unverified — and everything previously claimed "released" actually carries a tag + a `success` run. A green-looking dashboard over an empty gate or a cancelled HEAD run is not a tag-able state. -- Once the queue is empty, main is green, **and the traceability gate (step 4) passes**, **PAUSE for fork**: confirm the new tag (`v0.X.Y`) and whether this is the right moment to cut, vs. holding for more. Use `AskUserQuestion` — this is a genuine decision boundary, not a routine step. +- Once the queue is empty, main is green, **and the traceability gate (step 4) and the independence gate (step 4b) pass**, **PAUSE for fork**: confirm the new tag (`v0.X.Y`) and whether this is the right moment to cut, vs. holding for more. Use `AskUserQuestion` — this is a genuine decision boundary, not a routine step. - After confirmation: tag, push tag, watch the release workflow; the release is "verified" only once that run completes `success`. ### 5b. Mind the notes-vs-assets race diff --git a/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md index 689b84d..44b5f90 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md @@ -3,7 +3,7 @@ name: report-tool-friction description: This skill should be used whenever a PulseEngine tool (rivet, spar, witness, sigil, meld, loom, synth, kiln, gale, scry, ordeal, varve, smithy, temper — the roster lives in the pulseengine-toolchain memory) produces friction during real work — it errors, crashes, produces wrong or surprising output, is missing a capability you needed, has confusing/undocumented behavior, or forced you into a workaround. ALWAYS use this skill the moment you notice yourself working *around* a tool instead of *with* it, or saying "this should just work but doesn't." The friction is the signal; capturing it as an issue in the tool's own repo is the action. Fires inside [`pulseengine-feature-loop`] and [`release-execution`] and any standalone tool use. metadata: author: pulseengine.eu - version: "0.3.0" + version: "0.4.0" --- # Report tool friction @@ -52,6 +52,25 @@ reports a stale capability. Three measured instances of this exact waste: - a machine running rivet **0.28.0 against a v0.32.0 release** — four minor versions of shipped fixes invisible to everything running there. +**Under a [`varve`] pin, name the layer as well as the version.** `varve which ` +prints the binary, the layer and the manifest digest — so a capability gap filed from a +pinned project is reported against a *specific, reproducible* toolchain rather than +whatever happened to be on PATH: + +```sh +varve which # layer + digest — include this in the issue + --version +gh release list -R pulseengine/ --limit 1 +``` + +A pin makes staleness deliberate rather than accidental, but it does **not** make it +impossible: a project frozen on an old layer is exactly the case that produced the +13-days-late report above. If the pinned layer predates the fix, the finding is "our pin +is stale", not "the tool cannot do Y". (`varve status` is intended to surface line +staleness and known problems, but as of v0.13.0 it requires an ingested line-status +envelope — `no line-status document cached for line …` — and none is published yet, so +it is not usable for this check today.) + A bug or a crash is worth filing immediately regardless. A *missing feature* is worth thirty seconds of version-checking first, because the cost of getting it wrong is a maintainer re-deriving a fix they already shipped. From 865b46c99e4f6b42b34116b683d0c227462a525d Mon Sep 17 00:00:00 2001 From: Ralf Anton Beier Date: Sat, 8 Aug 2026 17:31:05 +0200 Subject: [PATCH 2/2] =?UTF-8?q?fix(skills):=20varve=20is=20a=20tool,=20not?= =?UTF-8?q?=20a=20skill=20=E2=80=94=20drop=20the=20dangling=20bracket=20re?= =?UTF-8?q?fs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The [`name`] convention resolves to skills and memory files only; it is never used for tools on main. Three new [`varve`] refs would have resolved to nothing, in a plugin whose subject is not shipping unverified assertions. Uses the roster's bold convention instead, and unnests one bold span that broke the markdown. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01G5qpB7zvxLvdrvn5YRyj4R --- .../skills/pulseengine-feature-loop/SKILL.md | 4 ++-- .../pulseengine-claude/skills/report-tool-friction/SKILL.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md index 0f5b174..c8122ef 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/pulseengine-feature-loop/SKILL.md @@ -26,7 +26,7 @@ This is a long-running explorer (see [`pulseengine-operating-contract`]): self-v Every step below invokes a tool, and by default gets *whatever is on PATH*. That is the mixed-toolchain hazard: half the pipeline running on one tool version and half on another, producing -an artifact no single toolchain ever built. Pinning a [`varve`] layer closes it by construction and +an artifact no single toolchain ever built. Pinning a **varve** layer closes it by construction and makes the outputs traceable to an exact toolchain. Two committed files — the realm supplies the registry and the trust root, so **no environment @@ -64,7 +64,7 @@ varve which rivet # which binary runs here — and which layer it came from by the ambient environment; the env var can. See the roster entry in [`pulseengine-toolchain`] for the negative control establishing this. - If a repo has no pin yet, say so plainly rather than implying the loop ran pinned. Adding - `varve.toml` is a reviewable change like any other — and per [`varve`]'s design, the *only* way a + `varve.toml` is a reviewable change like any other — and per **varve**'s design, the *only* way a project ever changes layers. **Artifact:** a committed pin, and a layer identity attached to whatever the loop produces. diff --git a/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md b/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md index 44b5f90..5296bbe 100644 --- a/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md +++ b/claude-tooling/plugins/pulseengine-claude/skills/report-tool-friction/SKILL.md @@ -52,7 +52,7 @@ reports a stale capability. Three measured instances of this exact waste: - a machine running rivet **0.28.0 against a v0.32.0 release** — four minor versions of shipped fixes invisible to everything running there. -**Under a [`varve`] pin, name the layer as well as the version.** `varve which ` +**Under a varve pin, name the layer as well as the version.** `varve which ` prints the binary, the layer and the manifest digest — so a capability gap filed from a pinned project is reported against a *specific, reproducible* toolchain rather than whatever happened to be on PATH: