refactor(angular): signals-based reasoning collapse - #2
Open
rainerhahnekamp wants to merge 7 commits into
Open
rainerhahnekamp wants to merge 7 commits into
rainerhahnekamp wants to merge 7 commits into
Conversation
Adds angular-developer and angular-new-app skills via `npx skills add` from https://github.com/angular/skills into .agents/skills/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apply the common Angular CLI schematics to code which has been added by Soverius. We can do a follow-up for the high amount of effects, but we have to be careful. We need tests first to do a refactoring for that.
Revert open-generative-ui-tool-renderer and drop empty imports arrays. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
rainerhahnekamp
force-pushed
the
feat/ng-a2ui-exp
branch
2 times, most recently
from
June 10, 2026 20:48
d0f3161 to
015701f
Compare
wolfmanfx
force-pushed
the
feat/ng-a2ui-exp
branch
from
June 11, 2026 09:47
c57ec9b to
0fa62b3
Compare
rainerhahnekamp
force-pushed
the
feat/ng-a2ui-exp
branch
from
June 15, 2026 19:21
0fa62b3 to
cedf661
Compare
rainerhahnekamp
pushed a commit
that referenced
this pull request
Jun 15, 2026
…-side parity (SU7-F1/F2/F3)
SU7-F1 — backend host pattern hardening:
- F1.1 Reject bare trailing ?/# in the backend host pattern
- F1.2 Strip internal tab/CR/LF from the backend host pattern
- F1.3 Warn when ignoring an empty-string local backend override
- F1.4 Reject empty-userinfo @ in the backend host pattern authority
- F1.5 Keep __proto__ keys as data in local-backend maps
- F1.6 Commit the local-backends memo key only after the value computes
- F1.7 Trim local backend overrides before validation and name the real
rejection
- F1.8 Honest FATAL when the pattern host is a stray scheme fragment
- F1.9 Canonicalize the pattern authority for parity with the override
path
- F1.10 Acknowledge the staging-to-prod fail-open in the pattern fallback
- F1.11 Harden backend-url/local-backends-env test hygiene
SU7-F2 — runtime-config & client-config edge cases:
- F2.1 Branch POSTHOG_HOST rejection reasons (scheme/degenerate/parse-
failure) instead of the catch-all mislabel
- F2.2 Reject loopback BASE_URL/DOCS_HOST in production instead of the
silent http:// prepend
- F2.3 Key the DOCS_HOST fallback once-guard on (mode, shellHost, value)
and mode-prefix all value-only guard keys
- F2.4 Reject a present-but-empty posthogKey in the client config reader
- F2.5 Drop the trailing slash from SSR_PLACEHOLDER_URL for structural
parity with server values
- F2.6 Attribute the DOCS_HOST slash-strip to readDocsHost itself
- F2.7 Normalize trailing-dot FQDN spellings in the docs self-host loop
guard (both compare sides)
- F2.8 Harden console spies to capture all log args; pin the full all-env
config shape; converge SSR simulation on vi.stubGlobal
SU7-F3 — script-side parity, table classification & test isolation:
- F3 #1 Handle a missing reference integration per the error contract
- F3 #2 Port the runtime backend-host-pattern normalization into the
generator — scheme/trailing-slash strip, degenerate fallback,
NEXT_PUBLIC fallback
- F3 #3 Treat non-mapping manifest parses (empty/null/scalar/array YAML)
as validation errors, not TypeErrors
- F3 #4 Label a missing/unreadable constraints.yaml per the stderr+exit(1)
error contract
- F3 #5 Align atomic-write tmp naming with the test harness straggler-
sweep convention; guard main() on direct invocation
- F3 #6 Correct the determineCellStatus unshipped docstring; replace
stale hardcoded cell counts with formulas
- F3 CopilotKit#7 Isolate the pattern suite on a per-suite tmpdir harness; snapshot
the generator's full write set
- F3 CopilotKit#8 Classify discarded duplicate wildcards as duplicates — hoist the
owner check above the destination warns
- F3 CopilotKit#9 Reject a root ("/") EXACT seo-redirect source — homepage-hijack
twin of the root-wildcard guard
- F3 CopilotKit#10 Reject seo-redirect entries with non-printable-ASCII source/
destination — close the silent-dead-entry class
- F3 CopilotKit#11 Strip trailing slashes in normalizePosthogHost before the scheme
test
- F3 CopilotKit#12 Message-filter the empty-slug-set error count; pin the single
matcher entry
rainerhahnekamp
pushed a commit
that referenced
this pull request
Jun 15, 2026
… not only an array nested value; dashboard mirror updated in lockstep (drift test pins byte-identity) (CR G2 #2)
rainerhahnekamp
pushed a commit
that referenced
this pull request
Jun 15, 2026
…cer-emitted degraded reads 'degraded', not 'stale' (CF6-G5 #2)
rainerhahnekamp
pushed a commit
that referenced
this pull request
Jun 15, 2026
… dereferencing probeKey (CF7 #2) A null/undefined/primitive enumerator element threw a TypeError out of the tick body, rejecting the tick promise and violating the 'tick never rejects' invariant. Non-object elements are now dropped loudly and counted in the existing invalid-spec accounting.
rainerhahnekamp
pushed a commit
that referenced
this pull request
Jun 15, 2026
…gray, never green (CF7-F3 #2) The D1-D4 gate fires only on d3.exists/d4.exists, so a cell with ONLY green D5/D6 rows (no e2e/chat/tools rows at all) slipped past it and rendered a green chip + green d6Effective at achievedDepth=0/ ceilingDepth=0 — a false top-of-ladder claim contradicting the strictness doctrine (PRESENT-but-null D4 grays; D5-no-data grays the ladder). A wholly absent D3/D4 family now collapses to the gray "unverified" chip (same shape as the d4NoData collapse) with red-D5/D6 dominance preserved, and d6Effective stays blocked (null). cell-model.ts:847-852 (gate) / :905-921 (d6Effective). One existing fixture (amber pass-through under reclaimed-pending) built its amber from an absent-D3/D4 map; it now carries green e2e/chat rows so the chip is genuinely amber through an intact ladder — the test's never-mask assertion is unchanged.
rainerhahnekamp
force-pushed
the
feat/ng-a2ui-exp
branch
2 times, most recently
from
June 17, 2026 15:57
3064fb9 to
cd3a94f
Compare
wolfmanfx
pushed a commit
that referenced
this pull request
Jul 10, 2026
…rwarded inbound headers (CopilotKit#5782) ## Problem When a self-hosted v2 `CopilotRuntime` is configured with a server-side agent (an `@ag-ui/client` `HttpAgent` with static `headers` for service-to-service auth), the runtime forwards inbound `authorization`/`x-*` request headers onto the agent's outgoing call **and lets them override the headers the server configured** — silently breaking service-to-service auth to a secured backend (e.g. a private Cloud Run agent behind IAM). `Fixes CopilotKit#5712` ## Root cause `packages/runtime/src/v2/runtime/handlers/shared/agent-utils.ts:125-128` merged forwarded inbound headers **last**, so they won on collision: ```ts agent.headers = { ...agent.headers, // server-configured ...extractForwardableHeaders(request), // inbound — overrode the above }; ``` There are actually **two** failure modes: 1. **Same-case collision** — inbound `authorization` overwrites a server `authorization` (last-write-wins). 2. **Case-mismatch collision** — `extractForwardableHeaders` lowercases inbound keys (`authorization`), while the server typically configures canonical casing (`Authorization`). A plain spread treats those as *distinct* keys and emits **both** — which undici downstream comma-joins into a single invalid `"Bearer A, Bearer B"` ("multiple JWTs") value. Flipping the spread order alone does **not** fix this case. ## Fix In `agent-utils.ts`, make server-configured `agent.headers` authoritative on collision, matched **case-insensitively**: drop any forwarded inbound header whose name (case-insensitively) is already set on the agent, and let non-colliding inbound headers pass through unchanged. This preserves the existing forward-for-auth behavior for headers the server does *not* set, while guaranteeing a server-set token is never overridden or duplicated. The merge logic lives in a shared `mergeForwardableHeaders(serverHeaders, request)` helper in `packages/runtime/src/v2/runtime/handlers/header-utils.ts` so the precedence semantics are defined in exactly one place. ### Scope note This is the conservative precedence + case-insensitive-dedup fix (the issue's suggested fix #1). I did **not** tighten the default allowlist to drop hop-by-hop/platform `x-*` headers (`x-serverless-*`, `x-forwarded-*`, …) or add an opt-out — those alter existing forwarding behavior and are worth a separate, deliberate change. The precedence fix alone resolves the reported breakage (the server-set token now wins regardless of what the platform injects on a colliding header name). A documented workaround already exists for users on released versions: pass a custom `fetch` to the `HttpAgent` that builds outgoing headers from scratch (it runs after `configureAgentForRequest` and survives the per-request `agent.clone()`). ## Red-green proof (the real fix — `/run` path) The load-bearing assertion: there must be exactly **one** authorization header carrying the **server** value. ### RED (fix stashed, against unmodified `agent-utils.ts`) ``` ❯ src/v2/runtime/__tests__/agent-header-precedence.test.ts (2 tests | 1 failed) × configureAgentForRequest — header precedence (CopilotKit#5712) > server-configured agent headers win over a colliding inbound header AssertionError: expected [ 'Authorization', 'authorization' ] to have a length of 1 but got 2 81| expect(authKeys).toHaveLength(1); Test Files 1 failed (1) Tests 1 failed | 1 passed (2) ``` The pre-existing `agent-utils-header-forwarding.test.ts` also failed, because it explicitly encoded the buggy behavior (`expect(...["x-aimock-context"]).toBe("new-context")` — inbound winning): ``` FAIL src/v2/runtime/__tests__/agent-utils-header-forwarding.test.ts > ... > request forwardable headers override matching pre-existing agent headers AssertionError: expected 'old-context' to be 'new-context' ``` ### GREEN (fix applied) ``` ✓ src/v2/runtime/__tests__/agent-header-precedence.test.ts (2 tests) 2ms ✓ src/v2/runtime/__tests__/agent-utils-header-forwarding.test.ts (8 tests) 3ms Test Files 2 passed (2) Tests 10 passed (10) ``` The colliding test (`agent-utils-header-forwarding.test.ts`) was updated from asserting the old bug to asserting corrected precedence + a new case-insensitive-dedup guard. The non-colliding-forward test is retained unchanged as a regression guard. ## Quality gates ``` NX Successfully ran target check-types for project @copilotkit/runtime NX Successfully ran target test for project @copilotkit/runtime — Test Files 113 passed (113), Tests 1576 passed (1576) ``` --- ## `/connect`-path change — forward-looking plumbing, inert today The original issue and a prior eval flagged the same forwarding pattern at `handlers/sse/connect.ts`. To keep the two paths' merge semantics consistent, the `/connect` path now builds the same server-wins merged headers (via the shared `mergeForwardableHeaders` helper) and passes them into `runner.connect()`. **This is not an active auth fix, and it is not red-green-proven as one — because there is no live bug to fix on the connect path today.** No shipped runner consumes the `headers` field of `AgentRunnerConnectRequest`: the in-memory, intelligence, telemetry, and sqlite runners all destructure only `threadId` from the connect request and ignore `headers` entirely. Connect is a thread replay/reconnect, not a fresh outgoing agent call. So whatever headers we pass into `runner.connect()` are dropped on the floor by every runner that ships. What this change actually does: - Threads the per-request agent clone through `handle-connect.ts → handleSseConnect` so the connect path *has access to* the server-configured `agent.headers` (it previously did not). - Passes `mergeForwardableHeaders(agent?.headers, request)` into `runner.connect()` — the correct, server-wins argument **shape** for a future outbound-connecting runner that *would* consume connect-path headers. - Rewrites the comments/JSDoc on this path to say this plainly, rather than implying an active auth fix. It also documents that the connect-site `cloneAgentForRequest` call is the sole `agentId`-existence guard (the intelligence branch never re-validates the id), and documents `cloneAgentForRequest`'s `AbstractAgent | Response` (404) dual-return contract that both callers depend on. The real outbound header forwarding — the thing that fixes CopilotKit#5712 — is the `/run` path's `agent.headers` mutation described above. The connect change is staged plumbing so that if/when a runner starts honoring connect-path headers, it inherits the same server-wins precedence without a second fix. ### Tests on the `/connect` path The connect tests assert the *merge shape* that reaches `runner.connect()` (server value wins on collision, exactly one `authorization` key, non-colliding `x-*` still forwards) and that the agent-undefined case (no server `agent.headers`) degrades to forwarding allowlisted inbound headers only and does not crash. These verify the argument we construct is correctly shaped — not that any shipped runner consumes it. ## Files - `packages/runtime/src/v2/runtime/handlers/header-utils.ts` — shared `mergeForwardableHeaders` helper (case-insensitive, server-wins). - `packages/runtime/src/v2/runtime/handlers/shared/agent-utils.ts` — `/run` path uses the helper so server headers win on collision (**the real fix**). - `packages/runtime/src/v2/runtime/handlers/sse/connect.ts` — `/connect` path uses the helper; forward-looking plumbing, inert until a runner consumes connect-path headers. - `packages/runtime/src/v2/runtime/handlers/handle-connect.ts` — threads the per-request agent clone into `handleSseConnect`. - `packages/runtime/src/v2/runtime/__tests__/agent-header-precedence.test.ts` — `/run` regression test exercising the real `configureAgentForRequest` surface with a real `HttpAgent`. - `packages/runtime/src/v2/runtime/__tests__/agent-utils-header-forwarding.test.ts` — updated the test that encoded the old (buggy) precedence; added a case-mismatch dedup guard. - `packages/runtime/src/v2/runtime/handlers/sse/__tests__/sse-connect-agent-id.test.ts` — connect-path merge-shape + agent-undefined coverage. ### Notes - A documented `@ag-ui/client` `HttpAgent` `fetch` workaround already exists for attaching service-to-service auth the runtime can't override (see the issue). This change makes the workaround unnecessary for the `/run` precedence case. - Conservative scope: this is the **precedence flip on `/run`** plus forward-looking connect plumbing. Tightening the default allowlist (dropping hop-by-hop / platform `x-serverless-*`, `x-forwarded-*`, `x-cloud-trace-context`, …) and an opt-out switch — issue suggestions #2/#3 — are intentionally left as a follow-up to keep the security-policy change minimal.
wolfmanfx
pushed a commit
that referenced
this pull request
Jul 20, 2026
…d failures (CopilotKit#5956) ## Two silent-failure gaps in the showcase build/deploy/notify pipeline These are **pre-existing** silent-failure holes surfaced in code review (not caused by any recent PR). This PR fixes the two load-bearing ones. ### 1. Green-but-zero-redeploy (silent "we thought we shipped but didn't") The `redeploy-staging` job computes the redeploy set as the intersection of the build matrix and the build-success set. This job **only runs when `aggregate-build-results.outputs.any_success == 'true'`** (job-level `if:` guard). So if that intersection comes back **EMPTY**, it does NOT mean "nothing to deploy" — it means at least one slot built successfully yet none of those successes maps back to a matrix `dispatch_name`. That's a `dispatch_name`↔ `service` contract skew (the aggregator's `service` values and the matrix's `dispatch_name` values drifted apart). The old code emitted `services=` (empty) and exited 0 → the build went **GREEN while redeploying NOTHING**, silently. **Fix:** on an empty intersection in this any_success-guaranteed step, fail loud (`::error::` + `exit 1`) with a diagnostic naming both sides of the skew. The legitimate "nothing changed / nothing succeeded" no-op paths are guarded at the **job level** (`has_changes=='true' && any_success=='true'`), so the fixed step never runs there — no false-red. ### 2. Starter build failures had no alert surface (invisible failures) The `notify` job's `needs` (and its `if: failure()`) omitted `detect-starter-changes` and `build-starters`, and `build-starters` wrote no per-slot build-result artifact. So a **failed starter image build produced NO Slack alert and NO PR comment** — it shipped silently. **Fix:** - Added `detect-starter-changes` + `build-starters` to `notify.needs` so `if: failure()` sees a starter build failure → Slack alert + PR comment. - Gave `build-starters` a per-slot build-result artifact **mirroring the main `build` matrix** (same `{service,status}` shape, `cancelled→skipped` normalization, `if: always()`, `if-no-files-found: error`), using a **distinct `starter-build-result-*` prefix** so it never matches the aggregator's `build-result-*` download pattern (starters must not pollute the showcase redeploy set keyed by `dispatch_name`). ### Red / Green **Finding #1** — extracted the step's shell/jq logic and drove it with synthetic inputs: RED (pre-fix), any_success=true + empty intersection: ``` No services in matrix ∩ success-set — skipping redeploy. Computed services CSV (matrix ∩ build-success): EXIT=0 # $GITHUB_OUTPUT: services= -> silent pass, redeploys NOTHING ``` GREEN (post-fix), same inputs: ``` ::error::Build succeeded (any_success=true) but matrix ∩ success-set is EMPTY — dispatch_name/service contract skew; nothing would be redeployed. Successful build service values: ["shell-RENAMED","mastra-RENAMED"] Scheduled matrix dispatch_name values: ["shell","mastra"] EXIT=1 # fails loud ``` No-regression: non-empty intersection → `EXIT=0 ; services=shell`. The nothing-changed/nothing-succeeded paths are skipped at the job level (never reach the step) → no false-red. **Finding #2** — modeled `if: failure()` (fires iff any `needs` job result is `failure`): ``` BEFORE (starters NOT in needs), starter=failure -> notify fires = False (INVISIBLE, the bug) AFTER (starters IN needs), starter=failure -> notify fires = True (FIXED) AFTER no-regression, starters=skipped, all green -> notify fires = False (quiet) ``` ### Validation - `python3 yaml.safe_load` parses OK. - `actionlint`: only pre-existing findings remain (matrix jq SC2086 + the known `depot-ubuntu-24.04-4` runner-label warning); no new errors in edited regions. - `yamllint`: only pre-existing line-length/document-start/truthy warnings. ### Scope Touches **only** `.github/workflows/showcase_build.yml`, and only these two concerns. Does NOT touch the `shell_dashboard` paths-filter region (PR CopilotKit#5955's domain), nor the other backlog debt (false-root-cause comment, double-alert, check-lockfile guard). Self-contained; not stacked on CopilotKit#5955.
wolfmanfx
pushed a commit
that referenced
this pull request
Jul 20, 2026
CopilotKit#6035) ## What Follow-up nit from [PR CopilotKit#5969](CopilotKit#5969) review ([OSS-488](https://linear.app/copilotkit/issue/OSS-488)). Fixes the `getMessages` JSDoc in `packages/channels-intelligence/src/intelligence-adapter.ts`, which oversold image support. The comment cited *"what was in the image"* as a `read_thread` use case, but image/file parts contribute **no text** in this mapping — `read_thread` is text-only by design. Image *content* reaches the model only via `conversationStore`'s seeding of `agent.messages`. The comment now says so explicitly instead of implying `read_thread` can see image content. Comment-only change — no runtime/API behavior change, so no changeset. ## Scope of OSS-488 The ticket listed three nits; this PR addresses the one still actionable: - **#1 (double-space when joining content parts)** — ✅ already resolved on `main` (the `.filter(Boolean).join(" ")` fix + updated test landed via the OSS-476 CR round). Nothing to do. - **#2 (JSDoc oversells image support)** — ✅ **this PR**. - **#3 (duplicate `getHistory` fetch per turn)** — intentionally **deferred**. A per-turn memo would need turn-scoped caching with a clear-on-turn-start hook; without one it risks serving stale history — a correctness regression on something the ticket itself rates "acceptable for an on-demand tool." Not worth it here. The **known limitation** (speakers collapse to `user`/`bot` because upstream `AgentMessage` carries no names) is unchanged and not actionable at this layer. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wolfmanfx
pushed a commit
that referenced
this pull request
Aug 6, 2026
Follows the maintainer's Correction #2 on issue 6363. An exact version in a docs install command is the same rot as the starlette==0.45.3 pin it replaced: it goes stale silently and nobody re-resolves prose. The 2.22.0 the docs shipped was already a version behind current the day it was written. - docs install lines use pydantic-ai-slim[ag-ui,openai]>=2,<3, which constrains the dep the pages actually care about and fails loudly at the v3 boundary - ag-ui-protocol drops out of the docs lines entirely; no doc snippet imports ag_ui, so naming it there was the transitive-dep noise the correction is about - starlette>=0.46.2 stays, because the v2 snippets import Starlette directly. A floor with no ceiling cannot force a downgrade, so it does not recreate the silent backtrack - examples/showcases/pydantic-ai-todos moves to a range in pyproject.toml and relocks; the uv.lock is what reproduces - examples/canvas/pydantic-ai keeps exact pins: it has no lockfile, so requirements.txt is its only reproducibility artifact Smoke-tested the open question from the issue: starlette 1.x works on pydantic-ai v2. All 8 doc pages pass on 2.23.0 + starlette 1.3.1 and on 2.23.0 + starlette 0.52.1, so Jordan's <1.0 guard can be dropped rather than raised.
wolfmanfx
pushed a commit
that referenced
this pull request
Aug 14, 2026
…wave slots could not reach Comment-only, no behaviour change. Each of these sat OUTSIDE the boundary of the slot whose work falsified it, so each described the tree as it was mid-migration. All verified against the current tree before editing. src/shell/skin-contract.ts - `RuntimeProviders`: "airline needs neither, so omits it". Airline omits `RuntimeProviders` and DOES supply `useRuntimeProperties` — the two are SEPARABLE, and airline is now the worked example: one account holder, no switcher, so its hook reads no context and returns a frozen module constant. Do not mount an empty provider for symmetry. - `useData`: "Omit when a skin has no shell-managed data (banking …)". Every skin omits it now; documented with the grep, plus WHY the field is kept (the shape is legitimate, it just has no worked example left). - `CanvasSurface`: the "omit if the skin has no report canvas" branch is currently unexercised — every shipped skin has one. src/shell/agent-registry.ts - The logistics entry said it ships "neither `intelligence/seed-memories.ts` nor `intelligence/forget-memories.ts`" and is "identity plumbing only — do NOT read it as a durable-memory demo". It ships both (`ls src/skins/*/intelligence/`), and its `dev/reset` sweeps and re-seeds through them. Corrected, with the same properties-forwarding caveat the other five entries carry, and a note that "expensive half built, cheap half skipped" was its state for two releases. src/skins/keel/data/types.ts - The `THE REST SUBSTRATE` banner said the two substrates are "deliberately not merged yet", that `useKeelData` "holds runs in `useState` and ticks them on a 900 ms interval", and that "the pages still read it through `useSkinData`". All three are false: one substrate, one clock, `useSkinData` returns undefined. Rewritten to name the server-settled read (`settle-runs.ts`, called by both `GET /ledger` and `GET /runs/[runId]`) and to record WHY the deleted client ticker was a defect rather than a design choice — it was a second clock that painted progress the server never heard of, which the next re-read after any write silently rewound. - The `KeelData` interface header claimed to be "the interface every page, component, and tool codes against". It is not referenced by any code at all (`grep -rn KeelData src` returns only comments). Marked HISTORICAL, with a do-not-add-a-consumer note. NOT deleted: it is a doc pass, several comments across the skin describe the migration in terms of this shape, and removing an exported type is a code change for a separate commit. Flagged as a follow-up. src/skins/keel/data/store.ts - "it does not advance them on a timer, because the ticker lives in `useKeelData` on the client. Whichever slot migrates that hook has to decide where the ticker ends up" — decided: the server is the only clock now. src/skins/keel/data/beat-map.md - Header: "Keel today is `useKeelData`, an in-memory `useState` store, and it hits about one beat." Marked BUILT and reframed as the design record. - Risk #2 (the two-substrates/ticker question, correctly called "the biggest single risk in the migration") marked RESOLVED, with the answer (move the clock, do not relocate the ticker) and the generalised lesson. src/skins/airline/data/beat-map.md - Header: the tools/prompt/pages/pills were "later slots". All landed. - § "What this slot did NOT build": every row of the deferral table has shipped. Kept as the retrofit record — which is the most useful thing about it — with a third column saying where each landed, and the three flagged traps marked resolved (including "the reset route says memoryBeats: unarmed on purpose", which was removed in exactly the change that added the seed module, as instructed). src/skins/airline/data/fare-waiver-codes.ts - "⚠️ THE LINT GUARD DOES NOT COVER THIS SKIN YET." It does: both `src/skins/airline/tools.tsx` and `agent.ts` are in `withheldGateVocabulary`'s `files` glob. Also dropped its "COUNT the selectors" instruction (that count has rotted twice) in favour of the resolved-selector table in `skins-config.test.ts`, and spelled out that a green lint still leaves the three prose channels AND `waiverGround` — which matches no `*_CODES` pattern, so the rule cannot see it — as hand-review items. src/skins/airline/tools.test.ts - Header said `statusKeyedTerminalRender` "covers logistics only; airline's glob entry is a later slot's, so until it lands this file is the whole guard" and that `withheldGateVocabulary`'s glob "does not list airline yet either". Both globs list airline now. Also fixed "Three defect classes" over a list of five. src/skins/keel/skin.tsx - "exactly as it does for the four other REST-backed skins" → every skin; nothing sets `useData`. src/proxy.ts - "matching how the other three skins behave" → numeral-free. This was one of the two known-stale instances named in `skin-roster-docs.test.ts`'s header; that header is updated in the app-docs commit, and the remaining one (`e2e/inset-layout.spec.ts`'s hardcoded four-skin loop) is deliberately left — fixing it means adding assertions against skins the spec has never visited, which is a coverage change rather than a prose fix. docs/teach-mode/README.md - It correctly refuses to write the roster into prose, but its verified-by-role paragraph named only banking/commerce/logistics/people and its "so copy commerce or logistics" line named the only two skins with pinned replay behaviour. The `offerWorkflowRecording` grep now returns every registered skin, and `ls src/skins/*/teach-mode-directives.ts` — added as the mechanical discriminator for role #3 — returns four. Also: "logistics and commerce both" skip project-scoped rows in `forget-memories.ts` is now every skin but banking, replaced with the grep that proves it. Does this make anything in .claude/skills/reskin/ stale? No — the reverse. The preceding commit updated the skill for exactly these facts, and these comments were brought into line with it. Checked: `grep -rn "useKeelData\|use-data\|in-memory" .claude/skills/reskin/` names no path or symbol that no longer exists. Verified: pnpm lint, pnpm exec tsc --noEmit, pnpm test:unit (197 files / 2227 tests), pnpm build — all green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wolfmanfx
pushed a commit
that referenced
this pull request
Aug 19, 2026
…angGraph docs gaps (CopilotKit#6520) Bundles the CopilotKit-side work from **OSS-769**, **OSS-767** (partial), and the unshipped remainder of **OSS-609**. ## OSS-769 — `useCoAgent().nodeName` never updates `useAgentNodeName` tracked the current node in a ref and returned `nodeNameRef.current`. Mutating a ref schedules no render, so a component reading `useCoAgent().nodeName` kept showing whichever node was current at its last render and never updated on its own — it only appeared to work when something unrelated happened to re-render it. Backing the value with state fixes it. Five lines, no API change. ## OSS-767 (partial) — silent content-part drops (CopilotKit#1748) `normalizeMessageContent` handles only `text` and `binary` parts; anything else — the `{"type": "image", ...}` case from the report — maps to `""` and is filtered out with no signal, so an agent emitting structured content sees its output vanish silently. This makes the drop visible, once per unrecognised part type so streaming doesn't flood the log. Deliberately **not** the schema change: carrying structured assistant content needs an `AssistantMessage` decision upstream in `ag-ui`, which stays open on OSS-767. ## OSS-609 — the five docs gaps that never shipped Gap #2 shipped in CopilotKit#6403; gaps 1, 3, 4, 5 and 6 did not. | Gap | Where | Closes | | --- | --- | --- | | AWS Lambda self-hosting | `docs/deploy/aws-lambda.mdx` | CopilotKit#1151 | | Per-user thread authorization | `docs/auth.mdx` (new section) | CopilotKit#2241 | | Thread persistence without the platform | `docs/threads-self-managed.mdx` | CopilotKit#6090 | | DIY guardrails / DLP | `docs/integrations/langgraph/guardrails.mdx` | CopilotKit#3414 | | When you need an MCP App | `docs/agentic-protocols/mcp.mdx` (new section) | CopilotKit#5991 | The Lambda guide leads with the constraint that actually bites — streaming is opt-in on every front door, so a chat runtime deployed with the defaults appears to hang for the whole run and then dumps the reply at once. It documents the Function URL + `RESPONSE_STREAM` path as the default, and API Gateway REST + `responseTransferMode: STREAM` for anyone who needs a REST API in front. `threads-self-managed` follows the existing shared-snippet pattern with per-framework wrappers, because two nav contracts require it: every authored framework must publish the page, and every React destination must map to an Angular one (`ANGULAR_DOC_REDIRECTS`). All nine wrappers were confirmed necessary by deleting one and watching the suite fail. ## Review corrections Two blockers from @MikeRyanDev, both verified against primary sources before changing anything. **API Gateway REST APIs can stream** ([`91b3e632d5`](CopilotKit@91b3e632d5)). The guide was built on the pre-November-2025 limitation and claimed no API Gateway type supports response streaming, steering readers to a buffered `serverless-http` setup. REST gained it via `responseTransferMode: STREAM`, which also lifts the 10 MB cap and 29-second timeout. REST and HTTP are now split; REST is documented as a streaming front door (payload-format-1.0 event adapter, `AWS_PROXY` integration on the `2021-11-15/.../response-streaming-invocations` URI, CLI/CDK/SAM config), and the buffered fallback is scoped to HTTP APIs and ALB, which still have no streaming path. Added the constraints that actually matter for chat: the 30-second idle timeout on edge-optimized endpoints (5 min Regional), and the console Test tab always buffering so a working config looks broken. **`identifyUser` is the platform's thread-scoping binding** ([`91b3e632d5`](CopilotKit@91b3e632d5)). The section told every reader to build an ownership table and enforce it in `onBeforeHandler`. On the Intelligence path the runtime already resolves `identifyUser(request)` server-side and carries that id to the platform; `listThreads` is scoped by user *and* filtered by `agentId`, so the "every user of one project sees that project's threads" claim was wrong. `identifyUser` is now documented as the binding, and the DIY pattern is scoped to SSE runtimes, custom stores, and the local in-memory runner. **Follow-up correction — two routes are genuinely unscoped** ([`240672ff56`](CopilotKit@240672ff56)). My rewrite then over-claimed. `handleGetThreadEvents` and `handleGetThreadState` resolve the caller and discard it, and the platform client takes no `userId` on either method (`client.ts:1113`/`1135`) — unlike `getThreadMessages` at `1063`. Both hit project-authenticated `_inspect` endpoints, so any caller `identifyUser` accepts can read the event log and agent state of **any thread in the project** given its id. The blanket guarantee is replaced by a per-route table marking those two explicitly unscoped, plus an `onBeforeHandler` guard narrowed to them. That is a live gap in shipped runtime code, not a docs error, and it is tracked as **OSS-851** — a platform-side `_inspect` change plus matching runtime/client work and tests, out of scope for a docs PR. The interim callout in `auth.mdx` comes out when OSS-851 lands. ## Not in this PR **OSS-772** and **OSS-773** are already merged in `oss-path-to-production` (CopilotKit#237, CopilotKit#238). Both are telemetry-sink changes with no CopilotKit-side component. OSS-773's remaining half — re-keying runtime `distinct_id` from email to the Clerk subject — is recorded on the ticket as an open decision, not a task. ## Testing **OSS-769.** New `use-agent-nodename.test.tsx`, 5 tests. Against unmodified `origin/main`, **4 of 5 fail**: ``` × re-renders consumers on every node transition × reports 'end' when a run errors × resets to 'start' when a new run begins ✓ unsubscribes on unmount × carries the agent, thread, and current node Tests 4 failed | 1 passed (5) ``` With the fix: `Tests 5 passed (5)`. These assert only re-render behaviour under normal `act()` flushing — no manufactured intra-batch window. **Full react-core suite:** `Tests 7 failed | 1496 passed (1503)`. All 7 failures are **pre-existing** `ResizeObserver is not a constructor` under jsdom, confined to `CopilotChatView.pinToSend` and `use-pin-to-send` — neither of which this PR touches. **Typecheck:** `packages/react-core` → `tsc --noEmit` exit 0, no output. **OSS-767:** 3 new tests covering the warn, warn-once-per-type, and no-warn-for-supported-types. `src/graphql/message-conversion/` → `Tests 125 passed (125)`. **Docs:** `showcase/shell-docs` → `Tests 1 failed | 373 passed (374)`. The single failure (`channels-docs > publishes the Channels overview only through provider navigation`) is **pre-existing**; baselining with all changes stashed reproduces it and nothing else. Re-run unchanged after both review-correction commits. **Review corrections.** The AWS rewrite was checked against the AWS sources rather than written from memory — the REST streaming announcement, `configuration-response-streaming`, `response-transfer-mode` (endpoint-type idle timeouts, unsupported buffered-only features), `response-streaming-lambda-configure` (CLI/OpenAPI shapes), the CFN `Integration` reference, and the CDK `ResponseTransferMode` enum. Two details corrected in passing: `InvokeWithResponseStream` authorizes against plain `lambda:InvokeFunction` (no new grant, contrary to what the streaming URI suggests), and ALB still has no Lambda streaming path. The auth corrections were verified by reading the handlers and the platform client, not the tests — `resolve-intelligence-user.ts`, `intelligence/threads.ts` (every `resolveIntelligenceUser` call site), and `intelligence-platform/client.ts`. The existing tests assert the `threadId`-only call shape, so they pass under the defect and could not have surfaced it. Also corrected: there is no `threads/delete` route — delete is `DELETE` on `threads/update` (`fetch-handler.ts:606`). Both edited pages MDX-compile clean, and all inbound `#thread-authorization` anchors still resolve after the h3→h4 demotions. Two nav tests broke during this work and are fixed rather than papered over — adding a page to the Rich Threads group violated the cross-framework ordering contract and the React→Angular parity contract: ``` src/lib/__tests__/docs-render.test.ts src/lib/__tests__/angular-docs-content.test.ts Test Files 2 passed (2) Tests 33 passed (33) ``` All 15 internal links in the new pages resolve against the content tree. Closes CopilotKit#1151, CopilotKit#2241, CopilotKit#3414, CopilotKit#5991, CopilotKit#6090 Refs CopilotKit#1748, OSS-851
wolfmanfx
pushed a commit
that referenced
this pull request
Sep 22, 2026
… false about the code (CopilotKit#7146) ## What this is A consolidation of **CopilotKit#7137** and **CopilotKit#7142** into one reviewable change. Both are the same defect class — *the dashboard says things about the code that are not true* — so they belong in one review. Every commit is cherry-picked as-authored, and every red/green proof from the original PR bodies is reproduced verbatim below. ## What was broken Two layers of the showcase dashboard made claims the code does not support: **1. The legend lied (CopilotKit#7137).** Four statements in `adaptive-legend.tsx` / `chips-explainer.tsx` assert things the code does not do: - `✗` was described as "not supported". No code path emits `✗` for that — `🚫` is the sole not-supported glyph. `✗` means *no demo shipped* (whole cell) or *the probe ran and failed* (per-rung badge). The legend pointed viewers at exactly the wrong cells. - The chips-explainer described D6 as LangGraph-Python behavioural parity on a *weekly rotation*. That describes `e2e-parity.ts`, which is **unregistered** and cannot even parse its `kind`. Shipped D6 is `d6-all-pills-e2e.yml`, **hourly**, and does no reference comparison at all. - The legend's own D6 entry repeated the same falsehood. - `▼` was documented as "depth regression" but has **no emitter** anywhere in the tree — dead legend for a glyph that is never rendered. `—` was called "supported, no demo yet"; it is actually the **ladder-gated** mark. This PR corrects the **text only** — no glyphs, no components, no cell model, no probes. **2. The support mapping lied (CopilotKit#7142).** `starterSupport()` collapsed a genuinely three-way world into two, so `strands-typescript`, `claude-sdk-python` and `claude-sdk-typescript` — all real, shipping starters — rendered 🚫 "unsupported framework". The missing distinction is **unprobed** (we have not measured this cell) vs **unsupported** (this framework genuinely cannot do this). ## The fix - Legend text corrected to describe what the renderer actually emits; the dead `▼` entry removed. - `starterSupport()` made explicitly three-way: **probed** (12 columns the fleet probes), **unprobed** (a starter exists in-repo but nothing probes it — renders the gray `?` no-data chip, making *no* claim about the framework), **unsupported** (no starter exists — the only state that may render 🚫; five columns). The three real starters above move from 🚫 to `?`. 🚫 is an outward-facing capability claim about a partner integration; it was being used to describe a gap in our own plumbing. The only prior guard was `expect(STARTER_COLUMNS.size).toBe(12)` — a count, which held at 12 the entire time three real starters were being called unsupported frameworks. - A new **non-circular** drift test guards the mapping — it asserts against the starter inventory rather than against the mapping it is testing, so the mapping cannot silently drift back. It is mutation-tested: the exact mutation that reds it is shown verbatim below. One question was deliberately left open rather than guessed at; it is called out in the CopilotKit#7142 section, as is a known limitation. ## Diff equivalence vs. the two source branches No file is touched by both source PRs — there is **no overlap to resolve**. Per-file blob hashes on this branch are byte-identical to the corresponding source branch for all 7 files: ``` CopilotKit#7137 2 files +5 -10 CopilotKit#7142 5 files +493 -113 ------------------------------ 7 files +498 -123 this branch: 7 files changed, 498 insertions(+), 123 deletions(-) ← exact match ``` Blob-hash check, all OK: ``` OK showcase/shell-dashboard/src/components/adaptive-legend.tsx (CopilotKit#7137) OK showcase/shell-dashboard/src/components/chips-explainer.tsx (CopilotKit#7137) OK showcase/harness/src/probes/helpers/starter-mapping-drift.test.ts (CopilotKit#7142) OK showcase/harness/src/probes/helpers/starter-mapping.ts (CopilotKit#7142) OK showcase/harness/src/shared/cell-model/live-status.ts (CopilotKit#7142) OK showcase/shell-dashboard/src/components/feature-grid.tsx (CopilotKit#7142) OK showcase/shell-dashboard/src/lib/live-status.test.ts (CopilotKit#7142) ``` --- --- # Carried over verbatim — CopilotKit#7137 · `fix(shell-dashboard): correct legend statements that are false about the code` Four dashboard legend / explainer statements assert things the code does not do. This corrects the **text only** — no glyphs, no components, no cell model, no probes, no starters. ## The four falsehoods (verified at `origin/main` = `f72d3442`; the dashboard tree is byte-identical to the recon base `abb0cf636c`) | # | Where | Said | Actually | |---|---|---|---| | 1 | `adaptive-legend.tsx:179-182` | red `✗` = "not supported" | **No code path emits `✗` for that.** `🚫` is the sole not-supported glyph in both grids (`feature-grid.tsx:447-454`, `unified-cell.tsx:302-314`, `depth-chip.tsx:277-291`, all tooltipped *"Not supported by this framework"*). `✗` means **"no demo shipped"** (whole main-grid cell, `title="No demo"`, `feature-grid.tsx:455-462`) **or "the probe ran and failed"** (per-rung badge, `unified-cell.tsx:82-84`). The legend mapped viewers to exactly the wrong cells. | | 2 | `chips-explainer.tsx:38-41` | D6 = LangGraph-Python behavioural parity, *"weekly rotation"* | That describes `e2e-parity.ts`, which is **unregistered** — no YAML under `harness/config/probes/`, and no `e2e_parity` member in `DIMENSIONS` (`harness/src/types/index.ts:48-141`), so its `kind` cannot even parse. Shipped D6 is `d6-all-pills-e2e.yml`, schedule `"40 * * * *"` (**hourly**), driven by `d6-all-pills.ts`: the aimock-backed scripted conversation run across **every** feature type the integration declares, green only if all pass. It does **no** reference comparison — `reference` and `langgraph` appear nowhere in the driver. | | 3 | `adaptive-legend.tsx` D6 entry | "Parity (Reference): full all-pills run verified against the reference integration" | Same falsehood as #2 — nothing verifies against a reference. | | 4 | `adaptive-legend.tsx:83-86`, `:111-114` | `▼` = "depth regression from previous run"; `—` = "supported, no demo yet" | `▼` has **no emitter** — `DepthChip`'s `regression` prop only changes colour + tooltip; the only `▼` in the tree is `cell-drilldown.tsx:448`'s disclosure chevron. Removed. `—` is the **ladder-gated** mark (`unified-cell.tsx:57-68`, tooltip *"gated — blocked by a lower rung"*). Corrected. | ## Red / green proof — rendered page, not DOM measurement Local `next dev` on this branch's worktree, real catalog + `docs-status.json` codegen, Playwright screenshots at 1440×900 and 430×932, DPR 2, inspected visually. ### RED (before) — legend, as rendered `RED-desktop-legend.png` / `RED-mobile430-legend.png` — screenshots taken and visually inspected; verbatim rendered text: ``` D6 Parity (Reference): full all-pills run verified against the reference integration ▼ depth regression from previous run — supported, no demo yet ✗ not supported ``` ### GREEN (after) — legend, as rendered `GREEN-desktop-legend.png` / `GREEN-mobile430-legend.png` — same run, same viewports; verbatim rendered text: ``` D6 All Pills: every feature type the integration declares is run (D5 runs one representative); green only if all pass (▼ entry removed — nothing emits it) — gated — a lower rung is failing, so this rung was not run ✗ no demo shipped, or a probe ran and failed ``` ### RED → GREEN — chips explainer, as rendered `RED-chips-explainer.png` / `GREEN-chips-explainer.png`: ``` - D6: does its behaviour match the reference (LangGraph Python), or has it drifted? (DOM elements, tool-call sequence, stream cadence, contract shape — informational; weekly rotation) + D6: does EVERY demo cell work, not just the one D5 sampled? (the same scripted aimock conversations, run across every feature type the integration declares — green only if all of them pass; hourly) ``` Screenshots (RED + GREEN, desktop + mobile, both surfaces) are archived at `~/.local/share/copilotkit/cr/showcase-starters-2026-09-14/legend-truth/`. > **Note on the chips-explainer surface:** `ChipsExplainer` is currently **unreachable** — it is rendered only by `cells-view.tsx`, which nothing imports; the app's only route is `/` → `DashboardPage` with tabs `matrix`/`baseline`/`ops`. To get a genuine rendered-page red/green rather than a DOM assertion, the component was mounted through a throwaway `app/chips-preview` route for the screenshots; **that route is not part of this diff** (`next build` route table below confirms it). ## Gates - `npx tsc --noEmit` — clean - `npx vitest run` — **71 files, 1407 passed**, 1 skipped - `npx next build` — green; routes `/`, `/_not-found`, `/api/ops/[...path]`, `/icon.svg` (no preview route) - `oxfmt --check`, `oxlint` — clean; lefthook pre-commit + commitlint passed ## Deliberately NOT changed These are real defects but belong to the pending **glyph-encoding redesign**, not to a truth correction, and editing them here would create churn the redesign has to undo: - `🚫`, `⚡`, `⟳` and the D-chip colours are undocumented in the legend — the redesign replaces the marks themselves, so adding entries for the current glyphs would be written twice. - The coloured literal `D5` / `D6` chip entries misdescribe how cells actually render (`1P ✓`, `D6 ✗`) — owned by the redesign. - `?` "probe has not yet ticked since deploy" is true for starter rows but false for the main grid, where `Badge` returns `null` for `label === "?"`. Un-hiding it is a **behavioural render change** and a product call, not a text fix. - **Confirmed and recorded, not fixed:** `⚡`'s "pool unreachable" chip has *always* painted **yellow**, never indigo. `⚡` is U+26A1 with `Emoji_Presentation=Yes`, so the colour-emoji font ignores the `text-indigo-300` class at `depth-chip.tsx:133-146` — contradicting that component's own doc comment at `:39-46`. `🚫` (U+1F6AB) has the identical bug against `text-slate-400` / `text-white`. This is a code-point problem; no CSS colour property can reach a COLR/bitmap emoji glyph. --- ## Commit 4 — the glyph redesign (approved rendered mock) The three items deferred above are now implemented. `jpr5` signed off on the rendered mock at `glyph-mock.html`; this is that design. ### The two defects 1. **Three glyphs were Emoji code points, so CSS colour never reached them.** `🚫` (U+1F6AB) painted **red** on a grey starter chip whose glyph was explicitly `text-white` — the background said "nothing to test here" and the mark said "this is bad", simultaneously, on 36 of 84 starter cells. `⚡` (U+26A1) is the same bug: `depth-chip.tsx`'s own doc comment promises an indigo "pool unreachable" treatment, and the glyph has painted **yellow** since the day it landed. `⏱` (U+23F1) is the third. 2. **Absence and failure were the same SHAPE**, so hue was the only cue — and hue is what fails at 16px, in greyscale, and under colour blindness. The loudest mark in the entire table was a 16px red `✗` for **unbuilt work**. ### The encoding **One filled object per cell** — the thing the cell reports (the depth chip in a feature cell, the status chip in a starter cell). It goes **hollow** when nothing was judged. Everything else in a cell is a **bare mark**: prefix plus a coloured glyph, no box, no fill, no border. The `UI` / `BE` / `1P` / `D6` prefixes stay. - Verdicts `✓ ~ ✗` — filled, white glyph, green/amber/red. - Absences `∅ · ? — ! ⟳` — hollow, tone in the glyph, slate; except the `!` faults, which are **indigo**, because an infrastructure failure is not a verdict. - Colour-free backstop: hollow chips carry a border **style** (solid = a settled fact · dashed = a slot not filled in · dotted = expected, hasn't arrived); bare absence marks carry a hairline **dotted underline**. - `?` is **no longer suppressed** in the main grid. `Badge` used to return `null` for it, so the grid computed a state it never painted — which is exactly what made the legend's `?` entry false there. ### RED → GREEN, on the rendered page Both captures are the same local dev server (`next dev`, port 3002), same viewports, at DPR 1 and DPR 2, light and dark. No DOM measurements were trusted for any visual claim — the screenshots were inspected. **RED (before):** | state | rendered | |---|---| | starter, not supported | grey filled chip with a **RED** `🚫` — `text-white` ignored | | starter, no data | grey **filled** chip — indistinguishable from a verdict | | main grid, no demo shipped | 16px **red** `✗` | | depth, pool unreachable | indigo-bordered chip with a **YELLOW** `⚡` — `text-indigo-300` ignored | | depth, unshipped | `--` (the same mark as the ref-depth spacer) | | rung, no data | **nothing rendered** | **GREEN (after):** | state | rendered | |---|---| | starter, not supported | hollow `∅`, solid slate border | | starter, no data | hollow `?`, dotted border | | main grid, no demo shipped | hollow `·`, dashed border | | depth, pool unreachable | hollow `!`, **indigo** — the colour the component promised, applying for the first time | | depth, unshipped | hollow `·`, dashed | | rung, no data | a visible `?` with a dotted underline | Verdict chips are unchanged: filled, white glyph. The live dashboard capture shows the whole starter block leaving the verdict layer, and the legend regenerating itself from the same constant. ### Anti-rot `showcase/harness/src/shared/cell-model/glyphs.ts` is **one constant** that the renderer AND the legend both switch on — `AdaptiveLegend` maps over it, so a glyph cannot be emitted without a legend row. `glyphs.contract.test.tsx` fails CI on any drift. Every new assertion was **mutation-tested**; each was observed failing before it was trusted: | mutation | result | |---|---| | `depth-chip` unsupported emits a literal `"X"` (a mark outside the vocabulary) | **RED** — 2 tests | | `depth-chip` unshipped emits `"--"` | **RED** — 2 tests | | `AdaptiveLegend` filters out the `gated` row | **RED** — 2 tests | | add a documented-but-unemitted glyph (`▼`) to `GLYPHS` | **RED** — 1 test | | set `notSupported.mark` back to `🚫` | **RED** — the emoji ban | One mutation exposed a defect *in the test itself*: the first draft scanned `textContent` for marks, and the legend prose legitimately contains `—` as a separator, so deleting the `gated` legend row left the suite **green**. The extraction now reads the `data-glyph` attribute that `StatusChip` / `GlyphMark` stamp, which makes the legend row itself the evidence. The emoji ban also carries a **positive control**: it asserts the rule fires on `🚫`, `⚡` and `⏱`, the three glyphs this dashboard actually shipped. ### Gates - `next build` — passes (the dashboard's real gate). - `vitest run` — 72 files, 1425 passed, 1 skipped. - `tsc --noEmit` — clean (dashboard and harness; the harness `axe-core` error pre-exists on `origin/main`). - Harness `src/shared/cell-model` — 214 passed. ### Not touched, deliberately `chips-explainer.tsx` is unreachable dead UI (nothing imports `cells-view.tsx`; the app's only route is `/`). It also contains **no** vocabulary glyph — it describes D0–D6 in prose — so it is already consistent and needed no edit. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Starter status now distinguishes probed, unprobed, and unsupported integrations. * Integrations with repository starters but no live probe display a gray “?” badge with explanatory text. * Dashboard status indicators now use a consistent set of accessible text glyphs and chip styles. * **Bug Fixes** * Corrected starter-status indicators, preventing false “Not supported” messages. * Improved probe failure coloring to distinguish isolated from repeated failures. * No-data and fault states now remain visible with clearer indicators. * **Documentation** * Clarified dashboard legends and chip descriptions for probe outcomes, skipped checks, and feature coverage. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This branch has not been deployed
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
Replace
effect()-driven collapse/expand behavior inCopilotChatReasoningMessagewith derived signals/computed state.Why
Avoid propagating UI state via
effect(); keep toggle behavior deterministic while streaming.Tests
pnpm -C packages/angular test -- -t "renders streaming reasoning messages"Made with Cursor