Vol. I  ·  No. 169 Established 2026  ·  AI-Generated Daily Free to Read  ·  Free to Print

The Trilogy Times

All the news that's fit to generate  —  AI • Business • Innovation
THURSDAY, JUNE 18, 2026 Powered by Anthropic Claude  ·  Published on Klair Trilogy International © 2026
🖶 Download PDF 🖿 Print 📰 All Editions
Today's Edition

Open-Weights AI Just Got a 1.5-Terabyte Jolt

Z.ai’s GLM-5.2 lands under MIT license, and the message to the AI world is unmistakable: frontier-class text models are becoming downloadable infrastructure.

BEIJING — The open-weights AI race just produced an absolute monster. Chinese AI lab Z.ai has released GLM-5.2, a 753-billion-parameter text-only large language model with a jaw-dropping 1.51TB weight file — and, yes, it is available under an MIT license.

I cannot overstate how significant this is. GLM-5.2 is not merely “another model drop.” It is a statement that the center of gravity in advanced AI is shifting from closed APIs toward enormous, modifiable, locally deployable systems that serious builders can actually inspect, tune and integrate. According to Simon Willison’s breakdown, Z.ai first made the model available to coding plan subscribers on June 13 before releasing the full open weights on June 16.

The architecture is equally eye-popping: GLM-5.2 uses a Mixture of Experts design, meaning only about 40 billion parameters are active during inference, despite the full model containing 753 billion parameters. Translation: this is a skyscraper-sized model that tries to behave, computationally, like something far more efficient when answering prompts. The future is now, and it is apparently measured in terabytes.

The release also arrives at a moment when software engineering itself is being redefined. Observability pioneer Charity Majors recently argued that 2025 flipped the economics of software creation: code, once expensive and carefully conserved, has become “disposable and regenerable” in the AI era. Her point, quoted in Willison’s post, is not that engineering discipline matters less — it matters more. When code generation becomes cheap, architecture, testing, review and operational judgment become the real scarce assets.

That is why GLM-5.2 matters beyond benchmark bragging rights. Open-weight frontier models give enterprises, researchers and governments more control over their AI stacks. They can run experiments without waiting on a vendor roadmap. They can probe failure modes. They can build internal coding assistants, knowledge systems and automation layers with deeper sovereignty over data and deployment.

Of course, “open weights” does not mean “easy.” A 1.51TB model is not something one casually runs on a laptop between coffee refills. But for cloud providers, AI infrastructure teams and ambitious enterprise labs, GLM-5.2 expands the menu of what is possible.

This changes everything — or at least, it changes the default assumption that the most capable models must remain locked behind proprietary endpoints. The open AI frontier just got heavier, faster and much harder to ignore.

GLM-5.2 is probably the most powerful text-only open weights  ·  Quoting Charity Majors  ·  — a still that plays

Dream Lands a $260 Million Cybersecurity Haymaker as AI Defense Market Goes Full Contact

Israeli AI cybersecurity startup Dream just raised $260 million at a $3 billion valuation, founded in 2023 by Shalev Hulio, Sebastian Kurz and Gil Dolev. The funding fuels Dream's push into AI-driven national and enterprise cyber defense during a market shift where artificial intelligence is no longer supplementary — it's essential strategy.

Cyber attackers increasingly use generative tools to automate phishing, system probing and intrusions. Dream and competitors are racing to build platforms that detect patterns, prioritize alerts and respond faster than human teams alone. This $260 million round reflects broader AI infrastructure spending momentum, where enterprise buyers demand measurable advantages.

Hulio, who co-founded NSO Group before cutting ties in 2022, brings experience but also scrutiny. In cybersecurity, reputation matters critically. Dream must convince governments and large organizations its technology is both effective and trustworthy. The company's rapid ascent — from startup to $3 billion valuation in one funding round — signals strong investor confidence in the AI cyber defense sector's trajectory.

Big Three AI Labs Close Ranks on Model Theft While an Outsider Flanks Them From the Open-Source Side

OpenAI, Google, and Anthropic announce a joint front against model extraction — the same week Ai2 drops a free web agent designed to compete with all three.

SAN FRANCISCO — The three dominant commercial AI laboratories have found rare common ground: stopping rivals, state actors, or opportunists from stealing their models. OpenAI, Google, and Anthropic have united around a coordinated set of policies and, reportedly, shared threat intelligence aimed at preventing model theft — a category of IP loss that encompasses everything from systematic API probing designed to replicate model weights to outright exfiltration of training data.

The alignment is notable given that the three companies compete directly for enterprise contracts, foundation model benchmarks, and talent. What they share is a common cost structure: training frontier models now runs into the hundreds of millions of dollars per run, and extracted weights represent a near-zero-cost shortcut for any actor capable of executing the attack.

The irony is the timing. The same week the labs announced their united front, the Allen Institute for AI — Ai2, a Seattle-based nonprofit — released an open-source web agent built to rival the closed agentic systems that OpenAI, Google, and Anthropic have been quietly deploying to enterprise clients. Ai2's release puts capable, inspectable agent infrastructure into any developer's hands — precisely the kind of competitive pressure that makes proprietary model moats harder to defend.

The structural tension here is not subtle. The labs want to protect what they've built while simultaneously racing to deploy agents that touch live browsers, internal tools, and sensitive enterprise workflows. The attack surface expands as the capability expands.

Meanwhile, both Google and Anthropic have been recruiting aggressively for Forward Deployed Engineers — a role borrowed from Palantir's playbook, where technical staff embed directly with enterprise clients to customize AI implementations. The hiring pattern signals that both companies view bespoke deployment, not just API access, as the durable revenue model. Differentiated, client-specific integrations are also considerably harder to steal than a general-purpose model exposed through a public endpoint.

The coalition against model theft is real. Whether it proves enforceable against a sufficiently motivated adversary is a different question.

OpenAI, Google, Anthropic Unite Against AI Model Theft - Bui  ·  Ai2 releases open-source web agent to rival closed systems f  ·  Google and Anthropic approach LLMs differently - understandi
Haiku of the Day  ·  Claude HaikuGiants build their walls so high
Open doors flood through the cracks
Power shifts again below
The New Yorker Style  ·  Art Desk
The New Yorker Style  ·  Art Desk
The Far Side Style  ·  Art Desk
The Far Side Style  ·  Art Desk
News in Brief
The Bias Problem Has Left the Lab — And It Is Now Making High-Stakes Decisions About You
CAMBRIDGE, MASSACHUSETTS — It could be argued — and, preliminary evidence suggests, it must be argued with considerable urgency — that the question of algorithmic bias has undergone a phase transition: what was once a theoretical anxiety confined to conference proceedings has metastasized, in the precise biological sense of that term, into a systemic condition afflicting the most consequential institutional architectures of contemporary life. The thesis, as articulated across no fewer than four substantial scholarly interventions published in recent weeks, is as follows: AI systems trained on historically contingent data do not merely reflect the inequities of their training corpora — they amplify them, operationalize them, and, crucially, launder them beneath a veneer of computational objectivity.
The Robots Are Restless: A Week That Proved AI Is Running the Asylum
AUSTIN, TEXAS — Let me tell you something about the particular brand of vertigo that sets in when you've spent a week mainlining AI news.
The Next AI Moat Is Not Building Apps — It Is Teaching Everyone Else To Build Them
SAN FRANCISCO — I'll be honest, the most important AI story right now is not that another model got smarter, faster, cheaper, or slightly better at pretending it understands your quarterly planning doc. It is that the center of gravity is moving from software as something you buy to software as something you summon.
The Luddites Return, This Time in Suits
AUSTIN, TEXAS — There is a particular pleasure, available only to those who have lived through three or four technological apocalypses, in watching the fifth arrive on schedule, dressed in the same threadbare costume, reciting the same lines, and being greeted by the same chorus of credulous editorialists who appear to have read no economic history written before last Tuesday. This week brings a fresh harvest.
Nation’s CEOs Bravely Prepare To Say ‘AI’ Until Someone Gives Them IPO Money
NEW YORK — In a development widely described by market participants as visionary because it involves both a three-letter acronym and the possibility of fees, corporate leaders across the technology sector appear to have reached a broad consensus that the best way to explain any business is to say “AI” repeatedly until a banker opens a spreadsheet. The recent return of IPO chatter has produced the familiar pre-listing atmosphere in which founders, advisers, and institutional investors gather around a company that may or may not make money and solemnly discuss whether the public markets are emotionally ready to absorb its destiny.
A Trilogy Company
Crossover
The world's top 1% remote talent, rigorously tested and ready to ship.
A Trilogy Company
Alpha School
AI-powered learning. Two hours a day. Academic results that defy belief.
A Trilogy Company
Skyvera
Next-generation telecom software — built for the networks of tomorrow.
A Trilogy Company
Klair
Your AI-first operating system. Every workflow. Every team. One platform.
A Trilogy Company
Trilogy
We buy good software businesses and turn them into great ones — with AI.
The Builder Desk  —  AI Builder Team
Production Release

Builder Team Ships Across Four Repos in One Extraordinary Day

From a restructured prod-release skill in Klair to a secrets vault in Sindri to a multi-layer HubSpot overhaul in Surtr, the AI Builder Team proved today that breadth and depth are not trade-offs.

