- The oracle harness masks the climb to the root a /-prefixed target
produces (<UP_TO_ROOT>/): the number of `../` is the staged tmpdir's depth
(7 on macOS, 2 on Linux), not the verb's behavior. surface-brief-path-slash
re-recorded.
- Two context test helpers canonicalized their temp dir, which on Windows
yields a \\?\ verbatim path that takes `/` literally; they strip the prefix
like Node's realpathSync. The critique-storage identity test compares
against the platform's own resolved path.
- Every job that drives the binary end to end (live-e2e smoke and full,
accept-cleanup, the DeepSeek sweep, the remote CLI smoke) builds it from
the checkout first; before, they looked for a release that does not exist.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
The detector is open source. The rules it ships were already public in this
repo's git history and in every npm tarball of the JS engine, so a closed
binary bought nothing it could keep; the moat is the service (the catalog,
the labs, the review pipeline), not the check functions. Keeping them behind
a prebuilt archive cost a C-ABI, an exact toolchain pin, a build-time
download, a second release to order ahead of every engine release, and a
serde layer that had to serve two encodings.
Deleted
- crates/core/src/ffi.rs, crates/core/build.rs, crates/core/tests/boundary.rs
and the shim modules under src/checks and src/browser.
- crates/foundation/src/boundary.rs and the postcard dependency.
- DETECTOR_VERSION, scripts/check-detector-release.mjs and its test, the
check:detector-release script, the detector gate and
IMPECCABLE_SKIP_DETECTOR_CHECK in scripts/release.mjs.
- scripts/lib/detector-bundle.mjs and tests/detector-bundle.test.mjs (the
vendoring path for the closed browser bundle).
- scripts/build-browser-detector.js and the build:browser script (a stub
since the JS engine left the tree).
- xtask's detector-archive subcommand and its public-repo lookup.
Came back
- crates/core is now the rule logic itself: every check_* / scan_*, the
browser adapters, the visual-contrast decisions. It re-exports foundation
as before, so no consumer changed. Its vectors dispatcher is the union of
both id tables again, and tests/vectors.rs replays the frozen vectors
straight through it.
- crates/wasm and crates/xtask join the workspace. cargo xtask bundle builds
the in-page bundle from browser-bundle/ plus the wasm core, writes
dist/, refreshes the tracked crates/live/assets/detect-antipatterns-
browser.js, and writes extension/detector/. bun run build:extension runs
it instead of downloading.
- crates/live/assets/detect-antipatterns-browser.js is tracked again; live
mode embeds it and serves it as /detect.js.
- Serde is back to plain derives: no is_human_readable branch in
js::json_number, derived Serialize for Rgba and BrowserFinding with their
skip_serializing_if attributes.
- profile.release has lto = "fat" again; rust-toolchain.toml is plain
stable plus the wasm32 target. The rust, rust-windows and oracle CI jobs
lose continue-on-error and can be required.
Verified
- cargo build --workspace --all-targets: clean, no warnings.
- cargo test --workspace: 346 pass, 0 fail (the 8 boundary tests are gone
with the boundary).
- cargo build -p impeccable-wasm --target wasm32-unknown-unknown --release: ok.
- cargo xtask bundle && cargo xtask bundle --check: reproducible; the
regenerated bundle is committed (it differs from the archived one, which
was built with a pinned rustc and lto = false).
- cargo build --release -p impeccable: no linker warnings, 12.5 MB (the
same source at lto = false is 13.1 MB).
- oracle: 795 pass, 0 fail, 0 accepted deltas, 0 missing goldens.
- bun run build, bun run build:extension, web-ext lint (0 errors,
8 warnings), bun run test: 363 + 80 + 1 + 1 + 133 + 180 + 4 pass, 0 fail.
- impeccable detect --no-config --json tests/fixtures/antipatterns: 128.7 ms
median of 5.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
The engine binaries move from the impeccable-dist channel to this repo's own
GitHub Releases (tag engine-v<ENGINE_VERSION>), and the closed detector the
engine links arrives as detector-v<DETECTOR_VERSION> releases on the same
repo. This commit wires the public side for that; the crates themselves land
in the next commit.
- Launcher (sh + cmd), npm shim, fetch-engine and check-engine-release now
download from github.com/pbakaus/impeccable/releases/download/engine-v<X>/.
- release.mjs gains `engine`: verifies ENGINE_VERSION against the platform
package pins and the detector release, tags, pushes; release-engine.yml
builds the five targets and publishes. check-detector-release.mjs is the
matching release-order guard (with tests).
- Root Cargo.toml (workspace, lto = false with the reason), rust-toolchain.toml
(exact pin), DETECTOR_VERSION, /target ignored.
- CI: rust + rust-windows jobs and an oracle job that replays the goldens
against a source build, warn-only until the first detector release exists;
ci-test-plan exposes a `rust` output.
- docs/ENGINE.md (the crate map and the closed-detector mechanism) and the
CLAUDE.md engine, release-order and rules sections.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
The launcher, npm shim, and `impeccable install` all resolve the engine
binary for the pinned ENGINE_VERSION, so a skill/CLI release or a rust-swap
merge published ahead of the engine release + platform packages dead-ends
every install path. Add a mechanical guard:
- scripts/check-engine-release.mjs: verifies all five dist binaries +
.sha256 and the five @impeccable/cli-<os>-<arch> npm platform packages
exist for the pinned ENGINE_VERSION; names missing assets, exits non-zero.
Honors IMPECCABLE_DOWNLOAD_BASE.
- release.mjs: hard-fails release:skill and release:cli when assets are
missing; extension is exempt (vendored WASM detector, no engine exec).
- CI engine-release-ready job: runs the check, continue-on-error with a
loud ::warning until the first engine release exists (flip to false then).
- CLAUDE.md Releases: documents the enforced ordering.
Prepared with AI assistance (Claude Code).
Byte-identical copies of the engine repo's launchers (engine main
af7572c): the retired 3.x npm CLI on PATH or in ~/.impeccable/bin is
rejected by the engine-probe handshake instead of hijacking every verb;
impeccable.cmd's download path is rewritten as straight-line goto flow
(the parenthesized blocks expanded %url%/%cached% at parse time, making
it dead code) with certutil sha256 verification and a windows-arm64 ->
x64 asset fallback; the final error points at the release download
instead of npm i -g (npm still serves the 3.x CLI).
ci.yml: the generated-output check no longer diffs the deleted
cli/engine/detect-antipatterns-browser.js, and a new oracle job fetches
the pinned engine (bun run fetch:engine) and replays tests/oracle/
against it. The job is continue-on-error with a loud warning until the
first engine release exists; flipping it to required is a release-time
toggle, documented in the workflow.
Verified here: sh -n on both launcher copies, bun run build green, full
oracle replay against the rebuilt engine binary green (770 pass, 0
fail), and a launcher behavior test proving a fake 3.x CLI on PATH is
skipped while the download + checksum chain completes against a local
file server.
Prepared with AI assistance (Claude Code).
Upgrade @babel/parser from 7.29.7 to 8.0.4 and raise the repository Node 22 minimum from 22.12.0 to 22.18.0 across package metadata, CI, and npm documentation.
No parser API migration was required. Validated with the full local suite and refreshed GitHub CI on Node 22.18.0 and Node 24.
Prepared and validated with AI assistance from OpenAI Codex under maintainer instructions.
cursor[bot]: the schedule run shared github.ref with pushes to main, so
cancel-in-progress let the nightly full matrix and a main push cancel
each other. Scheduled runs now use a dedicated group.
This work was produced with AI assistance (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
A ground-up hardening of live mode, driven by a production session in a
nested-app monorepo that hit six distinct failure classes. Full design
rationale in docs/LIVE-REWRITE-PLAN.md; every Codex-reported failure now
has a mechanical fix and a regression test.
Roots: live/roots.mjs resolves appRoot/repoRoot/contextRoot once at boot
(keyed on dev-server configs, not monorepo brand markers), persists a
manifest, and every live CLI re-anchors onto it at startup, so a helper
run from the wrong directory can no longer fork session state. Context
files are discovered upward to the git root.
Render truth: variant_mounted / variant_mount_failed events give the
journal per-variant mount state; failures reach the agent's poll queue,
raise a persistent error card with Retry (no more localStorage wipe), and
an attach probe names root/dev-server mismatches explicitly. The browser
rehydrates from the server when localStorage is gone.
Svelte: the scaffolder now parses with the app's own svelte 5 compiler.
Control flow survives (an each collection crosses the contract as one
structured prop), keyed each blocks hydrate synthetic keys, and anything
a detached preview cannot support falls back to source-preview instead of
shipping a wrong scaffold. Preview modules live in per-publish revision
directories, defeating stale transform caches.
Accept: CSS is reconciled, not appended. Matching selectors are replaced,
params bake from params.json kinds, the compiler's unused-selector pass
prunes superseded rules (pre-existing dead rules protected), a selector-
loss postcondition refuses any write that would drop hand-written rules,
and live-complete refuses to finish while live plumbing remains in source.
Also: framework registry (live/frameworks/) with a crash-safe injection
journal, session-store snapshot caching with read-only reads, protocol
enum consolidation, steer Send button, honest DESIGN-panel empty states.
Testing: new unit suites (roots, AST scaffolder, accept CSS, accept
pipeline, framework conformance); e2e now fails on preview-tree 404s,
proves computed-style mount for every variant, drives the Tune panel
through baked params, and injects failures (broken mounts, republish,
storage loss). New runtime fixtures: monorepo-nested-vite (repo root !=
app root) and vite8-sveltekit-stateful (each blocks + state). Nightly
full-matrix cron. An independent adversarial review pass preceded this
commit; its blocker and major findings are fixed and regression-tested.
This work was produced with AI assistance (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Upgrade actions/setup-node to v7 across CI, sheriff, and generated-output sync workflows.
The action migrated to ESM and updated its cache internals; existing inputs required no migration. The PR's full exercised CI matrix passed on v7, and all changed workflows passed local YAML validation.
AI assistance: Codex performed dependency review and validation under maintainer automation instructions.
Lower the CLI engine floor to Node 22.12 so npx no longer falls back to stale 2.x releases for Node 22/23 users.
Add Node 22.12 CI coverage while preserving the stable required test check, and document the 3.2.1 CLI release notes including the detector and installer fixes already waiting on main.
AI-assisted-by: Codex
Derive a Gecko-compatible manifest at build time and package
extension-firefox.zip alongside the Chrome zip:
- background service worker is declared as an event-page `scripts`
entry (top-level listeners + in-memory Map run unchanged on Gecko)
- browser_specific_settings.gecko with id, strict_min_version 140.0,
and data_collection_permissions (required by AMO; honored on 140+)
- packZip helper parameterized over cwd/excludes; `*.DS_Store` strips
junk at every depth and .DS_Store is excluded from the staging copy
- guard against a missing background.service_worker shape
CI now builds the extension and runs a pinned `web-ext@8 lint` over
the staged Firefox tree (innerHTML warnings are non-blocking); the
unpacked staging dir is excluded from the uploaded artifact. The
release script attaches both zips and points to AMO.
Bumps the extension to v1.2.0 with a changelog entry.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
* Improve CI test coverage
* Stabilize live E2E harness
* Shard live E2E CI
* Cache live E2E CI dependencies
* Stabilize live E2E smoke CI
* Update generated live browser bundles
* Tighten live E2E smoke runtime
* Prevent live E2E smoke hangs
* Stabilize live E2E CI coverage
* Fix stale accept DOM cleanup
* Regenerate live browser outputs
CI was running `bun test` which ran jsdom fixture tests in bun, causing
timeouts. Now uses `bun run test` which runs unit tests in bun and fixture
tests in node.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Run tests on push and PR to main
- Build project and upload artifacts
- Use Bun for fast JavaScript runtime
This ensures code quality and prevents regressions.