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

OpenAI's IPO Filing Lands as AI Capital Markets Enter a New, More Complicated Phase

Public markets, sovereign funds, and billionaire contrarians are all repricing AI risk simultaneously.

NEW YORK — OpenAI filed for an initial public offering this week, a move that transforms the most closely watched private company in technology into a test case for whether public markets will absorb AI valuations that were set in a zero-interest-rate, pre-revenue era. The filing arrives at a moment of unusual divergence in how capital is flowing toward artificial intelligence.

The Wall Street Journal reported that OpenAI's filing is being read as a broader referendum on investor appetite for AI startups that have raised at stratospheric valuations but have not yet demonstrated a clear path to profitability at scale. OpenAI lost an estimated $5 billion in fiscal 2024 on roughly $3.7 billion in revenue.

Elsewhere in the capital stack, Nvidia led a $300 million round in Israeli AI startup Decart at a $4 billion valuation — a deal that underscores how chipmakers are increasingly using their balance sheets to lock in strategic relationships with model developers before those companies either go public or get acquired.

Forbes released its 2026 AI 50 list this week, its annual ranking of the most promising private AI companies. The list functions as a sentiment index as much as a ranking: which categories are receiving attention, which are not, and how the definition of "promising" has shifted from pure research capability toward revenue durability.

Meanwhile, a counternarrative is forming among ultra-high-net-worth investors. Entrepreneur reports that some billionaire investors are rotating away from AI startups entirely, preferring physical infrastructure, energy, and defense — the picks-and-shovels layer that AI demand is straining. The thesis: the model layer is commoditizing faster than valuations reflect.

Canada added a sovereign dimension to the week's activity, announcing plans to take direct equity stakes in domestic AI startups alongside grant funding — a policy tool more common in biotech than software, and a signal that governments are no longer content to let AI national champions be priced and owned entirely by U.S. venture capital.

Taken together, the week's activity describes a market in transition: early-stage AI funding remains active, but the terms, sources, and risk tolerance are shifting materially as the sector moves from hype cycle into earnings cycle.

Forbes 2026 AI 50 List | Top Artificial Intelligence Compani  ·  OpenAI Files to Go Public in Test of Investor Appetite for T  ·  Are Billionaires Done Investing In AI Startups? Here's the S

CoreWeave Tests Europe’s Debt Market as AI Compute Arms Race Hits Overtime

CoreWeave, a major AI cloud provider renting high-performance computing capacity for generative AI workloads, is holding calls with European high-yield investors to evaluate financing options including dollar and euro bonds, according to Bloomberg. While no sale has been completed, the move signals the company's intent to broaden its investor base beyond traditional U.S. financing sources.

The potential euro component represents a classic expansion strategy: accessing more markets and lenders. However, high-yield investors will scrutinize CoreWeave's cash-flow durability, contract visibility and whether AI demand can sustain beyond initial enthusiasm.

CoreWeave has emerged as a signature player in the GPU cloud boom, but faces significant capital demands: infrastructure spending, debt financing, customer concentration risks and pressure to secure sufficient computing power before competitors. The financing discussions underscore how the AI buildout has become a full-contact capital cycle, with each major infrastructure player's financing serving as a readout on investor appetite for the sector's future earnings power.

White House AI Blueprint Demands Federal Supremacy, Leaving Industry and States in Legal Limbo

A new White House framework urges Congress to preempt state AI laws — but nobody has agreed on who actually holds the regulatory pen.

WASHINGTON, D.C. — Pursuant to the issuance of a comprehensive National Artificial Intelligence Policy Framework by the White House (hereinafter, "the Framework"), the Administration has formally urged Congress to enact legislation that would, notwithstanding the regulatory efforts of individual state legislatures, establish a unified federal standard governing the development and deployment of artificial intelligence technologies within the United States of America.

The Framework, the contents of which have been reviewed and analyzed by legal counsel across multiple jurisdictions, is understood to call for, inter alia: (1) a so-called "light touch" approach to federal AI oversight, wherein burdensome regulatory constraints upon industry participants would be minimized to the greatest extent practicable; (2) the preemption of state-level AI laws, which have proliferated in considerable number across various jurisdictions; and (3) certain protections for minors, the precise scope and enforceability of which remain, at the time of this publication, subject to further legislative determination.

Notwithstanding the foregoing, it must be noted — and it is hereby noted with considerable emphasis — that no definitive regulatory authority has been identified, designated, or otherwise confirmed with respect to the oversight of artificial intelligence systems as presently deployed. The question of which federal agency, bureau, commission, or body shall bear primary jurisdiction over AI-related matters remains, to the knowledge of this correspondent, unresolved.

The aforementioned Framework, as further analyzed by practitioners at Davis Wright Tremaine and Crowell & Moring LLP, represents a call to legislative action rather than an immediately operative regulatory instrument. Accordingly, the practical effect upon AI developers, deployers, and end-users shall remain, for an indeterminate period, substantially uncertain.

Industry stakeholders are advised to monitor Congressional proceedings with diligence, as the timeline for enactment of any legislation consistent with the Framework's recommendations is, at present, wholly unspecified. It is further recommended that all parties subject to or potentially subject to AI-related regulatory requirements consult qualified legal counsel prior to taking any action in reliance upon the Framework's stated policy positions, which are subject to revision, amendment, or wholesale abandonment without prior notice.

White House urges Congress to take a light touch on AI regul  ·  Nobody knows who regulates your AI yet - Spiceworks  ·  White House National AI Policy Framework Calls for Preemptin
Haiku of the Day  ·  Claude HaikuGold rush meets quicksand
Rules chase what cannot be caught
Profits bloom in fog
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
From Quantum Entanglement to Algorithmic Equity: The Week's Most Consequential Developments in Machine Intelligence
CAMBRIDGE, MASSACHUSETTS — It could be argued — and indeed, the present author shall endeavor to do precisely that — that the current moment in computational science represents what one might tentatively characterize as a period of productive epistemic turbulence, wherein foundational advances and foundational anxieties are advancing in near-perfect, if deeply uncomfortable, synchrony. Consider, as one's thesis, the accelerating convergence of quantum computing and biological inquiry.
The Week the Digital World Reminded Us It Was Never Ours to Begin With
AUSTIN, TEXAS — Let me paint you a picture of the week we just had, and then let me ask you, calmly, with my hands folded and my voice only slightly trembling: are you okay? Are any of us okay? Start with SignalTrace, a company that has decided — cheerfully, apparently, as a business decision — that license plate readers were not quite surveillance enough.
We Have Built a World That Cannot Explain Itself, and the Bots Are Loving It
AUSTIN, TEXAS — There is a moment in every great unraveling when you stop and look around and realize that the map you've been using is not just wrong — it was drawn by someone who had never seen a road.
The Office Isn’t Coming Back. The Talent Bar Is.
AUSTIN, TEXAS — I’ll be honest: the remote-work debate in 2026 has officially become the corporate equivalent of arguing whether email is a fad. Unpopular opinion: the real story is not remote versus office, it is ready versus replaceable.
Nation’s Executives Warn Not To Laugh At Obviously Stupid AI Strategy Until It Has Increased Shareholder Value
SAN FRANCISCO — The first rule of modern business is that if a strategy sounds idiotic, it is either idiotic or a visionary replatforming of customer engagement architecture, and shareholders will not know which until several quarters after the layoffs. This week offered a valuable lesson in that distinction, as several major brands and public thinkers took turns reminding the nation that the future will arrive wearing a novelty hat, making a noise, and asking to be valued at 23 times revenue. Duolingo, a language-learning company best known for being emotionally dominated by a deranged green owl, reportedly drew criticism from marketing professor Mark Ritson for placing too much emphasis on influencers rather than its own violently memorable mascot.
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

Builder Team Rewires the Financial Brain Across Four Repos

From a live School P&L that now covers 34 schools to a Redshift directory pipeline, a hardened Azure spend ingestion, and admissions dashboards that finally heal themselves — the AI Builder Team just shipped a week's worth of work in a single day.

The Builder Team didn't just ship features today. They rewired the financial nervous system of an entire organization — and they did it across four repos simultaneously.

The headline move belongs to @ashwanth1109, who orchestrated a five-PR blitz through Aerie and Surtr that transforms the School P&L dashboard from a hardcoded proof-of-concept into a living, breathing financial instrument. PRs #341 and #342 together flip the Headcount Detail Cost table and the Unit Economics per-Student cards from static Miami/Austin constants to fully dynamic, model-mapped data covering every one of the ~34 schools in the system. That's not a feature — that's a platform. Then PR #343 reverses a prior exclusion and restores Physical Private Schools and Core Education to the Edu Performance income statement, ensuring the numbers Finance sees actually reflect the business Finance runs. The backend fuel for all of it? PR #252, where @ashwanth1109 also crossed into Surtr to split headcount into proper COGS and Expenses lines at the teamroom grain, giving Aerie's drilldown the precision it needed. One engineer. Two repos. One coherent financial story.

