diff --git a/.github/workflows/upstream-watch.yml b/.github/workflows/upstream-watch.yml index e41e4362..ae5c9916 100644 --- a/.github/workflows/upstream-watch.yml +++ b/.github/workflows/upstream-watch.yml @@ -3,8 +3,9 @@ name: upstream-watch # The upstream watch (docs/UPSTREAM-WATCH.md, decision 14). The script decides # everything: which ledger comments count, where the check starts, and the # comment's text. This workflow only posts that text on the ledger issue and -# labels the issue when a released fix is ready to dispatch, which fires the -# dispatch routine. No model runs here. +# labels the issue when a released fix is ready to dispatch. The label is a +# marker for people reading the issue; the dispatch routine runs on its own +# daily schedule and reads the ledger. No model runs here. on: schedule: @@ -107,7 +108,7 @@ jobs: length=$(gh api "repos/$repo/issues/comments/$id" --jq '.body | length') echo "Posted length $length (file $(wc -c < body.md))" [ "$length" -gt 0 ] - - name: Signal the dispatch routine + - name: Mark the ledger issue for dispatch if: env.POST == 'true' run: | [ "$(jq -r '.dispatch | length' watch.json)" -gt 0 ] || { echo 'Nothing to dispatch.'; exit 0; } @@ -115,6 +116,6 @@ jobs: repo=$(jq -r '.watchPolicy.ledger.repo' "$REGISTRY") gh label create "$DISPATCH_LABEL" --repo "$repo" --color 5319e7 \ --description 'The upstream watch has a released fix to dispatch' --force - # Remove, then add: a label already present would fire no new event. + # Remove, then add, so the issue's timeline shows the latest run that found work. gh issue edit "$issue" --repo "$repo" --remove-label "$DISPATCH_LABEL" || true gh issue edit "$issue" --repo "$repo" --add-label "$DISPATCH_LABEL" diff --git a/.gitignore b/.gitignore index b39059b0..4efa22b1 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,13 @@ test-*.log !/.agents/skills/upstream-status/ .codex/ .mcp.json +# ak's receipts and backups beside the gitignored .mcp.json (AQE pin: aqe-project-pin.mjs; +# AQE embedding: aqe-embedding-projection.mjs). The ones beside .claude/ and .codex/ files +# are already covered by those folders. +.mcp.json.agentic-kit-aqe-pin.json +.mcp.json.ak-aqe-pin-backup.* +.mcp.json.agentic-kit-aqe-embedding.json +.mcp.json.ak-aqe-backup.* ruvector.db *.db CLAUDE.md.backup diff --git a/MAINTAINER.md b/MAINTAINER.md index f928b30a..20a6c950 100644 --- a/MAINTAINER.md +++ b/MAINTAINER.md @@ -107,6 +107,8 @@ docs/ `docs/adr/0051-supported-peer-delegation-and-host-realignment.md`, `docs/adr/0054-fleet-evidence-export.md`, `docs/adr/0055-aqe-embedding-lifecycle.md`, `tests/live/aqe-external-provider-transport.test.mjs`, +`tests/live/aqe-stop-hook-conformance.test.mjs`, `tests/live/aqe-codex-guidance-conformance.test.mjs` +(opt-in AQE conformance: `pnpm test:aqe-stop-hook-live`, `pnpm test:aqe-codex-guidance-live`), `tests/live/qe-court-participant-transport.test.mjs` (with its helper `tests/live/disposable-memory-project.mjs`), `tests/live/codex-context-contract.test.mjs`, and diff --git a/bin/agentic-kit.mjs b/bin/agentic-kit.mjs index a339d29a..a30f668e 100755 --- a/bin/agentic-kit.mjs +++ b/bin/agentic-kit.mjs @@ -45,6 +45,7 @@ const PLUMBING = Object.assign(Object.create(null), { 'aqe-embedding': () => import('../src/commands/x/aqe-embedding.mjs'), 'admin': () => import('../src/commands/x/admin.mjs'), 'aqe-provider': () => import('../src/commands/x/aqe-provider.mjs'), + 'aqe-store': () => import('../src/commands/x/aqe-store.mjs'), 'daemon-gc': () => import('../src/commands/x/daemon-gc.mjs'), 'dashboard': () => import('../src/commands/x/dashboard.mjs'), 'harvest': () => import('../src/commands/x/harvest.mjs'), @@ -93,6 +94,7 @@ const HELP_ALL = `${HELP} Plumbing (power users) — each takes --help: ak x aqe-embedding [status|configure|prepare|verify] AQE semantic backend lifecycle + ak x aqe-store [status|merge] [--yes] merge stray AQE stores into the project store, then archive them ak x admin [--port N] maintainer-only telemetry admin (localhost; GitHub/npm egress) ak x daemon-gc [--kill] list/stop stale ruflo daemons ak x dashboard [--port N] local health and guarded maintenance dashboard (localhost only) @@ -218,7 +220,7 @@ async function main() { // setup and host own complete mutation/reporting flows. Running the generic // nudge after a declined trust preflight could write version-cache state and // violate their "before any changes" boundary. - if (!values.json && !values['dry-run'] && !['sync', 'usage', 'telemetry', 'models', 'setup', 'host', 'audit', 'heal', 'maintain', 'ruflo-mcp', 'aqe-provider', 'aqe-embedding'].includes(cmd)) { + if (!values.json && !values['dry-run'] && !['sync', 'usage', 'telemetry', 'models', 'setup', 'host', 'audit', 'heal', 'maintain', 'ruflo-mcp', 'aqe-provider', 'aqe-embedding', 'aqe-store'].includes(cmd)) { try { const { driftReport } = await import('../src/lib/versions.mjs'); for (const r of await driftReport()) { diff --git a/docs/AQE-EMBEDDINGS.md b/docs/AQE-EMBEDDINGS.md index 861db5d2..9f015bcc 100644 --- a/docs/AQE-EMBEDDINGS.md +++ b/docs/AQE-EMBEDDINGS.md @@ -51,7 +51,7 @@ ak x aqe-embedding verify | Local Ollama | Recommended local, no-key setup | Downloads missing MiniLM and alias after consent; tests the selected service | | Existing endpoint | Shared or separately operated service | Preserves selection, projects configuration and tests synthetic text; never manages remote models | | In-process | Explicit upstream transformer-package opt-in | Tests the installed backend and existing cache; does not install the security-sensitive optional package | -| Unmanaged | Operator owns configuration, or semantic learning is deferred | Restores only unchanged owned projection values; makes no semantic readiness claim | +| Unmanaged | Operator owns configuration, or semantic learning is deferred | Restores only unchanged owned projection values; makes no semantic readiness claim; `ak x verify aqe` still runs and prints the embedding request but does not record its result for `ak status` | ```sh ak x aqe-embedding configure --aqe-embedding-endpoint https://embed.example --yes @@ -60,6 +60,13 @@ ak x aqe-embedding configure --aqe-embedding-mode in-process --yes ak x aqe-embedding configure --aqe-embedding-mode unmanaged --yes ``` +A passing check proves the embedder: ak sends synthetic text and gets a vector of +the expected size back. It does not prove that AQE's pattern index uses that +embedder. AQE 3.14.4 does not bind its pattern index when an embedder endpoint is +configured ([agentic-qe#754](https://github.com/proffesor-for-testing/agentic-qe/issues/754)), +so `ak status` reads "embedder verified; AQE pattern index binding unverified", and +compatibility with vectors already stored in the project is a separate question. + In-process transformers are an explicit security opt-in in AQE's published runtime. Consult the installed AQE guidance and dependency advisories before installing its optional package. Read-only verification never downloads weights; @@ -84,9 +91,9 @@ old environment and may retain an earlier failed initialization. Claude project MCP and hook settings and existing canonical Codex MCP tables have field-level receipts. On every host, ak edits only an AQE entry started by one -of AQE's own commands: `aqe-mcp`, `aqe mcp`, `agentic-qe mcp`, `aqe-v3 mcp` or -`npx -y agentic-qe@latest mcp` (npm `.cmd` shims included). Entries with other -commands, flags or wrappers are reported as unrecognized and left unchanged. OpenCode updates immediately through a narrow operation inside its existing +of AQE's own commands: `aqe-mcp`, `aqe mcp`, `agentic-qe mcp`, `aqe-v3 mcp`, or +`npx [-y|--yes] agentic-qe[@latest|@] mcp` (npm `.cmd` shims included). +Entries with other commands, version ranges, dist-tags, flags or wrappers are reported as unrecognized and left unchanged. OpenCode updates immediately through a narrow operation inside its existing full-entry owner, preserving permissions, plugins and unrelated MCP entries. Its receipt remains compatible with normal `ak sync`. Conflicting user values and unsupported TOML forms are reported, never overwritten. Unrelated Codex keys, including dotted root keys such as diff --git a/docs/HOOKS.md b/docs/HOOKS.md index d3eb7fb8..432c3383 100644 --- a/docs/HOOKS.md +++ b/docs/HOOKS.md @@ -139,8 +139,10 @@ consent, capability grants, and host permission state are never inferred or muta The audit reports registry validity, evidence freshness, and installed-version applicability separately. Opening or updating an upstream issue always requires explicit user approval. The constraint registry may retain either a draft or the published URL/time receipt after that -approval. Agentic-QE's 3.14.0 Stop generator is tracked in -[AQE #654](https://github.com/proffesor-for-testing/agentic-qe/issues/654); historical ETIMEDOUT is -detected and attributed. Exact reviewed project copies now have the compatibility repair -above; this does not claim that all upstream-generated variants are fixed. A -workaround is retired only after a released artifact passes the relevant conformance suite. +approval. Agentic-QE's 3.14.0 Stop generator +([AQE #654](https://github.com/proffesor-for-testing/agentic-qe/issues/654)) is fixed: 3.14.1 and +later generate hooks that run `node` with timeouts in seconds, and 3.14.4 passes the offline Stop +conformance (`tests/live/aqe-stop-hook-conformance.test.mjs`), so that constraint is retired and its +findings no longer link an upstream issue. Projects generated by 3.14.0 are still detected, and exact +reviewed project copies keep the compatibility repair above. A workaround is retired only after a +released artifact passes the relevant conformance suite. diff --git a/docs/HOST-ADAPTER-FREEZE-CHECKLIST.md b/docs/HOST-ADAPTER-FREEZE-CHECKLIST.md index 5260b610..edbc7649 100644 --- a/docs/HOST-ADAPTER-FREEZE-CHECKLIST.md +++ b/docs/HOST-ADAPTER-FREEZE-CHECKLIST.md @@ -82,7 +82,9 @@ design and are recorded as gated, not as failures: - `aqeProvider` is no longer an upstream freeze ceiling: Agentic-QE 3.13.12 shipped `externalProviders` for [#628](https://github.com/proffesor-for-testing/agentic-qe/issues/628). An adapter still must declare `aqe.provider`, pass the real `aqe-provider` tier at its current - content hash, and receive an explicit `aqeProvider` grant. + content hash, and receive an explicit `aqeProvider` grant. The kit's compatibility constraint for + #628 is retired: the live proof `tests/live/aqe-external-provider-transport.test.mjs` passes on + Agentic-QE 3.14.4 with no provider API key in its environment (it refuses to run with one). - `statusline` runtime rendering (no `ak` render surface for a third-party TUI yet). - Grant *consumption* last-mile: selecting an external host as primary, and a `commandStatusline` runtime reader. diff --git a/docs/HOST-SUPPORT.md b/docs/HOST-SUPPORT.md index cc245e0c..46c2d57a 100644 --- a/docs/HOST-SUPPORT.md +++ b/docs/HOST-SUPPORT.md @@ -152,6 +152,13 @@ The dated upstream risk inventory includes: | Default route projection | Yes | Yes | No | | QE-Court routed seat | Full routed role | Supported, with the integrated stall risk below | May call QE tools, but cannot be an AQE provider-backed seat | | Subscription-provider embeddings | Not supported | Not supported | Not applicable | +| One project store (AQE pin) | `.claude/settings.local.json` env and the `.mcp.json` AQE entry | The project `.codex/config.toml` AQE MCP env and `[shell_environment_policy.set]` | Not pinned (agentic-kit does not set up AQE for OpenCode) | + +Agentic-kit pins `AQE_PROJECT_ROOT`, `AQE_MEMORY_PATH` and `AQE_STORAGE_PATH` to the project root, +so an AQE command, hook or MCP server started in a subfolder uses the project's store instead of +creating its own. A `.mcp.json` or project `.codex/config.toml` that git tracks is not pinned, +because a committed absolute path would not exist on a teammate's machine. `ak x aqe-store merge` merges stores AQE made in subfolders before the pin +([ADR-0062](adr/0062-aqe-project-store-integrity.md)). The OpenCode boundary is precise: AQE can provision OpenCode agents, skills, MCP, and permissions, but OpenCode is not a built-in AQE LLM-provider type. Agentic-kit diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index a06e2a38..ac912b4a 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -410,8 +410,11 @@ Three checks establish different facts; do not collapse them: content hash, then `ak host adapters grant aqeProvider` must succeed. 2. `ak x verify providers` proves admission plus the exact project declaration, ownership receipt, default, fallback, and override projection. It deliberately warns that this is not a served - model response. It reads AQE's billing section (`aqe health`) only in a project where - `.agentic-qe` exists, because `aqe health` initializes a store where it runs. + model response. It checks the repository that holds the current folder, from its root, even + when you run it in a subfolder; outside a repository it skips these project checks and says so. + It reads AQE's billing section (`aqe health`) only in a project where `.agentic-qe` exists, and + runs it in the root with the project pin and AQE's in-memory backend, so it does not open the + project's `memory.db`. 3. Release proof starts fresh AQE CLI and MCP processes, lists the external id through `aqe llm providers --json`, invokes the real `test_generate_enhanced` MCP tool, and requires the served completion to carry the fixture's provider and model markers: diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 8ef41ca9..2c96eea9 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -72,6 +72,7 @@ ak sync # apply it | `status` says an external `agent-browser` is outside Ruflo's range | You installed a newer `agent-browser` yourself. ak never replaces a user-managed install, so `sync` cannot clear this, and Ruflo's browser tools may not work with that version | Install a Ruflo-compatible `agent-browser` 0.27.x yourself, or set `agentBrowser: false` in `~/.config/agentic-kit/kit.json` to stop ak managing the executor (Ruflo MCP then no longer gets ak's trusted browser config or readiness checks) | | `status` lists a stray memory store | A tool wrote a store where this project's hosts do not read it, usually because it ran in another folder. ak only reports it | Nothing breaks. To keep its rows, inspect it read-only first; see [Stray memory stores](#stray-memory-stores) | | `status` shows a `memory-pin` warning | `CLAUDE_FLOW_DB_PATH` is pinned to a dead or foreign path, so every memory op targets the wrong DB ("Database not initialized" beside a healthy in-repo DB). The pin may be deliberate, so `sync` never touches it | repoint (or remove) the pin in `.claude/settings.local.json` `env` | +| `status` shows an `aqe-pin` warning | AQE is not pinned to this project's root yet, a pin names another checkout's root (a copied `.claude/settings.local.json`), a file holds an `AQE_PROJECT_ROOT`, `AQE_MEMORY_PATH` or `AQE_STORAGE_PATH` value ak did not write, or git tracks `.mcp.json` or `.codex/config.toml` (ak never writes a machine path into a committed file). Without the pin, a command, hook or MCP server started in a subfolder creates its own `.agentic-qe` there | Not pinned: `ak sync`. Another root or a value you set: edit the named file by hand (remove the three keys), then run `ak sync` in this checkout. A tracked file: untrack it (`git rm --cached`, then `.gitignore`) and run `ak sync`, or start sessions from the project root; see [UPGRADING](UPGRADING.md#2026-09-27-aqe-is-pinned-to-the-project-root) | | MCP tool governance stays `unknown` | No Ruflo MCP tool call was audited in the last 24 hours. Ruflo below 3.46.0 does not route stdio MCP tool calls through its policy enforcer, so no audit records are written there even though ak wrote the policy file and set `RUFLO_MCP_ENFORCE_POLICY=1` | Use a Ruflo MCP tool in the project; on Ruflo below 3.46.0 run `ak sync` to upgrade. A project whose `.harness/mcp-policy.json` is invalid shows `mcpGovernance: blocked` instead: restore a valid, ak-written file and run `ak sync`, which also removes the enforcement variable for that project until the file is fixed | | A [ruflo component](MANAGED-TOOLS.md#managed-ruflo-components) stays `applied, not verified` | Claude Code, Codex, and OpenCode read their environment only at process start-up, so a change setup or sync just made has not reached a running session yet | Restart Claude Code, Codex, and OpenCode, then run `ak status --refresh` to re-collect evidence with the new environment in effect | | Want to run `ak sync` but Claude/Codex/OpenCode sessions are open in other terminals | Upgrade-bearing syncs stop **all** ruflo daemons machine-wide and swap the global npm trees live sessions execute hooks/statusline/MCP calls from; even a no-upgrade sync can repair configuration or missing dependencies | `ak sync --dry-run` first; a `versions` row means idle the other sessions or use `ak sync --no-upgrade` (or `ak sync --skip versions` to hold back only the package upgrades); see [Running `ak sync` while sessions are live](UPGRADING.md#running-ak-sync-while-sessions-are-live) | @@ -96,7 +97,7 @@ ak sync # apply it | A Context card says Not installed, Source unreadable, or No sessions for OpenCode, Codex or Claude | Not installed: the host's store was not found. Source unreadable: it exists but could not be read (the card shows the reason, e.g. `schema`), so an empty list does not mean no sessions ran. No sessions: readable, but nothing ran in the selected window | Not installed: nothing to do. Unreadable: repair the store or permission named in the reason (`ak status` shows the same source health). No sessions: widen the Usage window | | Inspect source says the Hook source changed | The audited file digest no longer matches the short-lived source reference | Close the dialog, refresh/reopen Hooks, and inspect the newly audited reference. Do not reuse an old path or assume the earlier finding still applies | | Usage → Hooks says runtime outcomes are unknown | The default read-only audit inspects configuration; native Claude/Codex/OpenCode executions do not feed the supervised-adapter receipt stream | Treat Stop diagnostics as configuration evidence only. Reproduce a failure from the host/upstream logs; do not read unknown as zero failures or run generated hooks from the dashboard | -| Stop reports AQE `ETIMEDOUT`, or the Hooks view flags AQE npx/timeout codes | Agentic-QE 3.14.0 generated Stop paths can fall back to npx and use millisecond-shaped values in Claude's seconds timeout field | Preserve the generated files, upgrade when Agentic-QE publishes a proven fix, and track [AQE #654](https://github.com/proffesor-for-testing/agentic-qe/issues/654). Agentic-kit detects/attributes the historical failure but does not patch the generated cache | +| Stop reports AQE `ETIMEDOUT`, or the Hooks view flags AQE npx/timeout codes | Agentic-QE 3.14.0 generated Stop paths can fall back to npx and use millisecond-shaped values in Claude's seconds timeout field | Upgrade Agentic-QE (3.14.1 and later generate `node` hooks with seconds timeouts; [AQE #654](https://github.com/proffesor-for-testing/agentic-qe/issues/654) is fixed) and regenerate the project integration, or accept ak's backed-up repair for an exact reviewed copy. Agentic-kit detects the 3.14.0 files but does not patch the generated cache | | Codex reports `hook returned invalid stop hook JSON output`, and Hooks shows **Stop output is not host-compatible** | Ruflo 3.38.20's signed AutoMemory helper writes human-readable sync status to stdout while Codex 0.152.1 expects empty success output or event-valid JSON | Do not edit the generated `.codex/hooks.json` or signed helper. Track [Ruflo #3163](https://github.com/ruvnet/ruflo/issues/3163), upgrade after a released fix passes Codex Stop conformance, regenerate the project integration, and start a fresh Codex process | | `ak setup --project` appears to duplicate or replace guidance | Current setup owns only complete agentic-kit sentinel spans; an exact old lean stub is migrated, AGENTS-only repos get a one-line `@AGENTS.md`, and upstream AQE sentinels remain separate | Upgrade Agentic Kit and rerun setup. Review [Setup guidance precedence](SETUP.md#guidance-precedence-and-repeatability); preserve/report incomplete sentinels or edited near-matches instead of deleting them | | `ak status` says there is no model inventory | No explicit model refresh has completed on this machine | Run `ak models refresh`, then inspect `ak models status` or Dashboard **Usage → Models** | @@ -347,7 +348,9 @@ run `ak sync` there. ### Stray memory stores A stray store is a memory file this project's hosts do not read. `ak status` lists -each one by owner, for information only. ak never moves, merges or deletes them. +each one by owner, for information only. ak never moves, merges or deletes them, with +one exception: a stray AQE store with a `memory.db` is a hand fix, and +`ak x aqe-store merge` merges it into the project store and archives it (below). | Stray | Usual owner | |---|---| @@ -355,7 +358,7 @@ each one by owner, for information only. ak never moves, merges or deletes them. | `./agentdb.db` | The AgentDB CLI's default file | | `./agentdb.rvf` | AgentDB's RVF backend, which defaults to the working directory | | `./ruvector.db` | RuVector's default store (`ruvector mcp start`; `ruflo memory init` also creates one) | -| A `.agentic-qe/` below the project root | AQE resolves a relative `AQE_MEMORY_PATH` against the folder a command or hook ran in | +| A `.agentic-qe/` below the project root | An AQE command, hook or MCP server that started in that folder before ak pinned AQE to the project root. AQE resolves its memory and storage paths against the working directory | | `~/.swarm`, or `.swarm` folders under `~/.codex/.chatgpt-projects/` (reported from any project) | Ruflo ran with your home folder or a Codex ChatGPT project folder as its working directory, before ak's launcher used the user-level store there | Ruflo's rotated backups in `.swarm/backups/` are not strays. The search skips @@ -363,6 +366,49 @@ Ruflo's rotated backups in `.swarm/backups/` are not strays. The search skips and says so when it stops early. Before you delete a stray, inspect it read-only as described above. It may hold rows that exist nowhere else. +### Merge stray AQE stores + +`ak x aqe-store status` shows, for each stray AQE store, its patterns and captured experiences, +how many patterns and experiences the project store already has (AQE skips those), how many are +AQE's starter patterns (imported only when the project store holds them already, so their usage +is kept), and which processes hold a store. Building the preview copies every store into ak's +state folder and starts AQE there twice. Close every Claude Code, Codex and OpenCode session +in the project (their AQE MCP servers and hooks write the store), then run +`ak x aqe-store merge --yes`. + +| The merge says | Why | Fix | +|---|---|---| +| `refused: N process(es) hold the AQE stores: PID …` | A session's AQE MCP server or hook has a store open. AQE takes no lock a merge could wait on | Close the named processes' sessions and run it again. There is no `--force` | +| `could not check which processes hold the AQE stores` | `lsof` is missing, failed, or timed out (macOS, Linux) | Install `lsof`, or run it again when the machine is less busy | +| `refused: … changed since …` | A store was written after the merge copied it: a hook, a manual `aqe` run or a session in a subfolder | Close that writer and run the merge again | +| `the project store … already fails integrity_check` or `foreign_key_check` | The project store was damaged before any merge; nothing was written | Repair the store with AQE first, or restore an earlier backup | +| `an earlier merge (…) was interrupted during its import` | A merge stopped between its imports; its receipt still says `applying` | Run the merge again to finish it, or restore that run's backup (steps below) | +| `…: partially moved: …` | Across filesystems the archive copy is complete, but removing the stray failed part-way | Close what holds it, then delete what is left of the stray by hand | +| `could not build AQE's starter pattern set` | The fresh AQE store the merge builds in its scratch folder holds no patterns, usually because the project's AQE embedder is unreachable | Start the embedder (for Ollama, `ollama serve`) and run it again | +| `merge failed: … count mismatch …` | The project store changed during the merge, or AQE imported fewer rows than the rehearsal | The strays stay in place. Restore the project store from the backup the message names (steps below) if you want the state before the merge | +| `left in place: … EBUSY` (Windows) | A process still held that folder | Close it and run the merge again | +| `left in place: … changed since it was copied` | The stray was written during the import; its data may be newer than the copy | Run the merge again to merge what it gained | + +#### Restore an AQE store from the merge archive + +Each merge keeps `/agentic-kit/aqe-store-merge/