Catalogue close-out and live dev checks

Task 9949 · Done · Coder · created · updated

Original request (verbatim): "Close the gap between Claude, Codex, Antigravity and Pi. More universal code, less provider specific" Settled inputs: PRD (Task 9932) and Architecture (Task 9933) of this epic. Approach (architecture §1): lifecycle events run in Jaah-owned code in front of every session (ACP: `jaah-acp-host`, `apps/jaahd/acp/host.py`; terminal: node daemon + vendor CLI events); tool events run in-band through ONE neutral dispatcher `tools/hook_bridge_core.py::dispatch`. Adapters contribute only declarations (event names, tool-name map, placement literals, error text patterns, question prefix), never a copy of the logic. Requirement R1 (verbatim): "Each of these mechanisms has exactly ONE provider-neutral implementation home that every provider uses; an adapter contributes only vendor literals and capability declarations, never its own copy of the logic: (a) hook/guard rendering & chaining, (b) hook-context injection into the model, (c) charter placement as system/built-in instructions, (d) session-start rule list (guard brief), (e) read-once guard reset signal, (f) prompt-submit and session-end lifecycle events, (g) StopFailure / API-error self-heal, (h) project-memory hooks, (i) token/cost (spend) reading, (j) usage-window (quota) reading, (k) the operator question / structured interview channel." R5 (verbatim): "Availability: every closed capability is ON by default on the dev control plane (`dev.jaah.ai`) — no new switch that ships OFF; if a switch is unavoidable it defaults ON and is wired in the real deployment." Closing-test naming contract (architecture §4): every removed degradation key must have a test named `test_closes_<key with - as _>` from its owning behaviour child; this child is the one that removes keys and checks the contract mechanically. ## Scope (this child) Architecture child C9 — after all behaviour children (C1–C7, C3a, C3b). Requirements R2, R3, R4 and the operator-visible ACs. R2 (verbatim): "Every degradation in the done-set is removed from its row in `apps/jaahd/agent_providers.py` (or kept under the feasibility escape), and the behaviour it described is delivered on that provider." R3 (verbatim): "Every \"stay published\" degradation remains, key and consequence unchanged." R4 (verbatim): "Claude and DeepSeek behaviour does not regress: their existing capabilities and degradations (except DeepSeek `no-quota-reading`) are unchanged." Done-set (PRD, verbatim): Codex: `no-stop-failure-self-heal`, `omx-hooks-off-on-acp`; project-memory hooks. Antigravity: `no-stop-failure-self-heal`, `charter-in-first-prompt`, `no-read-once-guard`, `no-hook-context`, `guard-brief-at-first-denial`, `no-prompt-submit-event`, `no-session-end-event`; project-memory hooks; `no-structured-interview`. Pi: `charter-in-first-prompt`; project-memory hooks; `no-spend-reading`; `question-by-command`. (Antigravity `no-spend-reading`, Pi and DeepSeek `no-quota-reading` are feasibility-escaped, architecture §6.) - Remove the done-set keys from `apps/jaahd/agent_providers.py` (including `_SHARED`'s `no-stop-failure-self-heal`). Each removed key must have its closing child's `test_closes_<key>` test (both halves for keys split across runtimes: `no-read-once-guard`, `no-prompt-submit-event`, `no-session-end-event`). Never remove a key without its closing test(s). The PRD allows a done-set key to stay published ONLY under the feasibility escape with cited vendor evidence — a blocked child is NOT that. So if any closing test is missing (e.g. a C3a/C3b that settled blocked on `agy1`), this child must NOT report the epic complete: it leaves that key published, raises ONE AskUserQuestion round (header `Human act`) naming the key, its blocked child and what clears it (e.g. `agy1` re-login), delivers everything else, and — if not cleared — states in its PR body and settle summary "EPIC INCOMPLETE: <keys> still published, blocked on <reason>" so the Finish stage files the follow-up. - Remove the `drop_memory` branch at `apps/jaahd/agents/base.py:699` (all five rows now `project_memory_hooks=True`; the field itself stays for AC2). - Keep every stay-published, deferred and I1-escaped key byte-identical. Add the architecture §6 evidence as a code comment beside each escaped key (antigravity `no-spend-reading`: agy-acp-server 1.4.1 measured in Task 8810, `apps/jaahd/README.md` §Antigravity, agy 1.2.11 transcript `apps/jaahd/agents/antigravity_transcript.py`; pi `no-quota-reading`: https://platform.claude.com/docs/en/api/rate-limits fetched 2026-10-25 — monthly spend cap + per-minute buckets, Admin key needed; deepseek `no-quota-reading`: https://api-docs.deepseek.com/quick_start/rate_limit and https://api-docs.deepseek.com/api/get-user-balance fetched 2026-10-25 — concurrency only, prepaid balance, no window). - Update `tools/tests/test_agent_providers.py` and `tools/tests/test_provider_capabilities.py`. - Expected catalogue after this child (AC1, architecture §5): - claude `[]` - codex `[device-code-login-workspace-gated, subscription-concurrency-throttling]` - deepseek `[beta-features-ignored, claude-model-names-remapped, document-blocks-unsupported, images-flash-only, model-quality-differs, no-quota-reading, prompt-cache-controls-ignored, web-search-extra-calls]` - antigravity `[home-is-account-dir, microvm-signed-in-legacy-runtime, no-spend-reading, not-yet-observed]` - pi `[acp-runtime-only, no-quota-reading, no-subagents]` - Live on dev (`https://app.dev.jaah.ai`), after the merge deploys (watch the Jaah Deploy of the PR succeed): AC5, AC6 (Antigravity `gem2` ACP + Pi `t7281-pi-key`), the ACP half of AC7 (Antigravity `gem2` console), AC9 (Pi token counts and cost), AC10 on Pi and Antigravity ACP, AC11 (Claude `acct1` terminal + `arqmulpj1jva` ACP). Enabling `t7281-pi-key` in the console (Accounts toggle) is the verifier's first step. Anything broken goes to a follow-up task per the project directive. - The Antigravity terminal half of AC7/AC10 and the live Codex half of AC8 belong to the Finish stage once the operator has re-logged in `agy1` and `cod1`. Credentials & reach: - C1–C7 unit and replay tests, AC1–AC4 | nothing beyond the worktree (`./dc check full`) | verified (worktree) - AC5, AC9, AC11 browser checks | `org/console/dev-login` (on roster, `credential_get` ok; its `base_url` field is stale, so use `https://app.dev.jaah.ai`) on dev | verified (probe: GET / → 200; Accounts page read in browser) - AC6/AC7/AC10 Antigravity ACP | dev account `gem2` (Antigravity API key, available, explicit-only) | verified (Accounts page row "available") - AC6/AC9/AC10 Pi | dev account `t7281-pi-key` (Pi API key; row present, currently Disabled, and its enable toggle is a live button on the Accounts page, so C9's verifier enables it as a console action); the Anthropic key behind it: roster `me/jaah/system/anthropic_api_key`, `credential_get` ok | verified (probe: Accounts page row read in browser, toggle present) - AC9 DeepSeek / AC4 regression | dev `deepseek1` (available); roster `org/deepseek` verified | verified - AC11 Claude regression | dev `acct1` (subscription, available), `arqmulpj1jva` (API key, available) | verified - C3a/C3b terminal measurements + AC7/AC10 Antigravity terminal (live half) | dev account `agy1` (Google sign-in; Accounts page shows "Needs attention: Login") | **deferred**: the login is an operator action (I4: "I'll re-login both"). C3a/C3b are held until `agy1` shows available (their measurements need it); the Finish stage then runs the live checks - AC8 live Codex replaced runner | dev account `cod1` (Accounts page: "no credentials") | **deferred**: awaiting operator re-login (I4). The Finish stage runs it once signed in; C7 replay fixtures prove the behaviour Out of scope (PRD, verbatim — do NOT touch): - MUST NOT retire, rewrite or change the runtime selection of the legacy terminal runtime; Claude `oauth` stays `legacy_only` (ADR in `docs/adrs/README.md`, ACP Claude entry). - MUST NOT remove or reword any "stay published" degradation (list above), including Pi `no-subagents` and `acp-runtime-only`. - MUST NOT build Pi subagents or a Jaah-side subagent lane. - MUST NOT add Jaah-side workarounds for vendor-intrinsic DeepSeek/Codex gaps (PDF conversion, model remap changes, throttling avoidance). - MUST NOT do live-verification work for Antigravity `not-yet-observed`, nor touch `home-is-account-dir` or `microvm-signed-in-legacy-runtime`. - MUST NOT change `tools/provider_branches.toml` patterns/allowlist scope beyond what removing branches requires (gate tightening was not selected), and set no line-count target. - MUST NOT add a new provider or retire one; no change to login/sign-in flows, model-tier resolution, or the plan gate (`non_claude_engines`). Stay-published keys (must stay byte-identical): DeepSeek `document-blocks-unsupported`, `images-flash-only`, `prompt-cache-controls-ignored`, `beta-features-ignored`, `web-search-extra-calls`, `claude-model-names-remapped`, `model-quality-differs`; Codex `device-code-login-workspace-gated`, `subscription-concurrency-throttling`; Pi `no-subagents`, `acp-runtime-only`. I1-escaped (stay, unchanged): Antigravity `no-spend-reading`; Pi and DeepSeek `no-quota-reading`. Done means: - AC1 (R2/R3 catalogue) → verify: `python3 -c "import sys;sys.path.insert(0,'apps/jaahd');import agent_providers as a;[print(p.value,sorted(d.key for d in p.degradations)) for p in a.PROVIDERS]"`; observe exactly the "stay published" + "deferred" + any feasibility-escaped keys per row and none of the done-set keys. Claude prints `[]`. (Must equal the expected catalogue above exactly; any deviation is a done-set key kept for a missing closing test and makes this child report EPIC INCOMPLETE as described in scope — never a pass.) - AC2 (project-memory hooks) → verify: same import, print `p.capabilities.project_memory_hooks` per row; observe True for all five. - AC3 (R1 mechanism homes) → verify: the spec names, per mechanism (a)–(k), its one home `file:symbol`; code review confirms no adapter in `apps/jaahd/agents/` re-implements it (adapter diff contains only vendor literals/declarations for that mechanism); `python3 tools/check_provider_branches.py` exits 0. - AC4 (tests) → verify: `./dc check full` green, including `tools/tests/test_agent_providers.py` (completeness/no-ghosts) and `tools/tests/test_provider_capabilities.py`; each removed degradation has a test proving the capability on that provider (e.g. ACP replay fixture under `apps/jaahd/tests/acp_replay/`). Mechanically: for every removed key `grep -rn "test_closes_<key with - as _>"` finds at least one test. - Stay-published consequence text byte-identical: `git diff` of `agent_providers.py` shows no change to any stay-published/deferred/escaped key's `consequence` (only added evidence comments). - R4: `git diff 839545026..HEAD -- apps/jaahd/agent_providers.py` (cumulative epic diff from the develop commit this plan was made on) shows no change to Claude's or DeepSeek's `Capabilities`/`AcpDialect`/degradations other than the DeepSeek `no-quota-reading` evidence comment. - R5: review of the epic's merged diffs (`git diff 839545026..HEAD`) finds no new switch, env knob or Settings toggle gating a closed capability — cite the grep for new `JAAH_*` env reads / settings keys. - AC5 (Settings > Providers, operator-visible) → verify: open `https://dev.jaah.ai` Settings > Providers in a browser; for Codex, Antigravity, Pi, DeepSeek observe the gaps list shows only the expected remaining keys' capability headings, readable (headings untruncated, consequence text in full), and the harness group for Codex/Pi is empty. Same in the Add Account dialog for each provider. (Use `https://app.dev.jaah.ai`; also check at phone width that headings stay untruncated and consequence text is not clipped — screenshot cited.) - AC6 (hook context + charter, harness) → verify on dev: run a Task on an Antigravity account (ACP) and a Pi account; open its session transcript in Audit > Sessions; observe the charter delivered as system/built-in instructions (not as the first user message), the project's guard rule list present at session start, and a hook-context note (e.g. context-architecture check after an edit) visible in the model context. - AC7 (guards & lifecycle, ACP half) → verify on dev: in an Antigravity console session, re-read a file twice → re-read guard fires; type into an idle chat → prompt-submit event reopens it; quit at the prompt → the session completes. (terminal half deferred — `agy1` re-login; Finish stage) - AC8 (self-heal) → verify: a replay/fixture of a vendor API error on Codex and Antigravity API-key runs produces an `error` that posts the break with `request_replace` immediately (not via reclaim sweep); observe in the test output and, on dev, the replaced runner in the task timeline. (live Codex half deferred — `cod1` re-login; Finish stage) - AC9 (spend & quota) → verify on dev: after a completed run on Antigravity and Pi, the task/session shows token counts and cost; Accounts page shows a usage window for Pi and DeepSeek accounts (or the item is feasibility-escaped with cited evidence). (Antigravity spend, Pi/DeepSeek quota escaped per architecture §6 — the evidence comments are the citation; Pi tokens+cost must show.) - AC10 (operator interaction) → verify on dev: a Task with Autonomous OFF on an Antigravity terminal session and on Pi asks through the structured question card (console shows the question with options, answering returns it to the same session), not a shell command/prose. (Pi and Antigravity ACP here; Antigravity terminal deferred — `agy1` re-login; Finish stage) - AC11 (no regression) → verify: a Claude subscription Task (terminal runtime) and a Claude API-key Task (ACP) on dev complete as before; their Settings > Providers rows are unchanged.

Outcome

Catalogue closed: every done-set key removed, each with its test_closes test, and it matches the expected AC1 output. PR #6927 merged with the full gate green, and Jaah Deploy to dev succeeded. Live on dev: Providers page, Pi question card and Pi cost/tokens pass. Remainder: Antigravity ACP live checks are blocked on gem2's depleted Gemini credits (operator: settle). Drafted #10115. Memory: none applied.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Awaiting response
  • Awaiting response
  • Runner resumed
  • Runner ended (done)