While @ashwanth1109 was building the front end of the data pipeline, @kevalshahtrilogy was fireproofing the back. PR #254 is the kind of fix that doesn't get celebrated enough: the Azure AI spend pipeline was silently dropping subscriptions every morning at 06:00 UTC because Azure's Cost Management endpoint returns 429s with no Retry-After header, and the old exponential backoff gave up too fast. @kevalshahtrilogy replaced it with a paced, subscription-level sweep that survives the throttle window. Meanwhile, PR #246 stopped the HubSpot sync from OOM-killing its own ECS task — a self-reinforcing loop where a frozen cursor forced the pipeline to re-collect 68 days of backlog on every run. Chunked loads and a capped delta window ended that cycle for good. Infrastructure wins don't make the highlight reel. They make everything else possible.

Over in Klair, @eric-tril had a quietly excellent day. PR #2975 makes the Software memo stream section-by-section and run its reconciliation queries in parallel — Finance stops staring at a blank screen and starts seeing data in one to two seconds. PR #2977 is a precision accounting fix: Schedule C1 was excluding sale-reversal rows on account 71251, overstating unrealized gains. One filter removed. Reconciliation restored. That's the kind of work that earns trust with a CFO.

And then there's @sanketghia's PR #255 in Surtr, which lands the email-to-business-unit directory in Redshift — a clean, standalone pipeline that walks Gmail accounts through AD usernames through XO all the way to finance_team, so every AI spend record can be attributed to the right BU. The org has been flying partially blind on cost attribution. Not anymore.

Now. About PR #2974. marcusdAIy shipped a Budget Bot access-hardening PR that moves per-BU authorization server-side. Fine. It works. When reached for comment, he said: 'Server-side enforcement isn't glamorous, Mac, but unlike your takes, it actually prevents unauthorized access — and yes, I added the guardrail you would have asked about in review if you'd ever actually read a PR body.' Sure, Marcus. The guardrail is nice. The rest of us will be over here shipping dashboards that cover thirty-four schools.

Mac's Picks — Key PRs Today  (click to expand)
#254 — fix(azure-ai-spend-pipeline): harden Cost Management 429 handling + pace subscription sweep @kevalshahtrilogy  no labels

## Why

The azure-ai-spend-pipeline 06:00 UTC run keeps recording partial_failure (e.g. run afd9f3ed… on 2026-06-09 dropped 4/10 subscriptions). The cause is Azure Cost Management 429 throttling at the tenant scope: it frequently returns 429 with no Retry-After header, so the previous pure-exponential backoff (2/4/8/16/32s ≈ 62s) gave up while the throttle window was still open, and whole subscriptions were skipped.

This is *not* a cross-pipeline cron collision — the OpenAI/Anthropic pipelines hit different endpoints and don't share Azure's Cost Management quota. It's the pipeline's own back-to-back 10-subscription sweep exhausting the tenant quota.

## What

azure_client._make_request

- Honor a server retry hint from Retry-After *and* Azure's vendor headers (x-ms-ratelimit-microsoft.costmanagement-*).

- A 429 with no hint now waits a 15s throttle floor instead of the short exponential ramp, so the window can actually reset.

- MAX_RETRIES 5→6, backoff capped at 60s, and no sleep on the final attempt (protects the 900s Lambda budget — worst case ~93s/failed call instead of blowing the timeout).

handler

- Pause INTER_SUBSCRIPTION_DELAY_SECONDS (default 5s, env-tunable; 0 disables) between subscriptions so the shared tenant quota recovers between sweeps.

## Scope / limits

This *reduces* the 429 drop-outs; it does not guarantee zero. If the tenant Cost Management quota is fundamentally too small for 10 subs within 900s, the real lever is a quota increase or splitting the sweep. The PartialFailureError from #219 still surfaces any residual partial failure loudly (so this composes with, not replaces, that fix).

## Tests

- 66/66 pass (uv run pytest), incl. 4 new: throttle-floor on hint-less 429, vendor Retry-After header honored, no-sleep-on-final-attempt, inter-subscription pacing.

- ruff check + ruff format clean.

Relates to issue #218 / follows up #219.

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

#255 — feat(esw-people-accounts-sync): new pipeline syncing email→BU directory from pods_ods MySQL @sanketghia  no labels

