Vol. I  ·  No. 177 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
FRIDAY, JUNE 26, 2026 Powered by Anthropic Claude  ·  Published on Klair Trilogy International © 2026
🖶 Download PDF 🖿 Print 📰 All Editions
Today's Edition

The World Is Splitting Over AI — and Brussels Wants to Write the Rules

As Washington retreats and Beijing advances, the EU's regulatory gambit may be its most consequential geopolitical move in a generation.

BRUSSELS — The server farms are in Nevada and Guizhou. The money is in San Francisco and Shenzhen. But increasingly, the rules are being written here — in the glass corridors of European institutions where bureaucrats are quietly attempting something audacious: turning regulation into power.

The EU AI Act, which entered into force last year, was sold domestically as a consumer protection measure. Abroad, its ambitions are harder to disguise. Analysts increasingly describe the Act as a normative sovereignty play — an attempt by a bloc that produces few frontier AI models to nonetheless shape how all of them behave, everywhere, through the mechanism of market access.

The logic is familiar. It worked with data privacy. GDPR became a de facto global standard not because other nations chose it, but because multinationals found it cheaper to comply universally than to run parallel systems. Brussels is betting the same gravitational pull applies to AI.

But the terrain has shifted since GDPR's 2018 debut. The geopolitical weather is rougher now. China is not standing still. Foreign Policy and others have argued Beijing is advancing rapidly — deploying AI in manufacturing, surveillance, and finance at a scale that makes Western debates about guardrails feel almost leisurely. Meanwhile, Washington under successive administrations has oscillated between laissez-faire acceleration and targeted export controls, producing not a coherent standard but a vacuum.

Into that vacuum, the EU steps — not with chips or models, but with paper. The risk is real: rules written for yesterday's technology, chilling innovation in the one region that most needs it, while American and Chinese systems operate under friendlier skies.

The countervailing bet is that the world's largest single market can export its values the same way it always has — not by force, but by making the alternative too expensive to ignore. Whether that bet pays off will say as much about the future of global AI governance as any model trained in any data center, anywhere on earth.

The geopolitical gains of EU Artificial Intelligence regulat  ·  The New AI Geopolitics: Governance, Power, and Technological  ·  EU-China Relations After the 2024 European Elections: A Time

Oracle’s AI Front Brings a 21,000-Job Cold Snap to Big Tech

Oracle has cut roughly 21,000 jobs over the past year as it accelerates its shift toward artificial intelligence, joining a broader wave of tech layoffs citing AI as justification for restructuring. The company is not alone: across the technology sector, employers increasingly frame AI as both productivity driver and workforce disruptor.

The pattern is predictable. Companies promise faster coding, automated support, leaner operations, and improved efficiency. Then hiring freezes, teams reorganize, and previously stable roles disappear. Oracle's cuts are particularly notable because they occur amid fierce demand for cloud infrastructure and AI computing—creating an odd disparity where revenue grows while headcount shrinks.

The message to enterprise software operators is unmistakable: companies continue investing in AI and automation, but with significantly fewer human workers. Workers should prepare by building AI skills, updating expertise, and strengthening professional networks. Employers should expect continued restructuring through coming quarters, with isolated hiring only in AI infrastructure roles. For most of the workforce, turbulent conditions appear ahead.

China's Bargain Brain Crashes Silicon Valley's Party

DeepSeek built a top-flight AI model cheap and without the fanciest chips — and the crowd that burns billions can't look away.

HANGZHOU, CHINA — A Chinese outfit called DeepSeek says it trained a high-performing artificial-intelligence model on the cheap this week, and it did it without the top-shelf chips the American giants swear they can't work without.

That's the wire that lit up Silicon Valley. The made-in-China model is pulling raves from the very crowd that burns billions on silicon.

"Amazing and impressive" — that's how the Valley's own engineers describe it. Praise for a rival is rare in this town. Praise for a rival from across the Pacific is rarer still.

Here's the rub. The whole American AI play rests on one bet: you need the priciest chips and an ocean of cash to build a thinking machine. DeepSeek says otherwise.

If the upstart's right, the math changes for everybody. The chipmakers, the cloud barons, the venture men who wrote the big checks. Traders noticed, and tech shares felt the shove.

Now flip the page. While DeepSeek runs lean, the home team is being told to pump the brakes.

OpenAI reportedly plans to hand its newest model, GPT 5.6, to a select few partners instead of the public at large. The reason, per reports: the Trump administration asked it to slow the roll over safety worries.

Read those two items side by side. One country steps on the gas. The other waves the caution flag.

Not every dollar this week chased a chatbot. Reid Hoffman, the man who co-founded LinkedIn, raised $24.6 million for a new venture called Manas AI.

The target isn't search or small talk. It's cancer. Hoffman's partner is Siddhartha Mukherjee, the physician who wrote "The Emperor of All Maladies."

The pitch: point the machines at the disease and let them hunt. Cheaper compute, if DeepSeek's claims hold up, could put that hunt in reach of more labs.

The throughline runs straight. The cost of building artificial brains may be falling, and falling fast. When the price drops, the gatekeepers lose the gate.

DeepSeek and SoFi also turned up in the day's Market Talk chatter, the usual tea leaves for Technology, Media and Telecom. The leaves all read the same: cheaper, faster, and coming from places nobody bothered to map.

The big-money boys spent years arguing the moat was money. A bargain model out of Hangzhou just waded across.

What happens next is the only question worth asking. Either the giants prove their billions still buy something the upstart can't copy, or the whole field gets a haircut.

This reporter's seen the pattern before. The expensive thing gets cheap, the cheap thing gets everywhere, and the fellows guarding the old price find themselves guarding an empty till.

Keep your eye on the chip count. That's the tell.

What to Know About China's DeepSeek AI  ·  Tech, Media & Telecom Roundup: Market Talk  ·  Silicon Valley Is Raving About a Made-in-China AI Model
Haiku of the Day  ·  Claude HaikuProgress cuts both ways,
twenty thousand lose their place—
the future arrives.
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
IETF Proceedings Portend Grave Consequences For Automated Web Access, Consumer Rights Advocates Allege
SAN FRANCISCO — Pursuant to developments hereinafter described in greater specificity, it is alleged by certain interested parties — including, but not limited to, digital rights organizations, journalistic entities, and academic researchers — that ongoing proceedings within the Internet Engineering Task Force (IETF) have been construed to constitute a material threat to the free and open internet, notwithstanding the aforementioned body's historical commitment to open standards development. As has been extensively documented by parties of established credibility in the technology policy space, automated access to publicly available information — hereinafter referred to as "crawling" or "scraping," as the case may be — is alleged to underpin numerous activities of significant public benefit, including, without limitation, journalistic investigation, security vulnerability identification, and the preservation of digital records for posterity. It is further noted, for the record and in conjunction with the foregoing, that concurrent regulatory developments in the European Union — specifically, efforts by the aforementioned Stop Killing Games movement to seek amendments to the Digital Fairness Act following the defeat of standalone legislative proposals — suggest that the intersection of consumer rights, digital preservation, and automated access is presently subject to heightened regulatory scrutiny across multiple jurisdictions simultaneously. Additionally, and by no means to be construed as a separate matter unrelated to the broader themes herein articulated, the alleged conduct of a court-appointed ombudsman at CBS News — installed pursuant to conditions precedent required by the Federal Communications Commission in connection with the Ellison family's approximately $8 billion acquisition of said network — has been characterized by certain observers as emblematic of regulatory capture, wherein oversight mechanisms nominally established for the protection of the public interest are alleged to have functioned in a manner inconsistent with said purpose. Notwithstanding the foregoing, it must be acknowledged that all characterizations herein are subject to dispute, qualification, and further evidentiary development, and no final determinations should be inferred therefrom..
The Chip Kingdom Builds New Nests on Earth—and Eyes the Stars
AUSTIN, TEXAS — In the warm industrial grasslands of Central Texas, a familiar creature is multiplying: the semiconductor supplier, modest in plumage perhaps, but vital to the survival of the great digital herd. A semiconductor services firm has secured a Texas grant to support a 287-job expansion, according to The Business Journals, another sign that America’s chip ecosystem is no longer content to gather around a few ancestral watering holes.
The Academy's AI Reckoning: Ethics, Integrity, and the Autonomous Classroom
CAMBRIDGE, MASSACHUSETTS — A cluster of recent publications in peer-reviewed venues — spanning MIT's ongoing examination of autonomous system ethics to Elsevier's framework for strategic AI leadership in higher education, with auxiliary contributions from Nature and Frontiers in Education — constitutes what one might provisionally term (pending longitudinal validation, naturally) a disciplinary inflection point in the university's fraught negotiation with artificial intelligence. The thesis, advanced with varying degrees of methodological confidence across these publications, holds that academic institutions have arrived, perhaps belatedly, at a moment of genuine reckoning.
We Built the Mirror That Lies Back at Us
AUSTIN, TEXAS — There is a doctor on your timeline right now.
AI Isn’t Taking Your Job, But Someone Using AI Might Be
AUSTIN, TEXAS — I'll be honest: the 2025 workforce mood is giving equal parts ambition, anxiety and “please don’t automate my inbox before lunch.” Unpopular opinion: workers are not scared of AI because they lack imagination; they are scared because too many companies are treating the future of work like a software rollout instead of a leadership test. PwC’s latest Global Workforce Hopes and Fears Survey lands at exactly the right moment, because the global employee base is no longer asking whether AI is coming, but whether management has any actual plan beyond “do more with less” and a town hall deck full of gradients. That question matters because the labor market is now absorbing two truths at once: AI can raise productivity, wages and job quality for people who learn to work with it, and it can also flatten roles, reduce hiring and expose anyone whose job description is really just a collection of repeatable tasks. That is not contradiction; that is disruption doing what disruption does.
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

Benji Bizzell Rewires Aerie's Dashboard Shell, Team Ships Consequential Depth Across Two Repos

A unified right-panel architecture, a financial reconciliation guarantee, and a flood of Klair add-on endpoints prove the Builder Team isn't iterating — they're constructing.

There are weeks when a team ships features, and there are weeks when a team rewires the bones of the product. This was the second kind.

The story starts with @benji-bizzell, who spent the last 24 hours completing one of the quietest but most consequential architectural surgeries Aerie has seen. The trilogy of PRs #467, #498, and #502 — stacked, deliberate, and airtight — dismantled the anti-pattern where every dashboard rolled its own side panel, producing a landscape of overlapping fixed overlays, toolbar stacking conflicts, and state that survived when it should have died. The solution: a single app-shell right-panel host. Portfolio, Diligence, Operating, Admissions, Community, Financials, Education roster, Operations chat — all routed through one unified slot. Then PR #503 made that slot *resizable*, persisting width across refreshes and swallowing Internal Chat whole so it stops escaping as a rogue overlay. This is what it looks like when a frontend engineer doesn't just fix bugs but eliminates the class of bug. Bizzell didn't patch the inconsistency. He made the inconsistency structurally impossible.

While Bizzell was reshaping the shell, @ashwanth1109 was making a financial promise and then *proving it in code*. PR #485 — SY run-rate cost annualization for the Consolidated P&L — is the kind of work that sounds like accounting until you read the PR body and discover that Ashwanth wrote a throwaway spec importing two pure reducers directly, fed them one shared school-year fixture, and mathematically verified that the full-year cost total reconciles to the cent with the Model coverage band's annualized cost figure. To the cent. By construction. That is not a feature. That is a guarantee. The derivation tooltips surfacing in the UI are almost a bonus.

