## Summary
Every `showcase_promote.yml` dispatch has failed at the
`resolve-targets` job's "Generate SSOT artifact" step since 2026-06-18
(last green run `27790968900`), blocking ALL promotes including the
team's regular `shell-docs` promote.
**Root cause:** `emit-railway-envs-json.ts` (`oxfmtCanonical`, ~L212)
does `execFileSync(<repo-root>/node_modules/.bin/oxfmt, ...)`. The
`resolve-targets` step's `npm ci` runs in `showcase/scripts` only and
never installs the repo-root oxfmt binary → `spawnSync
.../node_modules/.bin/oxfmt ENOENT` → exit 1.
**Fix (approach a — explicit opt-out, fail-loud-correct):** The JSON
emitted on the `resolve-targets` / `promote` path is **ephemeral** —
`resolve-promote-targets.sh` parses it with jq and `bin/railway` reads
it in-memory to pick the promote target; it is **never committed**, so
oxfmt-canonical formatting is irrelevant there. Added an explicit
`EMIT_SKIP_OXFMT=1` env opt-out that returns the raw `JSON.stringify`
form, and set it on both ephemeral workflow steps. The
**committed-artifact path stays unchanged**: oxfmt is REQUIRED and fails
loud if absent (the committed `railway-envs.generated.json` must stay
oxfmt-canonical or `static_quality.yml`'s `oxfmt --check` auto-format
bot fires). This is opt-IN-to-skip, never silent-on-absence — the
fail-loud-discipline-correct shape.
Approach (b) (read the committed JSON) was rejected to preserve the
existing regenerate-from-SSOT-at-runtime guarantee; approach (c)
(install root oxfmt in that job) is heavier and unnecessary for an
ephemeral consumer.
## RED-GREEN proof (real failure surface, oxfmt binary absent)
**RED — reproduce the production failure** (`npm ci` in
`showcase/scripts` only; repo-root oxfmt absent, exactly as CI's
resolve-targets):
```
$ npx tsx emit-railway-envs-json.ts
Error: spawnSync /private/tmp/cpk-oxfmt/node_modules/.bin/oxfmt ENOENT
at oxfmtCanonical (.../emit-railway-envs-json.ts:212:5)
at serialize (.../emit-railway-envs-json.ts:221:10)
at main (.../emit-railway-envs-json.ts:241:16)
EXIT=1
```
**GREEN — ephemeral path now works** (oxfmt still absent):
```
$ EMIT_SKIP_OXFMT=1 npx tsx emit-railway-envs-json.ts --out=/tmp/ephemeral-out.json
wrote /tmp/ephemeral-out.json
EXIT=0
$ jq '.services | length' /tmp/ephemeral-out.json → 41
$ jq -r '.services[]|select(.probe.prod==true)|.name' ... → aimock, dashboard, docs, ...
$ jq '.closure.services | length' ... → 39
```
And the actual downstream consumer parses it and resolves the team's
`shell-docs` promote:
```
$ INPUT=shell-docs GENERATED=/tmp/ephemeral-out.json ... resolve-promote-targets.sh
services_csv=docs
closure_csv=pocketbase,dashboard,harness,docs
closure_plan=0:pocketbase,1:dashboard,1:harness,2:docs
EXIT=0
```
**GREEN — committed path still canonical AND still fail-loud** (oxfmt
PRESENT, default path, no env var):
```
$ npx tsx emit-railway-envs-json.ts # regenerate committed artifact
wrote .../railway-envs.generated.json
$ git diff --quiet showcase/scripts/railway-envs.generated.json; echo $? → 0 (byte-identical)
$ npx tsx emit-railway-envs-json.ts --check → railway-envs.generated.json is up to date. EXIT=0
```
Committed/default path STILL fails loud when oxfmt absent (NOT
weakened):
```
# oxfmt removed, NO env var:
$ npx tsx emit-railway-envs-json.ts --out=/tmp/x.json
Error: spawnSync .../node_modules/.bin/oxfmt ENOENT (exit 1, nothing written)
```
## Call-site enumeration
- `showcase_promote.yml` **resolve-targets** — `EMIT_SKIP_OXFMT=1` (this
fix). ✓
- `showcase_promote.yml` **promote** — `EMIT_SKIP_OXFMT=1` (this fix;
same ephemeral regen). ✓
- `static_quality.yml` committed-artifact `--check` — unset → oxfmt
REQUIRED, canonical guarantee preserved. ✓
- `resolve-verify-matrix.ts` (`showcase_deploy.yml`) — invokes the
emitter only `if (!existsSync(SSOT_JSON))`; the checkout always carries
the committed JSON, so the default (oxfmt) path is correct and
unchanged. ✓
## Test plan
- [x] RED reproduced on the real surface (ENOENT at
oxfmtCanonical←serialize←main).
- [x] GREEN: ephemeral path emits valid JSON + downstream resolve script
works.
- [x] GREEN: committed path regenerates byte-identical (empty git diff,
`--check` passes).
- [x] GREEN: committed/default path still fails loud when oxfmt absent.
- [x] 2 new `EMIT_SKIP_OXFMT` unit tests; full showcase/scripts suite
2037 passing.
- [x] Pre-push: oxfmt --check, oxlint, actionlint all clean on changed
files.
- [ ] CI green.
The showcase_promote.yml resolve-targets job runs
`emit-railway-envs-json.ts`, which shells out to the repo-root
`node_modules/.bin/oxfmt` to produce oxfmt-canonical JSON. That job's
`npm ci` runs in showcase/scripts only and never installs the root oxfmt
binary, so every promote dispatch died at "Generate SSOT artifact" with
`spawnSync .../node_modules/.bin/oxfmt ENOENT` (exit 1) — blocking ALL
promotes, including the team's regular shell-docs promote, since the last
green run on 2026-06-18.
The emitted JSON on the resolve-targets / promote path is EPHEMERAL: it
is parsed in-memory by jq (resolve-promote-targets.sh) and bin/railway to
pick the promote target and is NEVER committed, so oxfmt-canonical
formatting is irrelevant there. Add an explicit `EMIT_SKIP_OXFMT=1`
opt-out that returns the raw `JSON.stringify` form, and set it on both
ephemeral workflow steps.
The DEFAULT (committed-artifact) path is unchanged: oxfmt stays REQUIRED
and fails loud if the binary is absent, because the committed
railway-envs.generated.json must stay oxfmt-canonical or CI's
static_quality.yml `oxfmt --check` auto-format bot fires on the drift.
This is opt-IN-to-skip, never silent-on-absence.
Call sites of emit-railway-envs-json.ts:
- showcase_promote.yml resolve-targets — EMIT_SKIP_OXFMT=1 (this fix).
- showcase_promote.yml promote — EMIT_SKIP_OXFMT=1 (this fix).
- static_quality.yml committed-artifact `--check` — unset, oxfmt required.
- resolve-verify-matrix.ts (showcase_deploy.yml) — only invokes the
emitter when the committed JSON is absent; the checkout always has it,
so the default (oxfmt) path is correct and unchanged.
Tests: 2037 showcase/scripts tests pass; 2 new EMIT_SKIP_OXFMT unit tests
assert the skip path emits valid (raw) JSON; the existing oxfmt-canonical
golden tests still gate the committed path.
> **DRAFT / WIP — not reviewed, not ready to merge.** Checkpoint per
request. The mandatory 7-agent cr-loop + CI-green gate runs before this
leaves draft. LGP and ADK ship together in this PR.
## Problem (a false-D6 in both directions)
Declarative A2UI demos wire `a2ui.injectA2UITool: true`, so the response
is a rendered `render_a2ui` surface with **no assistant text bubble**.
The D6 conversation-runner's turn-completion gate required the assistant
**text** to stabilize — so on a working declarative demo the run
finished and the dashboard painted, but text never settled →
`waitForTurnComplete` timed out (`reason=text-unstable`) **before the
render assertion ran**.
Result: `langgraph-python:declarative-gen-ui` (the gold standard)
reported **false-RED while rendering correctly** (all 4 pills verified
live on staging), while `google-adk` reported **false-GREEN**.
## Fix
Opt-in `ConversationTurn.completeOnMount` (set only by
`d5-gen-ui-declarative.ts`). For those turns the text-stability
completion conjunct is **replaced** by a surface-mount predicate:
run-finished (sseOk) + a new assistant bubble + the expected declarative
testids **newly mounting**. A non-rendering surface now yields a new
`surface-missing` failure reason (truthful RED). Text-based demos are
byte-for-byte unchanged (opt-in, per-turn).
## Proof (both directions, live D6)
- RED (before): `text-unstable` timeout; dashboard text painted.
- GREEN (after): passes in ~5s; `buildDeclarativeAssertion` actually
runs and verifies testids mount for all 4 pills.
- INTEGRITY: forced a broken render (renamed testids) → test goes
**red** (`surface-missing`). Not "always green now."
- Unit: 89/89 + 3 new (green-on-mount, red-on-surface-missing).
## Scope: LGP + ADK (ship together) — both truthful GREEN
- **LGP** gold-standard cell: false-RED → truthful GREEN (all 4 pills
assert).
- **ADK** realignment: **test-only, complete.** The shared-script fix
auto-applies; verified all 4 ADK pills truthfully GREEN (each surface
mounts from baseline 0 via surface-mount completion). Prior false-green
closed; **no ADK backend gap**.
## Out of scope (someone else's problem)
This shared-script change re-evaluates **every** declarative-gen-ui cell
truthfully. Integrations beyond LGP/ADK that don't actually render will
flip to **truthful RED** — e.g. `langgraph-typescript` pill 2
(team-performance `declarative-data-table` doesn't mount). Those are
real per-demo render gaps for their owners; **not fixed here.**
## Follow-up (not in this PR)
The `render_a2ui` call returns a ~5.9 MB SSE for a ~2 KB surface (LGT
worse) — a separate runtime amplification concern in the
`injectA2UITool:true` middleware path.
## Before ready/merge
- [x] ADK empirical verdict — all 4 pills truthful GREEN, realignment
test-only, no backend gap
- [ ] mandatory cr-loop → zero findings
- [ ] CI green
setHeaders typed headers as Record<string, string>, so there was no
type-safe way to clear a header (e.g. Authorization on logout) — passing
an empty string left the header present with a blank value.
Widen the signature to Record<string, string | null | undefined> and drop
any entry whose value is null/undefined. setHeaders remains a full overwrite,
so clearing one header while keeping the rest is the spread pattern:
setHeaders({ ...copilotkit.headers, Authorization: null }). A shared
normalizeHeaders helper enforces the same string-only invariant at both
write paths (constructor and setHeaders).
Update the react-core AuthTokenSync skill example to show the logout/clear
path and warn that a header must not be managed via both the headers prop and
imperative setHeaders (the provider re-applies prop-derived headers as a full
overwrite when its inputs change). Also update the setHeaders reference
signature docs. Tests cover null/undefined stripping, empty-string
preservation, overwrite-not-merge semantics, single-header clear via spread,
subscriber notification, and propagation to local and remote
(ProxiedCopilotRuntimeAgent) agents.
Fixes#5535
Opts each declarative-gen-ui pill into the new `completeOnMount` turn
completion so these surface-rendering demos are gated on their expected
declarative testids mounting rather than assistant-text stability.
Declarative A2UI demos render a surface (mounted testids) with no assistant
text bubble, so the assistant-text-stability completion gate never settled and
timed out on working demos — a false-RED.
This adds an opt-in `completeOnMount` turn-completion path that replaces the
assistant-text-stability conjunct with a surface-mount predicate: run-finished
+ a new assistant bubble + the expected declarative testids newly mounting.
A new `surface-missing` failure reason reports when the run finishes but the
expected surface never mounts. Turns that do not opt in keep the existing
text-stability behavior unchanged.
Add the Angular frontend quick-start at content/docs/frontends/angular.mdx
and wire it into the frontend picker (options, logo, page content, search
hrefs, search-index generation).
## Summary
Fixes the showcase promote dropdown so the 12 `starter-*` services are
dispatchable. The committed `.github/workflows/showcase_promote.yml`
`service` choice list was never regenerated after the starters landed in
the SSOT, so `gh workflow run showcase_promote.yml -f service=starter-*`
was rejected by GitHub with `HTTP 422: not in the list of allowed
values` (GitHub validates the `choice` enum server-side against the
default branch). This left main's "Showcase: Build & Push" red via
`verify-railway-image-refs`.
## Changes
- Regenerated `showcase_promote.yml` — the `service` dropdown now
includes all 12 starters plus `shell-docs` and every previously-listed
target (nothing dropped). 41 options total.
- `isProdPromotable` reads the canonical env-map shape
(`environments.prod.probe`), equivalent to the workflow resolve
predicate (`select(.probe.prod==true)` against the emitted JSON).
- Added a durable regression test asserting `shell-docs` AND all 12
starters are present in both the generator output and the committed
dropdown, so a future generator regression can't silently drop a promote
target.
## Test plan
- [x] `--check` exits 0 (committed dropdown in sync with SSOT)
- [x] vitest 24/24 pass; regression guard asserts shell-docs + 12
starters
- [x] every emitted token resolves to exactly one prod-eligible service
under the real resolve predicate
- [x] oxfmt/oxlint/typecheck clean on the diff
Regenerated the stale committed showcase_promote.yml so the 12 starter-*
services (+ shell-docs and all existing targets) appear in the service
dispatch choice list (fixes HTTP 422 on
gh workflow run -f service=starter-*). Reverted isProdPromotable to
env-map-only (environments.prod.probe), equivalent to the workflow resolve
predicate. Added a regression test asserting shell-docs + all 12 starters
remain in the generated AND committed dropdown.
## Summary
- Add a top-level Enterprise Intelligence Platform overview that
clarifies platform features, hosting options, plans/access, and the path
from cloud-hosted to self-hosted.
- Add Cloud-Hosted Enterprise Intelligence documentation covering
dashboard login, organization/workspace flow, projects, project API
keys, thread history/detail, and plan management.
- Refresh the Enterprise Intelligence Architecture and Threads &
Persistence Architecture pages so they are architecture-focused instead
of overlapping self-hosting/how-to content.
- Update self-hosting documentation to use the current product taxonomy,
call out Team self-hosted/custom Enterprise availability, and use a
tracked Enterprise-styled CTA for talking to an engineer.
- Add the CopilotKit CLI doc plus shared CLI content across root docs
and all visible authored/generated integration routes.
- Add CLI sidebar entries for authored framework docs and test that CLI
appears in both generated and authored framework nav.
- Add dashboard screenshots for ready, projects, thread list, API keys,
thread detail, and plan management/pricing.
- Update Threads, useThreads reference, multi-conversation tutorial,
architecture/concepts pages, and runtime snippets to point at the new
Enterprise Intelligence docs and remove early-access language from
Threads.
- Retire legacy Observability docs, remove observability references from
quickstarts/runtime docs/nav, and add SEO redirects from root,
troubleshooting, and framework observability URLs to the Intelligence
overview.
- Instrument Enterprise Intelligence CTAs with PostHog: signup CTAs fire
`try_for_free_clicked`, self-hosting engineer CTA fires
`talk_to_us_clicked`, and CLI command copying continues through
`cli_command_copied`.
- Rebase the PR branch onto current `origin/main` and fix the
integration docs doctest by adding LangGraph quickstart Python
dependencies plus clearer server-start diagnostics.
## Commits
- `docs(shell-docs): instrument intelligence ctas`
- `docs(shell-docs): add copilotkit cli docs`
- `docs(shell-docs): refresh intelligence platform docs`
- `docs(shell-docs): retire observability docs`
- `test(doc-tests): fix langgraph quickstart doctest`
## Validation
- `pnpm tsx scripts/doc-tests/extract.ts && pnpm tsx
scripts/doc-tests/run.ts`
- `pnpm exec vitest run scripts/doc-tests/__tests__/extract.test.ts`
- `pnpm exec oxfmt --check scripts/doc-tests/run.ts
showcase/shell-docs/src/content/docs/integrations/langgraph/doctest.json`
- `npm run test` in `showcase/shell-docs`
- `npm run typecheck` in `showcase/shell-docs`
- `npm run build` in `showcase/shell-docs`
- `pnpm run lint` at the repo root (0 errors; existing repo warnings
remain)
- `pnpm exec oxfmt --check` against PR-changed text files
- Local route checks for `/cli`, `/mastra/cli`, `/langgraph-python/cli`,
`/premium/managed-intelligence-platform`, `/premium/self-hosting`
- Local redirect checks for `/premium/observability`,
`/troubleshooting/observability-connectors`,
`/mastra/premium/observability`
Notes: build still reports the existing Next/Turbopack warnings about
deprecated middleware and NFT tracing in `next.config.ts`, but completes
successfully. Full repo `pnpm run check-format` currently fails on
pre-existing files outside this PR:
`examples/v2/react/demo/tsconfig.json`, `migrations.json`, and
`nx.json`; the PR-changed text files pass `oxfmt --check`.
Add an Angular SDK section to the reference docs (OSS-251), mirroring the
React and Vue references. Registers Angular in the reference infrastructure
(new Services and Directives categories, version selector label, subdir map,
overview card) and adds an index plus 17 pages covering provideCopilotKit and
the config/label functions, the CopilotKit service, injectAgentStore and
context APIs, tool registration (frontend, render, human-in-the-loop), the
CopilotKitAgentContext directive, and the prebuilt chat components.
All pages are written against the actual @copilotkit/angular source, use the
correct package name and top-level imports, and surface in llms.txt and
llms-full.txt.
## What
Adds the **"Build an Agentic Travel App with Oracle Agent Memory, Agent
Spec, and CopilotKit"** cookbook recipe, alongside `daytona.mdx` and
following the same section pattern (Try it live → Prerequisites → setup
→ Try it → key code → Going further → coding-agent prompt).
It wires together:
- **Oracle Agent Spec** — define the agent once as portable JSON
(`pyagentspec`)
- **LangGraph + AG-UI** — run that spec via the `ag_ui_agentspec`
adapter, served over AG-UI (SSE)
- **Oracle AI Database** — long-term memory (`oracleagentmemory`) so the
agent remembers across sessions
- **CopilotKit V2** — the chat frontend (generative UI +
human-in-the-loop), consuming the AG-UI endpoint with `HttpAgent`
The example is a travel concierge that recalls your preferences across
sessions, searches flights, and books them with a human-in-the-loop
confirmation card that stamps into a boarding pass.
## Try it live
Embeds the hosted demo as a live `<iframe>` — **cross-session recall
verified working end-to-end** (teach a preference in one thread, open a
new thread, it recalls from Oracle AI Database).
## Files
- `cookbook/oracle-agent-spec-memory.mdx` (new)
- `cookbook/meta.json` — sidebar entry
- `cookbook/index.mdx` — overview card
## Companion code
**#5563** adds the runnable demo at
`examples/showcases/oracle-agent-memory` (Python agent + Next.js
frontend + Oracle AI Database), beside `daytona-runcode`. The recipe's
"Get the code" links point there.
## No external asset dependencies
- "Try it live" is a live `<iframe>` — no CDN video to upload.
- The architecture diagram is an inline base64 data-URI SVG — no CDN
image to upload.
## Caveat kept honest in the doc
- **Recall is eventually consistent** — memory is
extracted/embedded/indexed asynchronously, so a just-taught fact becomes
recallable after a short delay.
## Verified
- `book_flight` is a CopilotKit **ClientTool** (`useHumanInTheLoop`) —
the confirm→book HITL resolves in a single agent run. Multi-turn
follow-ups work via a server-side full-history replace that sidesteps an
upstream Agent Spec × AG-UI `tool_call_id` correlation bug (documented
inline + in #5563's known-issues).
- Playwright E2E covers cross-session recall, flight search, and the
booking HITL (3/3 green).
- All CI green; ready for review.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Fix frontend selection, logo, and docs navigation behavior in shell
docs
- Update link rewriting, search href generation, SEO redirects, and
sitemap handling for frontend docs paths
- Refresh related docs pages and tests across framework and frontend
routes
## Testing
- Added and updated unit tests for frontend options, link rewriting,
search hrefs, SEO redirects, and framework shell layout
- Added route-level coverage for the llms-mdx endpoint
## Summary
Makes showcase cluster promotion **dependency-, env-, and
verification-complete** so prod matches staging after a full promote —
and folds the **starter template apps into the same cluster** so they
get identical treatment. (Design spec: Notion
`3843aa38185281629803fd926b793018`.) One PR.
### Engine (the 19 showcase-* integrations + infra)
- **Dependency-complete:** promote-closure SSOT
(`promoteTier`/`runtimeDeps`/`serviceRefs`) + pure
`computePromoteClosure` (tier-ordered 0→1→2, skip-with-reason, fail-loud
`assertClosureValid`); tier-ordered dependency-gated promote (tier-0
failure blocks 1+2 as NOT-ATTEMPTED, `--digest` escape retained);
`lint-prod` pinned-ness gate.
- **Env-complete:** Ruby preflight — service-ref assertion (REFUSE on
prod→staging host), replicate-class env-write mechanism (opt-in, empty
today), prod-specific assert-never-copy (R-A guard); resource
detect-and-WARN. (`limitOverride` WARN dropped — Railway exposes no
readable limit field, introspection-verified.)
- **Verification-complete:** cross-env pin-drift probe (prod-pinned vs
last-promoted digest — the real prod drift signal); dashboard folds
harness `driver-error`/`abort` + stale cells to gray (genuine failures
stay red — masks-real-red guard verified); prod↔staging equivalence gate
(ChipColor compare, gray-excluded, one-directional) fed by a verify-prod
re-sweep + freshness wait.
### Starters (the 12 starter-* template apps) — "one whole cluster"
- 12 starter SSOT entries (tier 2, `runtimeDeps:["aimock"]`,
`serviceRefs:OPENAI_BASE_URL→aimock`); reversed the 3 decoupling fences
(drift whitelist, `lint-prod` exemption, provisioner) so **`lint-prod`
now covers starters** (flags any prod `:latest`).
- Equivalence + re-sweep run starters on their **starter-smoke axis**
(`probeAxis:"starter"`): enqueue fires `starter_smoke:starter-<slug>`
triggers and the gate reads `starter:<col>/<level>` rows — agent axis
unchanged.
- **F1 value-tested:** all 12 starters carry prod
`OPENAI_BASE_URL`→prod-aimock (mirror showcase-* wiring), so the
service-ref assertion does NOT brick the promote.
### Verification
- 4-round 7-agent cr-loop converged to zero actionable findings (caught
+ fixed a verify-prod always-REFUSE cell-derivation bug, a dead
`limitOverride` WARN, and an incomplete starter enqueue axis). Red-green
on every unit; cross-env probe proven against live Railway.
- Pre-push CLEAN: oxfmt/oxlint, tsc 0 (scripts/harness/dashboard),
suites green (scripts 257, harness 194, dashboard 1118, ruby 160, bats
103), builds 0, actionlint clean.
### Out-of-band prod hotfix (already live)
Prod `aimock` was stale (06-16) and lacked the google-adk
`gen-ui-declarative` fixture → prod served a hallucinated dashboard.
Promoted prod aimock to staging's digest; **value-tested live** — prod
now serves the curated `$4.2M` fixture. This is the exact
dependency-incomplete-promote failure the redesign prevents.
### Phase-2 activation (to switch the new guarantees ON — not in this
PR)
The tier-closure + verify-prod gate ship **dormant/config-gated** (low
blast radius). To activate: (1) wire `CLOSURE_PLAN` into the live
promote step (currently feeds the leaf `SERVICES_CSV`); (2) provision
prod `harness-workers` + set `SHOWCASE_PROD/STAGING_POCKETBASE_URL`,
`SHOWCASE_RAILWAY_ENV_ID_PROD`, `SHOWCASE_RAILWAY_PROJECT_ID`; (3) set
`PROD_HARNESS_BASE_URL`/`PROD_HARNESS_TRIGGER_TOKEN` for the starter
re-sweep.
### Follow-ups (ledgered, non-blocking)
GHCR token-exchange for harness drivers; closure dual-impl imageOf
divergence (latent); discriminated-union type-hardening for
GateCell/CellComparison; misc defensive-branch coverage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
setup() ran logging.basicConfig(force=True) unconditionally at import (module
calls setup() at the bottom), tearing down the host app's root-logger handlers
on every backend even when cvdiag was disabled (CVDIAG_BACKEND_EMITTER off,
canary-safe default) — violating the byte-for-byte-inert contract. Replaced the
root basicConfig(force=True) with a scoped StreamHandler attached to the
"agents" logger, installed ONLY on the ENABLED path (after _ENABLED=True), so a
disabled/degraded setup performs zero logging mutation and the host root
handlers survive. capture-when-enabled (agents.* → stdout) preserved.
Call sites: setup() defined cvdiag_bootstrap.py:133, invoked at import-time
:273 (now no longer touches root). is_enabled() :206 unchanged (gates emit).
basicConfig() call REMOVED from :128; only doc references remain. New scoped
_install_agents_log_capture() runs on the enabled path; reset_for_test() now
detaches the handler.
The four §6-VERBOSE-only backend boundaries (request.ingress, llm.call.start,
llm.call.response, sse.first_byte) called _emit with no tier_gate, so they
over-emitted at DEFAULT tier — 4 extra events/request vs the middleware family,
breaking the §7 tier budget and cross-backend apples-to-apples parity. Gate
them with tier_gate=_VERBOSE_TIERS, matching emit.ts:58-63 and the agno
_BOUNDARY_TIER. langgraph-fastapi received the identical change (the two LGP
files differ only by docstring/plan-unit/_SLUG). Adds default-suppressed +
verbose-emits red-green coverage; updates the pre-existing first_byte
correlation test to drive at VERBOSE tier (the boundary is VERBOSE-only).
emit_cvdiag now early-returns when not is_enabled(), in addition to the
per-integration CVDIAG_BACKEND_EMITTER env check, so a degraded setup()
(_ENABLED=False) emits nothing — the degrade wins over the live env toggle.
Call sites: shared emit_cvdiag (this file, the single chokepoint) now gates on
is_enabled() (the previously-dead _ENABLED flag, set False by setup()'s
fail-closed degrade). Per-integration emitter_enabled() (langgraph-python,
langgraph-fastapi) and cvdiag_backend_enabled() (10 other _cvdiag_backend.py
modules) remain env-only and call into emit_cvdiag — out of scope here; the
shared gate is the defense-in-depth backstop for all of them.