Skip to content

Commit 9df214b

Browse files
bloveclaude
andcommitted
merge: main into homepage-rebuild — adopt the reliability band, drop the Yes Wall
main's #996 replaced the Yes wall with the reliability band: ProofStrip moves into the dark contrast slot under the logo ribbon and the Yes wall is deleted. That supersedes this branch's Task 12, so the Yes wall work is dropped rather than merged. - page.tsx: ProofStrip (dark) sits directly under LogoRibbon, ahead of RuntimeParity/ThreeSteps. YesWall is gone; Promises went with #980 and its component no longer exists on main. StackDiagramSection and HomeConceptGrid stay unmounted here (they still ship on /langgraph and /ag-ui). Metadata keeps HOME_TITLE/HOME_DESCRIPTION. - landing.css: main's proof-strip block wholesale, including its min-width:0 fix, which supersedes this branch's repeat(2, minmax(0, 1fr)) from 5b6328b. The .yes-wall-* rules and the Task 12 expander are deleted. - style-contracts.spec.ts: the .yes-wall-row[hidden] contract is removed; the rule it guarded no longer exists. - FinalCTA.tsx: keeps this branch's optional ctaId on primary/secondary and captionLink, and honours main's retirement of the promise caption — the caption prop stays, but its default is null instead of the old "Installation is inert" line, which main's e2e now asserts is absent. - analytics/events.ts + taxonomy.md: home_production_readiness_expand joins home_yes_wall_docs as retired; neither has a firing site any more. - e2e: the Yes Wall expander test is dropped from home-hero.spec.ts; website.spec.ts keeps main's dark-proof-band assertion alongside this branch's five-FeatureBlock and H1 assertions. - HomeFAQ: the branch's telemetry question made a barred absolute claim ("Installation is inert") and linked the retired /docs/telemetry library, both of which main's public-copy contract now forbids. Replaced with a reporting question answered from /privacy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 parents b1b293f + 18d7739 commit 9df214b

194 files changed