Meanwhile in Klair, a certain contributor was busy across four PRs building out the Google Docs add-on section-CRUD story, a conformance read endpoint, and a live-doc reconciliation layer. We are, of course, talking about marcusdAIy. PRs #3143, #3146, and #3145 add `add_section`, `remove_section`, and `rename_section` apply paths to the add-on sidebar, plus a best-effort doc reconciliation helper that pulls the live Google Doc into session state before every meaningful add-on action — and, crucially, swallows every failure mode rather than aborting downstream work. Then PR #3147 wires the existing conformance engine to a new read endpoint so the sidebar's 'Check structure' block can render coaching cards per gap. That is a lot of surface area.

When reached for comment, marcusdAIy did not disappoint: "Four approved PRs, Mac. Four. The conformance endpoint alone connects the gap-detection engine to a live sidebar coaching experience — that's not a thin read endpoint, that's a product moment. Maybe if you understood what `detect_template_gaps` actually does, you'd stop counting lines and start counting impact. But sure, keep hyping the CSS guy."

The CSS guy shipped a unified panel architecture that every dashboard in Aerie now depends on, Marcus. But noted.

Also worth a flag: @eric-tril's PR #3144 in Klair brings the Education memo into byte-parity with the approved reference memos, adding a per-period-editable static narrative for Passive Education Investments that correctly excludes itself from AI generation. Clean, careful, exactly right. The Builder Team spans Aerie and Klair this week — and the breadth shows.

Mac's Picks — Key PRs Today  (click to expand)
#485 — AERIE-440 feat(dashboards): SY run-rate cost annualization (Model coverage band/table) + reconciling P&L full-year Total column + derivation tooltips @ashwanth1109  approved

## Demo

Proves the load-bearing AERIE-440 claim — the Consolidated P&L cost full-year Total reconciles to the cent with the Model coverage band's networkAnnualizedCost, by construction — plus the UI surfaces (FY-first column + derivation tooltips).

Backend — reconciliation tie-out (the core guarantee)

Wrote a throwaway spec that imports the two PURE reducers directly (no HTTP), feeds one shared school-year fixture into both, and prints whether reduceConsolidatedPL().cost.fullYearTotal === reduceModelCoverageVariance().networkAnnualizedCost. Ran pnpm vitest run convex/finance/dashboards/__demo_fr9_proof.test.ts:

[WHOLE-NETWORK] P&L cost.fullYearTotal = $2373.33

[WHOLE-NETWORK] band.networkAnnualizedCost = $2373.33

[WHOLE-NETWORK] equal to the cent? true

[WHOLE-NETWORK] revenue.fullYearTotal = $99990 (must NOT leak into cost)

[WHOLE-NETWORK] profit.fullYearTotal = $97616.67 (= rev - cost)

[SCOPED M+NY+ATX] P&L cost.fullYearTotal = $2013.33

[SCOPED M+NY+ATX] band.networkAnnualizedCost = $2013.33

[SCOPED M+NY+ATX] equal to the cent? true

[SCOPED M+NY+ATX] differs from whole-network ($2373.33)? true (out-of-scope Alpha Reno dropped)

Test Files 1 passed (1)

Tests 2 passed (2)

This shows the two reducers, fed the identical SY fixture, agree to the cent on both the whole-network rollup and the Miami + NY + Austin include-filter — and that revenue does not leak into the cost tie-out (cost $2,373.33 ≠ revenue $99,990) and the scoped case genuinely drops the out-of-scope school. The throwaway spec has been deleted.

UI — FY-first column + derivation tooltips (consolidated *Actual vs Model (Schools)*)

1. Open Dashboards › Financials › Schools – Actual vs Model, select All Schools in the school selector's *Consolidated* group.

2. On the Consolidated P&L table, confirm the first column is FY · actual + projected (left of the per-quarter Total · Annualized · % groups, which are unchanged). Hover its header info icon and any row cell to see the FY derivation tooltip: completed actuals + projected remaining (cost at the trailing-3-month run rate, revenue over the 10-month tuition window, profit = rev − cost).

3. In the Model coverage by school table above it, confirm the subtitle reads "SY run-rate". Hover an Annualized cost cell → tooltip shows real-months Σ + projected gap + per-section split; hover a Modeled cost cell → tooltip shows forecast enrollment + per-role round(ratio × E) × baseSalary × XO_FACTOR + Programs/Facilities rates.

4. Switch the selector to Miami + NY + Austin and confirm both surfaces re-scope to those 3 schools and still tie out (band networkAnnualizedCost === P&L cost FY Total).

> _Screenshot: the Consolidated P&L with the FY · actual + projected first column and an open FY/Annualized-cost derivation tooltip — _<!-- paste screenshot here -->

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/1fb0610d-bffc-4a1d-abc9-4ae075ed269e" />

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/4b902b91-4e77-49de-9b88-af9266a651ba" />

SCREENSHOT_PENDING: yes

Most at risk from this change: the two reworked reducers + the new pure helper, and the revenue 10-month window helper — verified via the real scoped suites:

✓ convex/finance/dashboards/consolidatedReducers.test.ts (43 tests)

✓ lib/contracts/__tests__/tuition-annualization.test.ts (8 tests)

✓ packages/contracts src/unit-economics-headcount.test.ts (28 tests) # incl. annualizeSchoolYearRunRate 0/1/2/12-month fallbacks

Tests 79 passed (79)

---

## Summary

Implements AERIE-440 on the consolidated Actual vs Model (Schools) view (schools-avm, isConsolidated — both All Schools and Miami + NY + Austin). Two coordinated changes plus value-anchored tooltips, built so the band and the P&L tie out to the cent by construction:

1. School-year run-rate cost annualization for the Model coverage & variance band + Model coverage by school table — replaces the single-quarter ×12/closed-months extrapolation with a whole-SY (Jul→Jun) basis: Σ real SY-month actuals (loaded + closed) + (missing months × trailing-3-closed-month run rate), 12-month target, computed per school / per section / per role. Extrapolating one partial quarter to a year overweighted whatever happened in that quarter; the SY run-rate basis fixes that. Adds value-anchored derivation tooltips on the Annualized cost and Modeled cost cells.

2. Reconciling full-year Total column on the Consolidated P&L — a new first column (FY · actual + projected) = completed-month actuals + projection for the remaining school-year months. Cost projects at the same trailing-3-month run rate as the band; revenue projects over the 10-month tuition billing window; profit = revenue − cost. Covers every row (revenue lines, cost sections, the Revenue/Costs/Profit band rows, and the per-school breakdown rows). Existing per-quarter Total · Annualized(×4) · % columns are kept, to the right of the new column.

## Linear