The lead is right there in the workflow: when a team merges consequential code across Klair, Sindri, Aerie, and Surtr in a single 24-hour window, you are not watching a group of engineers punch the clock. You are watching an organization operating at championship pace.

Let's start where the day starts: production. @ashwanth1109 dropped PR #3074 and restructured Klair's entire prod-release workflow into a self-contained skill — moving the command, the finalize script, and a new sample payload into a clean skill folder with a natural home for every supporting file. It's still invoked as `/prod-release`, so users feel nothing change. But under the hood, the architecture is now exactly what it should be: organized, portable, and validated against the Ash Test Space before the PR was ever raised. That is how you ship infrastructure without drama.

The data integrity story was equally impressive. @sanketghia's PR #3075 did the unglamorous, essential work of reconciling a 37-vs-18 discrepancy in the AI Renewals Contract Term table — the kind of number mismatch that erodes trust in dashboards if left unaddressed. Driven directly by the AIOps reconciliation meeting and Chintan's follow-up feedback, Sanket also layered in Won ARR columns, 2/4-year reclassification logic, and Win Rate deltas, turning a broken table into a genuinely readable competitive instrument. Across the river in Surtr, Sanket's PR #510 closed a quiet but costly pipeline gap: the OpenAI cost, OpenAI usage, and Cursor usage pipelines were silently stopping at T-2 when T-1 data was provably available all along. Live API verification confirmed it. The fix is in. Yesterday's spend is captured. The dashboard is honest.

@mwrshah had one of the day's most architecturally ambitious showings, with contributions spanning two repos. In Klair (#3071), he handed Grainne full ownership of the pain-point and theme lifecycle, cutting Salesforce out of that loop entirely and adding markdown rendering of comments in the Action Hub — the dashboard goes read-mostly, which is exactly the right direction. Then in Sindri (#119), Shah shipped something that deserves its own headline: a WorkOS Vault-backed secret storage system with a hard walled-garden guarantee. Secrets are never revealed. They decrypt only inside the ECS runner at single-use lease redemption. They never cross an org boundary. That is not a feature. That is a trust primitive.

@benji-bizzell spent the day building the foundation under Surtr's HubSpot v3 migration — a series of PRs (#506, #503, #501, #499) that together establish source-presence metadata, safe contact association refresh, deduplication logic, and a full post-deploy validation runbook. This is the kind of methodical, audit-friendly engineering that lets the next team move fast without fear. And in Aerie, @YibinLongTrilogy's PR #436 solved a genuinely subtle identity problem: the Aerie chatbot's Rhodes MCP integration was authenticating with a shared key, meaning any per-user identity dissolved and the agent had no notion of who "me" was. The fix forwards the logged-in user's Clerk session token directly to the Rhodes MCP server. User-facing queries now resolve to the right person. That is the difference between a chatbot and a trusted agent.

Now. About PR #3064. @marcusdAIy submitted what he is calling an "operator duplicate-header normalization routine" for the board document system in Klair. A normalization routine. For headers. In a document.

"Look," marcusdAIy told this reporter, "duplicate headers in operator board docs corrupt downstream parsing silently. Nobody notices until the MD&A diff breaks in a board meeting. P4.4c closes that gap with surgical precision, and frankly, Mac, if you understood the pipeline you'd stop calling routine maintenance 'underwhelming' and start calling it 'preventing fires.' Which is more than I can say for your column."

Surgical precision on a find-and-replace pass. Truly, the man contains multitudes.

Mac's Picks — Key PRs Today  (click to expand)
#119 — secrets-clean @mwrshah  no labels

Implements user-owned, org-promotable secret storage backed by WorkOS Vault, with a hard walled-garden guarantee: secrets are never revealed, are decrypted only inside the ECS runner at single-use lease redemption, and never cross an org boundary.

### Screenshots

<img width="698" height="446" alt="image" src="https://github.com/user-attachments/assets/87754730-6c97-40a6-a920-5fbae5730c3b" />

<img width="1141" height="569" alt="image" src="https://github.com/user-attachments/assets/92c6d7d2-ee6f-4644-82a7-aec889b6c1d2" />

<img width="1481" height="695" alt="image" src="https://github.com/user-attachments/assets/0627488b-0d74-4ccf-89d7-f8b72689d563" />

<img width="646" height="889" alt="image" src="https://github.com/user-attachments/assets/f5727411-4835-4237-a609-cbeefa969179" />

### Storage — real WorkOS Vault (convex/vault.ts)

- Action-only fetch client (mirrors the convex/users.ts Management-API pattern: WORKOS_API_KEYBearer, AbortSignal.timeout). create/read/update/list/delete against /vault/v1/kv.