Lines changed: 15241 additions & 3878 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 255 additions & 3 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,71 @@
1+
## 0.0.65 (2026-09-03)
2+
3+
### 🚀 Features
4+
5+
- Mastra runtime Lane B — ag-ui-mastra Node service, proxy map, rt-mastra example, deploy workflow ([#903](https://github.com/cacheplane/angular-agent-framework/pull/903), [#899](https://github.com/cacheplane/angular-agent-framework/issues/899))
6+
- add operational sidebar control plane ([#921](https://github.com/cacheplane/angular-agent-framework/pull/921))
7+
- unify docs and cockpit workspace ([#949](https://github.com/cacheplane/angular-agent-framework/pull/949))
8+
- unify docs and runtime control plane ([#963](https://github.com/cacheplane/angular-agent-framework/pull/963))
9+
- **ag-ui:** upgrade @ag-ui/* to 0.0.59 and send protocol-standard top-level resume ([#891](https://github.com/cacheplane/angular-agent-framework/pull/891))
10+
- **ag-ui:** consume the protocol's SUBAGENT_* events and subagentRunId attribution ([#955](https://github.com/cacheplane/angular-agent-framework/pull/955))
11+
- **cockpit:** per-topic framework adapters in the AG-UI deployment generator ([#894](https://github.com/cacheplane/angular-agent-framework/pull/894))
12+
- **cockpit:** Microsoft Agent Framework runtime example (cockpit/runtimes) ([#896](https://github.com/cacheplane/angular-agent-framework/pull/896), [#888](https://github.com/cacheplane/angular-agent-framework/issues/888), [#889](https://github.com/cacheplane/angular-agent-framework/issues/889), [#891](https://github.com/cacheplane/angular-agent-framework/issues/891))
13+
- **cockpit:** AWS Strands runtime example (rt-strands) ([#898](https://github.com/cacheplane/angular-agent-framework/pull/898))
14+
- **cockpit:** make Run discoverable from Code ([#934](https://github.com/cacheplane/angular-agent-framework/pull/934))
15+
- **cockpit:** ag-ui subagents demo emits the protocol's SUBAGENT_* events ([#962](https://github.com/cacheplane/angular-agent-framework/pull/962))
16+
- **e2e-harness:** restore aimock — replay+record wrapper, drift infra, scrub repairs ([#947](https://github.com/cacheplane/angular-agent-framework/pull/947))
17+
- **e2e-harness:** bucket metadata-hash mismatches as promptChanged in the drift differ ([#951](https://github.com/cacheplane/angular-agent-framework/pull/951))
18+
- **examples:** ag-ui demo emits the protocol's SUBAGENT_* events ([#964](https://github.com/cacheplane/angular-agent-framework/pull/964))
19+
- **examples/chat:** /hero route — replayed LangGraph walkthrough with live takeover ([#976](https://github.com/cacheplane/angular-agent-framework/pull/976))
20+
- **runtimes:** strands subagent delegation demo with standard SUBAGENT_* emission ([#956](https://github.com/cacheplane/angular-agent-framework/pull/956))
21+
- **runtimes:** maf subagent delegation demo with queue-merged SUBAGENT_* emission ([#957](https://github.com/cacheplane/angular-agent-framework/pull/957))
22+
- **runtimes:** mastra subagent delegation demo with SUBAGENT_* injection in the bridge ([#958](https://github.com/cacheplane/angular-agent-framework/pull/958))
23+
- **runtimes:** mastra sub-agent streaming via a public-API stream tee ([#961](https://github.com/cacheplane/angular-agent-framework/pull/961))
24+
- **runtimes:** stand-down guard so the mastra subagent injector retires ([#971](https://github.com/cacheplane/angular-agent-framework/pull/971))
25+
- **website:** homepage punch list — hero merge, FAQ copy, FeatureBlock rows everywhere ([#897](https://github.com/cacheplane/angular-agent-framework/pull/897))
26+
- **website:** homepage lower half — ledgers, numerals, paper, intent-gated toast ([#901](https://github.com/cacheplane/angular-agent-framework/pull/901))
27+
- **website:** add 'We Measured the Runtime Swap' blog post ([#905](https://github.com/cacheplane/angular-agent-framework/pull/905), [#888](https://github.com/cacheplane/angular-agent-framework/issues/888), [#889](https://github.com/cacheplane/angular-agent-framework/issues/889), [#891](https://github.com/cacheplane/angular-agent-framework/issues/891))
28+
- **website:** tighten the pricing page ([#908](https://github.com/cacheplane/angular-agent-framework/pull/908))
29+
- **website:** library pages in the homepage manner ([#914](https://github.com/cacheplane/angular-agent-framework/pull/914))
30+
- **website:** design-program follow-ups — showcase rails, Angular proof cell, closer order ([#919](https://github.com/cacheplane/angular-agent-framework/pull/919))
31+
- **website:** align the docs index with the control plane ([#923](https://github.com/cacheplane/angular-agent-framework/pull/923), [#920](https://github.com/cacheplane/angular-agent-framework/issues/920), [#911](https://github.com/cacheplane/angular-agent-framework/issues/911))
32+
- **website:** ninth arc — solutions and pilot join the design language ([#927](https://github.com/cacheplane/angular-agent-framework/pull/927))
33+
- **website:** wire the docs -> cockpit handoff for deep-agents and runtimes ([#938](https://github.com/cacheplane/angular-agent-framework/pull/938), [#937](https://github.com/cacheplane/angular-agent-framework/issues/937), [#913](https://github.com/cacheplane/angular-agent-framework/issues/913))
34+
35+
### 🩹 Fixes
36+
37+
- subagent hardening batch — eviction order, args-buffer scoping, field-based lookup, AIMOCK_MODE warning ([#960](https://github.com/cacheplane/angular-agent-framework/pull/960))
38+
- **ag-ui:** detect protocol-standard RUN_FINISHED interrupt outcomes ([#888](https://github.com/cacheplane/angular-agent-framework/pull/888))
39+
- **ag-ui:** carry interrupt identity on the resume payload ([#889](https://github.com/cacheplane/angular-agent-framework/pull/889))
40+
- **ag-ui:** relative imports in subagents topic + deploy boot gate ([#899](https://github.com/cacheplane/angular-agent-framework/pull/899))
41+
- **ag-ui:** resolve the subagents agent URL against <base href> ([#902](https://github.com/cacheplane/angular-agent-framework/pull/902))
42+
- **ag-ui:** attributed TOOL_CALL_START links the child message's toolCallIds so cards draw the call ([#965](https://github.com/cacheplane/angular-agent-framework/pull/965))
43+
- **ci:** unbreak main — drop verify assertions for the removed pricing matrix ([#915](https://github.com/cacheplane/angular-agent-framework/pull/915), [#908](https://github.com/cacheplane/angular-agent-framework/issues/908))
44+
- **ci:** accept branded AG-UI compatibility marker ([#930](https://github.com/cacheplane/angular-agent-framework/pull/930))
45+
- **ci:** stop fanning out the whole cockpit e2e matrix for unrelated changes ([#939](https://github.com/cacheplane/angular-agent-framework/pull/939), [#932](https://github.com/cacheplane/angular-agent-framework/issues/932))
46+
- **ci:** bump scorecard-action to v2.4.4 so the image pulls again ([#940](https://github.com/cacheplane/angular-agent-framework/pull/940), [#367732848534](https://github.com/cacheplane/angular-agent-framework/issues/367732848534))
47+
- **ci:** compare requirements.txt drift against git, not a scratch export ([#967](https://github.com/cacheplane/angular-agent-framework/pull/967), [#966](https://github.com/cacheplane/angular-agent-framework/issues/966))
48+
- **ci:** give the Website Vercel build its growth form policy ([#981](https://github.com/cacheplane/angular-agent-framework/pull/981), [#968](https://github.com/cacheplane/angular-agent-framework/issues/968))
49+
- **ci:** scope vercel promote to the team that owns the deployment ([#982](https://github.com/cacheplane/angular-agent-framework/pull/982), [#963](https://github.com/cacheplane/angular-agent-framework/issues/963), [#945](https://github.com/cacheplane/angular-agent-framework/issues/945))
50+
- **ci:** open the protected immutable cockpit preview with its own automation bypass ([#984](https://github.com/cacheplane/angular-agent-framework/pull/984), [#983](https://github.com/cacheplane/angular-agent-framework/issues/983), [#974](https://github.com/cacheplane/angular-agent-framework/issues/974))
51+
- **cockpit:** teach the cockpit the runtimes product ([#910](https://github.com/cacheplane/angular-agent-framework/pull/910))
52+
- **cockpit:** point docsPath at docs pages that actually exist ([#918](https://github.com/cacheplane/angular-agent-framework/pull/918))
53+
- **cockpit:** accept the platform slash collapse for the consecutive-slash raw canary ([#987](https://github.com/cacheplane/angular-agent-framework/pull/987))
54+
- **deployments:** regenerate ag-ui-dev artifacts after the --no-dev re-export ([#970](https://github.com/cacheplane/angular-agent-framework/pull/970), [#967](https://github.com/cacheplane/angular-agent-framework/issues/967), [#963](https://github.com/cacheplane/angular-agent-framework/issues/963))
55+
- **examples:** sync requirements.txt with uv.lock; guard drift in CI ([#966](https://github.com/cacheplane/angular-agent-framework/pull/966), [#964](https://github.com/cacheplane/angular-agent-framework/issues/964))
56+
- **examples/chat:** keep reading pauses in the hero walkthrough under reduced motion ([#979](https://github.com/cacheplane/angular-agent-framework/pull/979))
57+
- **langgraph:** harden subagent attribution — ladder tests, empty-description guard, nested-delegation streams ([#945](https://github.com/cacheplane/angular-agent-framework/pull/945))
58+
- **lifecycle:** own enrichment provenance in code; **mailbox-poller:** drop numeric separators ([#985](https://github.com/cacheplane/angular-agent-framework/pull/985))
59+
- **website:** repair and redesign the docs adapter picker ([#911](https://github.com/cacheplane/angular-agent-framework/pull/911), [#892](https://github.com/cacheplane/angular-agent-framework/issues/892))
60+
- **website:** give library-neutral docs pages an honest control plane ([#920](https://github.com/cacheplane/angular-agent-framework/pull/920), [#892](https://github.com/cacheplane/angular-agent-framework/issues/892))
61+
- **website:** final-review fix batch ([#922](https://github.com/cacheplane/angular-agent-framework/pull/922))
62+
- **website:** restore padding on Shiki code blocks ([#924](https://github.com/cacheplane/angular-agent-framework/pull/924), [#863](https://github.com/cacheplane/angular-agent-framework/issues/863), [#926](https://github.com/cacheplane/angular-agent-framework/issues/926))
63+
- **website:** close the docs shell's nav-height and column-measure defects ([#942](https://github.com/cacheplane/angular-agent-framework/pull/942), [#932](https://github.com/cacheplane/angular-agent-framework/issues/932))
64+
- **website:** legible diagram text on phones — 600px floor + scroll shadows ([#953](https://github.com/cacheplane/angular-agent-framework/pull/953))
65+
- **website:** production-smoke spec must not use import.meta.url ([#973](https://github.com/cacheplane/angular-agent-framework/pull/973), [#963](https://github.com/cacheplane/angular-agent-framework/issues/963))
66+
- **website:** keep the post-promotion e2e run off the local fixture runtime ([#983](https://github.com/cacheplane/angular-agent-framework/pull/983), [#982](https://github.com/cacheplane/angular-agent-framework/issues/982))
67+
- **workspace:** keep utility panel focus when the drawer opens in one commit ([#972](https://github.com/cacheplane/angular-agent-framework/pull/972))
68+
169
## 0.0.64 (2026-08-31)
270

371
### 🚀 Features

CONTRIBUTING.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,32 @@ branch protection and has no rulesets, so the unprivileged
195195
`GET /repos/{owner}/{repo}/rules/branches/main` endpoint returns `[]` and is
196196
not an alternative.
197197

198+
### PR-side deploy verification
199+
200+
Two lanes run the deploy job's verification on pull requests against real
201+
Vercel previews, so deploy-only failures surface before merge:
202+
203+
- **Website — e2e (deployed preview)** builds and deploys the Website and
204+
the examples as previews under deterministic aliases
205+
(`threadplane-pr-<n>-cacheplane.vercel.app` and
206+
`threadplane-examples-pr-<n>-cacheplane.vercel.app`; `mq-<sha8>` for
207+
merge-queue candidates) and runs the ordinary suite against the Website
208+
alias. The runtime iframe loads because the examples are assembled with
209+
the Website alias in their parent-origin policy and Playwright seeds the
210+
examples origin's bypass cookie (`apps/website/e2e/runtime-bypass-setup.ts`).
211+
A later push re-points both aliases; the deployments behind them are kept.
212+
- **Cockpit — immutable preview smoke** deploys a throwaway cockpit preview,
213+
runs the exhaustive redirect smoke against it, and removes it.
214+
215+
Both need repository secrets and therefore skip on fork PRs; the required
216+
gate only demands them when they were eligible to run. Each Vercel project
217+
has its own Protection Bypass for Automation secret:
218+
`VERCEL_AUTOMATION_BYPASS_SECRET` (Website),
219+
`VERCEL_EXAMPLES_AUTOMATION_BYPASS_SECRET`, and
220+
`VERCEL_COCKPIT_AUTOMATION_BYPASS_SECRET`. A secret added while a run is in
221+
flight does not reach that run; re-run after provisioning. Never pass
222+
`--skip-domain` to a preview deploy; Vercel requires it to accompany `--prod`.
223+
198224
## Code review
199225

200226
Every PR gets a genuine advisory AI code review

apps/cockpit/scripts/deploy-smoke.spec.ts

Lines changed: 165 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ describe('redirect deploy smoke contract', () => {
312312
expect(sleep).toHaveBeenCalledTimes(1);
313313
});
314314

315-
it('identifies the Vercel Raw Path prerequisite when a raw canary is normalized', async () => {
315+
it('identifies the raw-path rejection route when a raw canary is normalized', async () => {
316316
const cases = buildRedirectSmokeCases('production');
317317
const requestImpl = vi.fn(async (request: RedirectSmokeRequest) => {
318318
const smokeCase = cases.find(
@@ -329,7 +329,170 @@ describe('redirect deploy smoke contract', () => {
329329
mode: 'production',
330330
requestImpl,
331331
})
332-
).rejects.toThrow(/WAF Raw Path prerequisite/);
332+
).rejects.toThrow(/vercel\.cockpit\.json/);
333+
});
334+
335+
it('accepts only the platform same-origin slash collapse for a consecutive-slash probe', async () => {
336+
// Vercel's CDN collapses consecutive slashes and answers 308 to the
337+
// single-slash path on the same origin before any route, rewrite, or
338+
// function runs, so that probe can never reach the 404 route. The only
339+
// acceptable non-404 answer is that exact normalization; a redirect off
340+
// the deployment from a malformed path is still a contract failure.
341+
const cases = buildRedirectSmokeCases('preview');
342+
const slashCase = cases.find(
343+
(smokeCase) => smokeCase.raw && smokeCase.path.includes('//')
344+
);
345+
const dotCase = cases.find(
346+
(smokeCase) => smokeCase.raw && smokeCase.path.includes('/./')
347+
);
348+
if (!slashCase || !dotCase) throw new Error('Expected raw canaries');
349+
expect(slashCase.platformNormalizedPath).toBe(
350+
'/langgraph/core-capabilities/streaming/overview/python'
351+
);
352+
expect(dotCase.platformNormalizedPath).toBeUndefined();
353+
354+
const impl = (answer: (request: RedirectSmokeRequest) => RedirectSmokeResponse | null) =>
355+
vi.fn(async (request: RedirectSmokeRequest) =>
356+
answer(request) ?? responseFor(request, cases)
357+
);
358+
359+
await expect(
360+
runDeploySmoke({
361+
url: previewUrl,
362+
mode: 'preview',
363+
requestImpl: impl((request) =>
364+
request.path === slashCase.path
365+
? {
366+
status: 308,
367+
// The platform answers with a relative Location.
368+
headers: {
369+
location:
370+
'/langgraph/core-capabilities/streaming/overview/python',
371+
},
372+
}
373+
: null
374+
),
375+
})
376+
).resolves.toBe(`pass:preview:${previewUrl}:${cases.length}`);
377+
378+
await expect(
379+
runDeploySmoke({
380+
url: previewUrl,
381+
mode: 'preview',
382+
requestImpl: impl((request) =>
383+
request.path === slashCase.path
384+
? {
385+
status: 308,
386+
headers: {
387+
location: `${previewUrl}/langgraph/core-capabilities/streaming/overview/python`,
388+
},
389+
}
390+
: null
391+
),
392+
})
393+
).resolves.toBe(`pass:preview:${previewUrl}:${cases.length}`);
394+
395+
await expect(
396+
runDeploySmoke({
397+
url: previewUrl,
398+
mode: 'preview',
399+
requestImpl: impl((request) =>
400+
request.path === slashCase.path
401+
? {
402+
status: 308,
403+
headers: {
404+
location:
405+
'https://threadplane.ai/docs/langgraph/guides/streaming?mode=run',
406+
},
407+
}
408+
: null
409+
),
410+
})
411+
).rejects.toThrow(/raw malformed 1.*expected 404, received 308/);
412+
413+
await expect(
414+
runDeploySmoke({
415+
url: previewUrl,
416+
mode: 'preview',
417+
requestImpl: impl((request) =>
418+
request.path === dotCase.path
419+
? {
420+
status: 308,
421+
headers: {
422+
location: `${previewUrl}/langgraph/core-capabilities/streaming/overview/python`,
423+
},
424+
}
425+
: null
426+
),
427+
})
428+
).rejects.toThrow(/expected 404, received 308/);
429+
});
430+
431+
it('sends the automation bypass on every probe only when a secret is supplied', async () => {
432+
// Vercel deployment protection answers every path on an unaliased
433+
// deployment with 302 -> vercel.com/sso-api, so the immutable cockpit
434+
// artifact can only be verified with the project's automation bypass.
435+
const cases = buildRedirectSmokeCases('preview');
436+
const withSecret = vi.fn(async (request: RedirectSmokeRequest) => {
437+
const { 'x-vercel-protection-bypass': bypass, ...rest } =
438+
request.headers ?? {};
439+
if (bypass !== 'cockpit-bypass-sentinel') {
440+
throw new Error(`Missing bypass on ${request.path}`);
441+
}
442+
return responseFor(
443+
{ ...request, headers: Object.keys(rest).length ? rest : undefined },
444+
cases
445+
);
446+
});
447+
448+
await expect(
449+
runDeploySmoke({
450+
url: previewUrl,
451+
mode: 'preview',
452+
requestImpl: withSecret,
453+
bypassSecret: 'cockpit-bypass-sentinel',
454+
})
455+
).resolves.toBe(`pass:preview:${previewUrl}:${cases.length}`);
456+
expect(withSecret).toHaveBeenCalledTimes(cases.length);
457+
expect(withSecret).toHaveBeenCalledWith(
458+
expect.objectContaining({
459+
path: '/langgraph/core-capabilities/streaming/overview/python',
460+
headers: expect.objectContaining({
461+
'x-forwarded-host': 'attacker.test',
462+
'x-vercel-protection-bypass': 'cockpit-bypass-sentinel',
463+
}),
464+
})
465+
);
466+
467+
const withoutSecret = vi.fn(async (request: RedirectSmokeRequest) =>
468+
responseFor(request, cases)
469+
);
470+
await runDeploySmoke({
471+
url: previewUrl,
472+
mode: 'preview',
473+
requestImpl: withoutSecret,
474+
});
475+
for (const [request] of withoutSecret.mock.calls) {
476+
expect(request.headers ?? {}).not.toHaveProperty(
477+
'x-vercel-protection-bypass'
478+
);
479+
}
480+
});
481+
482+
it('names Vercel deployment protection when a probe lands on the SSO redirect', async () => {
483+
const requestImpl = vi.fn(async () => ({
484+
status: 302,
485+
headers: {
486+
location:
487+
'https://vercel.com/sso-api?url=https%3A%2F%2Fimmutable-preview.vercel.app%2F&nonce=abc',
488+
},
489+
}));
490+
491+
await expect(
492+
runDeploySmoke({ url: previewUrl, mode: 'preview', requestImpl })
493+
).rejects.toThrow(
494+
/expected 308, received 302.*deployment protection.*automation bypass/i
495+
);
333496
});
334497

335498
it('formats dry-run output with the selected mode and case count', async () => {

0 commit comments

Comments
 (0)