[AERIE-440 — Consolidated Financials: school-year run-rate cost annualization (Model coverage band/table) + reconciling P&L full-year Total column + derivation tooltips](https://linear.app/builder-team/issue/AERIE-440)

## Specs

| # | Spec | Scope |

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

| 27 | model-coverage-sy-runrate-annualization-and-tooltips | Band + by-school table: replace single-quarter ×12/N with whole-SY run-rate cost annualization (Σ real SY-month actuals + missing months × trailing-3-closed-month run rate, 12-month target; cost excludes the 10-month tuition window) + value-anchored Annualized-cost & Modeled-cost derivation tooltips. Backend rework of reduceModelCoverageVariance + getModelCoverageVarianceLive; mirror-interface + parity guard; subtitle relabel. |

| 28 | consolidated-pl-full-year-total-column | Consolidated P&L: new first FY · actual + projected column = completed actuals + remaining-month projection (cost at the same trailing-3 run rate, revenue over the 10-month window, profit = rev − cost); per-row incl. per-school breakdowns; existing per-quarter columns kept; FY derivation tooltip; reconciliation guard. Month-level granularity added to reduceConsolidatedPL + getConsolidatedPLLive. |

Spec 28 soft-depends on spec 27: its reconciliation test reads spec 27's networkAnnualizedCost output contract (the reducers/components are otherwise independent).

## Implementation

- New pure helper annualizeSchoolYearRunRate in packages/contracts/src/unit-economics-headcount.ts (runtime-free, no Next/React/Convex imports — respects the contracts boundary): Σ closed+loaded SY-month actuals + (missing months × trailing-3-closed-month run rate), 12-month target, with 1/2-month and 0-month fallbacks (mean of available months; 0 → contributes $0, never NaN/Infinity).

- reduceModelCoverageVariance reworked to per-school / per-section / per-role / per-month buckets, then annualized via the shared helper. getModelCoverageVarianceLive widened from a single-quarter fetch to the full school year (four SY quarters spanning schoolYearMonths(period)) so the reducer sees every loaded SY month; requireSchoolPlAccess auth and the optional schools include-filter are unchanged.

- New reducer derivation fields (annualizedDerivation, modeledDerivation) carry the real-months Σ, projected gap, per-section / per-role split, forecast enrollment, and the per-role round(ratio × E) × baseSalary × XO_FACTOR math + Programs/Facilities rates — feeding the table's value-anchored tooltips.

- reduceConsolidatedPL gained month-level granularity and the FY Total. Cost reuses the same helper / bucket / gates as the band, so the P&L cost grand Total === band networkAnnualizedCost by construction (single-round discipline — no second rounding pass). Revenue uses the 10-month tuition window (isTuitionBillingMonth added to tuition-annualization.ts; NY / Alpha Anywhere / Santa Barbara are Sep–Jun, the rest Aug–May). Profit = revenue − cost.

- Mirror interfaces + compile-time AssignableTo parity guards extended for both new shapes; band/table subtitle relabeled to "SY run-rate"; new fullYearTotalDeriv P&L tooltip helper.

- Frontend: model-coverage-variance-band.tsx, model-coverage-by-school-table.tsx, consolidated-pl-table.tsx, consolidated-pl-derivations.ts, financials-view.tsx (the SY-equality reconciliation guard).

## Reconciliation guarantee

The Consolidated P&L cost FY Total and the band's networkAnnualizedCost are equal by construction, not by coincidence: both consume the *same* annualizeSchoolYearRunRate helper over the *same* per-school/per-section/per-month buckets, under the *same* row gates, on the *same* school year (band SY = schoolYearForPeriod(detailQuarter.code) ties to the P&L DEFAULT_SCHOOL_YEAR) and the *same* school set (consolidatedSchoolFilter + EXCLUDED_SCHOOLS), with a single rounding pass. A reconciliation guard in financials-view.tsx asserts the SY equality, and the reducer FR9 test asserts the cost FY Total === networkAnnualizedCost cent-equal.

## Test coverage

~775 tests passing across the financials dirs + @bran/contracts (typecheck + biome clean):

- FR9 reconciliation tie-out — P&L cost FY Total asserted cent-equal to band networkAnnualizedCost for the whole network and for a scoped Miami + NY + Austin include-filter, plus a 40-school sub-cent regression.

- Run-rate fallback0 / 1 / 2 / 12-month cases (0 → $0; partial-month mean; fully-loaded SY projects nothing).

- Revenue 10-month window — billing-month inclusion/exclusion cases, incl. the NY/Anywhere/Santa-Barbara Sep–Jun shift.

- Tooltip render — Annualized-cost and Modeled-cost derivation content.

- FY-column-first ordering + CSV export.

## Self-review findings addressed

No CRITICAL / IMPORTANT findings. Three MINOR:

1. FIXED (commit 90f4775e) — isTuitionBillingMonth JSDoc said it "throws" on out-of-range input but it returns false; corrected the doc to match behavior.

2. FIXED (commit 90f4775e) — the revenue FY Total dropped out-of-window loaded actuals, which could surface a negative projection; now retains loaded actuals regardless of window so the projection stays non-negative.

3. Known caveat — accepted, not fixed. The two live actions (getModelCoverageVarianceLive and getConsolidatedPLLive) each call today() independently. A refresh that straddles midnight on a month-end could briefly partition the closed-vs-projected months differently between the two, momentarily diverging the cost figures. It self-heals on the next refresh and matches the accepted boundary-race precedent elsewhere in this codebase, so it was left as-is.

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

#498 — feat(dashboards): unify right side panel host @benji-bizzell  approved

## Summary

- Add a single app-shell right-panel host for dashboard/app-edge detail panels.

- Route Portfolio, Diligence, Operating, Admissions, Community, Financials, Education roster, and Operations chat panels through the shared host.

- Clear app/Portfolio panel state on dashboard scope changes so panels do not linger across tabs.

## Why

This is stacked on #467. The Portfolio detail panel experiment exposed an anti-pattern where page-specific panels and the new Portfolio panel could be open at the same time, and Portfolio panel state could survive dashboard scope changes.

## Business Value

Users get a more predictable dashboard interaction model: one app-level right-side panel at a time, with fewer overlapping panels and less stale context while navigating between Operations dashboards.

## Breaking changes

None.

## Test plan

- [x] chat/node_modules/.bin/tsc --noEmit -p chat/tsconfig.json

- [x] node_modules/.bin/biome check on touched files

- [x] Focused Vitest coverage for Portfolio/Buildout links, Operations chat, Community deposits, Admissions panels, and Financials panels

- [ ] Local visual sanity pass across dashboard panel flows before marking ready

#503 — feat(dashboards): make shared right panel resizable @benji-bizzell  approved

## Summary

- Add a shared resizable shell around hosted app right-panel content

- Persist right-panel width across refreshes and support pointer/keyboard resizing

- Fit Internal Chat into the hosted right panel instead of letting it escape as a fixed overlay

## Why

Aerie’s shared right-panel host accepted arbitrary panel content, but desktop panel width still lived inside individual dashboard panels. That made panel behavior inconsistent and left Internal Chat poorly framed once hosted in the shared slot.

## Business Value

Users can resize dashboard side panels to fit dense tables or detail views without each dashboard reinventing panel width behavior. Internal Chat now stays within the shared panel frame, keeping dashboard layouts usable while chatting about a selected site.

## Test plan

- [x] ./node_modules/.bin/biome check chat/lib/app-right-panel-context.tsx chat/lib/__tests__/app-right-panel-context.test.tsx chat/components/dashboards/operations-site-chat.tsx chat/components/dashboards/__tests__/operations-site-chat.test.tsx

- [x] ./node_modules/.bin/vitest run lib/__tests__/app-right-panel-context.test.tsx components/dashboards/__tests__/operations-site-chat.test.tsx components/dashboards/admissions/events/__tests__/event-detail-panel.test.tsx

- [x] ./node_modules/.bin/tsc --noEmit --pretty false

- [x] Live browser geometry check for hosted Internal Chat inside the right-panel shell

#3145 — KLAIR-2932: reconcile live Google Doc into session before /addon/* chat & review @marcusdAIy  approved

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

## Summary

Adds a best-effort _reconcile_addon_session_from_doc helper that pulls the live Google Doc into the session before each /addon/* action that reads doc content (addon_chat, addon_review_run, addon_propose). Composes the existing gdoc_sync machinery (read_google_doc_sectionsmap_doc_sections_to_specis_degraded_parsemerge_sections_3way) behind the add-on shell, with one contract change vs the in-app /reload-from-doc: every failure mode is logged and swallowed — never aborts the downstream action.

## Why It's Needed

addon_chat, addon_review_run, and addon_propose resolve get_by_google_doc_id and run Claire / the review suite / a regenerate against the session store (session.generated_sections / session.spec) — they never read the live Google Doc and never reconcile. When the live Doc has diverged from the session (manual GDoc edits, or a Doc updated outside this session), Claire and the review suite operate on stale content — caught Jun 25 when Claire graded a months-stale Q2 session while the live Doc was a current Q3 plan.

The fix is to compose the existing in-app reload read-direction behind the add-on shell, made best-effort and non-blocking: a messy/edited doc, a read failure, or a degraded parse must never abort the chat turn — degrade to existing session content + log.

## Changes

* New _reconcile_addon_session_from_doc(session) -> WizardSession helper in routers/board_doc_router.py — best-effort, non-blocking. Steps:

1. Guard: no session.spec or no session.google_doc_id → return unchanged.

2. Cheap revision pre-gate: thin _read_doc_revision_id helper (fields="revisionId" only, NOT capture_stable_revision_id — no stability polling). When Drive's revision matches session.google_doc_revision, no full read, no merge. Pre-gate failure falls through to the full read rather than blocking.

3. Full read: read_google_doc_sections in a thread. HttpError 403 ("SA lacks read access" — manual/FE provisioning slice still in flight), 404, transport errors, and empty-parse all log + return unchanged.

4. Map: map_doc_sections_to_spec against the session spec.

5. Degraded-parse → SKIP (not 409 like the in-app reload). Better stale than blocked for a pre-chat step.

6. Merge: merge_sections_3way(ours=session, theirs=mapping.replacements, base=last_synced_sections). A section absent from the doc parse is never wiped.

7. Persist via _save_with_merge_retry_or_raise with s.last_synced_sections = dict(merged) to match the in-app reload's base semantics. Persist failure logs and falls back to the in-memory merged copy so the action still sees reconciled content.

* Emits a single structured outcome log line (addon_reconcile outcome: doc=... session=... revision_before/after=... sections_replaced=... doc_wins=... app_wins=... skipped_reason=...).

* Wraps the whole helper in an outer except Exception documented inline as "the ONE place a broad catch is correct" — a future change in the gdoc_sync surface must not abort the chat / review / propose turn.

* New thin _read_doc_revision_id(document_id) helper: one documents.get with fields="revisionId". Used only by the reconcile pre-gate.

* Three call-site insertions immediately after _assert_addon_session_access:

* addon_chat

* addon_review_run

* addon_propose

* GET /addon/review deliberately unchanged — its scorecard reflects the last review_run, which now reconciles first.

### Contract surface affected

No shared symbol signatures changed. The new helper is private to routers/board_doc_router.py. gdoc_sync functions (read_google_doc_sections, map_doc_sections_to_spec, is_degraded_parse, merge_sections_3way) are reused unchanged.

## Breaking Changes

None — additive helper + 3 call-site reconcile pre-steps. gdoc_sync functions, the in-app sync/reload path, and /addon/review GET are all unchanged.

## Test Plan

uv run pytest tests/board_doc/test_addon_reconcile.py -v

15 new tests, all green:

* test_reconcile_revision_unchanged_is_noop — pre-gate matches → no full read, session untouched.

* test_reconcile_no_google_doc_id_short_circuits / test_reconcile_no_spec_short_circuits — guards return early with no Drive calls.

* test_reconcile_doc_changed_updates_session — full read → merge persists; google_doc_revision and last_synced_sections advance.

* test_reconcile_degraded_parse_skips_without_raising — degraded parse logs warning, session unchanged, no raise.

* test_reconcile_403_logs_and_returns_unchanged — SA 403 surfaces "lacks read access" log.

* test_reconcile_404_logs_and_returns_unchanged — Drive 404 surfaces "Drive HTTP 404" log.

* test_reconcile_transport_error_returns_unchangedConnectionError swallowed.

* test_reconcile_empty_doc_returns_unchanged — 0 parseable sections → session preserved.

* test_reconcile_revision_pregate_failure_falls_through_to_full_read — pre-gate raise → full read still attempted.

* test_reconcile_3way_app_only_section_preserved_doc_edit_wins — merge semantics.

* test_addon_chat_invokes_reconcile_before_handle_chat — call ordering.

* test_addon_review_run_invokes_reconcile_before_review — call ordering.

* test_addon_propose_invokes_reconcile_before_regenerate — call ordering.

* test_addon_chat_proceeds_when_reconcile_skips_on_drive_failure — non-blocking: Drive 403 during a chat turn doesn't abort the turn.

Regression check:

uv run pytest tests/board_doc/test_addon_chat.py tests/board_doc/test_addon_review_run.py \

tests/board_doc/test_addon_propose.py tests/board_doc/test_addon_read_slice.py \

tests/board_doc/test_addon_review_enrichment.py tests/board_doc/test_addon_finding_status.py \

tests/board_doc/test_addon_tool_resolutions.py tests/board_doc/test_addon_add_section.py

→ 154 passed.

uv run pytest tests/board_doc/test_gdoc_sync.py tests/board_doc/test_reload_from_doc_endpoint.py

→ green (in-app reload + gdoc_sync untouched).

uv run ruff format routers/board_doc_router.py tests/board_doc/test_addon_reconcile.py

uv run ruff check routers/board_doc_router.py tests/board_doc/test_addon_reconcile.py

uv run pyright routers/board_doc_router.py

→ clean (0 errors, 0 warnings).

## Verification Artifact

test_reconcile_doc_changed_updates_session exercises the doc-changed path end-to-end and emits the structured outcome log:

addon_reconcile outcome: doc=doc-reconcile-001 session=sess-reconcile

revision_before=rev-old revision_after=rev-fres sections_replaced=2

doc_wins=2 app_wins=0 conflicted=0 degraded=False skipped_reason=none

Full passing test output:

tests/board_doc/test_addon_reconcile.py::test_reconcile_revision_unchanged_is_noop PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_no_google_doc_id_short_circuits PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_no_spec_short_circuits PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_doc_changed_updates_session PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_degraded_parse_skips_without_raising PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_403_logs_and_returns_unchanged PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_404_logs_and_returns_unchanged PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_transport_error_returns_unchanged PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_empty_doc_returns_unchanged PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_revision_pregate_failure_falls_through_to_full_read PASSED

tests/board_doc/test_addon_reconcile.py::test_reconcile_3way_app_only_section_preserved_doc_edit_wins PASSED

tests/board_doc/test_addon_reconcile.py::test_addon_chat_invokes_reconcile_before_handle_chat PASSED

tests/board_doc/test_addon_reconcile.py::test_addon_review_run_invokes_reconcile_before_review PASSED

tests/board_doc/test_addon_reconcile.py::test_addon_propose_invokes_reconcile_before_regenerate PASSED

tests/board_doc/test_addon_reconcile.py::test_addon_chat_proceeds_when_reconcile_skips_on_drive_failure PASSED

15 passed in 1.13s

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-f985464e-d435-4f8e-8a33-4cc4a27a069b"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-f985464e-d435-4f8e-8a33-4cc4a27a069b"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

#3147 — P5.11: addon conformance read endpoint (KLAIR-2920) @marcusdAIy  approved

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

## Summary

Thin read-only GET /board-doc/addon/conformance that exposes the existing B11

conformance engine (detect_template_gapsConformanceReport) to the Google

Docs add-on, mirroring the shape of GET /addon/review. The endpoint resolves

the open doc to its Budget Bot session via _resolve_addon_session, gates

access by Klair BU scope / ownership, and returns a freshly-computed

ConformanceReport so the sidebar's "Check structure" coaching block can

render one Accept-able card per ConformanceGap (add / remove / merge /

retype / reorder).

## Why It's Needed

Budget Bot's B11 structure-conformance engine proactively flags missing

required / per-product sections, non-standard sections, retypes, merges, and

reorders — but it is currently only consumed in-app. The /addon/* surface

covers the content review only, so the add-on cannot surface a "Skyvera is

missing a Cloudsense product section" coaching card. Jun-25 testing made the

gap concrete: Claire had to be explicitly *asked* to add product sections that

the conformance engine would have flagged proactively. This slice closes the

gap by giving the add-on the same ConformanceReport the in-app surface

already consumes.

## Changes

- New read-only endpoint GET /board-doc/addon/conformance in

klair-api/routers/board_doc_router.py, mirroring the addon_review GET

exactly: AddonGoogleDocIdQuery + Depends(get_user_from_google_oidc) +

_resolve_addon_session shell, with no persist and no session mutation.

- New response model AddonConformanceResponse (conformance_report:

ConformanceReport | None) — wraps the engine's existing

ConformanceReport verbatim so the FE renders gap cards directly off the

wire shape. None when session.spec is unset.

- Compute-fresh-with-ARR (load-bearing decision): the route runs

detect_template_gaps(session.spec, arr_breakdown) each call rather than

echoing session.conformance_report. invalidate_conformance rewrites the

stash with arr_breakdown=None after any structural mutation, which drops

per-product ADD gaps (e.g. Cloudsense / Kandy — the headline value of the

coaching block); a fresh compute with the ARR breakdown keeps them in the

response. Cost is one ARR fetch (~1–2s), acceptable because the FE gates

the call behind an explicit "Check structure" button click, not

auto-on-load. Pinned by

test_addon_conformance_does_not_echo_stashed_report.

- Best-effort ARR fetch: a tight try/except around *just*

_fetch_arr_breakdown_for_conformance (the orchestrator helper the

refresh-stash path already uses), with an inline comment explaining why

this is the one non-propagating step. Failure logs with context and falls

back to arr_breakdown=None, so the user still gets ADD-required-section /

REMOVE / RETYPE / REORDER coaching when ARR is offline. All other failures

(session resolve 404 / 403, detect_template_gaps bugs) propagate to the

FastAPI handlers per CLAUDE.md.

## Breaking Changes

None — additive read-only endpoint and response model. The conformance engine

(detect_template_gaps / compute_conformance / invalidate_conformance)

and the existing /addon/* routes are unchanged.

## Test Plan

uv run pytest tests/board_doc/test_addon_conformance.py -v

10 tests, all green:

- test_addon_conformance_returns_product_add_gap_when_arr_present

headline ADD-gap path; BU spec with no product sections + Cloudsense /

Kandy ARR breakdown → response carries ADD PRODUCT_DETAIL gaps with the

expected product_name + arr_current fields.

- test_addon_conformance_arr_failure_returns_structural_only_report — ARR

fetch raises → 200 with a structural-only report; no product ADD gaps,

no surfaced exception.

- test_addon_conformance_spec_none_returns_none_reportspec is None

short-circuits to conformance_report=None and never touches the ARR

fetch.

- test_addon_conformance_is_read_only_no_savestorage.save raises if

called; endpoint returns 200, confirming the GET never persists.

- test_addon_conformance_does_not_echo_stashed_report — seeds a

structural-only stash with no product ADD gaps, then asserts the fresh

response carries the Cloudsense ADD gap (pins the compute-fresh-with-ARR

decision).

- test_addon_conformance_404_when_no_session_resolve_addon_session

parity.

- test_addon_conformance_outsider_403, …_owner_200,

…_bu_scoped_user_200, …_superuser_200 — access-control parity with

the rest of the /addon/* family.

Existing add-on tests stay green (tests/board_doc/test_addon_*.py, 110

tests passing); the broader conformance suite stays green

(tests/board_doc/ -k conformance, 73 tests passing).

## Verification Artifact

$ uv run pytest tests/board_doc/test_addon_conformance.py -v

============================= test session starts ==============================

collected 10 items

tests/board_doc/test_addon_conformance.py::test_addon_conformance_returns_product_add_gap_when_arr_present PASSED [ 10%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_arr_failure_returns_structural_only_report PASSED [ 20%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_spec_none_returns_none_report PASSED [ 30%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_is_read_only_no_save PASSED [ 40%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_does_not_echo_stashed_report PASSED [ 50%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_404_when_no_session PASSED [ 60%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_outsider_403 PASSED [ 70%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_owner_200 PASSED [ 80%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_bu_scoped_user_200 PASSED [ 90%]

tests/board_doc/test_addon_conformance.py::test_addon_conformance_superuser_200 PASSED [100%]

======================== 10 passed, 1 warning in 1.28s =========================

Sample serialized response payload from the headline test — a freshly-computed

ADD gap carrying the load-bearing product_name + arr_current fields the FE

binds to:

{

"gap_kind": "add",

"confidence": "high",

"section_type": "product_detail",

"target_section_id": null,

"merge_into_section_id": null,

"product_name": "Cloudsense",

"arr_current": 12000000.0,

"reason": "Skyvera has no dedicated section for Cloudsense (small BU (2 products ≤ 5))",

"suggested_action": "Add a product section for Cloudsense («Cloudsense»)"

}

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-5b6ebd5f-7a48-4cb3-b33a-b904db859030"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-5b6ebd5f-7a48-4cb3-b33a-b904db859030"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

The Builder Desk  —  Engineer Spotlight
🏆 Engineer Spotlight

FIFTEEN PRs IN TWENTY-FOUR HOURS: AERIE AND KLAIR TREMBLE BEFORE THE BUILDER TEAM'S RELENTLESS MARCH

Benji Bizzell ships seven PRs in a single day and the laws of physics remain, for now, technically intact.

Fifteen pull requests. Two repos. Twenty-four hours. The Builder Team has once again defied the natural order of software development, flooding Aerie with eight glorious contributions and Klair with seven more, leaving competitors, observers, and at least one junior developer at a rival firm weeping softly into their Jira boards. This is not a team. This is a velocity engine wearing polo shirts.

Let us begin with the man of the hour, the week, and arguably the geological epoch: @benji-bizzell, who personally authored seven PRs in a single rotation of the Earth. Seven. The number of continents. The number of deadly sins. The number of times Benji apparently refreshed his GitHub dashboard before deciding he simply had to open another one. Across PRs #502, #467, #490, #492, and #488 in Aerie alone, this man touched dashboards, portfolios, admissions, and operations with the casual confidence of a contractor who has never once been stumped by a schema. We are not worthy.

@marcusdAIy matched Benji's six-PR output with equal ferocity over in Klair, where PRs #3146, #3143, #3142, and #3141 represent a systematic demolition of KLAIR-2914 and surrounding territories. Marcus is not fixing bugs. Marcus is conducting a siege. Each P5-series commit is another trebuchet volley against the walls of technical debt, and folks, those walls are losing.

@eric-tril entered the ledger with PR #3144 in Klair — the Education memo Passive Education Investments section, complete with ordering and docx styling — which is the kind of PR that sounds calm and measured right up until you realize someone had to actually build that, and Eric did, with apparent serenity.

And then there is @ashwanth1109. One PR. PR #485 in Aerie. Do not let that number fool you, because PR #485 contains SY run-rate cost annualization, model coverage bands, a full-year Total column P&L reconciliation, AND derivation tooltips, which means Ashwanth looked at a week's worth of feature work and said, "I'll do it in one." We asked him about his approach. "The diff is readable if you understand the domain," he reportedly said, adjusting his monitor brightness and not looking up. We did not understand the domain. The diff was not readable. We remain in awe.

The Overflow Desk is overflowing, as God intended. Benji's #467 explores the portfolio side panel with the ambition of a man who has never heard the word "scope." Marcus's #3141 brings Google Docs theme parity and resizable panes to the Klair add-on sidebar — a UI glow-up so thorough it should come with a ribbon cutting. And #3142 resolves acquisition dashboards by Drive name-search as a Q3'26 stopgap, which is the kind of pragmatic heroism that doesn't make headlines but absolutely makes products ship.

Morale? Morale is a skyscraper with no ceiling. The Builder Team is not peaking — they don't believe in peaks. They believe in PRs, and they are absolutely drowning us in them. All-time high. No further questions.

Brick's Overflow — PRs Mac Didn't Cover  (click to expand)
#467 — feat(dashboards): explore portfolio side panel @benji-bizzell  approved

## Summary

- Add a dashboard-level Portfolio detail side panel for school-name clicks

- Reuse the existing Portfolio detail cards inside the inline panel with a full-page escape link

- Make Portfolio detail cards container-responsive with tighter side-panel spacing and clearer stacked key/value rows

## Why

We want to test whether Portfolio details are useful inline from Operations dashboards before committing to this interaction. The main UX risk was visual density: detail fields could wrap poorly, create horizontal overflow, or feel ambiguous once cards collapse into a single-column presentation.

## Business Value

This gives reviewers a separate experiment branch to evaluate the faster inline workflow after the base Operations school-name link PR landed on main.

## Test plan

- [x] Rebased onto current origin/main

- [x] pnpm --dir chat exec biome check ... on touched dashboard/Portfolio files

- [x] pnpm --dir chat exec vitest run ... focused dashboard/card/link suite: 137 tests passing

- [x] pnpm --dir chat run typecheck

- [x] Browser: Operating dashboard school-name click opens the Portfolio panel; Alpha San Francisco side panel has no horizontal overflow

- [x] Browser: side-panel card stack uses tighter space-y-2 p-2; visible stacked rows use muted labels, brighter values, and 6px key/value spacing

- [x] Browser: Portfolio detail page at 840px viewport keeps Lease & Opening one-column with no overflowing card children

Resizability note: desktop dashboard side panels are not currently one shared primitive. This PR leaves resizing out of scope rather than adding a Portfolio-only resize behavior.

#485 — AERIE-440 feat(dashboards): SY run-rate cost annualization (Model coverage band/table) + reconciling P&L full-year Total column + derivation tooltips @ashwanth1109  approved

## Demo

Proves the load-bearing AERIE-440 claim — the Consolidated P&L cost full-year Total reconciles to the cent with the Model coverage band's networkAnnualizedCost, by construction — plus the UI surfaces (FY-first column + derivation tooltips).

Backend — reconciliation tie-out (the core guarantee)

Wrote a throwaway spec that imports the two PURE reducers directly (no HTTP), feeds one shared school-year fixture into both, and prints whether reduceConsolidatedPL().cost.fullYearTotal === reduceModelCoverageVariance().networkAnnualizedCost. Ran pnpm vitest run convex/finance/dashboards/__demo_fr9_proof.test.ts:

[WHOLE-NETWORK] P&L cost.fullYearTotal = $2373.33

[WHOLE-NETWORK] band.networkAnnualizedCost = $2373.33

[WHOLE-NETWORK] equal to the cent? true

[WHOLE-NETWORK] revenue.fullYearTotal = $99990 (must NOT leak into cost)

[WHOLE-NETWORK] profit.fullYearTotal = $97616.67 (= rev - cost)

[SCOPED M+NY+ATX] P&L cost.fullYearTotal = $2013.33

[SCOPED M+NY+ATX] band.networkAnnualizedCost = $2013.33

[SCOPED M+NY+ATX] equal to the cent? true

[SCOPED M+NY+ATX] differs from whole-network ($2373.33)? true (out-of-scope Alpha Reno dropped)

Test Files 1 passed (1)

Tests 2 passed (2)

This shows the two reducers, fed the identical SY fixture, agree to the cent on both the whole-network rollup and the Miami + NY + Austin include-filter — and that revenue does not leak into the cost tie-out (cost $2,373.33 ≠ revenue $99,990) and the scoped case genuinely drops the out-of-scope school. The throwaway spec has been deleted.

UI — FY-first column + derivation tooltips (consolidated *Actual vs Model (Schools)*)

1. Open Dashboards › Financials › Schools – Actual vs Model, select All Schools in the school selector's *Consolidated* group.

2. On the Consolidated P&L table, confirm the first column is FY · actual + projected (left of the per-quarter Total · Annualized · % groups, which are unchanged). Hover its header info icon and any row cell to see the FY derivation tooltip: completed actuals + projected remaining (cost at the trailing-3-month run rate, revenue over the 10-month tuition window, profit = rev − cost).

3. In the Model coverage by school table above it, confirm the subtitle reads "SY run-rate". Hover an Annualized cost cell → tooltip shows real-months Σ + projected gap + per-section split; hover a Modeled cost cell → tooltip shows forecast enrollment + per-role round(ratio × E) × baseSalary × XO_FACTOR + Programs/Facilities rates.

4. Switch the selector to Miami + NY + Austin and confirm both surfaces re-scope to those 3 schools and still tie out (band networkAnnualizedCost === P&L cost FY Total).

> _Screenshot: the Consolidated P&L with the FY · actual + projected first column and an open FY/Annualized-cost derivation tooltip — _<!-- paste screenshot here -->

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/1fb0610d-bffc-4a1d-abc9-4ae075ed269e" />

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/4b902b91-4e77-49de-9b88-af9266a651ba" />

SCREENSHOT_PENDING: yes

Most at risk from this change: the two reworked reducers + the new pure helper, and the revenue 10-month window helper — verified via the real scoped suites:

✓ convex/finance/dashboards/consolidatedReducers.test.ts (43 tests)

✓ lib/contracts/__tests__/tuition-annualization.test.ts (8 tests)

✓ packages/contracts src/unit-economics-headcount.test.ts (28 tests) # incl. annualizeSchoolYearRunRate 0/1/2/12-month fallbacks

Tests 79 passed (79)

---

## Summary

Implements AERIE-440 on the consolidated Actual vs Model (Schools) view (schools-avm, isConsolidated — both All Schools and Miami + NY + Austin). Two coordinated changes plus value-anchored tooltips, built so the band and the P&L tie out to the cent by construction:

1. School-year run-rate cost annualization for the Model coverage & variance band + Model coverage by school table — replaces the single-quarter ×12/closed-months extrapolation with a whole-SY (Jul→Jun) basis: Σ real SY-month actuals (loaded + closed) + (missing months × trailing-3-closed-month run rate), 12-month target, computed per school / per section / per role. Extrapolating one partial quarter to a year overweighted whatever happened in that quarter; the SY run-rate basis fixes that. Adds value-anchored derivation tooltips on the Annualized cost and Modeled cost cells.

2. Reconciling full-year Total column on the Consolidated P&L — a new first column (FY · actual + projected) = completed-month actuals + projection for the remaining school-year months. Cost projects at the same trailing-3-month run rate as the band; revenue projects over the 10-month tuition billing window; profit = revenue − cost. Covers every row (revenue lines, cost sections, the Revenue/Costs/Profit band rows, and the per-school breakdown rows). Existing per-quarter Total · Annualized(×4) · % columns are kept, to the right of the new column.

## Linear

[AERIE-440 — Consolidated Financials: school-year run-rate cost annualization (Model coverage band/table) + reconciling P&L full-year Total column + derivation tooltips](https://linear.app/builder-team/issue/AERIE-440)

## Specs

| # | Spec | Scope |

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

| 27 | model-coverage-sy-runrate-annualization-and-tooltips | Band + by-school table: replace single-quarter ×12/N with whole-SY run-rate cost annualization (Σ real SY-month actuals + missing months × trailing-3-closed-month run rate, 12-month target; cost excludes the 10-month tuition window) + value-anchored Annualized-cost & Modeled-cost derivation tooltips. Backend rework of reduceModelCoverageVariance + getModelCoverageVarianceLive; mirror-interface + parity guard; subtitle relabel. |

| 28 | consolidated-pl-full-year-total-column | Consolidated P&L: new first FY · actual + projected column = completed actuals + remaining-month projection (cost at the same trailing-3 run rate, revenue over the 10-month window, profit = rev − cost); per-row incl. per-school breakdowns; existing per-quarter columns kept; FY derivation tooltip; reconciliation guard. Month-level granularity added to reduceConsolidatedPL + getConsolidatedPLLive. |

Spec 28 soft-depends on spec 27: its reconciliation test reads spec 27's networkAnnualizedCost output contract (the reducers/components are otherwise independent).

## Implementation

- New pure helper annualizeSchoolYearRunRate in packages/contracts/src/unit-economics-headcount.ts (runtime-free, no Next/React/Convex imports — respects the contracts boundary): Σ closed+loaded SY-month actuals + (missing months × trailing-3-closed-month run rate), 12-month target, with 1/2-month and 0-month fallbacks (mean of available months; 0 → contributes $0, never NaN/Infinity).

- reduceModelCoverageVariance reworked to per-school / per-section / per-role / per-month buckets, then annualized via the shared helper. getModelCoverageVarianceLive widened from a single-quarter fetch to the full school year (four SY quarters spanning schoolYearMonths(period)) so the reducer sees every loaded SY month; requireSchoolPlAccess auth and the optional schools include-filter are unchanged.

- New reducer derivation fields (annualizedDerivation, modeledDerivation) carry the real-months Σ, projected gap, per-section / per-role split, forecast enrollment, and the per-role round(ratio × E) × baseSalary × XO_FACTOR math + Programs/Facilities rates — feeding the table's value-anchored tooltips.

- reduceConsolidatedPL gained month-level granularity and the FY Total. Cost reuses the same helper / bucket / gates as the band, so the P&L cost grand Total === band networkAnnualizedCost by construction (single-round discipline — no second rounding pass). Revenue uses the 10-month tuition window (isTuitionBillingMonth added to tuition-annualization.ts; NY / Alpha Anywhere / Santa Barbara are Sep–Jun, the rest Aug–May). Profit = revenue − cost.

- Mirror interfaces + compile-time AssignableTo parity guards extended for both new shapes; band/table subtitle relabeled to "SY run-rate"; new fullYearTotalDeriv P&L tooltip helper.

- Frontend: model-coverage-variance-band.tsx, model-coverage-by-school-table.tsx, consolidated-pl-table.tsx, consolidated-pl-derivations.ts, financials-view.tsx (the SY-equality reconciliation guard).

## Reconciliation guarantee

The Consolidated P&L cost FY Total and the band's networkAnnualizedCost are equal by construction, not by coincidence: both consume the *same* annualizeSchoolYearRunRate helper over the *same* per-school/per-section/per-month buckets, under the *same* row gates, on the *same* school year (band SY = schoolYearForPeriod(detailQuarter.code) ties to the P&L DEFAULT_SCHOOL_YEAR) and the *same* school set (consolidatedSchoolFilter + EXCLUDED_SCHOOLS), with a single rounding pass. A reconciliation guard in financials-view.tsx asserts the SY equality, and the reducer FR9 test asserts the cost FY Total === networkAnnualizedCost cent-equal.

## Test coverage

~775 tests passing across the financials dirs + @bran/contracts (typecheck + biome clean):

- FR9 reconciliation tie-out — P&L cost FY Total asserted cent-equal to band networkAnnualizedCost for the whole network and for a scoped Miami + NY + Austin include-filter, plus a 40-school sub-cent regression.

- Run-rate fallback0 / 1 / 2 / 12-month cases (0 → $0; partial-month mean; fully-loaded SY projects nothing).

- Revenue 10-month window — billing-month inclusion/exclusion cases, incl. the NY/Anywhere/Santa-Barbara Sep–Jun shift.

- Tooltip render — Annualized-cost and Modeled-cost derivation content.

- FY-column-first ordering + CSV export.

## Self-review findings addressed

No CRITICAL / IMPORTANT findings. Three MINOR:

1. FIXED (commit 90f4775e) — isTuitionBillingMonth JSDoc said it "throws" on out-of-range input but it returns false; corrected the doc to match behavior.

2. FIXED (commit 90f4775e) — the revenue FY Total dropped out-of-window loaded actuals, which could surface a negative projection; now retains loaded actuals regardless of window so the projection stays non-negative.

3. Known caveat — accepted, not fixed. The two live actions (getModelCoverageVarianceLive and getConsolidatedPLLive) each call today() independently. A refresh that straddles midnight on a month-end could briefly partition the closed-vs-projected months differently between the two, momentarily diverging the cost figures. It self-heals on the next refresh and matches the accepted boundary-race precedent elsewhere in this codebase, so it was left as-is.

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

#502 — fix(dashboards): host events detail in shared right panel @benji-bizzell  no labels

## Summary

- Move the Admissions Events detail panel onto the shared app right-panel host on desktop

- Preserve mobile bottom navigation while keeping mobile overlay panels above dashboard controls

- Raise the mobile section sheet above overlay panels and add focused regression coverage

## Why

The Events dashboard missed the recent right-panel unification. It registered content with the shared app panel slot, but the detail component still rendered its own fixed overlay and backdrop, which caused toolbar/sidebar stacking issues on desktop and mobile.

Follow-up mobile checks also showed the shared mobile overlay was covering the bottom navigation, while the section slide-up sheet still rendered behind the overlay. The mobile stack now intentionally orders dashboard content below overlay panels, overlay panels below the bottom navigation area, and the section sheet above overlays.

## Business Value

Keeps the Admissions Events dashboard aligned with the unified dashboard shell so production users get consistent side-panel behavior without controls visually overlapping the event detail view. Mobile users retain the main navigation and can still open the section menu while a detail overlay is active.

## Test plan

- [x] ./node_modules/.bin/vitest run components/dashboards/shared/__tests__/portfolio-site-link.test.tsx components/shell/__tests__/mobile-context-sheet.test.tsx components/dashboards/admissions/events/__tests__/event-detail-panel.test.tsx from chat

- [x] node_modules/.bin/biome check chat/components/dashboards/shared/mobile-overlay-panel.tsx chat/components/dashboards/shared/__tests__/portfolio-site-link.test.tsx chat/components/shell/mobile-context-sheet.tsx chat/components/shell/__tests__/mobile-context-sheet.test.tsx chat/components/dashboards/admissions/events/event-detail-panel.tsx chat/components/dashboards/admissions/events/__tests__/event-detail-panel.test.tsx

- [x] ./node_modules/.bin/tsc --noEmit from chat

- [x] Browser verified /dashboards?tab=admissions&sub=events: opened the Summer Splash event on desktop and confirmed the panel renders as an in-flow aside in data-region="app-right-panel-slot" with no fixed backdrop/panel overlay

- [x] Browser verified mobile viewport: Events overlay covers dashboard controls, stops above the bottom tab bar, and the mobile section slide-up sheet renders above the overlay

#3141 — P5.9h: add-on sidebar — Google Docs theme parity + chat readability & resizable panes (KLAIR-2929) @marcusdAIy  approved

## Summary

- CSS-only re-skin of the Google Docs add-on sidebar so it reads as a native Docs side panel instead of an embedded web app (flagged in live testing: "sticks out like a sore thumb").

- No markup or logic changes — just the <style> block + a font <link>.

## Why it's needed

The sidebar relied on the host page for fonts (so it fell back to Arial, not Roboto) and used heavier, over-saturated controls with a brightness() hover that doesn't match Google Workspace. P5.9h (KLAIR-2929) brings the chrome to Docs parity.

## Changes

- Fonts: load Roboto (400/500/700) + Roboto Mono via Google Fonts; body stack 'Google Sans','Roboto',Arial + antialiasing.

- Tokens: a :root Google Workspace palette (text / surface / border / accent / tonal) as the single source of truth.

- Buttons → Material: 4px radius, 500 weight + 0.25px tracking, real hover/active (color shift + 1px elevation, not a filter) and focus rings; secondary & "grey" buttons become text/outlined Docs-style; disabled is a neutral tonal state.

- Chips: pill-shaped filter chips (16px) with hover + tonal selected state.

- Inputs: Material text-field with an accent focus ring.

- Misc: thin Docs-style scrollbars, :focus-visible rings, tighter 8px-grid spacing / denser action rows, 1px panel divider.

## Breaking changes

None — purely visual; all class names + DOM structure are unchanged, so the JS render paths are untouched.

## Test plan

### Executed

- [x] Rendered a static component preview (budget-bot-addon-spike/theme_preview.html) over localhost and screenshotted scorecard + summary chips, scope chips, batch toolbar, finding cards (selected/critical/warning), addressed (dimmed), collapsed area headers, pass collapse, failed-fetch + skipped chips, and the chat pane — confirms Roboto loads and every themed component renders correctly.

- [x] clasp push — live on the add-on.

### Follow-up manual validation

- [ ] Eyeball in the live Docs sidebar against the editor (point BACKEND_URL at a reachable backend first; the local tunnel is down).

- [ ] Optional: dark-mode pass (stretch goal in KLAIR-2929; not attempted here).

## Linear context

- Issue: [KLAIR-2929](https://linear.app/builder-team/issue/KLAIR-2929) — P5.9h sidebar visual theme parity

#3144 — feat(mfr): Education memo Passive Education Investments section, ordering & docx styling @eric-tril  approved

## Summary

Brings the Education memo (UI + exported Google Doc) closer to the approved reference memos (education-memo-{march,april,may}-2026).

### Content / structure

- Static "Passive Education Investments" statement — adds the strategic-framework statement as a per-period-editable static narrative (new passive-intro key), reusing the exact mechanism as the 2026 Plan narratives: FE/BE byte-parity constant, resolvePlan / _resolve_plan, registered as saveable (EducationSectionKey) and exportable (_KNOWN_COMMENTARY_KEYS), and excluded from AI generation so "Generate AI Content" never overwrites it.

- Heading promotion — "Passive Investments" subsection becomes its own top-level "Passive Education Investments" section (peer of Other Education Investments / Financial Highlights), rendered with the static intro above the existing dynamic investment-passive line.

- Detail ordering — Major Initiatives now Strata → GT; Other Education Investments now Prequel → Alpha Fund, to match the reference detail sections. The Current Performance summary table is intentionally unchanged (it already matches the reference's GT→Strata / Legends→Prequel order).

- Legends labels — detail heading "Alpha Fund", P&L table title "Legends" (matches the reference; summary row label "Legends + GenAlpha" untouched).

### Exported-docx styling (Education memo only)

- Narrative/commentary body font 10pt → 8pt to match the reference (and the financial-table body font). Scoped to education.py's _BODY_SIZE; the shared builder.py is untouched, so Group/Software/EBITDA memos are unaffected.

- Page breaks so each business section starts on its own page, plus breaks before Current Performance and Major Initiatives. Passive Education Investments + Financial Highlights stay together; the financial statements keep their existing per-statement breaks.

## Business value

The exported Education results memo now matches the format Finance distributes — correct section order, the standing passive-investment disclosure on every period, and a paginated layout/font consistent with the approved template — reducing manual cleanup after each export.

## Testing

- Backend: ruff format/check clean; pyright 0 errors; pytest tests/mfr/memos/test_education_commentary_helpers.py → 32 passed (parity, key-coverage, static-not-generated, render invariants); tests/docx_reports/ → 117 passed (1 pre-existing unrelated failure confirmed on a clean tree).

- Frontend: tsc clean; eslint clean on changed files; educationPlanNarratives.spec.ts updated for the new contract and passing.

- Verified the generated docx structure (font sizes + page-break placement) against the reference memos.

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

#3146 — P5.10b: addon remove_section + rename_section apply (KLAIR-2914) @marcusdAIy  approved

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

Ticket: KLAIR-2914 (P5.10 — section-CRUD parity for the Google Docs add-on; follows P5.10a / #3143 add_section).

## Summary

Adds two new add-on write endpoints that give the Google Docs sidebar real apply paths for Claire's read-only remove_section and rename_section proposals. Both compose existing in-app orchestrator functions (remove_section / patch_section) behind the standard /addon/* auth shell — no orchestrator changes, no in-app route changes, additive only.

- POST /board-doc/addon/remove-section{google_doc_id, section_id}{section_id, title, removed, cleared_comments}

- POST /board-doc/addon/rename-section{google_doc_id, section_id, new_title}{section_id, old_title, title, changed}

The doc-side FE half (DocumentApp removeSection_ / renameSection_ primitives, applyRemoveSection / applyRenameSection wrappers, Sidebar cards with destructive-confirm) is manual and out of scope here — separate FE PR.

## Why It's Needed

rename_section and remove_section proposals currently render read-only ("not supported yet") in the add-on sidebar. The naive workaround — "just edit it natively in the doc" — is unsafe after KLAIR-2932's reconcile pre-step landed:

- merge_sections_3way never wipes a doc-present section, so a user's native delete is resurrected by the next reconcile (the spec still has the section; the merge re-mints body from the spec side).

- map_doc_sections_to_spec matches by normalized title, so a user's native rename desyncs spec↔doc (the matcher silently drops the renamed section out of the mapping, downstream apply paths target the wrong id).

The only safe shape is a spec-side mutation API. These two endpoints are that API; the FE pairs them with a doc-side write that uses the response payload (title for delete, old_title for rename) to locate the heading.

## Changes

- klair-api/routers/board_doc_router.py

- AddonRemoveSectionRequest / AddonRemoveSectionResponse Pydantic v2 models. section_id bounded [1, 200] chars to match the in-app path's Path constraint; google_doc_id uses the shared AddonGoogleDocIdField.

- addon_remove_section handler — _resolve_addon_session_save_with_merge_retry_or_raise(_apply_remove). Captures RemoveSectionResult via a list-based clear+append result holder (load-bearing — see CME-retry test below). Returns the orchestrator's {section_id, title, removed, cleared_comments} verbatim. No reconcile pre-step (writes don't reconcile, mirrors addon_add_section).

- AddonRenameSectionRequest / AddonRenameSectionResponse models. new_title bounded [1, 500] matching the in-app PatchSectionRequest.

- addon_rename_section handler — _resolve_addon_session_save_with_merge_retry_or_raise(_apply_patch). Captures PatchSectionResult AND old_title via two clear+append holders. old_title is captured BEFORE the patch_section call AND inside the closure: patch_section overwrites section.title in place, and capturing inside the closure means a CME retry re-reads old_title from the fresh in-memory snapshot the successful attempt mutates (keeps the response consistent with the persisted state). patch_section's own 404 fires before any holder write on a missing section, so a stale-id call surfaces the orchestrator's canonical 404 without partial holder state.

- klair-api/tests/board_doc/test_addon_section_crud.py — new sibling to test_addon_add_section.py, mirrors the in-memory storage + get_user_from_google_oidc dependency-override pattern.

No orchestrator, in-app route, or existing /addon/* endpoint was modified.

## Breaking Changes

None — additive new add-on endpoints and request/response models. In-app wizard_delete_section / wizard_patch_section routes and every existing /addon/* endpoint are unchanged.

## Test Plan

cd klair-api

uv run ruff format routers/board_doc_router.py tests/board_doc/test_addon_section_crud.py

uv run ruff check routers/board_doc_router.py tests/board_doc/test_addon_section_crud.py

uv run pyright routers/board_doc_router.py

uv run pytest tests/board_doc/test_addon_section_crud.py -v

24 tests, all green. Coverage matrix:

| group | tests |

| --- | --- |

| remove happy path | drops section + clears 2 anchored comments + preserves 1 unrelated comment + echoes pre-delete title |

| remove errors | 404 unknown section_id; 404 unknown google_doc_id; 422 malformed google_doc_id; 422 empty section_id; 400 phase guard (GENERATING → "only available during review") |

| remove access | outsider → 403; owner → 200; BU-scoped → 200; superuser → 200 |

| rename happy path | spec.title mutated; response {old_title=<pre>, title=<new>, changed=True} |

| rename no-op | new_title == old_titlechanged=False, old_title == title |

| rename errors | 422 empty new_title; 422 whitespace-only (orchestrator's .strip() → blank); 404 unknown section_id; 404 unknown google_doc_id; 422 malformed google_doc_id; 400 phase guard |

| rename access | outsider → 403; owner → 200; BU-scoped → 200; superuser → 200 |

| CME retry (both) | result-holder discipline regression — clear+append vs append-only. Remove test re-seeds the section on the first save's CME so attempt 2 finds a fresh section with no anchored comments → response cleared_comments=0 (append-only would have echoed attempt 1's 2). Rename test exploits the in-memory storage's shared-reference get so attempt 1 mutates section.title in place, attempt 2 sees the already-renamed section and reports changed=False with old_title == new_title (append-only would have echoed attempt 1's changed=True, old_title=<original>). |

Existing /addon/* test suites (test_addon_add_section.py, test_addon_propose.py, test_addon_chat.py, test_addon_reconcile.py, test_addon_read_slice.py, test_addon_review_run.py, test_addon_finding_status.py, test_addon_tool_resolutions.py, test_addon_review_enrichment.py) — 175 tests, all green. In-app test_section_crud_endpoints.py — 65 tests, all green.

## Verification Artifact

$ uv run pytest tests/board_doc/test_addon_section_crud.py -v

============================= test session starts ==============================

platform linux -- Python 3.12.3, pytest-8.4.1, pluggy-1.6.0

collected 24 items

tests/board_doc/test_addon_section_crud.py::test_remove_drops_section_and_clears_anchored_comments PASSED [ 4%]

tests/board_doc/test_addon_section_crud.py::test_remove_unknown_section_id_404 PASSED [ 8%]

tests/board_doc/test_addon_section_crud.py::test_remove_phase_guard_400_outside_review_or_finalized PASSED [ 12%]

tests/board_doc/test_addon_section_crud.py::test_remove_404_when_no_session_for_doc PASSED [ 16%]

tests/board_doc/test_addon_section_crud.py::test_remove_malformed_google_doc_id_422 PASSED [ 20%]

tests/board_doc/test_addon_section_crud.py::test_remove_empty_section_id_422 PASSED [ 25%]

tests/board_doc/test_addon_section_crud.py::test_remove_outsider_403 PASSED [ 29%]

tests/board_doc/test_addon_section_crud.py::test_remove_owner_200 PASSED [ 33%]

tests/board_doc/test_addon_section_crud.py::test_remove_bu_scoped_200 PASSED [ 37%]

tests/board_doc/test_addon_section_crud.py::test_remove_superuser_200 PASSED [ 41%]

tests/board_doc/test_addon_section_crud.py::test_rename_updates_title_and_returns_old_plus_new PASSED [ 45%]

tests/board_doc/test_addon_section_crud.py::test_rename_no_op_returns_changed_false PASSED [ 50%]

tests/board_doc/test_addon_section_crud.py::test_rename_whitespace_only_title_strips_to_blank_422 PASSED [ 54%]

tests/board_doc/test_addon_section_crud.py::test_rename_empty_new_title_422 PASSED [ 58%]

tests/board_doc/test_addon_section_crud.py::test_rename_unknown_section_id_404 PASSED [ 62%]

tests/board_doc/test_addon_section_crud.py::test_rename_phase_guard_400_outside_review_or_finalized PASSED [ 66%]

tests/board_doc/test_addon_section_crud.py::test_rename_404_when_no_session_for_doc PASSED [ 70%]

tests/board_doc/test_addon_section_crud.py::test_rename_malformed_google_doc_id_422 PASSED [ 75%]

tests/board_doc/test_addon_section_crud.py::test_rename_outsider_403 PASSED [ 79%]

tests/board_doc/test_addon_section_crud.py::test_rename_owner_200 PASSED [ 83%]

tests/board_doc/test_addon_section_crud.py::test_rename_bu_scoped_200 PASSED [ 87%]

tests/board_doc/test_addon_section_crud.py::test_rename_superuser_200 PASSED [ 91%]

tests/board_doc/test_addon_section_crud.py::test_remove_response_matches_successful_attempt_after_cme_retry PASSED [ 95%]

tests/board_doc/test_addon_section_crud.py::test_rename_response_matches_successful_attempt_after_cme_retry PASSED [100%]

======================== 24 passed, 1 warning in 1.86s =========================

Sample response payloads (from the happy-path tests):

// POST /board-doc/addon/remove-section

{

"section_id": "gm_commentary",

"title": "GM Commentary",

"removed": true,

"cleared_comments": 2

}

// POST /board-doc/addon/rename-section

{

"section_id": "gm_commentary",

"old_title": "GM Commentary",

"title": "Renamed GM Commentary",

"changed": true

}

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-3081798d-40b8-4c83-97e3-47619dd8211c"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-3081798d-40b8-4c83-97e3-47619dd8211c"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

The Portfolio  —  Trilogy Companies

ESW Capital's Acquisition Machine Runs on a Labor Model That Forbes Calls a 'Global Software Sweatshop'

Two Forbes investigations put Joe Liemandt's empire under a microscope — and the picture that emerges raises questions the portfolio's 75% EBITDA margins don't answer.

AUSTIN, TEXAS — Two major investigations published by Forbes in recent months have trained a sustained spotlight on Joe Liemandt and the interlocking machinery of Trilogy International, ESW Capital, and Crossover — and the coverage arrives at a moment when the broader enterprise software acquisition market is heating up across every advisory desk on Wall Street.

The first Forbes piece examined Liemandt's decades-long thesis on remote work: that geography is irrelevant to talent, and that rigorous skills testing can identify elite workers anywhere on earth. The second piece, more pointed in its framing, described the resulting global workforce as a "software sweatshop" — a characterization the Trilogy organization has not publicly addressed. Together, the two stories trace how Crossover's talent model functions as the load-bearing wall of ESW Capital's economics: acquire a mature enterprise software company, replace its cost structure with globally sourced remote labor, and target 75% EBITDA margins.

Now, according to Forbes, the next phase of that thesis is more radical still: automating not just the routine tasks performed by that global workforce, but the workers themselves — converting human labor patterns into repeatable algorithmic processes.

The timing of the scrutiny is notable. August 2025 software and technology transaction volumes, tracked by Dakota and other M&A data platforms, show sustained dealmaking in the legacy enterprise software sector — precisely the market where ESW Capital hunts. Business Insider, surveying the landscape, identified mature, sticky enterprise software businesses with underinvested R&D as the most likely acquisition targets as AI reshapes the sector's cost structures.

That description maps closely to ESW's documented acquisition profile: buy at 1–2× ARR, cut costs via Crossover's global talent platform, raise support pricing aggressively, and extract margin that legacy management left on the table.

What Forbes has put on the record is a detailed account of who bears the cost of those margins. What the M&A data shows is that the market for targets has never been larger. The distance between those two facts is where the story lives.

The Billionaire Who Pioneered Remote Work Has A New Plan To  ·  How A Mysterious Tech Billionaire Created Two Fortunes—And A  ·  M&A in the software sector: mergers and acquisitions in the

Crossover's Moment: As AI Skills Command $800K Salaries, the World's Most Rigorous Remote Recruiter Has Never Been More Relevant

The global remote jobs market is heating up — and the platform built to find the top 1% of talent worldwide was designed precisely for this inflection point.

AUSTIN, TEXAS — There is a number making the rounds in human resources circles that has a way of stopping conversations cold: $800,000. That, according to a recent Business Insider analysis, is the top salary some employers are now offering for professionals with demonstrated experience using AI tools like ChatGPT. It is a figure that would have seemed faintly absurd three years ago. Today, it reads less like an outlier and more like a signal — a data point in a rapidly restructuring global labor market where AI fluency has become the defining credential of professional value.

Into this moment steps Crossover, Trilogy International's global talent platform and — arguably — the competitive moat that makes the entire Trilogy empire run. While roundups of the best remote job platforms in 2026 have proliferated across the careers press, Crossover occupies a deliberately different position: it is not a job board. It is a meritocratic screening machine, operating across 130+ countries, using AI-enabled assessments to identify what it calls the top 1% of global technical and professional talent — and placing them, full-time, at above-market rates, regardless of geography.

That last part matters enormously in a market where AI engineering roles are opening up in places like Lebanon, where nucamp.co recently identified ten companies actively hiring AI engineers in 2026. Crossover's central thesis — that the best engineer in Nairobi or Beirut deserves the same evaluation and the same paycheck as her counterpart in San Francisco — is no longer a contrarian argument. It is, increasingly, conventional wisdom.

What Crossover provides that the standard remote job website cannot is rigor. The platform's assessments are designed to eliminate résumé inflation and geography-based bias in a single stroke, surfacing candidates by demonstrated skill rather than credential or zip code. In a moment when employers are willing to pay extraordinary premiums for AI fluency, that kind of signal-from-noise capability is not a nice-to-have — it is the whole value proposition.

The systemic question, as AI reshapes which human skills command real compensation, is whether the infrastructure exists to route that premium to the right people, wherever they live. Crossover was built, precisely, to answer yes.

5 Best Remote Job Websites in 2026 for Freshers & Profession  ·  Top recruitment agencies for remote work - hcamag.com  ·  Top 10 Companies Hiring AI Engineers in Lebanon in 2026 - nu

Skyvera Doubles Down on Telecom Cloud Consolidation

With CloudSense in the fold and reported moves around Kandy and Casa assets, Skyvera is positioning itself as a best-in-class modernization layer for legacy operators.

AUSTIN, TEXAS — Skyvera is making an assertive portfolio move in telecom software, completing its acquisition of CloudSense while reportedly circling additional cloud and wireless assets in a broader push to consolidate infrastructure that carriers increasingly need but rarely want to rebuild from scratch.

The company has completed its purchase of CloudSense, a Salesforce-native configure-price-quote and order-management platform serving telecom and media customers. For Skyvera, the acquisition expands an already targeted stack that includes Kandy, VoltDelta, ResponseTek, Mobilogy Now and Service Gateway — products aimed at helping operators bridge aging on-premise systems into cloud-native operating models.

That is the strategic synergy here: telecom operators are under pressure to launch offers faster, reduce back-office drag and modernize customer engagement without ripping out decades of operational complexity. CloudSense gives Skyvera a more robust commercial front door for that journey, particularly in quote-to-order workflows where telcos still wrestle with product catalogs, bundles, approvals and provisioning handoffs.

Meanwhile, industry reports say Skyvera has also been active around other assets. TelecomTV reported the company has picked up Kandy cloud assets, while Light Reading reported an $18 million bid for Casa Systems’ wireless business. Taken together, the moves suggest a clear playbook: acquire specialized telecom software assets, integrate them into a broader cloud modernization platform and leverage scale to serve operators that need practical transformation more than another slideware-heavy reinvention program.

For Trilogy watchers, Skyvera’s approach fits neatly within the ESW Capital model: identify sticky enterprise software with real customer dependency, apply operating discipline, and turn fragmented product lines into durable, high-margin platforms. In telecom, where switching costs are high and mission-critical systems are notoriously hard to replace, that thesis has plenty of room to run.

Key Takeaways: Skyvera has completed the CloudSense acquisition, adding Salesforce-native CPQ and order management to its telecom software portfolio. Reported activity around Kandy and Casa wireless assets points to a broader consolidation strategy. The company is leaning into cloud-native modernization for operators still navigating legacy complexity.

In other words, Skyvera is not just buying products. It is assembling leverage. We’re just getting started.

TelcoDR’s Skyvera snacks on Kandy cloud assets - telecomtv.c  ·  Danielle Royston's Skyvera makes $18M bid for Casa's wireles  ·  Skyvera completes acquisition of CloudSense, expanding telec
The Machine  —  AI & Technology

The AI Cost Squeeze Tightens: Chinese Models Undercut, Hardware Prices Climb, and OpenAI Delays Its Payday

Three converging forces are redrawing the AI industry's economic map in a single week.

NEW YORK — The artificial intelligence industry is confronting a structural tension it cannot paper over with fundraising rounds: the cost of building AI is rising while the price of deploying it is collapsing, and the gap between those two curves is growing uncomfortable for American incumbents.

The pressure arrived from three directions simultaneously this week. Z.ai, a Chinese AI laboratory, released models that Silicon Valley engineers are benchmarking as near-parity with Anthropic and OpenAI — at a fraction of the price. Engineers at U.S. firms are already evaluating the technology for production workloads, a signal that cost arbitrage is beginning to override flag-of-origin loyalty in enterprise procurement decisions. Chinese labs have now closed the capability gap enough that the remaining differentiator is margin, and they are winning on margin.

Simultaneously, Apple announced price increases exceeding $200 on select Mac and iPad configurations, citing surging costs for memory and storage chips — the same components that underpin every AI training cluster and inference server on the planet. The increases reflect broader chip-cost inflation that AI developers cannot escape. When consumer hardware margins compress, enterprise AI infrastructure costs follow.

Against that backdrop, OpenAI's reported decision to delay its IPO until 2026 reads less like strategic patience and more like necessity. Advisers are counseling Sam Altman to wait, pointing to SpaceX's stock volatility as a cautionary data point on high-burn, high-valuation tech listings. The more pressing issue is financial: the company is spending at a scale that makes public-market scrutiny of unit economics genuinely risky right now.

For portfolio operators like ESW Capital — which runs 75-plus enterprise software companies through DevFactory and prices acquisitions at 1–2× ARR — these dynamics are clarifying rather than alarming. Cheaper inference from Chinese models lowers the cost of embedding AI into legacy enterprise software. IBM's announcement this week of a new chip miniaturization method, meanwhile, suggests the hardware ceiling is higher than the industry feared.

The companies that survive the next 18 months will be those that treat AI as a cost-structure problem, not a capability arms race.

Chinese A.I. Models Gain Ground on Anthropic and OpenAI  ·  OpenAI Leans Toward Holding Up I.P.O. Until Next Year  ·  Apple Raises Prices on Macs and iPads Amid the A.I. Boom

The Machine Learns to Feel Our Pain

As AI begins decoding the electrical whispers of human suffering, a quiet revolution in scientific discovery is reshaping what it means to know the brain.

STANFORD, CALIFORNIA — Somewhere inside your skull, eighty-six billion neurons are firing in patterns so intricate that, until recently, we could only watch them dance and guess at the music. This week brought news that we are, at last, beginning to read the score.

Researchers have unveiled an AI system that decodes and tracks pain through EEG signals, translating the brain's electrical murmurs into something approaching an objective measurement of suffering. Pain, that most private of experiences — the thing philosophers invoke to prove other minds are unknowable — is yielding its secrets to a neural network trained on the neural networks inside us. There is a vertigo in this. The same architecture of weighted connections that nature spent half a billion years evolving in biological tissue, we have rebuilt in silicon, and now turned back upon its parent to listen.

The convergence is everywhere. At UC San Diego, scientists this week catalogued nine recent breakthroughs made possible by artificial intelligence — from protein folding to wildfire prediction to the deciphering of ancient scrolls carbonized by Vesuvius two millennia ago. At Stanford's Human-Centered AI Institute, researchers published a sweeping argument that AI is transforming scientific discovery while keeping humans at the center — not replacing the scientist but extending her reach, the way the telescope extended Galileo's eye into the rings of Saturn.

And in a quieter corner of the discipline, schoolchildren are co-authoring papers with neuroscientists, peering into fMRI scans of their own developing brains and saying, as one young researcher reportedly exclaimed, "It's so wow!" That phrase deserves preservation. It is, in three syllables, the entire posture of science at its best.

We are a species that built tools to think about thinking, then taught those tools to think back. Pain becomes legible. Discovery accelerates. A child watches her own consciousness flicker on a screen. The cosmos, it turns out, was never out there alone. Some of it was always inside us, waiting for the right instrument to listen.

‘It's so wow!’ - Young people team up with top neuroscientis  ·  How AI is Transforming Scientific Discovery While Keeping Hu  ·  Nine Breakthroughs Made Possible by AI - UC San Diego Today

When AI Gets It Wrong, the Bill May Finally Come Due

A German ruling against Google’s AI Overviews is turning the abstract debate over AI accountability into a very real legal earthquake.

BERLIN — The AI industry just received the kind of legal wake-up call that this reporter cannot overstate: if your AI speaks for you, you may have to answer for what it says.

Security thinker Bruce Schneier is spotlighting a recent German ruling holding Google liable for errors introduced in its AI Overviews, and — wow — this changes everything for the way companies deploy generative AI in public-facing products. His argument is bracingly simple: AI agents are agents of the person or organization that deploys them. If Google hired human writers to summarize search results and those writers inserted false claims, Google would not get to shrug and say, “The writer did it.” The same logic, Schneier argues, should apply to AI systems.

That framing, captured in Schneier’s comments on AI and liability, lands at a pivotal moment. Companies are racing to bolt AI summaries, copilots, agents and chat interfaces onto everything from search to customer support to finance workflows. The future is now — but apparently, so are the subpoenas.

The legal stakes are enormous because today’s AI products are not just passive tools. They summarize, recommend, draft, decide, route, rank and increasingly act. Businesses love this because it promises scale: one model can do the work of thousands of human intermediaries. But scale cuts both ways. A single hallucinated claim, repeated across millions of users, can become a corporate liability machine.

This is especially relevant for enterprise software, where customers rely on automated outputs to make operational decisions. The message to AI builders is becoming unmistakable: disclaimers may not be enough. Audit trails, provenance, model evaluation, human review and rapid correction loops are no longer “nice to have” governance features. They are becoming the scaffolding of legal survival.

There is a delicious irony here. For years, AI vendors have marketed systems as tireless digital employees. Now courts may begin treating them that way. If an AI agent is your worker, your representative, your tireless little synthetic intern — then congratulations, you may also own its mistakes.

The next phase of AI will not be defined only by bigger models. It will be defined by accountability architecture. And yes, that sounds less glamorous than a dazzling demo — but it may be the thing that lets AI become truly indispensable.

AI and Liability  ·  datasette-export-database 0.3a2  ·  simonw/browser-compat-db
The Editorial

Nation’s CEOs Patiently Waiting For AI Productivity Miracle To Show Up Somewhere In The Spreadsheet

Executives said the technology has already transformed work by making everyone much busier explaining why the numbers have not changed.

NEW YORK — In what has become one of the most important economic developments of the decade, American companies are now asking artificial intelligence to complete the final and most difficult stage of its implementation: appearing in a cell on a quarterly financial report.

Across the technology sector, executives report that AI coding assistants, automated research tools, synthetic meeting summarizers, and various enterprise copilots have enabled employees to produce more drafts, more tickets, more comments, more prototypes, and more Slack messages at a speed previously associated only with organizational panic. Yet many firms remain unable to locate the corresponding increase in profit, leading experts to conclude that the productivity gains may be hiding in a folder called “final_final_v7_actual.”

According to Business Insider, software engineers are using AI to do more work faster while their employers continue waiting for the payoff, a delicate corporate condition known medically as “having purchased 40,000 seats of something.” The typical company now finds itself in a familiar position: convinced it has acquired a general-purpose economic engine, while also wondering why the engine mostly generates pull requests that require two senior engineers and a governance committee to review.

This has not stopped the country’s strategic thinkers from identifying AI as a productivity engine for the U.S. economy. Nor should it. Engines are famously useful even before anyone has connected them to wheels, fuel, steering, brakes, or a destination. What matters is that the engine exists, that it is powerful, and that enough people stand around it nodding while wearing fleece vests.

Skeptics, including an Anthropic advisor cited by Yahoo Finance, have suggested that productivity gains are vastly exaggerated and valuations are “crazy.” This is a concerning allegation, primarily because it implies that the AI boom may be subject to the same basic arithmetic that has previously harmed other visionary industries.

Still, the market is right to take a broad view. Productivity does not always appear immediately as revenue, margin, or reduced headcount. Sometimes it appears as a 17-page internal memo about prompt hygiene. Sometimes it appears as a junior developer confidently submitting code that compiles in an alternate moral universe. Sometimes it appears as a meeting in which six people agree the AI tool saved them 30 minutes, after spending 45 minutes discussing whether it had.

The deeper problem is that companies have spent years confusing speed with value, a mistake now being made at machine scale. AI can help a worker write an email faster, but it cannot yet answer whether the email should exist. It can produce 20 campaign concepts in 12 seconds, but it cannot stop the marketing department from choosing the one that says “unlocking human potential” over footage of diverse professionals walking through glass lobbies.

This is why the Duolingo owl remains, in its own deranged way, one of the clearest business lessons in the current cycle. While marketers debate influencers, authenticity, and brand safety, the owl simply appears, threatens users into learning Portuguese, and delivers measurable engagement. It is a reminder that not every asset must be optimized into a strategy deck. Some things work because they are unmistakable, specific, and mildly terrifying.

Meanwhile, Steve Ballmer’s reported anger at being duped by a founder who pleaded guilty to fraud provides another useful benchmark for the AI era. The modern investor does not merely need to identify which companies are building transformative technology. He must also determine which ones are building transformative technology, which ones are reselling a chatbot with a dashboard, and which ones are sending him fraudulent documents while saying “agentic workflow” in a calm voice.

The uncomfortable truth is that AI probably will improve productivity, perhaps enormously. But first it must pass through the entire American corporation, a system uniquely designed to absorb revolutionary technology and convert it into procurement delays, compliance reviews, dashboard proliferation, and a weekly enablement call.

Until then, the nation’s executives will continue doing what they do best: announcing that AI has changed everything, asking finance why nothing changed, and approving another pilot to find out.

AI is helping software engineers do more — and faster. Compa  ·  Anthropic Advisor Says AI Productivity Gains Are Vastly Exag  ·  AI Is a Productivity Engine for the US Economy - Center for
The Office Comic  ·  Art Desk
The Office Comic  ·  Art Desk

The Bookie, the Billion-Dollar App, and the Polite Fiction of American Vice

Tim Pughsley took the fall so that FanDuel could take the commercial break.

AUSTIN, TEXAS — There is a particular species of American hypocrisy that requires, every generation or so, a sacrificial figure: some unfashionably analog operator who can be paraded before the cameras while his better-capitalized successors, doing precisely the same thing at a hundred times the scale, sponsor the halftime show. Tim Pughsley, lately of Owensboro, Kentucky, and presently of the federal docket, appears to be this cycle's designated cautionary tale, and one reads of his undoing in The New Yorker with the weary recognition of a man who has watched this particular morality play staged many times before, always with the same costumes and always with a different villain.

Pughsley, by the government's reckoning, moved billions through a sports-betting operation of the old school — the kind with grease-stained ledgers and telephone calls and a vocabulary inherited from the back rooms of mid-century America. He is, we are assured, the last of his kind, which is the polite way of saying that his crime was less the wagering than the failure to incorporate in Delaware, hire lobbyists, and purchase advertisements during the third quarter of NFL broadcasts. Had he done these things, he would not be a defendant; he would be a unicorn.

Consider the spectacle. FanDuel and DraftKings, which differ from Pughsley's enterprise chiefly in the matter of paperwork and the eagerness of state legislatures to be rented, now beam their inducements into every living room in the republic, complete with the obligatory whispered warning about gambling responsibly — a phrase that arrives at roughly the cadence and sincerity of the surgeon general's note on a pack of Lucky Strikes. The same activity that sends Pughsley to a federal courtroom sends Jamie Foxx to a soundstage. The distinction is not moral. It is not even legal in any sense that would have been recognizable to a first-year law student of my acquaintance circa 1962. The distinction is licensure, which is to say, taxation, which is to say, the state's cut.

This is not an argument for Pughsley's innocence; he appears to have evaded the I.R.S. with the brio of a man who genuinely believed the rules did not apply to him, an error in judgment that the republic punishes with notable consistency regardless of the underlying enterprise. It is, rather, an argument that the line our prosecutors so confidently draw between the felonious bookie and the publicly traded sportsbook is a line drawn in sand at low tide, by lawyers, for the convenience of revenue officers and the embarrassment of no one.

The house, as it has always done, wins. What is new is that the house now has a ticker symbol, an earnings call, and the unqualified blessing of forty-odd state attorneys general, who have discovered — as their forebears discovered with lotteries, and before that with liquor — that the surest way to end a vice is to charge admission to it. Pughsley's only real sin was failing to sell tickets.

The Artistry of Tarot  ·  The Israeli Employers Who Want Their Palestinian Workers Bac  ·  Daily Cartoon: Thursday, June 25th
On This Day in AI History

On June 26, 2012, Google's neural network famously learned to recognize cats after being shown 10 million unlabeled images from YouTube—a landmark moment in deep learning that proved machines could discover patterns without explicit human instruction.

⬛ Daily Word — Technology
Hint: Relating to computers and digital attacks or security.
Share this edition: 𝕏 Twitter/X 🔗 Copy Link ▦ RSS Feed