fix(aqe): one AQE store per project, safe stray-store merge, honest verification - #250
Merged
Merged
Conversation
The AQE transport recognizer accepted only `npx -y agentic-qe@latest mcp`, so registrations written as `npx agentic-qe mcp`, `npx --yes agentic-qe mcp` or with an exact version were reported as unrecognized and never received the embedder endpoint (audit item 5, choice A). npx now counts when it has an optional single -y/--yes, then agentic-qe unversioned, @latest or an exact version (prereleases included), then mcp and nothing else. Ranges, other dist-tags, scoped look-alikes, --package forms, repeated flags and extra arguments stay user-owned.
AQE's native solver (@ruvector/solver-node) was never published, and AQE made its TypeScript solver the implementation (agentic-qe#617, #620, released in 3.13.10). healAqeSolver only reported that state, so setup and sync printed an "aqe solver" line with nothing behind it. The heal and its calls in the sync security step and setup's machine security step are removed. The registry marks agentic-qe#617 and #620 adopted with the removal tests as proof; ADR-0023 marks its solver example historical and UPGRADING notes the dropped line.
`ak x verify aqe` recorded its live embedding result for `ak status` even when the kit does not manage AQE's embedding backend, so a backend the user owns showed up as a failed kit check. `ak status --live` already skipped it. One exported predicate, aqeEmbeddingManaged(cfg) (AQE on and an endpoint or in-process choice), now gates both the verify evidence and the live check. An unmanaged backend, no choice at all, or AQE turned off is still probed and printed, but nothing is remembered.
A passing embedding check proves the embedder answers with a vector of the expected size. AQE 3.14.4 does not bind its pattern index when an embedder endpoint is configured (agentic-qe#754), so a pass says nothing about AQE's pattern search. Status now reads "embedder verified <age> (<source>); AQE pattern index binding unverified (agentic-qe#754); corpus compatibility unverified", `ak x verify aqe` prints "embedder verified" with the same caveat, and setup's detail names the pattern index binding and existing corpus as separate. A test walks src/ so no surface claims pattern search works. The registry's #754 entry lists the three files; AQE-EMBEDDINGS and ADR-0055 describe what a pass proves.
The temporary live-lock busy rule said it goes away when the AQE release carrying agentic-qe#719 is the kit floor. 3.14.4 carries #719, but #719 is a partial fix and #574 is still open, so that condition would remove the rule too early. The rule, its test and ADR-0055 now say it is removed when a released agentic-qe fixes agentic-qe#574 and that release is the kit floor. The source comment no longer implies the rule stops at 3.14.3; the rule has no version gate. No behavior change.
AQE resolves its root, memory database and storage folder against the working directory unless told otherwise, so a command, hook or MCP server started in a subfolder created its own .agentic-qe store there. ak sync and ak setup now write absolute AQE_PROJECT_ROOT, AQE_MEMORY_PATH and AQE_STORAGE_PATH (B5-D1, B5-D1a) into .claude/settings.local.json, the recognized .mcp.json agentic-qe entry and the project .codex/config.toml agentic-qe env, each under a receipt. AQE's own relative AQE_MEMORY_PATH is replaced under the receipt; any other value is preserved and shown as a hand fix. ak status reports a missing pin as a sync repair and a pin naming another checkout's root as a hand fix; ak uninstall restores the receipted before-state in every recorded project. The user-level Codex config is never pinned. The test guards now also watch the repository's .mcp.json and .codex/config.toml.
ak x verify providers used the folder it started in: from a subfolder it read no AQE router file and ran aqe health there, which created a new .agentic-qe store. verifyProviders and verifyAqe now take the repository root that holds the folder, run every aqe and ruflo call in it with the AQE pin (AQE_PROJECT_ROOT, AQE_MEMORY_PATH, AQE_STORAGE_PATH), scan and read the root's store, and run aqe health with AQE_MEMORY_BACKEND=memory so its billing section prints without opening the project's memory.db. Outside a repository the project checks are skipped and the output says so.
…be written A file where ak writes two pin keys and preserves a third value it does not own was listed only in the sync row before the first sync, so the preserved value had no hand-fix row naming the file. Both rows now show, as the embedding rows do (audit decision 13).
Maintainer decision B5-D1b: the project .codex/config.toml
[shell_environment_policy.set] table, which Codex applies to the commands
and hooks it runs, is a fourth pin target with the same three absolute keys
(AQE_PROJECT_ROOT, AQE_MEMORY_PATH, AQE_STORAGE_PATH) and the same rule:
AQE's relative AQE_MEMORY_PATH is replaced under the receipt, any other
foreign value is kept and reported as a hand fix naming the file and table.
The table is a target only when it exists or [mcp_servers.agentic-qe] is in
that project file (then the table is added); the user-level Codex config is
never pinned. Other keys in the table and the file's formatting stay as they
were. Inline or dotted forms (set = {...}, shell_environment_policy.set.X,
quoted keys) are refused and preserved.
The table has its own receipt, .codex/config.toml.agentic-kit-aqe-shell-pin.json:
a receipt holds one table's keys, and planOwnedEnv releases every receipted
key a target does not want, so two tables sharing one receipt would strip
each other's keys. Uninstall restores both tables byte for byte.
Plan (B5-D1b), UPGRADING and the ADR-0055 Updated line name the new target.
.mcp.json is gitignored here, but the files ak writes beside it were not: the AQE pin receipt (.mcp.json.agentic-kit-aqe-pin.json) and backups (.mcp.json.ak-aqe-pin-backup.<uuid>, aqe-project-pin.mjs backupTag aqe-pin), and the AQE embedding receipt (.mcp.json.agentic-kit-aqe-embedding.json) and backups (.mcp.json.ak-aqe-backup.<uuid>, aqe-embedding-projection.mjs backupTag aqe). Receipts and backups beside .claude/ and .codex/ files are already covered by those folder patterns. Configuration only, no test: each name was checked with git check-ignore -v.
A routine's GitHub trigger supports only pull request and release events (https://code.claude.com/docs/en/routines#supported-events), so the upstream-dispatch label on the ledger issue cannot start the dispatch routine. Maintainer decision 4b-C' (2026-09-27): the routine runs on its own daily schedule at 15:07 UTC (7 15 * * *), after the 14:00 watch, reads the ledger and stops quickly when no line qualifies. The workflow keeps re-applying the label as a marker for people reading the issue. UPSTREAM-WATCH.md says so in the daily-workflow paragraph and gives the routine its schedule and new prompt; the audit record amends 4b-C under decision 14; ADR-0041 section 7 gets an Updated line; the workflow's header comment and step name no longer claim the label fires the routine. The ubiquitous-language entry does not mention the label trigger and is unchanged. The two doc tests now pin the schedule, the marker wording, the cited trigger limit and a prompt that runs daily and changes no labels.
storeHolders lists every process holding a store's files open, by file and not by name (agentic-qe#753, decision B5-D3): lsof on macOS, /proc/<pid>/fd on Linux with lsof as fallback, and on Windows the host-session census for the project, never reported complete. The caller's own PID is excluded; a failed look is incomplete, never "no holders".
…e them ak x aqe-store status|merge (decision B5-D2): the preview counts copies of the root and each stray store, never a store in place. merge --yes refuses while any process holds a store (B5-D3, no force), backs the root up with VACUUM INTO, rehearses AQE's brain export/import on copies with the audit trail rows removed, imports into the root, checks counts, integrity and foreign keys, and moves each whole stray folder to <state>/agentic-kit/aqe-store-merge/<time>/archive beside the backup and a receipt (B5-D4). The fixture schema is AQE 3.14.4's, captured in Task 0.2.
…stores A stray .agentic-qe with a memory.db holds learning the project's hosts never read, and ak x aqe-store merge now resolves it, so its status row is a warning with 'ak x aqe-store merge --dry-run' as a manual repair (decision B5-D2), not a sync step. A folder without memory.db has nothing to merge and stays information.
exec.mjs run() replaces an empty stderr with 'Command failed: ...', so lsof's exit 1 for a file nobody holds read as a failed look and the merge refused every time (found in the Task 6.3 disposable proof). storeHolders now runs lsof through execFile and keeps its exit status; a missing lsof still reports ENOENT and incomplete detection.
The version floor read npm's global tree, which npm_config_prefix or a second install can point elsewhere; the Task 6.3 disposable proof printed 'AQE not installed' while aqe 3.14.4 was on PATH. The merge now asks 'aqe --version', the binary that performs the export and import, and only when there is a stray to merge.
tests/kit/spawn-env-guard.test.mjs requires every child_process call in tests/ to pass env; the lsof probe and the holding child now get PATH only.
Decision B5-D5: every stray AQE store carries AQE's seeded starter patterns, and the project store no longer holds most of them, so a merge would put them back. The merge now builds a fresh AQE store in its scratch folder (aqe init --auto --minimal, then aqe learning stats --json to start the reasoning bank, which is what seeds it; cwd, AQE_PROJECT_ROOT and the npm prefix and cache all inside scratch; the project's AQE_EMBEDDER_* keys, since AQE stores no pattern without a working embedder) and treats its patterns as the starter set, keyed on (name, qe_domain, pattern_type). Each stray's scratch copy drops those patterns, and the rows that must reference them, before export, as it does its witness rows. Preview, text output and receipt report the count per stray; the expected root counts leave them out. No starter set (a failed build or an empty store) refuses the merge before the backup. The archived strays keep their starter patterns. Also corrects the project-memory stray-store comment that still said ak never moves or merges any stray store.
…ter its conformance run The live external-provider proof (tests/live/aqe-external-provider-transport.test.mjs) passed on agentic-qe 3.14.4 under env -i with no provider API key: advisor without fallback and generation with explicit fallback, over the CLI and the MCP server, served by the proof's local hook provider. agentic-qe#628 is adopted and its constraint removed. The proof inherits its environment, so it now refuses to start while any *_API_KEY is set, before it looks for AQE; a unit test holds that. The freeze checklist and ADR-0029 record the sunset.
…ts conformance run New opt-in tests/live/aqe-stop-hook-conformance.test.mjs (AK_AQE_CONFORMANCE=1): in a disposable project, aqe init --auto --minimal (npm prefix and cache in scratch) must generate Claude Code hooks that run node, never npx or npm exec, with timeouts in seconds, and every Stop hook must exit 0 within its budget with npm offline and npx off PATH. It passed on agentic-qe 3.14.4: the three Stop hooks exited 0 in 84-117 ms. agentic-qe#654 is adopted and its constraint removed. The AQE generator codes now map to no upstream constraint, so their findings link no issue; the detectors and the reviewed-copy migration for 3.14.0-generated projects are unchanged. HOOKS and TROUBLESHOOTING describe the fixed generator.
agentic-qe#735: the pin module is its kit file and the adjustment names the three pinned keys; a reviewed note records why the root alone was not enough on 3.14.4. agentic-qe#736: a reviewed note with Task 0.2's 3.14.4 result (no abort, so the merge runs no prune step); the merge module is its kit file. agentic-qe#753: the holder and merge modules are its kit files, with a note on the writer check. New watch entry agentic-qe#561 (commented 2026-09-27): ak reports vibium as AQE-owned; nothing for ak to change, watch for AQE aligning its vibium versions or making vibium optional. Retired the 20 entries the watch report put in ready-to-retire, each kept with a dated history note: the 16 of this morning plus agentic-qe#617, #620, #628 and #654, adopted in this branch. The pin module and the footprint module now cite #735 and #561.
New ADR-0062, AQE project store integrity (Accepted): the pin (three keys, four targets, receipts), provider checks from the root, the merge command's sequence, the live-writer rule with no force, archive semantics, and leaving AQE's starter patterns out (B5-D5), with removal conditions tied to agentic-qe#735, #736 and #753. ADR-0016 and ADR-0055 get Updated lines; the ubiquitous language gains the AQE pin, store merge, merge archive and starter patterns, and a stray AQE store is no longer report-only. TROUBLESHOOTING explains the merge's refusals and how to restore from the archive; UPGRADING announces ak x aqe-store; HOST-SUPPORT shows where each host is pinned; the command's help names the starter patterns and the restore steps. The audit record gains decisions B5-D1, D1a, D1b and D2 to D5 in decision format with commits (a test holds the format), a Branch 5 implementation-status block, and resolves the open items on AQE's relative AQE_MEMORY_PATH and on ak x verify aqe recording unmanaged failures. The program plan moves Branch 6a's ADR to ADR-0063.
A timeout or signal left execFile's code null, which rawRun mapped to exit 1, and viaLsof read a silent exit 1 as "no holders, complete": the merge went ahead while a writer held the store (review M1). rawRun now keeps the signal, viaLsof counts only a numeric exit as an answer, and a /proc fd link that cannot be read (other than one that closed) falls back to lsof instead of being skipped.
A nested repository, submodule or worktree inside the checkout keeps its own .agentic-qe, which ak's pin makes that repository's store, yet the stray search walked into it and the merge would import and archive it (review M3). The search now stops at any folder holding a .git folder or file and lists it; the merge reports such a store as skipped.
aqe init --auto after an AQE upgrade rewrites its Codex tables with the relative AQE_MEMORY_PATH. ak owned the key, so the changed value read as a user edit, was preserved for good and reported as a hand fix while the pin stayed broken (review M4). An owned key whose value is exactly AQE's own default is now written again under the receipt, which keeps its first before-state; on release the default stays as AQE wrote it. AQE writes no AQE_STORAGE_PATH into a config file, so only the memory path is adoptable. The single-key embedding receipt passes no adoptable rule and is unchanged.
Releasing the pin left the TOML table headers ak had added, an ak-created
settings.local.json holding {}, and one backup file per pin write beside
each target; the test named for the table removal asserted only that a
key was gone (review minors 1-3). The pin's receipt now records whether
ak created the file or the table; a release that leaves them empty
removes them (the test compares the released file byte for byte), and
ak keeps only its newest pin backup per file. Both are opt-in for the
pin; the other projections on the shared engine are unchanged. Receipts
written before this change carry no creation record, so nothing they
cover is removed.
The pin wrote this machine's absolute paths into .mcp.json and the project .codex/config.toml, files teams commit; a teammate, CI or a second checkout would then point AQE at a path that does not exist there (review M5). Per maintainer decision B5-M5, a pin target git tracks (git ls-files --error-unmatch, shell-free) is skipped, a pin ak wrote before the file was tracked is released under its receipt, and status shows a hand fix naming the file and why. .claude/settings.local.json is always pinned; outside git, and for untracked files, the pin works as before.
The merge ran integrity_check and foreign_key_check only on its own result, with no baseline: a root that already failed one made every merge fail after taking a full backup, and each retry added another (review minor 7). The preview now runs both checks on its copy of the root; a failure is reported and refuses the merge before anything is written, naming the check.
The preview copied each stray before the first holder check and the merge exported that copy, yet the archive step moved the live folder: a short-lived writer between the copy and the move (a hook, a manual aqe run, a Codex session in a subfolder) lost its rows to the archive while the merge reported success (review M2). Each store is fingerprinted when the preview copies it (size and mtime of every stray file; the root's memory.db and a non-empty -wal, since the backup's own read-only open creates an empty -wal and a -shm there). A changed root or stray stops the merge before the real import; a stray that changes during the import is left in place and reported.
The receipt was written only when the merge finished, so a run stopped between the imports of two strays left a partly merged root and a backup with no record (review minor 8). The receipt is now written with status applying before the first real import and replaced when the run ends. ak x aqe-store status reports every applying receipt for the project, with how to finish or undo it, until a later merge of the same root completes and marks it interrupted.
The merge deleted every starter pattern and its usage, null-result and lineage rows from the stray copies, although AQE's import maps a pattern the root already holds onto the root's id and remaps its child rows: the learned signal for those seeds reached only the archive (review minor 4). It also looked only at pattern_id, so a relationship whose target was a left-out seed was imported pointing at nothing (review minor 5). Only the starter patterns the root lacks are now left out; every *pattern_id column is handled (NOT NULL or a foreign key: the row goes; nullable: the reference is cleared). The preview and receipt count the starter patterns the root already holds.
AQE's import skips a stray experience whose id the root already holds, even when its content differs, and the count check passed without any trace of it (review minor 6). The preview, the status line and the receipt now count those experiences per stray.
…-way Across filesystems the archive step copies, checks, then removes the stray. A removal that failed part-way (EBUSY or EPERM on Windows) was reported as "left in place: a process still holds it" although part of the source was gone (review minor 10). It is now reported as partially moved, naming the complete archive copy and the files that remain.
…scard The restore text said to copy the backup, then delete -wal and -shm, and did not say that restoring discards every write made to the project store after the backup, which for a count mismatch caused by a live writer includes that writer's rows (review minor 9). It now says: close the sessions, delete -wal and -shm, then copy the backup with nothing opening the store in between, and names what is discarded. Same in TROUBLESHOOTING.
…warning The receipt-creation record, the adopt rule and the merge's refusal chain pushed planOwnedEnv, decideKey and mergeAqeStores past the complexity-25 warning; each now delegates to a small helper. Behavior is unchanged.
ak setup printed "agentic-qe initialized (+ codex skills)" whenever it passed --with-codex. AQE 3.14.4 run through its aqe command installs no Codex hooks or skills: its Codex installer finds its packaged files only when started as node dist/cli/bundle.js. Setup now checks .codex/hooks.json and the five .agents/skills folders AQE installs and names them only when they are there; otherwise it warns which are missing and that the cause is an AQE defect with an upstream report pending.
…ts conformance run failed Conformance on ak's own path (full aqe init --auto --with-codex --codex-guidance full|compact|none through the aqe command, agentic-qe 3.14.4, sandboxed) failed: full writes no block when AGENTS.md exists, compact adds bytes outside its sentinel, no Codex hooks or skills install through the aqe bin, and platform verify exits 0 on failed checks. The constraint's evidence and the #655 watch entry record the run, the adjustment names the live test that proves the sunset, and the retest date moves to 14 days after this run.
tests/live/aqe-codex-guidance-conformance.test.mjs runs ak's own path (full aqe init --auto --with-codex --codex-guidance <mode> through the aqe symlink, twice, then with --json, then aqe platform verify codex) in sandboxed projects that hold a user AGENTS.md. On 3.14.4 every mode fails, so each is a todo naming the upstream defects; AK_AQE_CONFORMANCE_STRICT=1 runs it without the todo to prove the sunset. package.json gains a script for it and for the #654 Stop-hook conformance, and ships both files, as for #628's live test.
…ew fixes UPGRADING said the preview "works on copies and opens no store in place", and --help said the same, without saying that it copies the whole project store and every stray into ak's state folder and runs aqe init --auto --minimal and aqe learning stats there, the init running npm exec ruflo --version (review minor 12). Both now say so. UPGRADING, TROUBLESHOOTING, HOST-SUPPORT and the ubiquitous language also describe the fixes: tracked files are not pinned, release cleanup, the new merge refusals and their fixes, nested repositories, and starter patterns the root already holds.
ADR-0062 gains an Updated line and describes every fix: tracked files (B5-M5), AQE re-init adoption, release cleanup, the holder timeout rule, nested repositories, fingerprints, the root check before backup, the applying receipt, starter usage kept, and AQE's database-free mode, which a disposable run showed the pin does not break (review minor 11). The plan's goal, row 9 and Task 9.3 now say #655 is kept, not sunset (review minor 13). ADR-0055's two overlapping 2026-09-27 pin lines become one, and its 2026-09-26 busy-rule line is restored to what it said then. The audit record corrects the #655 attribution, notes that 2f13f04's "without writing" means the project store's database files while aqe health may create witness-keys/, and lists the review fixes. ADR-0058 notes the owned-env engine's opt-ins; ADR-0016 notes the nested repository boundary.
The git-tracked pin tests probe for git with spawnSync and no env, which the spawn-env guard rejects: every child process in tests/ passes an env.
…lease A file ak had pinned before git tracked it has a pending release, which the status section counted as drift: status printed "AQE is not pinned ... pin the keys" beside the tracked-file hand fix, although ak sync releases rather than pins it. A tracked file's pending change is no longer drift; its hand-fix row covers it.
An interrupted run whose receipt recorded no backup printed "copy null over ..."; it now says no backup was recorded. The refusal for a root that fails integrity_check or foreign_key_check now also says that a copy torn by a session writing during the preview can cause it, and to close the sessions and run it again.
…kills When aqe init --with-codex leaves no Codex hooks or skills, ak setup's warning said an upstream report was pending. It is now filed as proffesor-for-testing/agentic-qe#755, so the warning and the comment beside it name it.
Register proffesor-for-testing/agentic-qe #755-#759 (relation filed, status watching, done when closed-completed with an npm release). #755 and #756 carry the kept constraint agentic-qe-3.14.0-codex-guidance-policy; #757 and #758 leave ak unchanged; #759 is the reason ak x aqe-store merge deletes a stray copy's witness_chain rows. The merge's comment and the #655 live conformance's todo text now cite the issues they work around. Add a dated commented line, with the comment id, to the 16 existing entries commented on today: agentic-qe #734 #735 #736 #753 #754 #574, ruflo #2885 #3046 #3163 #3416-#3419 #3508 #3509, ruvnet-brain #335. lastCheckedAt and lastVerifiedAt stay at 2026-09-27: only the five new issues were re-read today (gh issue view, all open), and no constraint retest was re-run.
Add "Reporting upstream": the five parts every upstream issue or substantive comment carries (problem, system info, steps to reproduce, proposed fix approaches, impact for the project's own users and then downstream), the friendly and appreciative tone, one issue per root cause, the duplicate search with related links, maintainer approval of the exact text, the read-back after posting and same-day registration in the watch.
…nd tests A developer shell that exports AQE_EMBEDDER_ENDPOINT made the live request read "unavailable"; CI, with no such variable, reads "not-configured". The tests now clear AQE_EMBEDDER_* for their duration and assert only that a failed request is printed, which is what they are about.
On Windows ak names the file as .codex\config.toml, the native path; the M5 skip itself worked there. The two assertions hard-coded '/' and failed on windows-latest.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wave 2, Branch 5: one AQE store per project, a safe merge for the stray stores that already exist, honest AQE verification wording, and three constraint decisions (#628 and #654 sunset, #655 kept). Plan:
docs/superpowers/plans/2026-09-27-branch-5-aqe-store-integrity.md; decisions B5-D1…D5, D1a, D1b, M5 in the audit record; new ADR-0062 (Accepted).ak sync/ak setuppinAQE_PROJECT_ROOT, an absoluteAQE_MEMORY_PATHand an absoluteAQE_STORAGE_PATH(AQE 3.14.4 creates<cwd>/.agentic-qefromembedder-identity-store.jsandtoken-bootstrap.jsregardless ofAQE_PROJECT_ROOT) in.claude/settings.local.json,.mcp.json's agentic-qe env, and the project.codex/config.tomlMCP env and[shell_environment_policy.set], each under a receipt; git-tracked targets are skipped with a hand fix; AQE's own relative value is taken back after a re-init; uninstall restores the before-state. Newaqe-pinstatus row.ak x verifyruns provider checks from the repository root (aqe healthwithAQE_MEMORY_BACKEND=memory), no store in the subfolder.ak x aqe-store status|merge(B5-D2..D5): dry run by default,--yesapplies; holders found by open file (lsof //proc; Windows: host-session census + rename failure), checked before backup, import and archive — refuses, no force; root integrity checked first;VACUUM INTObackup outside every.agentic-qe; rehearsal on scratch copies; witness rows and AQE starter patterns removed beforeaqe brain export/import; fingerprints re-checked; whole stray folders archived under ak state with a receipt; nested repositories skipped. On this machine: 9 strays → +0 patterns, +99 experiences (preview on copies; the merge refuses while liveaqe-mcpsessions hold the store).tests/live/aqe-codex-guidance-conformance.test.mjs, todo until AQE fixes #755/#756/#758). Setup now says Codex hooks/skills are installed only when they exist (else names agentic-qe#755).docs/UPSTREAM-WATCH.mdgains the "Reporting upstream" standard.Known follow-up (not in this PR): the codex-mcp status row's hint suggests
aqe platform setup codex …, which fails on AQE 3.14.4 (agentic-qe#757).Test plan
node scripts/run-tests.mjs unit— Node 26 5486/0, Node 22 5485/0; tripwire: concurrent writer~/.claude.jsononlynpm packships the 4 new files🤖 Generated with Claude Code