Repository navigation
Conversation
Size Report
Startup median (7 runs, lower is better):
|
|
At bea660f, two likely defects need checking before this is ready for human review. There are no conflicts. Could the bundled dependency configuration give the installed plugin a private diagnostics With an empty plugin store, could The 15 failed checks look related: 13 mutation shards lack the plugin installation supplied by the unit-test global setup, and their missing reports fail the aggregate; Repo Guards fails because the compound Could an explicit resolver on the client and writer hosts replace the ambient binding, per-flow registries and global test setup? The CLI could share one store scope per command, filtered to the declared package, while the embedded client uses its runtime’s resolver. Would adding an optional Not blocking: count only active backends in shutdown reports, open Maestro lazily for its fuzz target, and keep the remaining test/type cleanups and #3871 failure-classification work separate. After the fixes, please attach packed-dist Android and iOS replay results, including selector taps, an animation or screenshot wait, and debug output with both diagnostic events above; also include the ADR 0015 Android timing comparison and the empty-store embedded run. The placeholder publication and trusted-publishing setup remain separate draft blockers. |
|
bea660f now conflicts with the target branch, |
9e95c90 to
87c8830
Compare
|
Thanks for the rebase. The two new commits fix the mutation shard and Repo Guards failures from bea660f, and all 32 checks pass at 2e004ce. Two problems from my earlier review (#4505 (comment)) are still in the code, and the live validation is still missing. There are no conflicts. The bundled engine still loses its diagnostics. packages/maestro/tsdown.config.ts:19 bundles every Embedded hosts still split the plugin set. Before merge, please run the packed plugin dist, not the workspace symlink ( Not blocking: the Validation section in the PR body still names bea660f, "86 files; 2,393 gross lines"; it could name 2e004ce on 4d75aa4 with 88 files and 1,685 gross lines, and say which review items this push addressed. Take it or leave it. After the two fixes and the live run, package publication ( |
10eba62 to
8e6c1fe
Compare
118c264 to
284b35f
Compare
|
I reviewed 284b35f against the earlier findings at #4505 (comment). The code fixes landed: the engine now gets diagnostics and process execution through the host, and the packed embedded empty-store run is covered by One item is still open. This change moves device-facing Maestro dispatch (selector taps, animation and screenshot waits, Not blocking, take or leave: |
284b35f to
0ef1318
Compare
|
The rebase to 0ef1318 keeps all 25 checks green, and the delta is one upstream conformance fixture line from #4538. The packed-plugin evidence asked for in the earlier review (#4505 (comment)) is still missing, so this is not ready to merge yet. The PR moves device-facing Maestro dispatch (selector taps, animation and screenshot waits, runScript children) into a bundled plugin that users install separately. CI exercises the packed dist only with a fake invoke (packed-runtime.mjs:164). The PR body gives only a summary of a packed run at 284b35f, with no output or diagnostics lines. So nobody has shown real tap dispatch (daemon-runtime-tap.ts:235) or the screenshot worker on real captures from the installed tarball, and ADR 0015 Android timing parity is unchecked. Please install the packed tarball, not the workspace symlink (pnpm pack and agent-device plugins add , or scripts/install-workspace-maestro.ts with source=false). Start a daemon from 0ef1318 or later. On one Android and one iOS device, run replay flow.yaml --maestro --debug on a flow with a selector tapOn and a waitForAnimationToEnd or screenshot wait. Paste the success output, the plugins list line that shows the store-installed version, and the maestro_tap_dispatch and maestro_screenshot_compare diagnostics lines. Add the ADR 0015 Android timing comparison against upstream Maestro. After that, the private:true and trusted-publishing draft gate is the next step before merge. |
|
Thanks for the update. The build config change at 2f016c0 looks fine, and all 24 checks pass, including the packed-runtime and package-smoke jobs. One thing is still missing before this can merge. Device-facing Maestro dispatch (selector tap, animation and screenshot waits, runScript children) now runs from a separately installed packed plugin, but CI drives it only with a fake invoke (packed-runtime.mjs#L164). No run has gone through a daemon started from this head with the packed tarball in the plugin store and a real device. So real tap timing, the screenshot worker on real captures and ADR 0015 Android timing parity are unverified for the installed artifact. The issue and the earlier reviews ask for this before merge. Please pack the plugin and install the tarball, not the workspace symlink. Start a daemon from 2f016c0 or later. On one Android and one iOS device, run I did not run the build or inspect the packed d.mts, so I inferred the type-only effect from the import kind and the PR body. I could not check live device behavior. The branch has no conflicts. |
|
Thanks for checking the public-type fix. The requested exact-head device/timing acceptance is still open; I am keeping this draft. Here is the concrete evidence already captured, with its actual source attribution rather than calling it a new 2f016 execution. At source {"backend":"maestro","source":"store","package":"@agent-device/maestro","version":"0.0.0","state":"active"}Its managed factory was apiVersion 2 / replay-backend / maestro, without a symlink. Plugin tar SHA256 Earlier selector/animation paths were actually executed at {"phase":"maestro_tap_dispatch","data":{"kind":"selector","selectorKey":"text","expectedPoint":{"x":338,"y":822}}}
{"phase":"maestro_screenshot_compare","data":{"purpose":"animation","result":"stable","differencePercent":0.0006035887973621569}}Those are inherited iOS trace excerpts, not fresh head performance or Android diagnostic attestation. The Android run also used the bundled android-helper 0.21.38-dev / API2; packed include/replay and authored screenshot execution succeeded there. Runtime-byte identity across the later declaration-only fix does not turn these into new executions. ADR0015 timing is not admitted: unchanged full Pager correctness runs were base 6/9, extracted 6/9, upstream 7/9, with the exact failure locations retained; React Navigation ARM Release/Debug builds are blocked by the pinned Reanimated/Worklets output-path mismatch. I have not timed a passing subset or changed assertions. The Android shutdown route subsequently reported success with console KO while inventory remained booted; cleanup is explicitly partial and that route stopped. Current 2f016 frozen install/build, affected 42/25 and full 41/25, plus hosted checks passed. These establish code/validation evidence separately from fresh current-head two-platform selector/animation execution, canonical timing and npm placeholder/trusted-publisher clearance. Local evidence roots: C3-report.txt under |
There was a problem hiding this comment.
All reported issues were addressed across 105 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Found 1 test failure on Blacksmith runners: Failure
|
Apex Sentinel · 🟠 Request changesSince the last review: 1 new · 0 still open · 0 no longer raised 1 finding(s): 1 major. Required fixes
🟠 Major (1)
Not in the reviewers' prompt (1 file)
Reviewed with this repository's own Sentinel configuration ( 💬 Talking to SentinelIn a finding's thread, reply with:
On this conversation, comment Earlier reviewsReview of
|
| Where | Finding |
|---|---|
packages/command-surface/src/replay/index.ts:293 |
test --maestro opens and disposes the plugin registry once per flow file |
scripts/vitest-tmpdir-global-setup.ts:58 |
Global test setup installs the Maestro plugin for every suite in the run |
src/host.ts:43 |
Daemon-side replay loses the bound resolver when composeDeps is overridden |
Not in the reviewers' prompt (1 file)
pnpm-lock.yaml: generated or a lockfile, so its lines were left out
2 findings below minor hidden (user_settings.min_severity).
Reviewed with this repository's own Sentinel configuration (d38e35e61193).
There was a problem hiding this comment.
Apex Sentinel: 3 new findings on 2f016c0. The verdict and the full list are in the summary comment.
|
The newly enabled Android smoke lane now supplies concrete head execution evidence, but it is red: the emulator booted and the fixture completed earlier scenarios, then The workflow calls |
|
At 2f016c0 this branch now conflicts with its base |
2f016c0 to
e0d4859
Compare
There was a problem hiding this comment.
4 issues found across 23 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/fuzz/harness.test.ts">
<violation number="1" location="scripts/fuzz/harness.test.ts:253">
P3: This parameterized test leaks one temporary directory per case on every run. Wrap the harness invocation and assertions in `try/finally` and remove `dir` in the `finally` block so repeated CI runs do not accumulate artifacts.</violation>
</file>
<file name="scripts/fuzz/execute.ts">
<violation number="1" location="scripts/fuzz/execute.ts:203">
P2: A concurrent `close()` resolves before the first cleanup finishes, so a racing cleanup caller can proceed while the worker and plugin scope are still alive. Store and return the in-flight close promise so repeated calls share completion rather than returning immediately.</violation>
</file>
<file name=".github/workflows/android.yml">
<violation number="1" location=".github/workflows/android.yml:34">
P1: GitHub Actions does not expose the `runner` context in a job-level `env`, so `${{ runner.temp }}` cannot initialize `AGENT_DEVICE_HOME` here. Use a job-level path based on an allowed context such as `${{ github.workspace }}`, or export `$RUNNER_TEMP` inside the emulator step before installing the plugin.</violation>
</file>
<file name=".github/workflows/apple.yml">
<violation number="1" location=".github/workflows/apple.yml:39">
P1: GitHub Actions does not expose the `runner` context in a job-level `env`, so `${{ runner.temp }}` cannot initialize `AGENT_DEVICE_HOME` here. Use a job-level path based on an allowed context such as `${{ github.workspace }}`, or set `$RUNNER_TEMP` in a step-level environment before installing the plugin.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| runs-on: blacksmith-4vcpu-ubuntu-2404 | ||
| timeout-minutes: 80 | ||
| env: | ||
| AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-android-smoke-home |
There was a problem hiding this comment.
P1: GitHub Actions does not expose the runner context in a job-level env, so ${{ runner.temp }} cannot initialize AGENT_DEVICE_HOME here. Use a job-level path based on an allowed context such as ${{ github.workspace }}, or export $RUNNER_TEMP inside the emulator step before installing the plugin.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/android.yml, line 34:
<comment>GitHub Actions does not expose the `runner` context in a job-level `env`, so `${{ runner.temp }}` cannot initialize `AGENT_DEVICE_HOME` here. Use a job-level path based on an allowed context such as `${{ github.workspace }}`, or export `$RUNNER_TEMP` inside the emulator step before installing the plugin.</comment>
<file context>
@@ -30,6 +30,8 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 80
+ env:
+ AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-android-smoke-home
steps:
- name: Checkout
</file context>
| AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-android-smoke-home | |
| AGENT_DEVICE_HOME: ${{ github.workspace }}/.tmp/agent-device-android-smoke-home |
There was a problem hiding this comment.
Valid. GitHub documents github, not runner, among the contexts allowed at jobs.<job_id>.env. Local commit 0d097fcd301ea3ec33b0b4788d5682f393d062ac uses ${{ github.workspace }}/.tmp/agent-device-android-smoke-home, retaining job-wide inheritance across the emulator action’s separate shells. actionlint reproduces the baseline context error and removes it with this change; the existing unknown Blacksmith runner-label diagnostic remains, so the overall lint invocation is not reported as passing. Source: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#context-availability . The correction is local and awaits reviewed stack publication; I am leaving this thread open.
| runs-on: blacksmith-6vcpu-macos-26 | ||
| timeout-minutes: 90 | ||
| env: | ||
| AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-apple-smoke-home |
There was a problem hiding this comment.
P1: GitHub Actions does not expose the runner context in a job-level env, so ${{ runner.temp }} cannot initialize AGENT_DEVICE_HOME here. Use a job-level path based on an allowed context such as ${{ github.workspace }}, or set $RUNNER_TEMP in a step-level environment before installing the plugin.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/apple.yml, line 39:
<comment>GitHub Actions does not expose the `runner` context in a job-level `env`, so `${{ runner.temp }}` cannot initialize `AGENT_DEVICE_HOME` here. Use a job-level path based on an allowed context such as `${{ github.workspace }}`, or set `$RUNNER_TEMP` in a step-level environment before installing the plugin.</comment>
<file context>
@@ -36,6 +36,7 @@ jobs:
runs-on: blacksmith-6vcpu-macos-26
timeout-minutes: 90
env:
+ AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-apple-smoke-home
BASE_SHA: ${{ github.event.pull_request.base.sha }}
IOS_STATE_DIR: ${{ github.workspace }}/.tmp/ios-agent-device-state
</file context>
| AGENT_DEVICE_HOME: ${{ runner.temp }}/agent-device-apple-smoke-home | |
| AGENT_DEVICE_HOME: ${{ github.workspace }}/.tmp/agent-device-apple-smoke-home |
There was a problem hiding this comment.
Valid. Local commit 0d097fcd301ea3ec33b0b4788d5682f393d062ac switches the Apple job home to ${{ github.workspace }}/.tmp/agent-device-apple-smoke-home, an allowed job-env context, and preserves the shared installer/smoke home. actionlint reports the baseline runner context error and removes it after the change; existing Blacksmith label diagnostics remain unchanged. GitHub context table: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#context-availability . The separate top-layer iOS-only installer condition remains part of the local preparation stack. No hosted/native pass is implied; this thread stays open until publication.
| return failure; | ||
| }, | ||
| close: async () => { | ||
| if (closed) return; |
There was a problem hiding this comment.
P2: A concurrent close() resolves before the first cleanup finishes, so a racing cleanup caller can proceed while the worker and plugin scope are still alive. Store and return the in-flight close promise so repeated calls share completion rather than returning immediately.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/fuzz/execute.ts, line 203:
<comment>A concurrent `close()` resolves before the first cleanup finishes, so a racing cleanup caller can proceed while the worker and plugin scope are still alive. Store and return the in-flight close promise so repeated calls share completion rather than returning immediately.</comment>
<file context>
@@ -200,8 +200,19 @@ export async function createCaseRunner(
return failure;
},
close: async () => {
+ if (closed) return;
closed = true;
- await endSession(session);
</file context>
There was a problem hiding this comment.
Valid. Local commit 0d097fcd301ea3ec33b0b4788d5682f393d062ac stores and returns the in-flight close promise; subsequent callers wait for the same cleanup acknowledgement and worker exit, and run() remains closed once cleanup starts. A new test uses the real forked self-check worker and asserts the second close cannot finish before the first. All 17 focused harness tests pass after frozen install/build; an isolated baseline-versus-fix detection run is now delegated and remains pending. No timeout/retry changes or fake engine. The fix is not published; leaving this thread open.
| it.each([['--help'], ['--target', 'selector', '--iterations', '1']])( | ||
| 'fuzz entrypoint %j does not require an installed Maestro plugin', | ||
| (...args) => { | ||
| const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'fuzz-no-plugin-')); |
There was a problem hiding this comment.
P3: This parameterized test leaks one temporary directory per case on every run. Wrap the harness invocation and assertions in try/finally and remove dir in the finally block so repeated CI runs do not accumulate artifacts.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/fuzz/harness.test.ts, line 253:
<comment>This parameterized test leaks one temporary directory per case on every run. Wrap the harness invocation and assertions in `try/finally` and remove `dir` in the `finally` block so repeated CI runs do not accumulate artifacts.</comment>
<file context>
@@ -246,3 +246,14 @@ describe('artifact promotion', () => {
+it.each([['--help'], ['--target', 'selector', '--iterations', '1']])(
+ 'fuzz entrypoint %j does not require an installed Maestro plugin',
+ (...args) => {
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'fuzz-no-plugin-'));
+ const result = runHarness([...args, '--artifact-dir', dir], {
+ AGENT_DEVICE_HOME: path.join(dir, 'empty-home'),
</file context>
There was a problem hiding this comment.
I added per-case try/finally cleanup in local commit 0d097fcd301ea3ec33b0b4788d5682f393d062ac, including when an assertion fails. The run-level Vitest temporary-root teardown also already removes these directories at the end of a normal run, so I do not claim the old case necessarily leaked across completed runs; the improvement reclaims each case promptly and safely on its own failure path. The focused harness passes 17 tests. Publication is pending, so this thread remains open.
There was a problem hiding this comment.
Apex Sentinel: 1 new finding on 0158fac. The verdict and the full list are in the summary comment.
| const setup = slot.replaySetup; | ||
| if (!setup) throw invalidPlugin(`Replay backend was not set up: ${id}`); | ||
| return await (slot.replayLoading ??= Promise.resolve().then(async () => { | ||
| try { | ||
| return validateReplayBackend(id, await setup.replayBackend.create(host)); | ||
| } catch (error) { | ||
| slot.failure = asPluginFailure(error, 'plugin_load_failed'); | ||
| inventory.splice(0, inventory.length, ...resolved.inventory()); | ||
| throw slot.failure; | ||
| } | ||
| })); |
There was a problem hiding this comment.
🆕 🟠 Major · A transient replay engine load failure is cached for the daemon's whole life
A transient EIO/ENOENT during the first agent-device replay flow.yaml --maestro after daemon start gets permanently cached: every later replay/test --maestro on that daemon keeps throwing plugin_load_failed even after the package is readable again, until the daemon restarts. Cause: resolveRegisteredReplayBackend memoizes slot.replayLoading and in its catch sets slot.failure without clearing that memo, so the next call hits if (slot.failure !== undefined) throw slot.failure and never retries the load.
| const setup = slot.replaySetup; | |
| if (!setup) throw invalidPlugin(`Replay backend was not set up: ${id}`); | |
| return await (slot.replayLoading ??= Promise.resolve().then(async () => { | |
| try { | |
| return validateReplayBackend(id, await setup.replayBackend.create(host)); | |
| } catch (error) { | |
| slot.failure = asPluginFailure(error, 'plugin_load_failed'); | |
| inventory.splice(0, inventory.length, ...resolved.inventory()); | |
| throw slot.failure; | |
| } | |
| })); | |
| return await (slot.replayLoading ??= Promise.resolve().then(async () => { | |
| try { | |
| return validateReplayBackend(id, await setup.replayBackend.create(host)); | |
| } catch (error) { | |
| slot.replayLoading = undefined; | |
| slot.failure = asPluginFailure(error, 'plugin_load_failed'); | |
| inventory.splice(0, inventory.length, ...resolved.inventory()); | |
| throw slot.failure; | |
| } | |
| })); |
Details
Also raised here
Also raised at this location by persona senior-developer: Transient engine load failure now permanently disables the backend for the daemon's life — A Maestro engine create(host) that fails once — e.g. a transient EAGAIN/ENOENT while the engine chunk or the PNG worker dependency loads — leaves agent-device replay flow.yaml --maestro failing with plugin_load_failed for every later request until the daemon restarts, even though the failure was momentary. resolveRegisteredReplayBackend memoizes the rejected promise in slot.replayLoading and also sets slot.failure, so the early throw slot.failure short-circuits all subsequent resolution and create is never retried (the new test pins load.create to toHaveBeenCalledTimes(1)). The predecessor explicitly refused this: the deleted replay-backend-registry.test.ts case "a failed load is not cached, so the next call retries it" states that a failed import() must stay retryable because the pre-registry call sites imported fresh per invocation. …
persona: senior-developer, javascript
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if it is wrong — I will re-check the cited code.
There was a problem hiding this comment.
The three earlier findings are separately disposed: the suite lifetime was fixed, and the hermetic fixture/private composition claims were rejected with source evidence. This newer finding remains open. The current source retains the lazy-creation failure for later requests; I am checking that behavior against the prior builtin retry contract, failure classification and cleanup ownership in the already-running independent source review. Clearing only replayLoading would not bypass the existing slot.failure guard, so I will not apply that suggestion blindly. The local review candidate is frozen during review; no retry/fallback change or published fix is claimed yet.
There was a problem hiding this comment.
Accepted after independent owner review. Local e8e95cd25b774694a0cc6c1d25d6ecd8162039f8 clears the rejected promise, keeps recoverable inventory diagnostics separate from permanent setup/duplicate failures, and clears the diagnostic on recovery. Isolated unchanged-test RED/GREEN proves that later callers recover. Typecheck, lint, full format and layering passed.
The first two-file follow-up failed with 11 passes and a 5000 ms cancellation-drain timeout. The corrected controlled comparison now passed all 12 cases on both unchanged base 204fb29d and candidate e8e95cd2, once each with the same argv, captured environment and worker limit. This does not explain or erase the earlier timeout; infrastructure causation remains unproven. The preceding environment-metadata comparison ran zero tests.
A new independent Apex medium source/design/scope recheck is running. The consumer is still 2,508 gross lines and needs an honest scope disposition. Nothing is pushed; this thread remains open until the reviewed correction is published and verified. No broad, hosted, live, package or merge clearance is claimed.
|
Thanks for the update. I reviewed 0158fac against the earlier review (2f016c0 conflict). Most review threads are now fixed, but three problems remain, so this is not ready to merge yet. The new job-level The private-package thread is only half answered. The changeset and run-maestro-flows.md now say the package is private, but the hint in replay-backend-declarations.ts:44 and website/docs/docs/plugins.md:61 still tell users to run The live-evidence ask is still open. packed-runtime.mjs:164 drives the packed plugin through a fake invoke only, and no run uses a daemon with the packed tarball in the plugin store on a real device. Selector tap dispatch, animation and screenshot waits on real captures, Not blocking: the new Simplicity question: could On the other review threads: the android.yml env thread and the apple.yml env thread still apply (first finding). The private-package thread is marked resolved but still applies (second finding). One lower-priority thread still applies: the temp directory and one non-blocking resilience note on registry.ts:290-297 (thread). These do not apply, so please resolve them: execute.ts:203 ( The pull_request CI, Linux, Coverage and Integration lanes pass. The pending action-required check likely comes from the open resilience note on registry.ts, a file this PR changes. The Android and Apple push runs fail only because of the invalid workflow files above. Before merge, the smoke workflows must start and pass, For scope: I reviewed the delta 1a9eadd..0158fac and did not run tests, builds or the packed smoke, so the 46 focused tests and 6 packed cases are unverified by me. The workflow rejection is inferred from GitHub's documented context rules and the run records, not from an annotation text. I did not check whether 0.22 is cut from this branch before the package can be published, and I did not re-read the resolved threads on files outside the delta (replay-plugin-setup.ts, vitest-tmpdir-global-setup.ts, host.ts). |
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
Extract Maestro into the managed v2
@agent-device/maestroplugin for #3377. Core keeps engine-free routing; the supplied host owns diagnostics, command scope and cleanup. The package stays private and unavailable from npm.Published layer: 117 files, 2,769 gross lines. The unpublished independent preparation split now measures 400 gross lines; its consumer measures 2,463. Cumulative series growth remains disclosed at 2,851.
Validation
Published
0158fac999f447ff592e753ccdbbcf760fe7177e, base61d027bd3f4c2b19418df2d62ddb514dad6528f8. Current published-head exact gates remain pending. Sentinel remains action-required until the accepted cached-load fix is published.Independent Apex source review found no regressions in local
e8e95cd2recovery, inventory and cleanup. The review validated relocating oracle selection into the independent preparation layer. The reviewer disclosed an accidental ADR edit and immediate restoration; final source was clean.Local preparation
51361bdfand consumerc2ca3108retain the reviewed endpoint except one npm-availability qualification. Exact affected validation is running; consumer full validation follows only after affected passes. Narrow independent recheck of the final allocation/prose remains pending.Retry regression red/green is proven. A historical 11-pass/one-timeout run remains failed and unexplained; the frozen-input paired comparison subsequently passed 12/12 on both base and head. These focused results do not replace new-head gates.
Canonical Pager, Navigation ARM, current-client/platform/remote, performance/ADR0015 and npm placeholder/trusted-publisher blockers remain. Ready for review; no merge clearance.