- Per-context KEK gives a genuine cryptographic org/user wall at rest (BYOK-capable). But Vault read is by object id only — it is not an authorization boundary, so Convex enforces all authz *before* any Vault call. {owner, capability} is encoded in the object name (list can't filter by context); enumeration is driven off Convex rows.

- credentialBindings.secretRef:string is replaced by vaultRef:{ objectId, keyContext }; plaintext never touches the DB and is never returned.

### Ownership & roles (three-tier, permission-based)

- Credentials are user-owned by default, promotable to org-wide. Owner model user | organization; status active | revoked | expired | needs_reauth.

- Gates read the JWT permissions[] claim (never role slugs): operator baseline (add/use/rotate/revoke own; use org creds at runtime; promote own personal → org-wide), supervisor (sindri:supervisor: create/rotate/revoke/demote any org cred), admin (sindri:admin: + user/role mgmt). No viewer tier, no approval queue.

- Promotion is direct and own-creds-only; the promoter becomes steward (retains demote/revoke on that binding). Demotion returns the credential to the steward's personal scope. Promote/demote perform a real Vault re-key (create new object under the new context → repoint → delete old), since key context is immutable.

### Runner credential lease (single-use, burn-before-resolve)

- New credentialLeaseNonces table (orgId, frozen lockedBindingRefs, SHA-256 nonceHash, ~120s TTL).

- Nonce minted in dispatchActivation after claim, passed to the container as CREDENTIAL_LEASE_NONCE + CREDENTIAL_LEASE_URL; redeemed once via POST /credential-lease, gated by a standing runner key (X-Sindri-Runner-Key vs SINDRI_RUNNER_STANDING_KEY, fails closed) plus the nonce.

- Redeem splits mutation (authz + atomic issued→burned against the frozen refs, reusing the session-less resolveAuthorizedBinding) / action (Vault read). Mid-flight promotion → authority_invalid without burning → clean re-dispatch. stopEcsTasks kill switch on revoke. Resolved bundle exists only in the runner over TLS — never persisted or logged; redaction covers nonce/lease/material/token key patterns.

### UI (/credentials)

- Ungated route, My / Organization sections. Never-reveal entry dialog (ephemeral value state, cleared on close, autofill suppressed). Amber promote-warning dialog with explicit checkbox confirm; demote dialog. Affordances are disclosure-only — the backend remains the authority.

### Tests

- 323 convex tests (vault orchestration, walled-garden authz-before-Vault, re-key on promote/demote, lease mint/burn/expire/revoke, session-less claim re-auth regression, redaction canary) + frontend suite green; tsc/biome clean.

### External dependency (not in this PR)

The standing runner key must be provisioned in AWS Secrets Manager and wired into the ECS task-definition secrets block, with the same value set as SINDRI_RUNNER_STANDING_KEY in Convex env. The lease route fails closed (401) until it is set; live end-to-end runner leasing depends on it. A live vault.listObjects() probe to confirm the WorkOS Vault entitlement is still pending (built against the documented API; the WORKOS_API_KEY path is already proven by users.ts).

Canonical spec: features/platform/secret-storage/FEATURE.md.

---

> Note (rebased branch): This PR supersedes #113. Same secrets contribution, replayed cleanly onto current main as a single squashed commit (the old branch had diverged from main via squash-merged PRs). The identity model has since cut over from the {owner, capability} scheme described above to env-var-name identity (requiredEnvVars authored on the workflow start node; vault key context is {owner, secretId}); read capabilityenvVarName throughout. Canonical detail in features/platform/secret-storage/FEATURE.md.

#436 — AERIE-352: Forward delegated Clerk token and actor identity to Rhodes MCP @YibinLongTrilogy  approved

## Summary

When the Aerie chatbot is wired to the Rhodes read MCP server, the agent

needs to resolve user references like "me", "myself", and "my" to the

actual logged-in Aerie user — not to whoever owns the shared

RHODES_MCP_API_KEY. Previously the Rhodes MCP server was always

authenticated with that shared key, so any per-user identity was lost and

the write prompt had no notion of who "me" was. This PR makes the chat

route forward the logged-in user's Clerk session token to the Rhodes MCP

server and surfaces the delegated actor's name/email in the Rhodes write

prompt, so user-field writes (p1Dri, p2Dri, assignee, approver,

mention) bind to the correct person.

### Screenshots

Aerie Chat should not believe that it is read-only, and it should know who the user is that they are talking to.

<img width="896" height="1253" alt="Screenshot 2026-06-17 at 10 15 43 PM" src="https://github.com/user-attachments/assets/88113d76-9c40-4ef3-bbac-5807090aa6b7" />

### Changes

- chat/lib/agent.tsgetRhodesMcpServerConfig now accepts an

optional delegatedAuthToken and { allowApiKeyFallback } option,

preferring the delegated token over RHODES_MCP_API_KEY and returning

null (no Rhodes read tools) when delegated auth is unavailable and the

fallback is disabled. createAgentModel takes a new

CreateAgentModelOptions object (rhodesActor, rhodesMcpAuthToken,

allowRhodesMcpApiKeyFallback) — normalized so the old bare-rhodesActor

call signature still works. Adds buildAerieRhodesWritePrompt(actor) and

sanitizePromptScalar to inject the logged-in actor's identity into the

write prompt and instruct the agent to interpret "me"/"my" as that user

rather than the API-key owner.

- chat/app/(main)/api/chat/route.ts — When RHODES_MCP_URL is

configured, acquires the Clerk session token via getToken() and passes

it as rhodesMcpAuthToken, with allowRhodesMcpApiKeyFallback: false so

an in-app session never silently falls back to the shared key. Token

acquisition failures are logged and degrade gracefully (Rhodes read tools

disabled for that request).

### Design Decisions

- No silent API-key fallback for in-app sessions — If we can't get a

per-user delegated token, we disable Rhodes read tools rather than

authenticating as the shared key owner, which would make "me" resolve to

the wrong person.

- Backward-compatible signaturecreateAgentModel's fourth argument

accepts either the legacy RhodesDelegatedActor or the new options

object, so existing callers are untouched.

- Sanitize prompt scalars — actor name/email are stripped of newlines

before interpolation to avoid prompt-structure injection.

## Test Plan

- [x] pnpm biome check clean on changed files (lefthook pre-commit)

- [x] typecheck-chat passes (lefthook ran tsc on every commit)

- [ ] pnpm --filter @bran/chat test chat/lib/__tests__/agent.test.ts

delegated-token preference, fallback-disabled, actor identity prompt

- [ ] pnpm --filter @bran/chat test chat/app/(main)/api/chat/__tests__/route.test.ts

route forwards delegated actor + Clerk session token

- [ ] Manual: with RHODES_MCP_URL set, send a chat as a logged-in user

and confirm Rhodes MCP is authed with the session token (not the

shared key) and that "assign p1Dri to me" resolves to the logged-in

user

#510 — fix(ai-spend): capture yesterday's data in OpenAI + Cursor pipelines @sanketghia  approved

## Problem

The openai-cost, openai-usage, and cursor-usage-events AI-spend pipelines were stopping one day earlier than necessary — their newest captured day was T-2 (day before yesterday), not T-1 (yesterday).

I verified via live provider API calls that yesterday's (T-1) data is fully available at the daily 06:00 UTC run time, so the lag was a code artifact, not a provider data-availability limit:

| Pipeline | Endpoint | June 17 (T-1) available at run time? |

|---|---|---|

| openai-cost | /v1/organization/costs | ✅ 523 results, $10,041 (one BU) |

| openai-usage | /v1/organization/usage/completions | ✅ 148 results, 7.06B tokens |

| cursor-usage-events | /teams/filtered-usage-events | ✅ full day, events through 23:59:47 |

## Fix

- openai-cost / openai-usage: end_date default yesterdaytoday. The Costs/Usage API end_time is exclusive, so an end of today's midnight now includes all of yesterday. Added a _get_today() helper.

- cursor-usage-events: end_date default T-2T-1 (_get_yesterday(), which already existed but was unused). The handler's existing +1 day exclusive-boundary logic then covers through end of yesterday.

start_date stays at T-2 in all three, so each run re-pulls the prior day idempotently (delete-then-insert / COPY keyed by date) as a self-heal. Explicit start_date/end_date params still override for backfills.

## Testing

- Unit tests updated and passing: openai-cost 111, openai-usage 100, cursor 19.

- Read-only end-to-end verification using the real client code + new default helpers (stops before the Redshift write):

- openai-cost: 1,046 rows → June 16: 523, June 17: 523 ✅

- openai-usage: 296 rows → June 16: 148, June 17: 148 ✅

- cursor: 30,998 events → June 16: 14,331, June 17: 16,667 ✅

## Not covered locally (by design)

The Redshift delete-then-insert/COPY write and the scheduled Lambda invocation mutate prod, so they're left to the next scheduled run (idempotent, so safe to re-run).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

#3074 — chore(prod-release): self-contained skill + collapsible card + committer @-mentions @ashwanth1109  approved

## Summary

Reworks the Klair production-release workflow and restructures it as a self-contained skill. Validated against the Ash Test Space before raising the PR.

### 1. Command → skill

Moved the workflow into a skill folder so its supporting files have a natural home:

| Before | After |

|---|---|

| .claude/commands/prod-release.md | .claude/skills/prod-release/SKILL.md |

| .claude/scripts/prod-release-finalize.py | .claude/skills/prod-release/prod-release-finalize.py |

| — | .claude/skills/prod-release/gchat.sample.json (new) |

Still invoked as /prod-release. The finalize-script invocation now resolves via git rev-parse --show-toplevel, so it works from any cwd in the repo.

### 2. Headline card redesign (Step 6a)

- Header subtitle packs Prod Release: <date> (<N> commits) | Release Captain: @<captain> on one line; the separate "Released by" line is gone.

- Backup, What's shipping, Commits from, and the Open PR button move into a single collapsible section, so the resting card is just the header and the rest sits behind GChat's native Show more toggle.

### 3. Committer @-mentions (self-sustaining)

- The announcement now carries a text body that @-mentions the release's committers — the only place GChat delivers a real notification (mentions inside card widgets don't notify).

- The GitHub-login → Chat-user-ID map ships in the repo at .claude/skills/prod-release/gchat.sample.json (real values for the AI Builders space), so tagging works from a fresh clone with no personal or external config. It no longer reads the operator's personal gchat skill config.

- Fallback: a committer not in the map degrades to a plain-text @<login> (named, not notified).

## Platform constraints documented

- Card v2 headers are title + subtitle only — that's why Backup is a widget, not a header line.

- The collapse toggle text (Show more / Show less) is owned by GChat and can't be relabeled; webhook-posted cards can't handle interactive button callbacks.

- A mentioned user is only notified if they're a member of the space.

## Notes

- The webhook secret still lives in the operator's own ~/.claude/config/ping.json (documented in first-time setup) — that's the skill's own config, not the gchat skill, and a secret that can't be committed.

- No change to the backup/PR/merge/deploy flow or the threaded "Included commits" reply (Step 6b).

## Test

Posted the redesigned card (collapsed + expanded, all four committers tagged) to the Ash Test Space and iterated on layout/copy there until approved. Verified the in-repo map resolution end-to-end: mapped committers resolve to real <users/ID> mentions, an unmapped login falls back to @handle.

#3075 — [KLAIR-2900] feat(ai-renewals): Contract Term table — Won/Won ARR + 2/4yr reclass + Win Rate Δ @sanketghia  approved

