The bounded record of answered targets evicted its oldest entry, and a
generate event naming an unrecognized target was admitted, so a Go
delayed past enough later resolutions could still open a session for
a request the CLI had reported as failed.
The admission rule is now positive: a generate event naming an agent
target is welcome only while that target is pending without a rival
lease, or when it comes from the session that answered it. Unknown
targets, evicted or never issued, are refused like any other superseded
Go, so eviction can never reopen a request. The record keeps 256
entries for the answering session's sake.
Tests: a Rust integration case and a Node protocol case (an envelope
naming an unheld target is refused and journals nothing; the same event
without an envelope is an ordinary Go); contract doc updated.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Only targets answered with a session were fenced against a delayed
generate event. A request that timed out (or ended in another failure
verdict the CLI already reported) was simply forgotten, so a Go whose
capture outlasted the timeout still opened a session nobody was told
about.
`resolve_agent_target` now records every terminal resolution, with the
answering session when the verdict carried one, and
`agent_target_refusal` refuses a generate event for any answered
target unless it comes from the answering session itself. The
browser_timeout instructions no longer send the agent to live-status
for a session that can no longer start. The overlay's refusal toast
covers both causes.
Tests: a Rust integration case and a Node protocol case (claim, time
out, late Go refused with 409 and nothing journaled), a unit test for
the timeout instruction; contract doc updated.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An overlay renews its lease right before Go, then captures and uploads
the element before its generate event leaves. When that outlasts the
lease and its result post is lost, a rescuer can claim the target and
Go, and the helper accepted both generate events: two sessions for one
request.
The generate envelope now carries this page's clientId, and the helper
refuses a generate event for a target that another page holds under a
live lease, or that was already answered with a different session
(`served_agent_targets`, recorded on every ok resolution): 409
`agent_target_already_served`, nothing journaled. The overlay treats
that refusal like a foreign session and hands the surface back. The
answering session's own event stays welcome, so the common path (result
post first, then the event) is unchanged.
Tests: two Rust integration cases (rival lease, answered elsewhere,
welcome for the serving session) and a Node protocol case, contract
pins for the envelope and the refusal handling, contract doc.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A winning overlay could reload after handleGo() minted a session but
before its result post landed. The close released its lease, the
server replayed the still-pending target, and another tab (or the
reloaded page, once it abandoned the unknown session) could claim it
and fire a second Go for a request that already had a session.
The overlay now names the target on the generate event it fires for it
(`agentTarget: {targetId, result}`, the same result it posts), and the
helper resolves the pending request the moment that event is accepted,
stripping the envelope before journaling. Whichever of the event and
the result post lands first answers; a page that dies between Go and
its result cannot leave the request pending, and a request whose event
never reached the helper is served exactly once by the rescuer.
Tests: a Rust integration case and a Node protocol case (claim, Go
event without a result post, verdict carries the session, a late claim
finds nothing pending, the journal carries no envelope), contract pins
for the handoff, and the contract doc.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Marking a target done on reply opened a window: an EventSource reconnect
replays the still-pending target while the result is on the wire, the
tab is GENERATING by then, so it declined busy, the server handed the
lease back mid-resolution, and another tab could claim and fire a second
Go. `agentTargetTaken` now covers both acting and done, so a replay of a
target this page took a lease on is ignored, and the late-mount watch
stops on either. Contract pins for the guard and the watch.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four review threads on the agent-target protocol and the hook stand-down.
Overlay: a tab acting on one target is busy for every other target
(`agent_target_in_flight`), so two held generate requests can never both
be claimed by one tab and the second Go can never overwrite the session
the first one minted. Every exit from actOnAgentTarget ends the acting
state, and teardown clears the target ledger, so a Go that never happened
does not refuse the next connection's targets. A miss after a granted
claim now declines (handing the lease back so another page or a remount
can serve) instead of posting a result that ended the request for every
tab.
Hook: the live-preview marker probe runs before the per-session edit cap,
so a file already past the cap stands down for a variants wrap instead
of emitting the suppression notice.
Server: each overlay's first no_match word extends the resolution grace
by the full window (its watch re-reports do not), so an overlay that
reports after another page's grace lapsed still gets its late-mount
watch instead of completing the roll call with a no_match verdict.
Tests: a Rust and a Node protocol case for the late overlay's grace, a
hook case for the cap-then-wrap order, and contract pins for the busy
check, the decline on a granted miss, and the teardown clear.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the unresolvable page's decline was the last word, the roll call
completed on it, the answer said pending:false, and the page's watcher
never started, so an element that mounted a moment later was still
answered no_match. A page's no_match is a provisional word: the server now
keeps an all-no_match roll call open for IMPECCABLE_AGENT_TARGET_RESOLVE_GRACE_MS
(default 3000) after the first such report, re-judging when the grace
lapses, so a page that keeps watching can still claim (the stale report is
dropped on its eligible claim); a busy report still answers at once. The
overlay reports a miss immediately and re-checks every half second for as
long as the answer says pending. A genuine no_match now takes about the
grace instead of tens of milliseconds, inside the server's hold.
Rust integration case for the late mount claiming within the grace, the
protocol case, and the contract assertions updated; the contract documents
the grace and its env override.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two ways a page's word could go stale after the resolve-before-claim
change: an element that mounts later than the quick re-checks, and an
EventSource reconnect that did not overlap the old connection (the server
drops that page's word on the close, replays the target, and the replay
guard ignored it, so the roll call waited on a word that never came).
A decline's answer now carries pending, like a denied claim does, so a page
that could not resolve the target reports the miss after the quick
re-checks (the roll call can complete on the other overlays' words) and
keeps re-checking once a second for as long as the server says the request
is pending, claiming the moment the element mounts; the server drops the
stale report on an eligible claim and ends the watch by answering
pending:false once the request resolved or timed out. The overlay tracks
its participation per target: a replayed target is ignored only while this
page is acting on it, and is otherwise handled again, so a busy or
unresolvable page re-declines (idempotent) and an idle page claims.
Unit, protocol, and contract cases updated; the decline answers now say
whether the request is still pending.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A page's element can be momentarily absent (a route still rendering, an
HMR commit mid-swap), so a failed resolution is not that page's final
word. The overlay now re-checks at 300, 700, and 1500 ms, claims the moment
the element mounts (the server already drops the stale report on an
eligible claim), and reports only the last miss. A genuine no_match now
takes about two seconds instead of tens of milliseconds, well inside the
server's hold.
Also normalizes a path separator in the new hook unit test, which failed
on rust-windows because the audit's file path carries backslashes there.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field-testing with two pages open showed the first-wins claim letting the
wrong page answer: a tab whose page lacks the element won the claim,
resolved the selector locally, and replied no_match while another page had
the element. The overlay now resolves the selector before any claim and,
when its page cannot resolve it, declines with reason no_match and the
resolution verdict; the same check runs on the busy-to-idle re-claim. The
server records that verdict on the report and, once every connected
overlay has declined, prefers a report that could serve later (a tab
mid-session or with an apply in flight, which answers busy so the agent
retries) over no_match, and returns the resolution verdict only when no
page can serve; the timeout uses the same precedence.
Also from the same field tests: a tab on another page of the app was
resuming this page's session from the per-origin localStorage cache after
a dev-server reload re-initialised it, then sat in GENERATING for a wrapper
it never renders and declined every later target. restoreSessionWithoutWrapper
now resumes a cached session only on the page that saved it, the check the
server-adoption branch beside it already applied.
Covered by two Rust integration cases, two protocol cases, and contract
assertions for the resolve-before-claim path and the page gate; the
cross-page scenario of the field harness passes on a two-page site.
AI-assisted: found by field tests and fixed with Claude Code under
maintainer direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field-testing the generate command on a Vite React app showed the
per-file stand-down was not enough: an edit to the wrapped App.jsx skipped
that file but still co-scanned the stylesheet it imports and spoke up
about it (a clean ack or findings) mid-session, which is exactly the noise
the stand-down exists to prevent. When the edited primary file carries the
markers, the whole PostToolUse event now returns skipped: live-preview
with the audit naming that primary, co-scanned stylesheets included; a
marked file that is only co-scanned still skips alone. A unit case covers
both, and the contract documents the event-level stand-down.
AI-assisted: found by field tests and fixed with Claude Code under
maintainer direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An EventSource reconnect opens a replacement connection under the same
page-level clientId before the old connection is seen to close, so the
close handler used to retire the reconnected overlay's report and hand
its lease back mid-flight. remove_sse_client now retires a client's word
only when no other connection still carries its id, the roll call counts
distinct overlays (plus id-less connections) instead of raw connections,
and the overlay ignores a replayed target it already handled, so a
reconnect never starts a second claim or a second Go. Covered by two new
HTTP cases in crates/cli/tests/agent_target.rs, a protocol case in
tests/live-agent-target.test.mjs, and the overlay contract suite.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Node-era server, CLI, hook, and pin halves of the generate command move
into the Rust workspace, with the protocol unchanged:
- crates/live: POST /agent-target is held open on a channel plus a timer
thread (the manual-apply deferred pattern), releasing its turnstile
ticket before it parks like /poll; /agent-target-result resolves it;
/agent-target-claim is the roll call with its renewable lease. SSE
connections carry the overlay's clientId: a late overlay is replayed
every pending target, and a disconnect retires that overlay's report,
releases its lease, and re-judges each roll call. Shutdown drains held
requests with server_stopping.
- crates/live/src/live_generate.rs: the live-generate verb (the router
already forwards every live* verb), same flags, verdicts, and
_instructions, spelled with the engine's self command.
- crates/hook: every entry stands down on live preview markers
(skipped: live-preview), checking the proposed content and the file on
disk for hook-before-edit.
- crates/context: pin accepts generate; the crate's command-metadata.json
copy carries its entry.
Tests: crates/cli/tests/agent_target.rs (six HTTP cases with an SSE reader),
tests/live-agent-target.test.mjs rewritten to drive the binary (28 cases,
registered in the live suite), hook stand-down cases, oracle goldens for
live-generate plus the re-recorded pin list goldens, the e2e prompt
assertion waiting for the journaled event, and the contract documented in
docs/CLI-CONTRACT.md.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Squash of the ten commits reviewed on PR #626, plus the last review
round's connection-aware roll call, before the rebase onto the Rust
engine: the generate command reference and router row, the overlay's
agent-target handling (roll call, leases, replay, rescue), the Node-era
live-server routes and live-generate CLI, the hook stand-down, the pricing
cards e2e fixture, and the unit, contract, e2e, and skill-behavior tests.
The server, CLI, hook, and pin halves are ported to the engine crates in
the commits that follow.
AI-assisted: implemented and tested with Claude Code under maintainer
direction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace three duplicated UTF-8 escaping loops with one private encoder and explicit component character sets. Preserve existing URL behavior with a narrow characterization test.
Prepared with AI assistance by Codex under pbakaus’s standing authorization for the daily architecture-simplification automation.
Retain eight dependency updates and ai 7.0.69 with its private provider stack. Validated frozen install, Rust release build/workspace tests, full default suite including engine oracle, extension/VS Code packaging, new-work browser tests and exact-head GitHub checks.
The additional full live sweep has one inherited orphan-session cleanup failure, reproduced identically on unchanged main and the candidate; 35 other tests pass. Provider-backed behavior remains unverified and the known ai regression hold is preserved.
AI-assisted dependency review, minimal fix, and merge by Codex for the maintainer-authorized sweep.
Validated the unchanged OIDC inputs, Node 24 action runtime, default client-ID masking, workflow signing boundaries, core tests, distribution build, and exact-head required GitHub checks. The tag-only Azure signing workflow was not executed locally.
AI-assisted dependency review and merge by Codex for the maintainer-authorized sweep.
* Fix: detect placeholder contrast (#790)
`detect` never read `::placeholder` color, so pale placeholders passed. Score them with the same WCAG math as body text, without host class/clip heuristics.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: match descendant ::placeholder hosts (#790)
`.form ::placeholder` kept the ancestor as the host. Reuse the hover combinator star-fill so the color lands on the inputs inside.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: placeholder-shown and gradient alpha (#790)
Browser scans skip when :placeholder-shown is false, so a live filled field does not keep the HTML value attribute's empty state. Translucent placeholders flatten over each gradient stop before scoring.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: trailing combinator only for ::placeholder hosts (#790)
`star_empty_compounds` turned `.label + ::placeholder` into `.label *+*`. Fill only a trailing empty compound so adjacent-sibling hosts still match.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: verify touch gestures in adapt, audit, and harden (#805)
The verification sections of adapt.md, audit.md, and harden.md listed
environments and layout properties but never had the agent exercise a
control's primary gesture, so an emulated viewport plus screenshots
could pass as touch testing. adapt now exercises the primary gesture
and the scroll-across trade and reports what produced the evidence,
audit checks broken touch interaction with code-level tells, harden
covers interrupted gestures and recovery, and a reference-contract
test pins the three sections.
Prepared with AI assistance (Claude Code), directed by @abdulwahabone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Pin the scroll, exercise, and cleanup sentences in the reference test (#805)
Greptile flagged that the contract test pinned the new labels but not
adapt's scroll-across trade, audit's instruction to exercise the
gesture, or harden's drag-state and capture cleanup.
Prepared with AI assistance (Claude Code), directed by @abdulwahabone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* Add degraded Setup path: must-read pack when the context launcher is refused
When the host denies the impeccable context launcher (issue #789, measured
in #744), the Setup fallback now names the degraded path and its
unconditional must-read pack: the routed command's reference and
craft-floor.md before any UI edit, and document.md before writing DESIGN.md.
init.md gains the degraded Step 1 behavior, docs/CLI-CONTRACT.md documents
the degraded contract, and scenario 19 gains a denied-launcher documentation
case asserting document.md and source reads precede the DESIGN.md write.
No version bump, no changelog entry, no generated harness sync.
AI was used for assistance.
Includes AI_PR_NOTICE.txt per the repository's contribution policy: this
change was prepared without maintainer approval on issue #789, so no PR is
opened by the agent.
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
* Drop restated degraded-setup prose; keep the scenario 19 documentation case
The launcher-unavailable path already lives on main. This removes the
notice file and the restated SKILL, init, and CLI-contract text, and keeps
the denied-launcher documentation coverage. The notice must now land before
the first tool call after the denial, not only before the eventual write.
AI was used for assistance.
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Successful --reply was exit 0 with empty stdout, so agents could not tell delivery from a hang. Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
Complete and discarded snapshots no longer keep carbonize_cleanup_required after cleanup is done.
AI assistance: Cursor Grok 4.6.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix silent launcher setup failures
Report cache creation, cache write, and download failures with recovery guidance while preserving lazy engine downloads.
AI-assisted by Codex.
* Fix Windows staging-write failure handling
Branch directly on redirection failure and reject staging directories before cleanup. Add coverage for an existing read-only staging file.
AI-assisted by Codex.
Collapsing every separator run turned \\server\share into /server/share, so doctor would probe the wrong file. Leading // after a quote is left intact.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
JSON-quoted absolute paths doubled backslashes, so merge failed to recognize the group it had just written and appended another copy on every update.
Prepared with AI assistance.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Release engine 0.1.5, CLI 4.1.0 and skill 4.3.0
Ship GPT Image 2.5 Flare and native transparent assets. Refresh generated provider distributions for the release.
Prepared with AI assistance under the maintainer's instructions.
* Fix: lock released engine platform packages
Regenerate all five 0.1.5 platform resolutions after npm publication and verify frozen installation.
Prepared with AI assistance under maintainer instructions.
* Use GPT Image 2.5 Flare for image generation
Add explicit model selection and cover generation/edit request provenance. Compare 24 comp samples with Image 2 and Sunburst, documenting efficiency gains and the photo-preservation tradeoff.
Prepared with AI assistance under maintainer instructions.
* Validate native image transparency for asset production
Add repeatable cutout, glass, and reference-plate experiments with alpha measurements and compositing evidence. Record fidelity limits and the remaining asset-producer integration work.
Prepared with AI assistance under the maintainer instructions.
* Add native transparent PNG asset generation
Wire background options through generation and edits, preserve alpha, and update asset production to use supported commands with visual cutout checks.
Prepared with AI assistance under the maintainer's instructions.
* Fix native alpha review findings
Validate PNG paths for all background modes, score sparse and partial alpha over the sampled ground, and correct launcher and plate workflow guidance.
Prepared with AI assistance under the maintainer's instructions.
* Fix launcher paths in comp workflow commands
Quote existing launcher filenames for the target shell while retaining multiword command prefixes. Cover relative and absolute paths and actual shell argument parsing.
Prepared with AI assistance under the maintainer's instructions.
* Remove evaluation artifacts and docs from image PR
Keep the PR focused on runtime behavior, source skill instructions, and regression coverage. Preserve evaluation material locally.
Prepared with AI assistance under the maintainer's instructions.
Engine assets and all five platform packages are published and verified. Frozen install, CLI download fallback, and regression checks passed. AI assistance: Codex, under maintainer direction.
Clarify launcher fallback and completed documentation handoffs; separate bounded protocol checkpoints from opt-in browser-backed completion diagnostics. Correct fixture containment, target syntax, and artifact assertions. AI assistance: Codex, under maintainer direction.
Fixes#760. Use the existing line-based confirmation prompt on Windows instead of unsupported Unix raw mode. Preserves Unix and confirmation behavior. AI assistance: Cursor Grok 4.6 (implementation), Codex (maintainer-directed review and merge).
Fixes#367. Resolve design rules per target file in the Rust post-edit, before-edit, and Stop hooks, preserving repository fallback and session state. Credit to tylerjryan for the original report and proposed approach. AI assistance: Codex, under maintainer direction.
* Test nested Windows CSP candidate paths
Regression coverage for #761 before the path-normalization fix.
AI assistance: Codex, under maintainer direction.
* Fix Windows CSP candidate path normalization
Normalize native relative paths before slash-based CSP classification and signal output. Preserve literal Unix backslashes.
AI assistance: Codex, under maintainer direction.
* Avoid reusing stale CSP test fixtures
Retry an unused test directory on AlreadyExists without deleting or reading any pre-existing fixture contents.
AI assistance: Codex, under maintainer direction.
The engine verified TLS against the Mozilla roots bundled through
webpki-roots only, so behind a TLS-inspecting proxy (Aikido, Zscaler,
Netskope) whose root lives in the OS trust store, `impeccable update`
and `install` failed with `invalid peer certificate: UnknownIssuer`
while curl and npm on the same machine succeeded.
crates/context/src/http.rs builds one rustls ClientConfig per process:
the OS trust store (rustls-native-certs: Keychain, Windows store, the
OpenSSL paths on Linux) merged with the bundled roots. A union, not a
replacement, so a container without ca-certificates or a store that
fails to load still verifies exactly as before. SSL_CERT_FILE and
SSL_CERT_DIR replace the OS store the way they do for OpenSSL and curl.
Every HTTPS call site (bundle and signature downloads, /api/version,
/api/commands, the roll API, image generation) builds its agent from
this module; the plain-HTTP live-server calls on localhost are
untouched.
Verified against a local HTTPS server signed by a throwaway CA: trusted
through SSL_CERT_FILE the update check reaches it; without it the same
server is rejected as UnknownIssuer; with SSL_CERT_FILE pointing at that
CA or at a missing file, impeccable.style still verifies through the
bundled roots. cargo test --workspace and the oracle corpus (832) pass.
Written with AI assistance (Claude Code).
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Use renaissance-geek for the Impeccable extension and guard the publisher identity in packaging tests.
AI assistance: Codex, under maintainer direction.
* Add declarative VS Code skill extension packaging
Stage a launcher-only Copilot skill bundle, validate relocation and VSIX packaging, and keep project-install hooks out of the extension.
AI assistance: Codex, under maintainer direction.
* Document verified Copilot extension smoke test
Record the successful read-only VS Code 1.136.1 run and the reload required after initial workspace trust. Keep minimum-version and remote smoke gaps explicit.
AI assistance: Codex, under maintainer direction.
* Fix VS Code packaging test version source
Derive the provider fixture version from the skill manifest and assert the packaged skill and extension versions agree.
AI assistance: Codex, under maintainer direction.
* Fix truncated slug collisions
Prepared with AI assistance under maintainer-authorized automation.
* Preserve legacy long-slug reads
Prepared with AI assistance under maintainer-authorized automation.
* Harden legacy slug compatibility
Require target metadata before reading collision-prone legacy brief and critique paths. Add regressions for two long targets with the same pre-hash suffix.\n\nPrepared with AI assistance.
* Keep explicit access to legacy critiques
Allow identity-less pre-hash snapshots to be read by their exact legacy slug while keeping path and URL fallback identity-gated. Document the compatibility boundary and extend collision coverage.\n\nPrepared with AI assistance.
Accept eight grouped dependency updates while retaining ai 7.0.69 and its private provider stack pending provider-backed tool-loop regression validation. Frozen install, Rust engine build and workspace tests, full Bun/Node suite with local engine oracle, extension build/lint, browser probe, and exact-head CI passed. AI-assisted dependency maintenance by Codex.
Validated release workflow inputs, signing boundaries, full SHA pins, and exact-head required CI checks. v8 enforces artifact digest mismatches as errors; no workflow input migration required. AI-assisted dependency review and validation by Codex.
* Clarify permitted work after launcher refusal
Correct behavior-test skill metadata and DeepSeek output limits; document the measured remaining Gemini warning-order failure and hook download trust boundary.
AI assistance: Codex, under pbakaus direction.
* Clarify behavior harness host-modeling scope
AI assistance: Codex, under pbakaus direction.
* Preserve planning-only scope after launcher refusal
Clarify applicable setup steps and cover denied-launcher planning. Retain the observed playbook-read failure under issue #744 rather than weakening its assertion.
AI assistance: Codex, under pbakaus direction.
* Test planning fallback warning order
Require an assistant warning after context launcher denial and before fallback context reads. Cover silent, late, and unrelated warnings with deterministic tests; retain the observed Sonnet omission under #744.
AI assistance: Codex, under pbakaus direction.
Pin existing action versions to verified commit SHAs, restrict CI to a read-only repository token, and document the optional live-edit validation script. Preserve required sync/sheriff permissions and existing runtime behavior. Related to #480; extension permission assessment remains separate.
AI assistance: Codex, under maintainer direction.
Use verified first-edit baselines to distinguish pre-existing text findings from new or unknown Stop findings. Preserve dirty worktrees, bound notice rendering, and keep explicit scans unchanged. Verified with the full Rust and Bun/Node suites and real Claude Code edit-to-Stop sessions. Related to #522; keep it open until an engine release ships the fix.
AI assistance: Codex, under maintainer direction.