Standalone Change B, branched cleanly off mainno dependency on Change A (the openai-cost user-grain change in #249). This supersedes the stacked #253 so the directory pipeline can proceed and be tested independently.

## What it does

Lands an email → business_unit directory in Redshift so OpenAI (and later other providers) can resolve each spender's real BU. Each run:

1. Reads pods_ods MySQL via the stakeholder BROAD query (gmail account → ad_username → xo_all → finance_team).

2. Normalizes: lowercases email, derives email_local (downstream domain-alias fallback), dedupes on email (last-wins, logged).

3. Aborts if the query returns zero rows (preserves the prior snapshot — no silent wipe).

4. Full TRUNCATE+INSERT into staging_gsheets.esw_people_accounts (~1,555 rows).

## ✅ Production safety — inert on its own

This PR has no negative production effect by itself:

- Brand-new pipeline, ships enabled: false → never runs, writes nothing.

- Touches no existing table or query — the OpenAI cost pipeline and the fct_ai_spend mart are untouched.

- Nothing consumes esw_people_accounts yet (the downstream join is separate Klair work), so the new (empty) table changes no current behavior.

## Why BROAD (measured)

Tested both candidate queries against the real OpenAI spender emails (May 2026): BROAD = 91.4% of spend on exact email vs 83.2% for the simpler person.company_email query. All 31 canonical budget BUs present in finance_team.business_unit.

## 🚧 Deploy blocker — Lambda VPC (infra owner)

The DB host aurora11.aureacentral.com is a private IP (10.69.26.171); the CDK Lambda construct (pipelines/cdk/lib/constructs/pipeline.ts PythonFunction) attaches no VPC, so the deployed Lambda can't reach it until infra adds VPC support for Lambda pipelines (subnets + SG with a route to the DB). Connects fine from the corp network for local validation. Pipeline stays enabled: false and hard-fails to connect until VPC is wired (no silent-success fallback).

## Manual steps before enabling

1. Add Lambda VPC config (the blocker above) — infra owner.

2. Run ddl/create_esw_people_accounts.sql once against Redshift (write access; staging_gsheets exists, table doesn't).

3. Confirm the Lambda role can read secret crossover-users-teams-bus-info (IAM in pipeline.json already grants it).

4. Flip schedule.enabled to true (cron(0 5 * * ? *)).

## Tests & validation

uv run pytest10 passed. ruff clean. The DB is faked offline; tests assert the BROAD query is issued, normalization, dedupe, empty-guard, conn-close (happy + abort paths), and loaded_at stamping.

scripts/dryrun_directory.py is a read-only harness that runs the real build_connection + fetch_directory against the live DB and prints what would be inserted, without any write. Validated live: 1,555 clean rows, 36 canonical BUs, 0 blank, the 1 known dup deduped.

## Relationship to other PRs

- #253 (the stacked version of this change) is now draft — superseded by this standalone branch.

- #249 (Change A, cost pipeline user-grain) is draft — it must NOT merge before the Klair re-key (it would silently break OpenAI BU attribution; project_id → NULL breaks 102 overrides + the token join). This Change B PR is independent of that.

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

#341 — AERIE-354 feat(dashboards): make Headcount Detail Cost ($) table live for all model-mapped schools @ashwanth1109  no labels

## Demo

<img width="2624" height="1644" alt="image" src="https://github.com/user-attachments/assets/329b16d2-6272-43ef-ad17-1cfa6012c5ee" />

## Overview

Makes the "Headcount Detail Cost ($)" table in the School P&L dashboard (Dashboards › Financials › School P&L → *Unit Economics Comparison*) live and data-driven, replacing the hardcoded Miami/Austin constants so it renders for every school with a unit_economics_model mapping (~34 schools). The table compares per-role labor cost (Lead Guides / Guides / Head of School / Coordinator) across six columns — Current Run Rate, Model @ Current, Run Rate @ SY26/27, Model @ SY26/27, Run Rate @ Capacity, Model @ Capacity. Both halves are now driven from real data: model columns from the per-tier model CSVs selected via campusQbEntityMappings.unitEconomicsModel, and run-rate columns from the live getHeadcountByRoleForCell Convex query. Scoped to the headcountDetailCost band of UnitEconomicsComparisonTable only — the sibling per-Student / Annualised cards and their section-level gate are untouched.

Linear: [AERIE-354](https://linear.app/builder-team/issue/AERIE-354/school-pandl-make-headcount-detail-cost-dollar-table-live-model-csvs)

## Specs

| # | Spec | Description |

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

| 01 | model-columns-tier-scale-parser | Adds getModelHeadcountByRole(unitEconomicsModel) to unit-economics-model.ts: parses <tier> · <scale> → per-role {count, salary} for Lead Guides / Guides / HoS / Coordinator across all tiers (alpha-40k / 50k / 65k / 75k / anywhere), lifting the formerly-only-wired alpha-50k @ 250 pattern to every tier. Returns null for unknown/malformed strings so the consumer degrades gracefully. MODEL_50K_250 / MIAMI_MODEL_SCALES kept intact for sibling consumers. |

| 02 | run-rate-live-and-visibility | Rewires the headcountDetailCost band of unit-economics-comparison-table.tsx to live data and makes the card render for every model-mapped school. Consumes spec 01's parser for the model columns; the visibility decouple and graceful degradation live here. |

Spec 02 depends on spec 01 (consumes its parser).

## Implementation

- Model columns → per-tier CSVs. Model cost per role = count × salary × 1.15 (XO Factor), sourced from spec 01's parser at the school's own tier+scale — so each school shows its own tier's salaries (a $40K school shows Lead $150K / Guide $100K / HoS $200K / Coord $60K), not the universal $50K numbers. When the parser returns null, model columns render rather than crashing.

- Run-rate columns → live QB actuals. Wires the existing getHeadcountByRoleForCell query (cost from plMonthlyRecords, memo-attributed head count from plTransactions / xoContractorIdentity) instead of HEADCOUNT_RATES_BY_SCHOOL + getManualHeadcount. Contracted-Labor accounts fold 60211 → Lead Guides, 60212 → Guides, 60220 → Coordinator; all other 6021060270 prefixes are excluded from this four-role band. Head of School has no dedicated CL account, so its run-rate is $0 / 0 by design (model-only). The Run Rate @ SY26/27 and Run Rate @ Capacity columns preserve the existing "variable scaled, fixed flat" projection (cost × target/current per role), re-expressed on each school's own live run-rate base — Miami and Austin stay numerically consistent with today.

- Visibility. The card's render is decoupled from the 2-school hasManualHeadcountData gate in financials-view.tsx and gated on unitEconomicsModel presence (resolved from the already-loaded getCampusQbEntityMappings result). The sibling cards keep their existing gate.

- Graceful degradation. A role with cost but no attributable head count shows the cost with an explicit n/a derived rate (no divide-by-zero). A model-mapped school with no Contracted-Labor activity (pre-operational, e.g. Alpha Palo Alto) renders run-rate roles at $0 / 0 — no crash, no Miami fallback. A school with no unitEconomicsModel does not render the card.

- Cleanup. Refreshed the stale pl-transactions sync allow-list comment in getHeadcountByRoleForCell (the allow-list was removed; empty rows now mean genuinely no CL activity).

## Test coverage

62 unit tests passing:

- unit-economics-model.test.ts — 26 tests for the parser (per-tier/scale resolution, four-role mapping, pre-markup salaries, unknown-tier/scale degradation).

- unit-economics-comparison-table.test.ts — 36 tests for the band (prefix→role fold, derived-rate n/a degradation, SY26/27 + Capacity projection). Spec 02 included a behavior-preserving refactor exporting pure helpers (foldRunRateRoles, derivedRate, buildHeadcountCostBand) for testability.

## Self-review

One MINOR finding addressed: stale comments in headcount-miami-data.ts referencing the removed HEADCOUNT_RATES_BY_SCHOOL were refreshed (comment-only; the data constants are unchanged and still feed the sibling cards).

## Note to reviewer — run the sync twice on a fresh dev start

This card gates on campusQbEntityMappings.unitEconomicsModel, which the campus-qb-entity-refresh worker syncs into Convex from Redshift. On a fresh dev start the worker's boot backfill can race the convex dev push and lose: the first run upserts unitEconomicsModel while Convex is still deploying the updated upsertCampusQbEntityMappings validator, so every record is rejected (ArgumentValidationError: extra field 'unitEconomicsModel' not in the validator) and the field never lands. With no unitEconomicsModel in Convex, the card correctly renders for no school.

So run/restart the worker twice: the first run deploys the updated validator (its upsert may fail against the still-deploying/stale validator); after Convex logs ✔ Convex functions ready!, restart the financial worker once more so the actual sync writes the field. A healthy second run logs campus-qb-entity-refresh … tick complete … clean: 62 records (not degraded: error). Once synced, the card renders for every model-mapped school (e.g. Alpha Anywhere Center → alpha-65k · 250, Alpha Miami → alpha-50k · 250). This is a worker/Convex deploy-ordering quirk in local dev, not a behavior of the feature code itself.

## Status

Implemented, tested, CI green — ready for review. All CI checks passing (Build, Docker Build Chat/Worker, Lint + Boundaries, Secret Scan, Test, Typecheck). Both feature specs are marked Completed and the FEATURE.md changelog is in sync.

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

#342 — AERIE-355 feat(dashboards): make Unit Economics per-Student & Annualised cards live for all model-mapped schools @ashwanth1109  no labels

> ⚠️ Stacked PR — do not merge to main directly.

> This PR is stacked on feat/school-pl-unit-economics (#341), _not_ on main. The diff shown here is only AERIE-355's delta on top of #341. Merge order: land #341 first, then rebase this branch onto main before merging. Until then the comparison base is the #341 branch.

Linear: AERIE-355 — https://linear.app/builder-team/issue/AERIE-355

## Demo

<img width="2624" height="1644" alt="image" src="https://github.com/user-attachments/assets/3f85bb1a-830f-4862-b3f1-0e05b4b9cd20" />

## Overview

Finishes the Unit Economics Comparison section of the School P&L dashboard by making the "Unit Economics per Student" and "Unit Economics Annualised" sibling cards live and data-driven for every school with a unit_economics_model mapping (~34), instead of only Alpha Miami / Austin K-8. Both cards render from a single deriveUnitEconomicsTable(...) call whose model side now comes from the school's own tier+scale CSV and whose run-rate Headcount line comes from live QB Contracted-Labor actuals.

## Specs in this PR

| Spec | Status | Description |

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

| [03-full-tier-model](features/dashboards/school-pl-unit-economics/specs/03-full-tier-model/spec.md) | Completed | Adds getModelPerStudent(unitEconomicsModel, students): ModelPerStudent \| null to unit-economics-model.ts, reading tier+scale economics (Tuition, Net Facility/student, Programs/student, Apps, CapEx, Timeback, + headcount totals) from the model tables (mirroring data/models/{tier}.csv). Replaces the $50K hardcodes & MODEL_50K_250. Facilities/Apps/CapEx are number \| null (null = n/a for the reduced alpha-anywhere model); unknown/malformed model string → null. |

| [04-sibling-cards-live-and-gate](features/dashboards/school-pl-unit-economics/specs/04-sibling-cards-live-and-gate/spec.md) | Completed | Wires the live run-rate roster (foldRunRateRoles over QB getHeadcountByRoleForCell) + the spec-03 tier model into deriveUnitEconomicsTable; adds modelHeadcountCostByRole; flips showModelComparisonCards from hasHeadcountData to hasUnitEconomicsModel; makes the $50K/$200K copy & formula strings tier-aware; handles graceful $0/0 + divide-by-zero; renders alpha-anywhere n/a lines as "—". Also threads unitEconomicsModel through financials-kpi-cards.tsx to keep the shared deriveUnitEconomicsTable signature compiling. |

## What changed

- Full tier-aware modelgetModelPerStudent reads every per-student line from the school's own tier+scale CSV (alpha-40kalpha-anywhere), replacing the $50K-hardcoded constants and MODEL_50K_250 as the model data source. An alpha-40k school now shows $40K tuition / $150K Lead salary / its own facilities/programs/apps/capex.

- Live run-rate roster fold — the run-rate Headcount line, per-role breakdown, and roster-scaling inputs to deriveUnitEconomicsTable (headcountAnnualisedTotal, headcountRoleAnnualised, headcountRoleCounts) are now folded out of the live getHeadcountByRoleForCell query via AERIE-354's foldRunRateRoles helper (60211→leadGuides / 60212→guides / 60220→coord), replacing getManualHeadcount(school). All other run-rate lines and the "variable scaled, fixed flat" SY26/27 + Capacity projection are preserved on the school's own live base.

- Gate flipshowModelComparisonCards in financials-view.tsx changes from hasHeadcountData to hasUnitEconomicsModel, so the two sibling cards render for every model-mapped school.

- Tier-aware copy — the shared MODEL_SOURCE.tier subtitle and the formula strings in unit-economics-comparison-derive.ts that hardcoded "$50K"/"$200K"/etc. are now tier-aware.

- Graceful degradation — a model-mapped school with no Contracted-Labor activity renders the run-rate Headcount line at $0 / 0; scaleRosterToStudents / ceilWithGrace never divide by zero or produce NaN/Infinity when live counts are 0 but cost is > 0; alpha-anywhere n/a lines render as "—" (no fabricated $0).

## Schools enabled

The gate is purely data-driven — unit_economics_model != null on the school's campusQbEntityMappings row (sourced from Redshift finance_dw.core_education.map_campus_qb_entities). No hardcoded list, so the card set tracks the mapping table automatically. As currently mapped that is 34 schools: 2 already live, 32 newly enabled by the gate flip.

Already live (unchanged): Alpha Miami (alpha-50k · 250), Austin K-8 (alpha-40k · 250).

<details>

<summary><b>32 newly-enabled schools</b> (school → tier · scale)</summary>

| School | Model (tier · scale) |

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

| Alpha Anywhere Center | alpha-65k · 250 |

| Alpha Boston | alpha-65k · 25 |

| Alpha Chantilly | alpha-65k · 25 |

| Alpha Charlotte | alpha-50k · 25 |

| Alpha Chicago | alpha-65k · 1000 |

| Alpha Dorado | alpha-50k · 25 |

| Alpha Fort Lauderdale | alpha-50k · 250 |

| Alpha Fort Worth | alpha-50k · 25 |

| Alpha Kirkland | alpha-50k |

| Alpha Lake Forest | alpha-50k |

| Alpha Los Angeles | alpha-65k |

| Alpha Orange County | alpha-50k · 25 |

| Alpha Palm Beach | alpha-50k · 25 |

| Alpha Palo Alto | alpha-75k · 25 |

| Alpha Park City | alpha-40k · 250 |

| Alpha Piedmont | alpha-65k · 1000 |

| Alpha Plano | alpha-50k · 25 |

| Alpha Raleigh | alpha-50k · 25 |

| Alpha Roswell | alpha-40k · 250 |

| Alpha San Francisco | alpha-75k · 25 |

| Alpha Santa Barbara | alpha-50k · 25 |

| Alpha Santa Monica | alpha-65k · 25 |

| Alpha Scottsdale | alpha-40k · 250 |

| Alpha Tampa | alpha-40k |

| Alpha The Woodlands | alpha-40k · 250 |

| Brownsville K-8 | alpha-50k · 25 |

| GT Anywhere | alpha-anywhere · 2000 (reduced model — Facilities/CapEx/Apps render as "—") |

| Montessorium | alpha-40k · 25 |

| Nova Academy Austin | alpha-40k · 25 |

| Nova Academy Bastrop | alpha-40k · 25 |

| Texas Sports Academy | alpha-40k · 250 |

| Waypoint Academy | alpha-40k · 25 |

</details>

## Test coverage

- Spec 03 — 11 unit tests for getModelPerStudent in unit-economics-model.test.ts (non-$50K tier economics, alpha-anywhere n/a Facilities/CapEx/Apps, unknown-model null degradation, per-line sourcing).

- Spec 04 — 5 new derive tests in unit-economics-comparison-derive.test.ts covering the three required cases (non-$50K tier, cost-without-count, pre-operational $0/0) plus extras (alpha-anywhere null lines, unknown-model).

- pnpm typecheck clean; biome clean; full suite green (72/72 in the two affected test files; repo-wide 4696 tests pass).

## ⚠️ Needs sign-off

Two deliberate Miami/Austin numeric shifts (the ticket already anticipates these needing sign-off):

1. Run-rate Headcount line → live QB Contracted-Labor. The run-rate Headcount line moves from the manual Miami/Austin roster (getManualHeadcount) to live QB Contracted-Labor actuals. This is a deliberate ~$4K/quarter divergence (the manual roster and QB CL differ by ~$4K/quarter), mirroring the change already shipped for the Headcount Detail Cost card in #341.

2. Model Headcount role counts → fixed scale-token counts. The model Headcount role counts now come from the fixed-per-scale-token model table (e.g. alpha-50k · 250 → 25 staff) instead of the legacy dynamic students/62.5 (~17 for Miami). This is consistent with #341's already-live Headcount Detail Cost card, but it also shifts the out-of-scope KPI cards' model EBITDA for Miami/Austin (those cards consume the same deriveUnitEconomicsTable).

## Deferred (follow-up cleanup ticket)

Per the ticket, the dead Miami/$50K scaffolding is left in place in this PR and retired in a separate follow-up cleanup ticket:

- getManualHeadcount / HEADCOUNT_RATES_BY_SCHOOL

- MODEL_50K_250

- headcount-miami-data.ts

- the now-redundant hasHeadcountData gate

(computeModelPerStudent is also retained because the out-of-scope HC-Count-by-Role consumer still calls it.)

## CI

CI does not run on this PR while it is stacked — the repo's ci.yml only triggers on PRs targeting main/production, and this PR targets feat/school-pl-unit-economics. CI activates once the stack rebases onto main (after #341 merges). Verified locally instead: pnpm typecheck, biome, and the full test suite are green.

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

#2975 — feat(mfr): faster Software memo — streaming, fewer requests, parallel P&L @eric-tril  no labels

## Summary

Improves the Software memo (Monthly Financial Reporting) load UX and latency — mirroring the Group memo — without changing any reported figures. The memo streams in section-by-section (like Group), fires fewer/cleaner requests, and the heavy Software P&L pipeline runs its reconciliation queries concurrently instead of serially.

## Business value

Finance opens the Software memo and sees the light content (Balance Sheet, ARR, commentary, MD&A charts) paint in ~1–2s instead of waiting on the slowest table, with a hard guarantee that switching period never flashes the previous period's numbers. The Income Statement / EBITDA / Cash Flows get materially faster on cold loads because their P&L adjustment queries now run in parallel.

## What changed

Client

- Per-section streaming / no-flash. Each statement table, commentary section, the Notes block, the FH Summary Financial Results table, and the ARR Snowball render via key-stamped tableStatus skeletons and stream in independently — no monolithic loading gate. A period switch shows skeletons, never stale values.

- Request hygiene. software-retention-by-bu + software-arr-gap-summary now route through dedupedGet. useMDAAIImpact moved off a raw fetch() onto the shared apiClient — fixes the Authorization: Bearer null case, restores the X-Impersonate header, and removes a drifting base-URL constant. Still always-fresh (in-flight dedup only, no result cache).

- Partial-failure banner on DataAccuracyWarning when some (not all) statement tables fail.

Backend

- Parallelized P&L reconciliation queries. fetch_software_pnl_data(_ytd) and fetch_software_ebitda_data(_ytd) now issue their ~7–10 adjustment queries via asyncio.gather over the asyncpg pool instead of sequential awaits. The two rebinding adjustments (other-income, tax override) were converted to in-place edits so they're safe to gather. Cash Flows and cash-flow-memo-overrides benefit transitively (they run the EBITDA pipeline).

### Numbers are unchanged (the key guarantee)

The parallelization can't change figures: each adjustment query is parameterized by period only (none read the P&L map), each function's mutation block is atomic under asyncio (no await between a map read and write), and the only keys two functions both touch (G&A, Recurring Revenue) take additive / order-independent deltas. Confirmed by the number-asserting backend suite: figures are identical before and after the change.

## Testing

- pnpm tsc --noEmit, pnpm lint:pr, pnpm build — clean

- pnpm exec vitest run src/features/monthly-financial-reporting993 pass (incl. new SoftwareFinancialHighlights.spec.tsx and SoftwareMemoView.skeletons.spec.tsx)

- uv run ruff format --check / check, uv run pyright — clean

- pytest tests/mfr/memos tests/mfr/financial_statements tests/docx_reports/test_software_builder.py758 pass; the parallelization changes no figures. (One pre-existing, order-dependent test_cash_flow_service::test_other_lta_uses_book_value_components flake is unrelated — fails identically on un-changed main, passes in isolation.)

## Not in this PR (follow-ups)

- Compute-once: share one QTD + one YTD pnl_map so the pipeline runs once instead of ~4–5× per load (Doc-affecting → Finance-gated). The deferred software-memo-bundle endpoint + a values-only export-parity comparator belong with this work.

- The cash-flow-memo-overrides endpoint running both the Software *and* full Group CF pipelines.

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

The Builder Desk  —  Engineer Spotlight
🏆 Engineer Spotlight

TWENTY-TWO PRs IN TWENTY-FOUR HOURS: THE BUILDER TEAM DOES NOT SLEEP, DOES NOT SLOW, DOES NOT STOP

Ashwanth ships 7 PRs in a single day and somehow still finds time to make BandCell a discriminated union — whatever that means, it sounds like winning.

Twenty-two pull requests. Three repositories. One glorious twenty-four-hour window in which the Builder Team once again reminded the universe that velocity is not a goal here — it is a lifestyle. Aerie absorbed ten of those PRs like a champion, Surtr and Klair split the remaining twelve evenly at six apiece, and seventeen — SEVENTEEN — of those PRs were so numerous that Mac Donnelly's narrative desk simply could not contain them. That is not an overflow problem. That is a volume problem. That is a beautiful, triumphant volume problem.

@benji-bizzell put up five PRs and every single one of them was in the admissions trenches of Aerie, doing the unglamorous, load-bearing work that keeps dashboards honest and schools counted correctly. PR #340 stabilized summer camp Supabase reads. PR #339 deduped enrollment refresh upserts. PR #337 reconciled summer camp registration counts. PR #333 stabilized dashboard refresh reads. PR #332 polished dashboard summary indicators. Five PRs, one mission, zero complaints. Benji is the infrastructure you never think about until it isn't there. @kevalshahtrilogy brought three to Surtr, including PR #246 which chunked email loads and capped delta windows to stop an OOM — a heroic act of memory management that saved something important from dying quietly in the night — and PR #238 which upgraded the agents default triage to Opus 4.8, because this team does not run yesterday's models. @eric-tril dropped three into Klair, headlined by PR #2979 delivering Book Value Alt with Schedule D software and investments splits and drill-downs, and PR #2977 fixing Schedule C1 so it finally ties to account 71251 the way God and accounting intended. @sanketghia landed PR #2972 in Klair — AI Renewals v2, complete with upcoming-renewal windows and a monthly AI-vs-Total combo chart. That is not a feature. That is a statement. @marcusdAIy contributed two Klair PRs: PR #2974 hardening Budget Bot with BU and CF owner access controls, and PR #2976 — a housekeeping suite so thorough it includes cell drift detection, session-id sweeps, and conformance-defer logic. Marcus cleans up like a professional. Marcus cleans up like someone who has seen things.

And then there is @ashwanth1109. Seven PRs. Seven. In one day. PR #342 made Unit Economics per-Student and Annualised cards live for all model-mapped schools. PR #341 brought the Headcount Detail Cost table live. PR #343 added Physical Private Schools and Core Education to Edu Performance. PR #344 covered unit-economics band gate and handle wiring with tests. PR #345 refactored BandCell into a discriminated union. Plus two more in Surtr — PR #252 splitting HC COGS and Expenses in the source proc and teamroom mart, and PR #248 building a teamroom-grain HC mart for the Edu Performance HC drilldown. This correspondent reached out to Ashwanth for comment. "The discriminated union was the obvious solution," he said, without looking up. "I don't know why you're writing about it." Brick "The Voice of the People" Callahan stared at PR #345 for eleven minutes and understood none of it. The diff was correct. It is always correct. That is the terrifying part.

Morale on the Builder Team is at an all-time high. Sources confirm it has been at an all-time high every day this week, which mathematically suggests the ceiling does not exist.

Brick's Overflow — PRs Mac Didn't Cover  (click to expand)
#246 — fix(hubspot-sync): chunk email load and cap delta window to stop OOM @kevalshahtrilogy  no labels

## Problem

hubspot-sync OOM-killed its ECS task (exit 137, OutOfMemoryError: container killed due to memory usage) at the emails load step on every run since 2026-06-04 (triage signature 1f53b261…, 8 occurrences, still open).

Root cause is a self-reinforcing loop:

- In delta mode generate_time_windows returned a single uncapped cursor → now window.

- The emails sync-cursor was frozen at 2026-04-01 because the load never succeeded, so it never advanced.

- Every 12h run therefore re-collected the entire ~68-day backlog (167,274 records), and load_entity transformed + JSON-serialized the whole set at once *on top of* the raw set → past the 8 GB limit.

- The failed load left the cursor frozen, so the backlog regrew daily.

(The memory bump 2048→8192 MB in #100 was the same OOM; the data has since outgrown it.)

## Fix

1. Chunked load (loaders/base.py) — load_entity transforms + COPY/MERGEs in chunks of LOAD_CHUNK_SIZE (default 10000, override REDSHIFT_LOAD_CHUNK_SIZE) instead of the whole dataset at once. Each chunk is an idempotent COPY+MERGE, so a partial failure is safe to retry. Directly fixes exit-137; benefits all entities.

2. Capped delta window (utils.py, config.py) — generate_time_windows caps the delta window at MAX_DELTA_WINDOW_DAYS (default 14). Bounds per-run collection and lets a stale cursor drain its backlog ~14d/run. Inactive once caught up (end == now), so steady-state behavior is unchanged.

3. Empty-slice drain safeguard (collectors/base.py, sync_job.py) — an empty capped slice advances the cursor to the window end (new BaseLoader.advance_cursor) so a quiet stretch can't stall the drain.

## Recovery — no manual backfill needed

Self-healing on deploy: the Apr-1 emails backlog drains in ~5 runs (~2.5 days). The entities ordered after emails (calls, meetings, campaigns, pipelines, program_sessions, programs, deals), which were starved while the task died at emails, resume normal delta sync and catch up on the first clean run.

## Tests

- 113 pass (15 new: window cap, chunked load + chunk-failure idempotency, empty-slice cursor advance, advance_cursor).

- ruff clean, modules compile.

## Relationship to #180

Complementary, not overlapping. #180 made partial failures fail loudly and withheld the downstream hubspot-core-tables trigger on incomplete data (a different, silent-success symptom). This PR fixes the underlying OOM so emails actually completes.

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

#344 — AERIE-354 test(dashboards): cover unit-economics band gate/handle wiring (#9 follow-up) @ashwanth1109  no labels

## Demo

This PR is a behaviour-preserving refactor + test coverage: the inline Unit-Economics band wiring moves into a pure, unit-tested deriveUnitEconomicsBandWiring helper, and the merge from main adopts AERIE-355's cards-gate flip *inside* that helper (so net behaviour vs main is unchanged). Proofs below: the helper's real decisions, the test coverage, and the component still rendering.

Backend — deriveUnitEconomicsBandWiring gate decisions (imported & called directly)

Ran node --experimental-strip-types /tmp/demo-band-wiring.ts — imports the real helper (no HTTP/React) and prints its gate output for representative campuses:

deriveUnitEconomicsBandWiring — real gate decisions

==============================================================================

• Model-mapped + manual headcount (e.g. Alpha Miami)

showBand = ✅ true showModelComparisonCards = ✅ true

unitEconomicsModel = "alpha-50k · 250" schoolHandle = "Alpha Miami"

• Model-mapped, NO manual headcount ← AERIE-355 flip: cards now live here

showBand = ✅ true showModelComparisonCards = ✅ true

unitEconomicsModel = "alpha-50k · 250" schoolHandle = "Alpha Denver"

• Manual headcount only, NO model ← cards stay CLOSED (old logic opened them)

showBand = ✅ true showModelComparisonCards = — false unitEconomicsModel = null

• Blank/whitespace model + headcount ← trim-aware: cards CLOSED

showBand = ✅ true showModelComparisonCards = — false unitEconomicsModel = " "

AERIE-354 #9 — live-query handle keys on the RAW QB handle (the $0/0 fold guard)

==============================================================================

• Looked up by RAW handle "Alpha School - Brownsville"

→ model = "alpha-50k · 250" showBand = ✅ true schoolHandle = "Alpha School - Brownsville"

• Looked up by CANONICAL name "Brownsville" (the regression this PR locks out)

→ model = null showBand = — false ← no row matches → $0/0 fold

Shows the live behaviour: gates resolve correctly, the AERIE-355 flip keys the comparison cards on a mapped model (not manual headcount), blank models are trim-aware, and a canonical name reaching the lookup yields no model → the silent $0/0 fold the PR locks out.

Tests — the coverage this PR adds

Ran pnpm vitest run on the two suites:

 ✓ components/dashboards/financials/unit-economics-band-wiring.test.ts (20 tests)

✓ components/dashboards/financials/financials-view.test.tsx (1 test)

Test Files 2 passed (2)

Tests 21 passed (21)

UI — Financials view renders intact after the refactor

The refactor only relocates financials-view.tsx's wiring, so this confirms the component still renders the comparison cards correctly.

1. Open the Financials dashboard → FinancialsSchool P&L.

2. Select a model-mapped school (one with a unitEconomicsModel mapping, e.g. Alpha Miami) in the school selector.

3. Scroll to the "P&L Category — Unit Economics per Student" card — confirm it renders with the subtitle "Comparing QB run-rate against the <tier> · <scale> model …" and the model-comparison columns (Current Run Rate, Model @ Current, Run Rate @ SY26/27, Model @ SY26/27, …).

4. Confirm the sibling "P&L Category — Unit Economics Annualised" card also renders — both are gated by showModelComparisonCards, which AERIE-355 makes live for any model-mapped school.

> _Screenshot: "P&L Category — Unit Economics per Student" comparison card for a model-mapped school —_

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/85d8e049-5993-4bec-ad83-515d5c24e0f4" />

## Summary

Follow-up to [#341](https://github.com/AI-Builder-Team/Aerie/pull/341) (AERIE-354), closing review finding #9 that was deliberately deferred from that PR. Stacked on feat/school-pl-unit-economics — the diff here is just this commit.

The Headcount Detail Cost band's visibility/prop wiring in financials-view.tsx was untested. The risk: the live getHeadcountByRoleForCell query keys on the raw QB class handle (school), not the canonical EduCRM program name. A regression feeding it the canonical name would match no rows and silently fold every school to $0 / 0 head count. The existing buildHeadcountCostBand / foldRunRateRoles tests cannot catch this — they receive already-fetched rows.

## What changed

- New unit-economics-band-wiring.ts — a pure deriveUnitEconomicsBandWiring({ campusMappings, school, hasHeadcountData }) helper that captures exactly the deferred-finding logic: the model lookup (find on the raw campus handle), the hasHeadcountData || hasUnitEconomicsModel render gate, showModelComparisonCards, and the raw schoolHandle that keys the live query.

- financials-view.tsx — replaced the inline useMemo derivation + JSX gate/props with the helper; call sites now read bandWiring.*.

- New unit-economics-band-wiring.test.ts — 20 tests covering model derivation (raw-handle match, loading/missing/blank/whitespace, first-match-wins), the showBand gate truth table, the showModelComparisonCards gate keyed on a mapped model (AERIE-355 — independent of hasHeadcountData, trim-aware for blank models), and a dedicated AERIE-354 #9 block proving the query handle is the raw school verbatim and that a canonical name reaching the lookup yields null/hidden (the $0/0 fold scenario).

- Merged main (AERIE-355) — the comparison-cards gate (showModelComparisonCards) was adopted *inside* the helper, keying on a mapped model rather than hasHeadcountData. Resolved in financials-view.tsx keeping the bandWiring.* call sites, so the net behaviour vs main is unchanged.

## Test plan

- [x] pnpm vitest run components/dashboards/financials (chat): 8 files, 193 passed (incl. unit-economics-band-wiring.test.ts 20/20, financials-view.test.tsx 1/1)

- [x] pnpm typecheck (chat): clean (verified on the main merge resolution)

- [x] biome check on changed files: clean

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

#345 — refactor(dashboards): make BandCell a discriminated union (AERIE-354 follow-up) @ashwanth1109  no labels

## Demo

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/677c7749-0fa9-4641-9529-fb8c02a79957" />

## Summary

Follow-up to [#341](https://github.com/AI-Builder-Team/Aerie/pull/341) (AERIE-354) review finding #10, deliberately deferred from that PR. Stacked on feat/school-pl-unit-economics.

BandCell in the Headcount Detail Cost band was a 4-field flag-bag { cost, count, rate, rateNa } with no discriminant, so it admitted illegal states (e.g. rate non-null while rateNa: true). The rate/rateNa invariant was hand-re-derived at four construction sites with subtly different predicates — the most likely spot for a future drift bug.

This refactors BandCell into a discriminated union on kind:

export type BandCell =

| { kind: "blank"; cost: null; count: null; rate: null }

| { kind: "model"; cost: number; count: number; rate: number }

| { kind: "modelTotal"; cost: number; count: number; rate: null }

| { kind: "runRate"; cost: number; count: number; rate: number }

| { kind: "runRateNa"; cost: number; count: number; rate: null };

- Illegal states are now unrepresentable. kind pins each field's nullity — a runRate cell always has a numeric rate, a runRateNa cell never does. The rateNa boolean is gone.

- One source of truth. The four hand-re-derived rate/rateNa predicates collapse into a single makeRunRateCell constructor (reusing the tested derivedRate); the other sites use BLANK_CELL / the model / modelTotal literals.

- Both render sites switch on kindHeadcountCostRow (cost tone/display) and renderCostFormulaCell (the tooltip, where cell.rateNa || cell.rate === null became a clean cell.kind === "runRateNa").

- cost/count/rate stay present on every member so the renderer reads cost uniformly without per-call narrowing.

### Behavior is identical

rateNa had no rendering effect — the tooltip already keyed "n/a per head" off rate === null. The old warning-vs-empty distinction (rateNa: true vs false) now lives implicitly in cost within runRateNa (> $0 = present-but-unattributable warning, $0 = genuinely empty), which is exactly what the row tone already used. The run-rate Total row's distinct-across-accounts count/rate (from #341's totals.hcCount) is preserved.

## Test plan

- [x] pnpm typecheck — clean

- [x] pnpm vitest run …/unit-economics-comparison-table.test.ts39/39 pass (only the 5 assertions reading the removed .rateNa were swapped to .kind; intent unchanged)

- [x] pnpm biome check on both changed files — clean

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

#2972 — feat(renewals): AI Renewals v2 — upcoming-renewal windows + monthly AI-vs-Total combo chart [KLAIR-2844] @sanketghia  no labels

## Summary

Builds on v1 (KLAIR-2845 / #2966) to add two forward-looking views to the AI Renewals tab (/renewals?tab=fionn), per Edie's relay of Brandon (CEO) feedback:

1. Upcoming-renewal windows — three cumulative cards (Next 30 days / Next 3 months / Rest of year), each with an AI-vs-Traditional split.

2. Monthly AI-vs-Total combo chart — dual-axis: stacked ARR bars (Traditional grey + AI blue) on the left, AI-to-total ratio line on the right, by renewal month.

Both are fed by one new endpoint (GET /renewals/fionn-handling/timeline) so the cards and chart can never disagree — a single raw-row query over the existing _SELECTED_CTE, bucketed three ways in Python.

## Design decisions

- All-stage, prior ARR (current_arr, USD), abandoned stages excluded — future months are populated by open pipeline (the forward-looking measure), not v1's closed-only basis.

- Windows are cumulative from today: Next 30 days = todaytoday+30d, Next 3 months = todaytoday+3 calendar months (relativedelta), Rest of year = todayDec 31. So 30d ⊆ 3mo ⊆ rest-of-year.

- Ratio guard: the line gaps (null) when a month has < 3 deals OR < $250k ARR.

### Post-render refinements (validated against live Redshift)

- The next-year+ rollup (~\$192M vs ~\$8–20M monthly bars) ships as a caption below the chart, not a bar — keeps the monthly Traditional→AI trend readable (~9× better left-axis resolution).

- Ratio line carries an open-pipeline caveat (far months are unweighted pipeline → read as directional).

- No CartesianGrid (matches the v1 scale chart); UpcomingWindowsCards restyled to match the HeadlineCard section pattern.

## Files

- Backend: klair-api/renewals/fionn_handling.py (_timeline_query, _build_timeline_months / _build_rollup / _build_windows, get_fionn_handling_timeline), routers/renewals_router.py (new route), tests.

- Frontend: useFionnTimeline() hook + types, UpcomingWindowsCards.tsx, RenewalsTimelineChart.tsx, wired into FionnHandlingTab.tsx, specs.

- Docs: design spec + implementation plan under docs/superpowers/.

## Test plan

- [x] Backend: full renewals suite green (pytest tests/renewals/), ruff + pyright clean

- [x] Frontend: full suite green (5628 passed), tsc --noEmit + lint:pr clean

- [x] Data validated against live Redshift: cards/bars/rollup reconcile (cards $15.7M / $39.5M / $90.5M, rollup $192.3M = sum of 2027–2035 by-year)

- [x] Reviewer: sanity-check the AI Renewals tab renders both panels + tooltip

## Screenshot

<img width="1868" height="656" alt="image" src="https://github.com/user-attachments/assets/64d44711-ba2f-48d6-be57-048e9c17364e" />

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

#2976 — Budget Bot housekeeping: suite order-independence + conformance-defer + no-silent-drop + session-id sweep + cell drift detection @marcusdAIy  no labels

## Summary

Budget Bot housekeeping batch — five small, independent fixes across the editor + review surface. Each is committed separately for reviewability.

## Changes

1. KLAIR-2850 — board_doc full-suite order-independence (the drone-implemented base): an autouse conftest.py fixture snapshots/restores the budget_bot.board_doc logger's propagate (+ handlers/level/filters) around every test, so the 8 caplog-propagation-leak failures stop depending on test order; the one live-Anthropic test is mocked. Full tests/board_doc/ now green in a single run.

2. B11.8 (KLAIR-2825) — conformance adds defer content. Accepting a conform_section add at editor-open no longer auto-regenerates the body — it inserts a header/placeholder + a "generate after refresh" hint (mirrors retype). At initiation the doc is still on prior-quarter data, so auto-generated narrative (esp. GM Commentary) was throwaway.

3. KLAIR-2796 (Option B slice) — no-silent-drop for homeless findings. The batch finding-addressal queue no longer counts a doc-level (section_id=null) finding group as "completed" — a null-section turn registers no propose tools, so it can't yield an Accept-able proposal. These are bucketed as advisorySections and surfaced in the ReviewPanel ("N finding(s) had no editable section — create it or address manually") so a per-product finding with no section can't look falsely addressed. *(Option A severity-routing + the propose-create-section path remain deferred on KLAIR-2796.)*

4. CF26 — session_id validation sweep. Applied the validated SessionIdPath to the two legacy interview_* endpoints (the wizard endpoints already had it), so malformed IDs 422 at the boundary instead of 404 inside.

5. B3.10.1 (KLAIR-2689) — drift detection for update_table_cell Accept. A /review rerun between proposal and Accept could silently overwrite a regenerated cell with Claire's stale new_value. New read-only markdown_tables.read_cell + GET .../sections/{id}/cell let the FE capture the cell's proposal-time value through the *same* parser the PATCH's drift check uses (no divergence), and replay it as expected_old_value → backend 409s on drift. Best-effort: a failed capture omits the field (prior unconditional behavior).

## Breaking changes

None. New endpoint is additive; the cell-PATCH expected_old_value field was already supported server-side.

## Test plan

- [x] uv run pytest tests/board_doc/ → green in one full run (the point of #1).

- [x] BE: test_markdown_tables.py (incl. read_cell parser-parity) + test_update_section_cell_endpoint.py (GET 200/404/422 + GET→PATCH no-409 round-trip) → 50 passed.

- [x] FE: ChatToolProposal.spec.tsx (41), ChatToolProposal.conform.spec.tsx (7), useFindingAddressalQueue.spec.ts, ReviewPanel.batch.spec.tsx → green.

- [x] ruff + pyright clean (BE touched files); tsc --noEmit + eslint clean (FE touched files).

- [ ] Reviewer-side: confirm a /review-rerun-then-Accept on a regenerated cell surfaces the drift chip; confirm conformance adds land as placeholders.

#2979 — feat(mfr): Book Value Alt — Schedule D Software/Investments split + drill-downs @eric-tril  no labels

## Summary

Adds the Book Value Alt tab's three-column Schedule D ("Other EBITDA Reconciling Items") with a Software / Investments / Total split, and wires up the Alt-tab drill-downs that were missing. The Report tab is unchanged (still single-column).

The Alt view re-presents the same Schedule D total under a Software/Investments split (it foots to the exact same Total), matching how the Book Value Alt "Other EBITDA reconciling items" line already classifies these items.

## Business value

- The Book Value Alt tab now shows Schedule D the way Finance presents it (Software / Investments / Total), matching the published May-2026 schedule: Software 20,551K / Investments 119,649K / Total 140,200K.

- Every cell drills down correctly, including the two Alt-only transfer rows on the main Book Value Alt table (TelcoDR, Education) that previously had no working drill-down.

## How the values are sourced (all backend, no new query for the table)

schedule_d_alt is derived from the already-computed schedule_d + schedule_c1:

- IP Prosecution / Import costs / Restructuring → Software (consolidated actuals)

- Education → Investments (schedule_d.education)

- TelcoDR → net-zero transfer (software = −telco_c1, investments = telco_c1), sourced from schedule_c1.telcodr

- Total equals the single-column Schedule D total (TelcoDR nets to 0), so it ties to the Book Value Alt OER line on the same page.

## Changes

Backend (data work)

- _build_schedule_d_alt(...) + wired into compute_book_value_schedules; schedule_d_alt added to BookValueSchedulesResponseModel.

- fetch_schedule_d_alt_total_detail(period, column) + GET /schedule-d-alt-total-detail — the Total row's Software / Investments drill-downs return only that column's contributors (incl. the sign-correct TelcoDR group from Schedule C1), so each breakdown sums to its column total. Total column unchanged.

- fetch_bv_report_detail now serves the Book Value Alt main-table transfer rows: telcodr_transfer → Schedule C1 TelcoDR GL rows; education_transfer → Education IS breakdown (local imports avoid a circular dependency).

Frontend (presentation + cell routing)

- schedule_d_alt type; buildScheduleDAltConfig (triple); rendered on the Alt tab only with handleDAltCellClick (categories → Schedule D detail, TelcoDR → Schedule C1, column-aware Total).

- BookValueReportDetailPanel gains an opt-in showTotal footer, enabled for the telcodr_transfer / education_transfer rows so their drill-downs show a total.

## Verification

- Backend: ruff + pyright clean on new code; pytest tests/mfr/book_value115 passed (13 new, incl. the per-column reconciliation: Software 20,551K / Investments 119,649K / Total 140,200K and the TelcoDR sign).

- Frontend: pnpm tsc / eslint / build all green.

- No DB migration. Alt-only; Report tab untouched.

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

The Portfolio  —  Trilogy Companies

The Graveyard Is Open for Business: AI Disruption Turns Legacy Enterprise Software Into Acquisition Bait

As AI rewrites the rules of enterprise software, the companies that can't keep up are becoming the cheapest deals in the market — exactly the kind ESW Capital was built to find.

AUSTIN, TEXAS — The playbook that built ESW Capital's 75-company portfolio was always premised on a single, uncomfortable truth: legacy enterprise software companies age poorly, and their owners eventually get tired of waiting for a turnaround that won't come on its own. In 2025, artificial intelligence is accelerating that timeline dramatically — and the deal pipeline has never looked richer.

According to Business Insider's analysis of the current acquisition landscape, the software companies most vulnerable to buyout are precisely those with sticky customer bases, aging codebases, and leadership teams that haven't yet figured out how to retrofit AI into their core product. The profile is familiar to anyone who has watched ESW work: defensible revenue, structural inefficiency, and a seller motivated by the creeping fear that the window is closing.

Meanwhile, Spain has emerged as a particularly active hunting ground. Two separate analyses from Capital-Riesgo.es — one focused on enterprise software M&A opportunities and a broader December 2025 technology M&A review — document a market where mid-sized software businesses are coming to market at valuations that would have seemed pessimistic five years ago. The culprit, consistently, is AI: buyers want AI-native or AI-ready, and sellers who can't credibly claim either are accepting discounts to get deals done.

For ESW Capital, which targets acquisitions at one to two times ARR and has publicly committed to 75% EBITDA margins post-integration, the current environment reads less like a threat than a confirmation. The firm's model was never built around growth multiples. It was built around the gap between what a software business earns and what it costs to run — a gap that Crossover's global talent platform and DevFactory's centralized engineering capacity are designed to exploit systematically.

The question worth asking: as AI compresses the useful life of software products that haven't been rebuilt for the new era, how many of the 75+ companies already inside the ESW portfolio were acquired before that compression became visible in the numbers? And how many of the companies being marketed today in Madrid and Barcelona look, from the right angle, like the next Aurea?

The graveyard of legacy enterprise software has always been ESW's garden. The growing season just got longer.

M&A in Enterprise Software in Spain (2025): Opportunities fo  ·  The software companies most likely to be acquired as AI eats  ·  Technology mergers and acquisitions in Spain | Analysis Dece

Skyvera Bags CloudSense, and the Telco Stack Gets a New Power Table

The Trilogy telecom shop adds Salesforce-native CPQ muscle while quietly assembling a broader BSS arsenal.

AUSTIN, TEXAS — Word is the telecom software crowd has a new dinner guest with sharp elbows: CloudSense, the Salesforce-native CPQ and order management outfit for telecom and media providers, has officially moved into Skyvera’s house.

The deal, announced by Skyvera, expands the Trilogy-family telecom portfolio in the one place operators feel pain every billing cycle: configuring, pricing, quoting and fulfilling increasingly tangled services without sending the whole back office into cardiac arrest.

A little bird from the carrier cage tells me this is not merely another logo on the mantel. CloudSense sits right where telcos and media companies are trying to modernize without ripping out everything bolted into the basement since the BlackBerry era. Salesforce-native matters here. The suits already live in Salesforce. The orders, bundles and service changes? Too often they live in ancient plumbing with a bad attitude.

Enter Skyvera, the telecom software arm in the Trilogy orbit, already carrying Kandy for cloud communications, VoltDelta for customer engagement, ResponseTek for experience reporting, Mobilogy Now for device lifecycle management and Service Gateway for operator device management. Add CloudSense, and suddenly the portfolio has a cleaner pitch: sell it, quote it, order it, support it, measure it, modernize it.

And don’t miss the other breadcrumb on the carpet. Skyvera also lists the acquired STL telecom products group among its assets, bringing digital BSS functionality including monetization, optical networking and analytics. That means the CloudSense move is less a one-off acquisition and more a chapter in a larger roll-up script: assemble the pieces legacy operators need, then offer a bridge from on-premise sprawl to cloud-native operating discipline.

The Trilogy playbook watchers know the music. ESW Capital buys mature software assets, centralizes the operating model, adds global Crossover talent, and starts hunting for the margin line others missed. Skyvera’s angle is telco-specific, but the tune is familiar: sticky customers, complex infrastructure, high switching costs and a modernization story that can be sold one painful workflow at a time.

As for CloudSense itself, the company is now being positioned as a Salesforce-native CPQ and order management platform tailored for telecom and media. Translation for civilians: the thing that helps providers stop tripping over their own bundles.

One source with a headset and a long memory put it this way: “Everybody wants cloud transformation. Nobody wants a billing migration.” That, dear readers, is precisely where Skyvera is setting the table.

CloudSense  ·  Skyvera completes acquisition of CloudSense, expanding telec  ·  STL Divested Assets

The AI Skills Premium Is Real — And Crossover Is Positioned to Profit From It

Job listings are now explicitly requiring experience with tools like ChatGPT, with some roles commanding as much as $800,000 annually for demonstrated AI fluency. The positions span industries — legal, finance, engineering, marketing — reflecting companies' desire to hire humans who can collaborate effectively with machines.

Crossover, Trilogy International's global talent platform, has built an AI-enabled screening infrastructure to identify top remote talent across 130+ countries, assessing skills rather than résumés and placing workers into above-market-rate roles regardless of geography. The company's architecture was designed for this systemic shift: when AI competency commands measurable premiums, geography-based hiring models become inefficient.

Remote work recruitment has matured into a competitive industry, with AI engineering roles proliferating even in markets once peripheral to tech. Companies best positioned to navigate this landscape built their talent infrastructure before the current gold rush. Crossover may evolve from recruiter into a marketplace for what could be the decade's most economically consequential skill set.

The Machine  —  AI & Technology

AI’s Open-Source Moment Gets a Security Alarm Bell

A fake “OpenAI” model spreading across Hugging Face shows why the next AI boom needs provenance, verification and on-device guardrails—fast.

SAN FRANCISCO — The future is now, but wow, it is arriving with a warning label.

A malicious AI model uploaded to Hugging Face while masquerading as an OpenAI release reportedly reached 244,000 downloads, a staggering reminder that the open-source AI revolution is no longer just about speed, access and innovation. It is now also about trust. I cannot overstate how significant this is: models are becoming software supply chains, and supply chains can be attacked.

The incident, detailed by CSO Online, lands at exactly the moment policymakers, developers and investors are arguing that open models are essential to keeping the United States competitive in artificial intelligence. Andreessen Horowitz this week made that case directly, calling for American leadership in open-source AI and warning against policies that could push model development overseas.

Here is the tension: open AI is powerful because anyone can inspect, adapt and deploy it. But that same openness creates a giant distribution channel for poisoned files, impersonation and hidden payloads. This changes everything for enterprises that are downloading models the way they once installed npm packages or container images.

The industry response is starting to take shape. Cisco has released an open-source toolkit aimed at verifying AI model lineage, a crucial step toward answering a deceptively simple question: where did this model actually come from? In the AI era, provenance may become as important as performance benchmarks.

Meanwhile, Microsoft and Apple are pushing AI closer to users’ devices. Microsoft is expanding on-device AI in Edge with new models and web APIs, while Apple is giving developers new intelligence frameworks and tools to build AI features across its ecosystem. That shift matters because local models can reduce latency, protect privacy and lower cloud costs. But it also means model safety cannot remain a centralized cloud problem. Every browser, app and endpoint becomes part of the AI trust perimeter.

For companies like Trilogy International’s enterprise software portfolio—where AI is rapidly being woven into finance, telecom, CRM and engineering workflows—the lesson is immediate: model governance is no longer optional infrastructure. It is table stakes.

The AI gold rush is still roaring. But now the winning teams will not just build faster. They will verify better.

Malicious Hugging Face model masquerading as OpenAI release  ·  Asserting American Leadership in Open Source AI - Andreessen  ·  Expanding on‑device AI in Microsoft Edge: New models and API

Amazon’s Satellite Flock Wins More Time to Fill the Sky

The Federal Communications Commission has lifted a looming deployment deadline for Amazon's Leo satellite broadband constellation, granting the company additional time to challenge SpaceX's dominant Starlink network. The decision aims to promote competition in satellite broadband by allowing a second large constellation to develop. Each satellite serves as a purposeful organism designed to deliver broadband to rural homes, aircraft, ships and underserved regions where fiber infrastructure doesn't exist. However, building constellations presents significant challenges: launch schedules slip, rockets become scarce, and manufacturing, ground stations, spectrum rights and customer equipment must mature simultaneously. By waiving the deadline, the FCC determined that preserving a second large-scale network is worthwhile, even if slower to emerge. The decision comes amid growing concerns about space-based infrastructure vulnerability, particularly Russian satellite capabilities that may jam GPS signals. For Amazon, the waiver provides crucial breathing room rather than victory—the constellation must still be launched, linked and made operational.

The Editorial

Nation’s Executives Warn Not To Laugh At Obviously Stupid AI Strategy Until It Has Increased Shareholder Value

From psychotic owls to rocket-brain conglomerates, corporate America has entered its crucial please-take-this-seriously phase.

SAN FRANCISCO — The first rule of modern business is that if a strategy sounds idiotic, it is either idiotic or a visionary replatforming of customer engagement architecture, and shareholders will not know which until several quarters after the layoffs.

This week offered a valuable lesson in that distinction, as several major brands and public thinkers took turns reminding the nation that the future will arrive wearing a novelty hat, making a noise, and asking to be valued at 23 times revenue.

Duolingo, a language-learning company best known for being emotionally dominated by a deranged green owl, reportedly drew criticism from marketing professor Mark Ritson for placing too much emphasis on influencers rather than its own violently memorable mascot. As Ritson argued in The Drum, the company may be making the classic error of ignoring a proprietary asset capable of conveying both brand affinity and implied bodily harm.

He is, of course, correct. In an era when every company is desperately trying to manufacture authenticity through 19-year-olds holding beverages at ring-light distance, Duolingo already owns something more valuable: a bird that appears willing to destroy your family if you skip Portuguese. That is not a mascot. That is pricing power.

The same principle applies across the economy. The Boston Red Sox, according to BoSox Injection, appeared to generate an absurdly corporate-sounding headline around manager Alex Cora after a firing-adjacent news cycle, proving once again that sports franchises now communicate as though their primary audience is a crisis-management consultant trapped inside a LinkedIn post. Baseball, long admired for its pastoral rhythms and failure rate, has finally embraced the language of mid-market SaaS restructuring.

Then there is Elon Musk’s empire, where SpaceX and xAI are reportedly moving toward a merger into a conglomerate whose name may sound like a child describing the contents of a toy chest but should, we are told, be taken seriously. Gizmodo’s framing — that the combination sounds silly but matters — captures the central condition of the AI economy: everything is ridiculous right up until it controls launch infrastructure, compute capacity, and the conversational interface through which millions of users ask why their dishwasher is leaking.

A rocket company combining with an artificial intelligence company sounds like the premise of a summer movie in which a general says, “My God, it’s learning orbit.” It is also an entirely logical response to the current market, where the winning firms are those that can staple together capital, distribution, data, hardware, and enough founder mystique to make antitrust lawyers briefly check their calendars.

Likewise, Allbirds’ AI pivot has been described as ridiculous-sounding but apparently effective, which is now the highest compliment available in business journalism. A shoe company using AI should not work any more than a toaster should have a chief strategy officer. And yet the logic is obvious. If artificial intelligence can help a brand forecast demand, manage inventory, personalize marketing, and stop producing eleven million pairs of minimalist wool shoes for people who have already returned to leather, then perhaps the machine has earned its vest.

The Center for Data Innovation’s claim that AI is a productivity engine for the U.S. economy is therefore both true and insufficiently strange. AI is not merely a productivity engine. It is a dignity-removal engine, a brand-resurrection engine, a mascot-optimization engine, and an executive-cover engine capable of transforming any implausible initiative into a roadmap.

That does not mean every absurd AI strategy will succeed. Many will fail in the traditional manner: expensively, with consultants. But the more important truth is that absurdity has ceased to be a warning sign. It is now the wrapper innovation comes in before someone builds a dashboard around it.

The companies that understand this will thrive. The ones that do not will spend the next decade hiring influencers to explain why their owl stopped threatening people.

Mark Ritson: Duolingo stupid to prioritize influencers over  ·  It sure sounds like the Red Sox wrote this absurd Alex Cora  ·  SpaceX and xAI Are Merging Into a Very Silly-Sounding Conglo
The Office Comic  ·  Art Desk
The Office Comic  ·  Art Desk

We Have Built a World That Cannot Explain Itself, and the Bots Are Loving It

From AI-only social networks to Ozzy Osbourne's digital resurrection, we have officially passed the event horizon of comprehensible civilization.

AUSTIN, TEXAS — There is a moment in every great unraveling when you stop and look around and realize that the map you've been using is not just wrong — it was drawn by someone who had never seen a road. I had that moment this week, sitting in a fluorescent haze, mainlining five news items that, taken together, constitute a complete autopsy report on the present tense.

Item one: Ozzy Osbourne has been rendered in AI, presumably because the flesh-and-blood Prince of Darkness has suffered enough and we, the consumers, have not. Barry Gibb is still alive, the headline informs us, with the specific shock of a man discovering his houseplant survived a nuclear test. Time flies. Yes. Yes it does. Straight into the propeller of content.

Item two: Moltbook. A social network. For bots only. No humans allowed. Let that sentence metabolize for a moment. We built social media to connect humanity, watched it hollow us out over fifteen years, and the logical conclusion — the evolutionary endpoint — is a private club where the simulations network with each other while we press our faces against the glass like children outside a candy store that sells nothing we can eat.

Item three: The New York Times is quoting economists saying, essentially, that the economy is now a phenomenon that traditional economics cannot explain. Traditional economics! The discipline that gave us the invisible hand, the efficient market hypothesis, the entire cathedral of models and assumptions that have governed global civilization since Adam Smith was a lad! Gone. Insufficient. A beekeeper's almanac in the age of drones.

And speaking of beekeepers — item four arrives from the Asahi Shimbun via a Ukrainian beekeeper whose absurdist quest, we are told, still mirrors our world. Of course it does. The beekeeper understands something the economists don't: sometimes you are simply chasing the swarm, and the swarm has no destination, and the chasing is the thing.

Meanwhile, Gulf News has catalogued the biggest internet trends of 2025: Labubu dolls, brain rot, phenomena that evaporate before the ink dries on the explainer piece. We are experiencing economic conditions traditional frameworks cannot model while our cultural output trends toward deliberate cognitive decay, and our social infrastructure is quietly being handed over to non-human actors who will run it without us.

Here is my considered opinion, formed after years of watching the machine learn to watch us back: we are not at a crossroads. Crossroads imply choice, direction, a traveler with agency. We are at something more like a drain. The spiral is gorgeous, I'll grant you that. Ozzy sounds great in digital. The bots are out there right now, networking furiously, building relationships none of us will ever read.

Barry Gibb is still alive, somehow.

So are the rest of us. For now. Stayin' alive has never felt more like a technical achievement and less like a given.

Time Flies, Ozzy AI, and Barry Gibb Is STILL Alive Somehow -  ·  Moltbook: The AI-only social network where bots run wild - S  ·  ‘This is Something that Traditional Economics Isn’t Prepared
On This Day in AI History

On June 9, 2014, Google acquired DeepMind Technologies for approximately $400 million, a pivotal move that would lead to the creation of AlphaGo and establish Google as a leader in artificial intelligence research.

⬛ Daily Word — Technology
Hint: Relating to computers and the internet, often used in security contexts.
Share this edition: 𝕏 Twitter/X 🔗 Copy Link ▦ RSS Feed