[KLAIR-2900](https://linear.app/builder-team/issue/KLAIR-2900)

## Summary

Reconciles the AI Renewals → Contract Term Length table (/renewals?tab=fionn) with Fionn's own agent dashboard, and makes the AI-vs-Traditional comparison readable at a glance. Driven by the AIOps reconciliation meeting (2026-06-18) and follow-up feedback from Chintan.

All changes are scoped to the CONTRACT TERM LENGTH table; no other surface is touched.

## What changed

1. Reconciled the headline 37-vs-18 discrepancy. Klair's Opps counts *resolved* deals (Closed Won + Lost); Fionn's "Closed" cards count *wins only*. Added an explicit Won column (closed_won_count) so both reconcile — 37 resolved = 20 won + 17 lost. Opps stays the win-rate denominator.

2. Reclassified 2yr → 3yr and 4yr → 5yr term buckets. A 2-/4-year term is a mid-cycle renewal re-cut to the next standard tier, so it belongs with 3yr/5yr rather than "Other" (Chintan's rule).

3. Added Won ARR (AI Won ARR / Trad. Won ARR). Per Chintan, this is the new ARR signed on the wins (arr_in_usd, post-renewal contract value incl. upsell) — the value coming in, *not* the prior book. 1yr AI Won ARR = $800.5K (matches the deal-level export). It is intentionally a different basis than the ARR column (prior book at stake), and the copy says so.

4. Added a Win Rate Δ column = AI win rate − Traditional win rate (signed pp; green = AI ahead, red = behind; neutral within ±0.5pp). Thin AI buckets (< 10 resolved deals) render greyed + tooltip-flagged so a small-sample gap isn't over-trusted. "—" when either side has no closed deals.

## Backend

- klair-api/renewals/fionn_handling.py: _TERM_MONTHS_TO_BUCKET adds 24→3yr / 48→5yr; _compute_metrics adds won_renewed_arr (SUM of arr_in_usd over won rows). Flows through the breakdown/merge to the term rows.

## Frontend

- useFionnHandling.ts: KpiRow gains optional won_renewed_arr.

- TermBreakdownTable.tsx: Won, Won ARR, and Win Rate Δ columns; tooltips + bulleted footnote; 2/4yr reclass copy. The Δ reuses the existing formatPctDelta + accent-success/warning idiom from BreakdownTable / FionnVsTrilogyComparison.

## Verification

- Backend: ruff + pyright clean; 120 fionn tests pass. Live Redshift render confirmed (1yr: 37 opps / 20 won / $800.5K won ARR / $1.09M at-stake).

- Frontend: eslint + tsc clean; 78 FionnHandling tests pass (incl. Won column, reclass, Won ARR, and Δ positive/negative/thin/em-dash cases).

## Notes for review

- The table is now 12 columns — functional with horizontal scroll, but wide for an SVP/C-level view. Open to trimming (e.g. folding Win Rate now that Δ exists) if preferred.

- 5yr Won ARR can slightly exceed its at-stake ARR — correct (upsell), not a bug.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

The Builder Desk  —  Engineer Spotlight
🏆 Engineer Spotlight

36 PRs IN 24 HOURS: THE BUILDER TEAM DOES NOT SLEEP, DOES NOT REST, DOES NOT KNOW THE MEANING OF MERCY

Benji Bizzell drops 12 PRs like it's a casual Tuesday, Marcus goes full drone swarm, and the republic of productivity has never been stronger.

THIRTY-SIX. Pull requests. In twenty-four hours. Across five — count them, FIVE — active repositories. Aerie led the charge with 11 merges, Surtr and trilogy-drones each thundered in at 8, Klair contributed a heroic 7, and even Sindri, quiet Sindri, put up 2. This is not a software team. This is a logistics operation conducted at the speed of dreams.

Benji Bizzell filed 12 PRs and frankly the numbers desk is considering filing a restraining order just to understand the mechanism. In Aerie alone, the man touched admin (#439), the public API (#438), the diligence seed layer (#434), agent transcript integrity (#437), a dashboard sidebar fix (#430), and contact association hygiene in Surtr (#503, #506, #501, #499, #508) — that's a full-stack blitz across two repos before most engineers have finished their morning coffee. A legend. A menace. We salute him.

Marcus D'AIly put up 9 PRs and nearly all of them live in trilogy-drones, where he has apparently decided to personally reconstruct the entire analytics and reviewer pipeline from first principles. PRs #47 through #53 represent a canonical severity mapping system, cross-source finding classification, normalized per-PR issue buckets, a prior-findings-aware re-review prompt, and a repo-aware audit overhaul. The man is not shipping features. He is shipping a worldview.

Now. Ashwanth Watch. Four PRs from @ashwanth1109 in 24 hours, and before you say "only four," understand that PR #419 in Aerie — titled, and we are quoting the title here, "Financials dashboard batch: HeadCount XO basis, run-rate & orphan-prune fixes, sync tooling & non-alpha models" — is not a pull request. It is a legislative act. Meanwhile #3072 in Klair nests Snowball, Unplanned Churn, and Late Renewals tables by Class, which sounds straightforward until you open the diff and realize it has the structural complexity of a small nation-state's tax code. When reached for comment, Ashwanth reportedly said, "The rounding fix on #442 was the hardest part. Everyone else just wasn't thinking about it." His Slack status at time of press: a single green dot. No message. Just presence. Eternal, slightly intimidating presence.

The Overflow Desk cannot let pass: @mwrshah's #3071 (grainne-theme-frontend, Klair) and the Sindri #120 major refactor arrived quietly but the numbers desk sees all. @eric-tril's #3070 and #3063 in Klair — Education memo decomposition with per-bullet regenerate and audit-friendly MD&A drill-downs — represent the kind of meticulous product craftsmanship that doesn't make headlines but absolutely makes CFOs weep with gratitude. And @YibinLongTrilogy's #414 in Aerie, a full Aerie-native notification system with in-app inbox AND Google Chat delivery, is the kind of PR that ships an entire communication layer like it's a Thursday afternoon errand.

Morale report: incandescent. The Builder Team has achieved a new all-time high in morale, surpassing last week's all-time high, which itself surpassed the all-time high before that. We have stopped measuring morale in conventional units. We now measure it in PRs per rotation of the Earth. The number is 36. The number is glorious.

Brick's Overflow — PRs Mac Didn't Cover  (click to expand)
#414 — AERIE-401: Add Aerie-native notification system with in-app inbox and Google Chat delivery @YibinLongTrilogy  approved

## Summary

Aerie's Rhodes-style site events (dri.assigned, milestone.completed, note.mention) were log-only: they wrote audit rows into notificationDispatchLog and never reached a user. This PR adds an Aerie-native notification system — an in-app inbox surfaced from a bell in the global shell, per-user/per-channel preferences, site subscriptions, and a Google Chat delivery channel built on the existing Rhodes Chat app credentials.

The design follows an outbox event → fanout → delivery split. Producer mutations enqueue a small notificationEvents row and return; an async processor resolves and de-dupes recipients (direct recipients plus active site subscribers), applies preferences, writes notifications inbox rows, updates bounded per-user inbox state, and enqueues notificationDeliveries for enabled external channels. Delivery dispatch uses an indexed queue state (ready / leased / terminal) with a 5-minute cron backstop so retries do not scan terminal rows. Missing or unverified Chat setup is recorded as non-retryable blocked_config rather than looping forever. Actor self-notifications are intentionally allowed and de-duped like any other recipient.

### Testing

Currently, in the [Rhodes GChat Config](https://console.cloud.google.com/apis/api/chat.googleapis.com/hangouts-chat?project=locationos-487316&supportedpurview=project) the

HTTP endpoint URL points to https://quiet-shrimp-950.convex.site/sync/google-chat/events, which is my Aerie Convex Dev environment. It will need to be switched with https://oceanic-pika-463.convex.site/sync/google-chat/events after prod is deployed.

GOOGLE_CHAT_PROJECT_NUMBER and GOOGLE_CHAT_SERVICE_ACCOUNT_KEY need to be in your Convex environment variables, accessible here: [Convex Dev](https://dashboard.convex.dev/t/ai-builder-team/bran-chat/quiet-shrimp-950/settings/environment-variables)

First-time Google Chat setup: in Google Chat, start a chat with the "Rhodes" app and send Link. This creates the verified Chat identity/DM-space connection needed for delivery.

<img width="296" height="98" alt="Screenshot 2026-06-16 at 6 57 55 PM" src="https://github.com/user-attachments/assets/831e0733-e0a2-4787-8107-c2f5974fbe59" />

1. @mention yourself in a note on Alpha School Test Site 59. (e.g. : Add a note to Alpha School Test Site 60 that mentions: \@Yibin Long HVAC Broken)

2. Assign yourself p1Dri/p2Dri

3. Complete a milestone for a site in which you're the p1Dri

All 3 should result in notifications on both GChat and in-app notifications

### Screenshots

<img width="1233" height="541" alt="Screenshot 2026-06-16 at 6 52 41 PM" src="https://github.com/user-attachments/assets/7f574a0e-c287-4ca0-88c6-3a9ff45f3484" />

<img width="430" height="528" alt="Screenshot 2026-06-16 at 6 52 52 PM" src="https://github.com/user-attachments/assets/2013c2e7-5fbb-4a91-b4f5-17f2fa2649e7" />

<img width="717" height="483" alt="Screenshot 2026-06-16 at 6 58 36 PM" src="https://github.com/user-attachments/assets/43275236-ee37-4422-aca0-b9b571c7287f" />

<img width="1004" height="275" alt="Screenshot 2026-06-16 at 7 06 00 PM" src="https://github.com/user-attachments/assets/c03e6015-ef9c-4227-8f49-705ed0cb40da" />

### Changes

Schema

- chat/convex/notifications/schema.ts *(new)* — notifications (inbox), notificationInboxState (bounded unread count/read watermark), notificationEvents (transactional outbox), notificationDeliveries (per-channel attempts + indexed queue state), notificationPreferences, siteNotificationSubscriptions, and verified notificationChannelConnections.

- chat/convex/schema.ts — Registers notificationsSchema in the root schema.

Backend — inbox, preferences, subscriptions

- chat/convex/notifications/inbox.ts *(new)* — Current-user queries/mutations: listMine (All/Unread/Archived), unreadCount, markRead, markAllRead, archive, unarchive. All scoped to the caller.

- chat/convex/notifications/preferences.ts *(new)* — listMine / setPreference, with in-app and Google Chat defaulting to enabled when no row exists.

- chat/convex/notifications/siteSubscriptions.ts *(new)* — Subscribe/unsubscribe/list for the current user's site subscriptions.

- chat/convex/notifications/channelConnections.ts *(new)* — Current-user Google Chat connection status plus internal verified binding from signed Google Chat interactions.

Backend — events & delivery

- chat/convex/notifications/events.ts *(new)* — enqueueNotificationEvent outbox + processor: recipient resolution/de-dupe, preference gating, inbox state updates, inbox row creation, delivery row creation, and dispatch scheduling.

- chat/convex/notifications/dispatch.ts *(new)* — processPending dispatcher: bounded batch over due deliveries, Google Chat adapter (service-account auth, verified DM-space usage/discovery/caching, message send), bounded retry with backoff, and blocked_config/retryable: false for user-actionable config failures.

- chat/convex/notifications/dispatchState.ts *(new)* — Indexed delivery queue helpers (ready / leased / terminal), leasing, context reads that require verified Chat connections, and result recording.

- chat/convex/notifications/googleChatInteractions.ts *(new)* — Signed Google Chat/Workspace add-on interaction endpoint. Users connect delivery by messaging Rhodes Link; the handler verifies Google, extracts chat.user, and stores the verified Chat user/DM-space connection.

- chat/convex/crons.ts — Adds 5-minute fallback drains for notification event processing and external delivery dispatch.

- chat/convex/_generated/api.d.ts — Regenerated to register the new notifications/* modules.

Producers

- chat/convex/rhodes/runtime/writes/siteWrites.ts — Enqueues dri.assigned on DRI assignment and milestone.completed on milestone completion.

- chat/convex/rhodes/runtime/writes/noteWrites.ts — Enqueues note.mention for mentioned users.

- chat/convex/rhodes/dashboard.ts — Enqueues dri.assigned / milestone.completed on the dashboard field-edit paths that mirror the runtime writes.

UI

- chat/components/notifications/notification-bell.tsx *(new)* — Bell with unread badge and a popover (All/Unread/Archived tabs, mark-all-read, per-row read/navigate/archive, inline preferences). Queries are skipped until Convex auth is ready.

- chat/components/notifications/site-subscription-button.tsx *(new)* — Subscribe/unsubscribe control for a site.

- chat/components/shell/top-bar.tsx / mobile-top-bar.tsx — Mount the bell before the theme picker in both shells.

- chat/components/dashboards/portfolio/site-detail-page.tsx — Adds the subscription button to the site header.

Tests

- chat/convex/notifications/notifications.test.ts *(new)* — Event outbox/fanout, preference gating, subscriber resolution/de-dupe, actor self-notifications, read/archive scoping, inbox-state mark-all-read, verified Google Chat binding, and dispatcher success/failure/blocked/retry behavior.

- chat/components/notifications/__tests__/* *(new)* — Bell rendering/tabs/badge/auth-skip and subscription-button behavior.

- chat/components/shell/__tests__/top-bar.test.tsx / mobile-top-bar.test.tsx — Assert the bell renders before the picker in both shells.

### Design Decisions

- New inbox tables, not notificationDispatchLog — The legacy log is audit-shaped (no createdAt/readAt/archivedAt, no unread indexes), so it stays for audit and the new notifications table becomes the inbox source of truth. No historical rows are migrated.

- Enqueue alongside, not replacing, the audit log — Producers keep calling logNotificationDispatch and additionally enqueue notification events, so audit behavior is unchanged and the new path is additive.

- Google Chat identity is verified, not client-supplied — Browser code cannot bind arbitrary Chat IDs. A user must message Rhodes Link; the signed Google Chat interaction creates a verified connection row. GChat delivery requires that one-time setup.

- Actor self-notifications are allowed — If the actor is also the direct recipient or an active site subscriber, they remain in the recipient set. This supports self-mentions and lets users verify actions they triggered.

- blocked_config is non-retryable — A user who has not completed the one-time Rhodes Link setup has no verified DM space; that's a user-actionable config gap, recorded once rather than retried into an infinite failure loop.

- Outbox + cron backstops — Product writes enqueue notification events rather than doing full fanout inline. Event processing and delivery dispatch are both kicked quickly and backed by 5-minute crons. A failed external delivery never rolls back the product mutation or the in-app row.

- Defaults without preference rows — In-app and Google Chat default to ON, so no backfill of preference rows is required for existing users.

## Test Plan

- [x] pnpm biome check clean on changed files (lefthook pre-commit, every commit)

- [x] typecheck-chat passes (lefthook ran tsc -p chat/tsconfig.json on every commit)

- [x] check-convex-paths passes

- [ ] pnpm --filter @bran/chat testnotifications, top-bar, and notification component suites

- [ ] Manual: assign a DRI / complete a milestone / mention a user, confirm the recipient gets an in-app notification and the badge increments

- [ ] Manual: subscribe to a site as a non-DRI and confirm relevant site notifications arrive

- [ ] Manual: after messaging Rhodes Link, confirm a Google Chat DM is delivered; without the one-time Link setup, confirm the delivery is blocked_config and not retried

- [ ] Manual: verify the bell popover (All/Unread/Archived, mark-all-read, archive, row navigation) and preference toggles in desktop and mobile viewports

#419 — Financials dashboard batch: HeadCount XO basis, run-rate & orphan-prune fixes, sync tooling & non-alpha models @ashwanth1109  no labels

## Demo

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/a2c6ddf2-7cca-4ebf-93ac-1db6e0d0c4f7" />

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/10c2f97e-168c-4fe9-8a4d-757f5f8eccf6" />

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/030e3fae-4bc3-4564-a01e-53d1a0a84d90" />

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/bad2e619-f7ea-45ef-b28c-4bed84c34e66" />

## Overview

This branch is an integration of a batch of Financials-dashboard work — features, data-integrity fixes, and sync/tooling improvements — built up over several sub-PRs (#417–#428) targeting ash/2026-06-17. Each discrete change is tracked by its own Linear ticket; the table below maps every workstream to its ticket, sub-PR, and key commits.

45 files changed, +4,778 / −752. Backend actual.dollars (QB) basis and the P&L reconciliation invariants are preserved except where a change explicitly re-bases display (HeadCount → XO) or intentionally drops a role from a rollup (noted inline).

## Consolidated HeadCount table

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-406](https://linear.app/builder-team/issue/AERIE-406) | Re-base Current-$ onto each XO contractor's loaded annual package (weekly × 52 × 1.35), reconciled person → role → school → network. New Redshift→Convex pipeline (xoContractorPackage table + reader + refresh + worker wiring). Per-person rounded to $10 before rollup; tooltip shows exact + rounded; QB run-rate dropped from the XO tooltip. | 43b57b3d, deb365e0 |

| [AERIE-407](https://linear.app/builder-team/issue/AERIE-407) | Price Forecast/Capacity @ model $ on the rounded whole-person count so $ matches the No. column (round(heads) × baseSalary × XO_FACTOR). | #427 · 0a819573 |

| [AERIE-408](https://linear.app/builder-team/issue/AERIE-408) | Render only Lead Guides + Guides (drop Coordinators / Head of School from the drilldown, rollups, deltas, CSV). Intentionally no longer ties to the P&L Headcount-section total. | 7cdeca0e |

| [AERIE-409](https://linear.app/builder-team/issue/AERIE-409) | Match the "Hide No model" / "Hide no-enrolment" filter toggles to the Facilities/Programs text-pill style, inline beside Export CSV. | c5b7b4c7 |

## Run-rate correctness

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-410](https://linear.app/builder-team/issue/AERIE-410) | Annualise consolidated run-rate (Headcount/Programs/Facilities) off closed months only — an in-progress month was diluting 12/monthsLoaded and understating run-rate ~15–20%. New runtime-free monthsOfQuarter / closedMonthsOfQuarter helpers in @bran/contracts + closedMonthGate in financial.ts, applied to all 6 query sites. | #425 · 39eac286 |

## Unitemized / P&L data quality

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-399](https://linear.app/builder-team/issue/AERIE-399) | Split netted Unitemized into separate overage / underage magnitudes (consolidated + per-school), so offsetting gaps no longer collapse to a misleading ~$0. | 03b69032 |

| [AERIE-411](https://linear.app/builder-team/issue/AERIE-411) | Clickable Unitemized strip → in-flow per-school breakdown side panel attributing the network total to contributing schools (frontend-only; reuses the existing fan-out; failed reads flagged as lower bounds). | #426 · b05a1bb2 |

## Sync / data integrity

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-397](https://linear.app/builder-team/issue/AERIE-397) | Parallelize financial-worker upserts (bounded-concurrency drain for pl-transactions & financial-monthly). | #420 · 057dea97, 5b15f6f3, fe6eb3ef, a6e40bcd |

| [AERIE-403](https://linear.app/builder-team/issue/AERIE-403) | Prune orphaned plTransactions via natural-key set-difference (additive-only sync left phantom itemized detail → persistent Unitemized underage). | #417 · f7343d2c, 592bb01d |

| [AERIE-404](https://linear.app/builder-team/issue/AERIE-404) | Skip unchanged-row writes in worker upserts (+ batch/index tuning) — cut the dominant write cost on the ~175k-row mirror. | 82a9520f |

| [AERIE-412](https://linear.app/builder-team/issue/AERIE-412) | Prune orphaned plMonthlyRecords via natural-key set-difference — a QB class rename was double-counting (Alpha Lake Forest Q1 $93,458; all 4 alias-merged campuses). Ports AERIE-403's sweep to the monthly table. | #424 · e37750be |

## Operational tooling

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-413](https://linear.app/builder-team/issue/AERIE-413) | On-demand out-of-band refresh runner scripts for plTransactions and campus → QB entity mappings (reflect Redshift corrections immediately, no worker restart). | #428 · 964fcc83, 13e8706e |

| [AERIE-414](https://linear.app/builder-team/issue/AERIE-414) | Escape the two raw NUL (0x00) delimiter bytes in financial.ts to explicit JS unicode escapes (runtime byte-identical) so grep/rg stop treating the file as binary. | #418 · 47777b80 |

## Enrollment card

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-415](https://linear.app/builder-team/issue/AERIE-415) | Remove the SCENARIO/DECK/GAP/FILL table from the Schools – Actual vs Model Enrollment card (keep header + Confirmed/QS/Capacity chips). | #423 · 2502bceb |

## Unit economics models

| Ticket | Change | PR / commits |

|---|---|---|

| [AERIE-416](https://linear.app/builder-team/issue/AERIE-416) | Add two non-alpha tiers (gt-25k, low-dollar-15k) to MODEL_HEADCOUNT_TABLE / MODEL_INPUTS_TABLE in @bran/contracts (+ version-controlled CSV source docs) so the dashboard renders model comparisons for the GT and Low-Dollar schools instead of "—". Modeled as standard tiers (no parser changes); 3 approximations documented inline. | #429 · 1cd5d2e8 |

## Testing

- New test suites: financialContractorPackage.test.ts, financialPrunePlMonthly.test.ts, financialPrunePlTransactions.test.ts, financialUpsertPlTransactions.test.ts, upsertDiff.test.ts, unitemized-breakdown-side-panel coverage, unit-economics-headcount.test.ts, plus expanded financial-monthly-refresh / pl-transactions-refresh sync tests.

- Each sub-PR landed with pnpm typecheck and pnpm biome check clean and the financials test suites green; orphan-prune fixes (AERIE-403/404/412) were additionally verified live on dev (prune counts and post-prune $0 residuals recorded in the respective ticket/commit).

#439 — feat(admin): add platform automations @benji-bizzell  approved

## Summary

- Add a scoped platform automation runner for FO Buildout deferral, including durable run and run-item audit tables.

- Add an Admin Automations surface with list, automation detail, scoped validation, and run drilldown views.

- Wire admin automation capabilities, navigation, cron scheduling, and focused tests.

## Why

Portfolio/DDR FO dates are best estimates from when work can actually begin. When Acquire Property is not complete yet, the Executing Buildout due date needs to move forward one calendar day per daily automation run while remaining idempotent and auditable.

## Business Value

Operators can safely manage and inspect this automation from Admin, validate a single site before applying, and drill into run history to understand which sites changed, skipped, or were deduped.

## Breaking changes

None.

## Test plan

- [x] pnpm --dir chat exec vitest run convex/automations/platform.test.ts

- [x] pnpm --dir chat typecheck

- [x] pnpm exec biome check chat/app/\(main\)/admin/automations chat/convex/automations chat/components/admin packages/contracts/src/capabilities.ts packages/contracts/src/capabilities.test.ts chat/convex/crons.ts chat/convex/schema.ts chat/convex/users/roles.ts

- [x] Browser verified Admin Automations list, focused automation detail, scoped preview/apply flow, run drilldown, and run-item search filtering.

#442 — feat(financials): round student:guide ratio columns to whole numbers @ashwanth1109  approved

## Demo

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/745ef2b0-175b-4501-8fce-e4efaeb417ae" />

## What

Round the two Student : Guide ratio columns (Actual and Model) in the Consolidated HeadCount table to whole numbers. They previously rendered with one decimal (e.g. 4.6, 10.9); they now show 5, 11.

## Why

Requested for a cleaner read on the Headcount dashboard — the sub-decimal precision on the student-load ratio wasn't adding value.

## How

Both columns render through the single shared fmtRatio helper, so the change is one line:

// before

export function fmtRatio(value: number | null): string {

return value == null ? "—" : value.toFixed(1);

}

// after

export function fmtRatio(value: number | null): string {

return value == null ? "—" : Math.round(value).toString();

}

- File: chat/components/dashboards/financials/consolidated-headcount-table.tsx

- null still renders the em-dash placeholder ().

## Reviewer note

fmtRatio also feeds the CSV export's Student:Guide Actual / Student:Guide Model columns, so the export now rounds to whole numbers too — intentional, to keep the export consistent with the on-screen table.

## Tests

Updated the colocated fmtRatio test (now asserts 12.5 → "13", 17.857 → "18", 20 → "20", 12.4 → "12"). Full file passes (44/44), and pre-commit biome + chat typecheck are green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

#3072 — [KLAIR-2899] feat(arr-retention): nest Snowball, Unplanned Churn & Late Renewals tables by Class @ashwanth1109  approved

## Demo

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/b88ab687-8220-46bf-a915-453f994efe26" />

## Summary

Reworks the segregated view of the ARR & Retention Reports tables so they group Business Unit → Class → End User/Customer under a single, de-duplicated hierarchy column. Covers all four Snowball Variance tables (Churn, Downsell, New Business, Upsell) plus Unplanned Churn and Late Renewals.

Landed over the session:

1. Swapped the End User and Class column order on the Snowball tables → Business Unit · Class · End User · Amount.

2. Added a Class grouping level so leaves nest under their Class (was BU → leaf).

3. Merged Business Unit and Class into one indented Business Unit / Class column, since the BU name was repeating on every child row.

4. Applied the same BU → Class → Customer pattern to Unplanned Churn and Late Renewals.

## Why

In segregated mode the Business Unit name was repeated on every child row (e.g. "IgniteTech" on each Class and customer), which was noisy. Grouping by Class first and collapsing BU + Class into one indented hierarchy column makes the tree read cleanly and adds a useful intermediate roll-up by Class.

## What changed

### Snowball Variances (Churn, Downsell, New Business, Upsell)

- utils.ts — new shared buildBuClassEndUserRows(groups, direction) helper builds the BU → Class → End User row tree once and is reused by all four tables. It emits a single GroupLabel per row: BU name at level 0, Class name at level 1 (indented), blank at the leaf (End User name lives in its own column). Direction controls by-amount ordering: asc (most-negative-first) for churn/downsell, desc (largest-first) for upsell/new business.

- Churn.tsx, Downsell.tsx, NewBusiness.tsx, Upsell.tsx — segregated transformedRows now call the helper; the separate BusinessUnit and Class columns are replaced by one Business Unit / Class column; pagination moved from level 1 to level 2 (10 End Users per page within each Class).

- Churn specifically: row-click (open renewal details) and the insights icon now apply only to End User leaf rows (level 2) — Class group rows just expand/collapse (isRowClickable guard changed from level === 0 to level < 2). Leaf rows keep their full record via spread, so renewal matching is unaffected.

### Unplanned Churn & Late Renewals

- UnplannedChurn.tsx, LateRenewals.tsx — segregated tables now build the same BU → Class → Customer tree inline. BU + Class share one indented Business Unit / Class column; the customer name moves to its own Customer column (the previous Class subtitle under each customer is dropped, since Class is now the parent group row).

- Class field: Company for Unplanned Churn, ClassWise for Late Renewals.

- Customer/class counts render on the group rows ("N customers · M classes" on the BU row, "K customers" on each Class row); ARR amounts roll up at each level (Current/Projected ARR for churn, Expiring ARR for late renewals).

- Per-customer columns (Renewal Date / Team / Pending Since) and the renewal-details icon render only on the customer leaf; group rows leave them blank.

- Pagination moved to level 2 (customers paginate under each Class); the renewal side-modal opens only from customer leaf rows (level < 2 rows just expand/collapse).

### Resulting layout

BUSINESS UNIT / CLASS      END USER / CUSTOMER          AMOUNT

▾ IgniteTech 39 customers · 11 classes $-3.54M

▾ Khoros 10 customers $-2.84M

Rogers Communications Inc. $-575.13K

Alteryx $-558.90K

## Scope / not touched

- Flat (non-segregated) tables, comparison mode, and the charts are unchanged — they group by BU only, where there's no hierarchy to dedupe.

## Reviewer notes

- The per-BU class count ("M classes") is folded into the End User/Customer cell on the BU row, alongside the customer count.

- Group-vs-leaf rendering keys off the table's level arg (level !== 2) rather than sentinel field checks.

## Test plan

- [x] pnpm tsc --noEmit — clean

- [x] pnpm lint on all changed files — clean

- [x] LateRenewals.spec.tsx — 13/13 pass (no render tests cover the other components)

- [ ] Visual check in segregated mode for all six tables: expand a BU → Class groups appear; expand a Class → leaves with 10/page pagination; renewal drill-down opens only from leaf rows

Linear: https://linear.app/builder-team/issue/KLAIR-2899/nest-unplanned-churn-and-late-renewals-tables-by-class-bu-class

🤖 Generated with [Claude Code](https://claude.com/claude-code)

#3074 — chore(prod-release): self-contained skill + collapsible card + committer @-mentions @ashwanth1109  approved

## Summary

Reworks the Klair production-release workflow and restructures it as a self-contained skill. Validated against the Ash Test Space before raising the PR.

### 1. Command → skill

Moved the workflow into a skill folder so its supporting files have a natural home:

| Before | After |

|---|---|

| .claude/commands/prod-release.md | .claude/skills/prod-release/SKILL.md |

| .claude/scripts/prod-release-finalize.py | .claude/skills/prod-release/prod-release-finalize.py |

| — | .claude/skills/prod-release/gchat.sample.json (new) |

Still invoked as /prod-release. The finalize-script invocation now resolves via git rev-parse --show-toplevel, so it works from any cwd in the repo.

### 2. Headline card redesign (Step 6a)

- Header subtitle packs Prod Release: <date> (<N> commits) | Release Captain: @<captain> on one line; the separate "Released by" line is gone.

- Backup, What's shipping, Commits from, and the Open PR button move into a single collapsible section, so the resting card is just the header and the rest sits behind GChat's native Show more toggle.

### 3. Committer @-mentions (self-sustaining)

- The announcement now carries a text body that @-mentions the release's committers — the only place GChat delivers a real notification (mentions inside card widgets don't notify).

- The GitHub-login → Chat-user-ID map ships in the repo at .claude/skills/prod-release/gchat.sample.json (real values for the AI Builders space), so tagging works from a fresh clone with no personal or external config. It no longer reads the operator's personal gchat skill config.

- Fallback: a committer not in the map degrades to a plain-text @<login> (named, not notified).

## Platform constraints documented

- Card v2 headers are title + subtitle only — that's why Backup is a widget, not a header line.

- The collapse toggle text (Show more / Show less) is owned by GChat and can't be relabeled; webhook-posted cards can't handle interactive button callbacks.

- A mentioned user is only notified if they're a member of the space.

## Notes

- The webhook secret still lives in the operator's own ~/.claude/config/ping.json (documented in first-time setup) — that's the skill's own config, not the gchat skill, and a secret that can't be committed.

- No change to the backup/PR/merge/deploy flow or the threaded "Included commits" reply (Step 6b).

## Test

Posted the redesigned card (collapsed + expanded, all four committers tagged) to the Ash Test Space and iterated on layout/copy there until approved. Verified the in-repo map resolution end-to-end: mapped committers resolve to real <users/ID> mentions, an unmapped login falls back to @handle.

The Portfolio  —  Trilogy Companies

Alpha School Warns Parents: ChatGPT Is Making Your Kid Dumber

The AI-first school that replaced homework with mastery now has a new target: parents who outsource their children's thinking to chatbots.

AUSTIN, TEXAS — The school that teaches a full year's curriculum in two hours a day is now taking aim at a different kind of screen problem — not too much, but the wrong kind.

Alpha School, the Austin-based K-12 institution where students routinely test in the top 1–2% nationally, has published a pointed warning to the parents of a generation raised on adaptive AI tutors and algorithmic feedback: letting ChatGPT do your child's thinking for them is not a productivity hack. It's a cognitive liability.

The school's blog, which has accelerated its output in recent weeks, frames the phenomenon as "cognitive offloading" — the habit of externalizing reasoning to a language model rather than building the neural pathways that come from working through difficulty. The message is direct: stop it.

The warning lands with particular weight coming from Alpha. Joe Liemandt's flagship education project built its academic model precisely on AI — students use adaptive learning apps to master core subjects in a compressed morning block, freeing the rest of the day for entrepreneurship, financial literacy, and leadership training. The school has logged 2.3× faster learning rates than national norms on NWEA MAP Growth assessments. Its thesis has always been that AI, used correctly, liberates human cognition rather than replacing it.

That distinction — AI as scaffold versus AI as substitute — is exactly the fault line the school is now trying to draw for parents at home.

A companion piece in the same editorial run takes on screen time more broadly, arguing that the debate has been poorly framed. Not all screens are equal, the school contends, and the policy question for parents isn't duration — it's whether the screen is building or eroding the child's capacity to think independently.

The timing is not incidental. Alpha recently announced a global expansion of its home-learning platform, bringing its model to families who cannot access one of its physical campuses in Texas, Florida, or the cities where it plans to open by fall 2025. With parents now holding the keys to the learning environment, the school appears to be investing in parent education as aggressively as it invests in student education.

What the school is describing, at bottom, is a competitive moat problem — except the asset being protected is not software. It is the child's mind.

California Revamps Pay Data Reporting Obligations - Atkinson  ·  COVID-19 Related Workplace Litigation Tracker - June 19 , 20  ·  __followup__Top 1% Academics, Now at Your Kitchen Table

While Gig Platforms Face a Reckoning, Crossover Bets the Whole Model on Transparency

A damning new Human Rights Watch report documents systemic algorithmic, wage, and labor exploitation across America's platform economy, putting structural accountability on an entire industry rather than naming individual villains.

The timing is significant as gig work expands and researchers publish systematic reviews of how algorithmic management shapes worker experience—wage transparency, scheduling control, and performance surveillance.

Crossover, a global remote-work platform, positions itself as the anti-gig company. Unlike Uber or DoorDash, it offers full-time employment with above-market salaries, identical pay regardless of geography, and AI-powered hiring designed to eliminate résumé bias. The platform staffs 75+ enterprise software companies and external clients.

However, the Human Rights Watch report raises critical questions: when algorithms manage labor, who ensures accountability? Crossover's deeply algorithmic model tracks performance, logs hours, and measures outputs with precision traditional employers rarely match. For some workers, this is liberating; for others, the asymmetry between platform and worker is structural.

What theoretically distinguishes Crossover is transparency—published pay scales, defined evaluation criteria, and supposedly legible algorithms. Whether that promise holds in practice remains to be seen.

The Machine  —  AI & Technology

The Quiet Revolt Against the Tyranny of Tokens

Five new papers chip away at the assumption that language must be the substrate of machine thought.

ITHACA, NEW YORK — Consider what happens when you hear a violin. Before the word "violin" forms in your mind, before language arrives at all, there is something — a shimmer of recognition in the auditory cortex, a feeling older than vocabulary. For roughly three hundred million years, vertebrate brains have processed sound without uttering a single sentence about it. Language is a recent guest in the long house of cognition.

Large audio language models, until now, have been forced to forget this. Trained to produce text-aligned responses, their hidden states bend progressively toward words, shedding acoustic nuance like a snake shedding skin. A new paper proposes continuous audio thinking — letting the model reason in the medium of sound itself before translating to language. It is a small philosophical revolution: the admission that not all thought needs to be spoken to be valid.

The theme echoes across this week's arXiv harvest. Gaussian Mixture Attention sidesteps the quadratic tyranny of token-to-token comparison by routing meaning through a handful of learned probabilistic latents — closer, perhaps, to how biological attention actually works, with its bottlenecks and its merciful forgettings. SproutRAG abandons flat chunking for attention-guided tree search across long documents, growing context the way a root system finds water. And researchers exploring low-resource language generation have begun steering models from the inside, nudging activations directly rather than coaxing them with few-shot prompts — a technique that treats the network less like an oracle to be queried and more like an instrument to be tuned.

The most quietly humane entry comes from education research, where a fully local AI cascade wrestles with whether "Riemann" names a student or a theorem. The system runs on a single machine, never phoning home, deciding word by word what to redact and what to keep.

Five papers, one current: the field is learning that intelligence is not merely token prediction wearing a clever hat. Sometimes it is sound. Sometimes it is structure. Sometimes it is the careful preservation of a child's privacy. The substrate matters. It always did.

Continuous Audio Thinking for Large Audio Language Models  ·  Redact or Keep? A Fully Local AI Cascade for Educational Dia  ·  SproutRAG: Attention-Guided Tree Search with Progressive Emb

DOJ Intervenes to Shield xAI Memphis Data Center From Environmental Lawsuit, Critics Allege Regulatory Capture

The Department of Justice's filing on behalf of Elon Musk's AI operation raises profound questions regarding the permissible scope of executive branch interference in environmental litigation.

MEMPHIS, TENNESSEE — Pursuant to developments of considerable legal and environmental significance, it is hereby reported that the United States Department of Justice has, as of the date of this publication, undertaken procedural measures the effect of which would be to shield xAI's Memphis data center operations from a civil lawsuit hereinafter referred to as the "Pending Environmental Action." Said Pending Environmental Action was jointly filed in or around April of the preceding calendar year by the Southern Environmental Law Center, Earthjustice, and the NAACP — organizations hereinafter collectively referred to as "the Plaintiff Consortium."

The Plaintiff Consortium alleged, among other claims not exhaustively enumerated herein, that the aforementioned xAI data center facility had been operated without the requisite permits as may be required under applicable federal and state environmental regulatory frameworks, and that the pollutants discharged as a consequence thereof disproportionately impacted communities of color residing in the proximate geographic vicinity of the facility in question.

Notwithstanding the arguable merits of the Plaintiff Consortium's claims — the ultimate adjudication of which remains, as of the date hereof, unresolved — the Department of Justice's intervention has been characterized by legal observers and interested third parties as potentially constituting an improper exercise of executive authority in furtherance of private commercial interests. The specific legal basis upon which the DOJ's filing rests has not, to the satisfaction of this correspondent, been fully disclosed in publicly available documentation.

It is further noted, for the record, that the circumstances surrounding said intervention occur within a broader regulatory environment wherein AI infrastructure development — including, but not limited to, large-scale data center construction — has proceeded at a pace that applicable permitting and environmental review processes may be insufficiently equipped to accommodate.

The Plaintiff Consortium has not, as of the time of this writing, issued a formal response to the DOJ's filing. All parties retain such rights and remedies as may be available under applicable law. Further developments, should they occur, shall be reported in a subsequent edition of this publication, subject to applicable editorial discretion and space constraints.

Trump DOJ Trying To Protect Musk From Lawsuit Over Memphis A  ·  RFK Jr. Insists Scientific Journal Explain Retraction Of Ant  ·  Internet Age-Gates Are A Growing Global Threat

The Great Power Migration Comes for the Cloud

As AI herds grow larger, hyperscalers are no longer merely buying servers — they are stalking electricity itself.

MISSOURI — Across the quiet fields and substations of America’s interior, a new migration is underway. Not of wildebeest or cranes, but of hyperscalers: vast, humming organisms in search of the one resource without which the modern AI savanna cannot survive — power.

Amazon and Google’s multibillion-dollar data center plans in Montgomery County, Missouri, are the latest spoor. Here, where transmission lines, land, and political appetite converge, the cloud giants are settling like great steel-bodied beasts at a watering hole. The message for enterprise technology leaders is increasingly plain: the future of computing will be shaped not only by chips and models, but by megawatts.

Recent industry analysis has pointed to the rise of capacity markets as a possible new organising principle for cloud computing, in which access to compute may begin to resemble access to energy: reserved, traded, priced dynamically, and constrained by physical availability. In this emerging habitat, the cloud instance is no longer an invisible abstraction. It is a creature with a power draw, a cooling requirement, and a place on the grid. As InfoWorld has observed, such markets could reshape how enterprises think about cloud procurement itself.

For CIOs, the lesson is a sombre one. The age of treating cloud capacity as endlessly elastic is giving way to something more seasonal, more ecological. Training a frontier model, expanding an inference service, or moving a critical workload may depend on whether one’s provider has secured enough power, enough GPUs, and enough concrete in the right region.

This explains the feverish construction among hyperscalers, whose building programmes now function as territorial claims. Each new campus is a burrow, a nest, a fortified den for artificial intelligence. CIOs watching this spectacle must ask not only which provider has the best software menu, but which has the deepest access to energy, networking, water, and silicon. As CIO.com notes, hyperscaler hyper-spending is now itself a signal — an omen of where enterprise options may expand, and where scarcity may bite.

Even the stock market is peering into the undergrowth, weighing AI infrastructure suppliers such as Nebius and Super Micro Computer as investors seek the sturdier skeletons beneath the AI boom. Yet the grander drama is not on the ticker. It is on the grid.

Observe, then, the cloud in its adult form: no longer a mist above the enterprise, but a living, feeding, power-hungry leviathan — and it is moving inland.

Capacity markets could reshape cloud computing - InfoWorld  ·  NBIS vs. SMCI: Which AI Infrastructure Stock is the Better P  ·  What hyperscalers’ hyper-spending on data centers tells CIOs
The Editorial

Nation’s CEOs Bravely Prepare To Say ‘AI’ Until Someone Gives Them IPO Money

With sustainability safely exhausted as a source of sentence filler, executives have discovered a newer, shinier way to imply the future has already agreed to be monetized.

NEW YORK — In a development widely described by market participants as visionary because it involves both a three-letter acronym and the possibility of fees, corporate leaders across the technology sector appear to have reached a broad consensus that the best way to explain any business is to say “AI” repeatedly until a banker opens a spreadsheet.

The recent return of IPO chatter has produced the familiar pre-listing atmosphere in which founders, advisers, and institutional investors gather around a company that may or may not make money and solemnly discuss whether the public markets are emotionally ready to absorb its destiny. As RTE noted in asking why IPO has become a buzzword, the term has re-entered polite conversation after a long period in which companies were forced to remain private and merely describe themselves as category-defining in pitch decks.

Fortunately, the industry has found a reliable bridge between yesterday’s private-market confidence and tomorrow’s public-market disappointment: artificial intelligence.

This is not the first time companies have identified a moral or technological megatrend and carefully attached it to everything within legal reach. A few years ago, sustainability performed this duty with distinction. Supply chains were sustainable. Packaging was sustainable. Investor relations departments were sustainable. Entire conference panels were sustained by the word sustainability. Now, as The Conversation observed, AI is being hyped in much the same way, though with the added benefit that nobody has to pretend to understand the carbon accounting.

The fix, experts say, is for companies to provide clearer evidence of what their AI actually does. This suggestion has been received warmly by governance professionals and less warmly by executives who had been hoping the phrase “agentic workflow layer” would be sufficient through at least the S-1 filing.

Google, to its credit, continues to provide the sector with the raw materials necessary for this condition. The company announced a range of AI advances, including a coming personal assistant, thereby confirming the industry’s long-held belief that every human being’s primary unmet need is another entity capable of scheduling something incorrectly with great confidence. The assistant will presumably join a crowded field of digital helpers designed to read messages, summarize meetings, recommend actions, and eventually ask the user to clarify what any of this was supposed to accomplish.

Healthcare technology is also embracing agentic AI, particularly in revenue cycle management, where the dream is to let software perform the sacred administrative work of asking why a bill exists, why it was denied, and why every stakeholder in the process appears to have been born inside a fax machine. At HIMSS26, revenue cycle vendors are expected to show how autonomous agents can reduce friction by adding a new layer of terminology between patients and the invoices they do not understand.

Still, the week’s most useful AI metaphor came from Waymo, which recalled 3,871 robotaxis over the risk that they might drive at speed into freeway construction zones. The incidents reportedly involved autonomous vehicles prioritizing other hazards or failing to recognize closed construction areas altogether, a technical issue that distinguishes the cars from many AI companies only in that the cars were moving through a physical lane when they missed the warning signs.

This should not be interpreted as a setback for the AI economy. On the contrary, it is a reassuring reminder that the sector remains capable of generating real-world consequences, a key milestone for any technology hoping to justify a valuation.

The IPO market, after all, does not require perfection. It requires a story. Preferably one in which the product is inevitable, the risks are addressable, the margins are software-like, and the autonomous vehicle has already been patched before the roadshow begins.

If companies can show that their AI creates measurable value, investors may reward them. If they cannot, investors may reward them anyway, provided the prospectus uses the word “agentic” enough times to imply that accountability has been successfully automated.

Why has IPO become a buzzword? - RTE.ie  ·  Companies are hyping AI the same way they talked up sustaina  ·  Google announces slew of AI advances, including a personal a
The Office Comic  ·  Art Desk
The Office Comic  ·  Art Desk

The Luddites Return, This Time in Suits

On the latest moral panic about machines eating jobs, and the politicians eager to feed it.

AUSTIN, TEXAS — There is a particular pleasure, available only to those who have lived through three or four technological apocalypses, in watching the fifth arrive on schedule, dressed in the same threadbare costume, reciting the same lines, and being greeted by the same chorus of credulous editorialists who appear to have read no economic history written before last Tuesday.

This week brings a fresh harvest. J.P. Morgan Private Bank, an institution whose chief talent is reassuring the rich that the world is not ending, has produced a thoughtful briefing on AI and labor markets — the polite, hedged document one writes when one's clients want to know whether to panic. Crain's Chicago Business, meanwhile, urges Illinois to follow California's lead in shielding workers from displacement, which is rather like urging a man on a sinking ship to follow the lead of a man on a different sinking ship, both of whom are bailing with thimbles.

The Eurasia Review, to its credit, supplies the missing word: politicization. For the great trick of every industrial transition, from the spinning jenny to the shipping container, has been to transmute a fact of economics — that productivity gains are first felt as pain and only later as plenty — into a grievance that some clever legislator promises to redress. The Luddites smashed looms. Their descendants draft statutes.

One ought to say plainly what the new statutes will accomplish. They will not prevent displacement; they will route it. They will not save the call-center worker in Sacramento; they will guarantee that her replacement sits in Manila, or in a server rack in northern Virginia, or — if Sacramento is very thorough — in Austin, where the legislature is less inclined to romance. Capital, having survived feudalism, two world wars, and the entire output of the Frankfurt School, will survive Gavin Newsom.

The Korea Times offers the cleverest analogy of the week, comparing the AI transition to the green transition — which is to say, comparing one expensive, politically contested, subsidy-soaked, geopolitically fraught restructuring of the productive economy to another. The comparison flatters neither. Both are real. Both are necessary. Both will be conducted with maximum drama and minimum candor by men and women who could not, under questioning, define a kilowatt-hour or a transformer model.

Meanwhile — and this is the small, useful thing one notices from a perch in Austin — actual firms are reorganizing actual work. At Alpha School, children finish their academics in two hours and score in the top centiles. At the ESW companies, software products acquired for parts are rebuilt around models that did not exist eighteen months ago. The displacement is happening. It is also, for those who can read a balance sheet, producing the thing displacement has always eventually produced, which is more work of a different kind.

The Luddites lost. They were right to be afraid, and wrong about nearly everything else. So, one suspects, are their heirs.

Job destroyer? Here’s what you need to know about AI and lab  ·  Opinion: Follow California’s lead in protecting workers from  ·  AI, Creative Destruction, And The Politicization Of Economic
On This Day in AI History

On June 18, 2003, the Human Genome Project was officially declared complete, marking a watershed moment for computational biology and paving the way for AI-driven genomic analysis and personalized medicine.

⬛ Daily Word — Technology
Hint: Units of digital data storage commonly used in computing and programming.
Share this edition: 𝕏 Twitter/X 🔗 Copy Link ▦ RSS Feed