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

Anthropic Eclipses OpenAI on Valuation After $65 Billion Round

The Claude maker's latest fundraise reshuffles the AI hierarchy — and raises fresh questions about who's actually winning the foundation model race.

SAN FRANCISCO — Anthropic has surpassed OpenAI as the most valuable private AI company following a $65 billion funding round, a milestone that would have seemed implausible eighteen months ago when OpenAI's GPT-4 dominated enterprise conversations and Anthropic was still regarded as a well-capitalized challenger.

The valuation inversion is significant for several reasons. OpenAI's last disclosed valuation stood at $157 billion following its October 2024 round — a figure that assumed continued dominance in both consumer and enterprise segments. Anthropic's $65 billion post-money figure doesn't exceed that number outright, but multiple reports indicate OpenAI's implied secondary-market valuation has compressed while Anthropic's has climbed, producing the crossover.

The shift reflects enterprise buyers hedging. Large organizations that standardized on GPT-4 have spent the past year quietly running parallel evaluations of Claude. Anthropic's Constitutional AI approach and its emphasis on interpretability research have resonated with regulated industries — financial services, healthcare, legal — where explainability carries compliance weight that raw benchmark performance does not.

The funding round also arrives against an uncomfortable backdrop for the broader sector. A separate lawsuit filed this week accuses an unnamed investment firm of surveilling an AI startup founder — a reminder that the capital flooding into foundation models has attracted actors whose due diligence methods are, at minimum, legally contested.

For enterprise software buyers and the portfolio companies that serve them, the Anthropic-OpenAI valuation swap matters less than the underlying dynamic it signals: the foundation model market is not consolidating around a single winner. Two well-capitalized competitors with distinct technical philosophies are now both valued at figures that justify sustained, parallel investment in capabilities. That's a longer race than many predicted in 2023, and a more expensive one for every company building on top of either platform.

Anthropic Overtakes OpenAI as Most Valuable AI Startup Follo  ·  Investment firm accused of ‘surveilling’ AI startup founder  ·  Anthropic surpasses OpenAI as most valuable AI startup after

Alibaba's AI Agent Eyes the Globe While China's Tech Ambitions Multiply

A new enterprise AI tool from Hangzhou signals Beijing's broader strategy to win not one AI race, but several simultaneously.

HANGZHOU — The press release arrived, as they always do, dressed in the language of inevitability. Alibaba International has launched Accio Work, an enterprise AI agent designed to help global businesses automate procurement, supplier discovery, and cross-border trade workflows. The product targets the sprawling middle layer of international commerce — the importers, wholesalers, and sourcing managers who move goods across oceans and time zones, often with inadequate tooling and too many spreadsheets.

Accio Work is Alibaba International's clearest bid yet to plant a flag in the enterprise software market beyond China's borders. It is not a search engine. It is an agent — something that acts, not merely answers. The distinction matters enormously in 2025, when the ability to execute multi-step tasks autonomously separates the serious AI platforms from the demos.

The timing is not accidental. A Brookings Institution analysis published this week argues that China is not running a single AI race but many — competing simultaneously in foundational models, AI-enabled hardware, robotics, and now enterprise software deployment at global scale. Accio Work is one piece of that mosaic. Alibaba is not chasing OpenAI. It is chasing the entire stack.

For Western enterprise software incumbents, the competitive pressure is real and arriving faster than most boardrooms have processed. Alibaba's distribution advantages — deep integration with global supply chains, established trust among manufacturers in Southeast Asia and the Middle East — give Accio Work a runway that a startup launching the same product would spend years trying to build.

What the product actually delivers at scale remains to be proven. Enterprise AI agents have a habit of performing brilliantly in demonstrations and struggling in production environments where data is messy and workflows are older than the vendors pitching replacements.

Still, the direction is clear. From the server farms of Hangzhou to the procurement offices of Frankfurt and São Paulo, the geography of AI competition is expanding. The race, it turns out, has no single finish line.

Fort Worth’s Trilogy Aviation Group Launches Quartet Jet Adv  ·  Alibaba International Launches Accio Work, an Enterprise AI  ·  Key appointments: Trilogy Hotels, Marriott International - h

The Memory Heist: $135M Bet Says AI's Real Bottleneck Isn't Compute

Seoul outfit Xcena pockets a $570M valuation arguing the pipes — not the processors — are what choke artificial intelligence.

SEOUL — South Korean chip startup Xcena hauled in $135 million this week at a $570 million valuation, wagering that artificial intelligence chokes on memory bandwidth long before it runs out of raw compute.

The pitch cuts against industry gospel. Nvidia's empire and every GPU buyer in the queue have assumed compute is the limiting reagent. Xcena says the bottleneck moved — and it moved to the pipes.

The memory wall has haunted computing since the 1990s, the yawning gap between processor speed and how fast data gets in and out. Large language models turned the chronic ache into a five-alarm fire. Every token a model spits requires fresh weights yanked from memory, and the pipes don't keep up.

Money's behind the thesis. Xcena's round values an outfit still in early innings at over half a billion dollars. Backers are betting the memory layer is where the next pile of margin gets made.

The timing is no accident. Enterprise AI quit being a science project. Glean, the AI search startup, said this week its top line crossed $300 million, triple last year, with budget-watching CIOs naming it a cheaper option than rolling their own stack.

Per Morningstar's tally, OpenAI and Anthropic dominate AI revenue and burn megawatts doing it. Megawatts cost money. Memory costs more, when you can get it.

HBM — the high-bandwidth flavor stacked beside every serious GPU — has been rationed by SK Hynix and Samsung at premium prices since 2023. Squeeze more useful work per gigabyte per second and every hyperscaler takes the meeting. That's Xcena's whole sales deck in one breath.

The hardware build-out marches regardless. Waymo this week led all autonomous vehicle registrations in Texas, per a new state tracker, with Tesla trailing behind. Robotaxis don't run on hope — they run on silicon, and the silicon runs on memory.

Whether Xcena's silicon delivers in production is the next chapter. Korea's chip bench runs deep, and Seoul wants to own the memory side of the AI stack the way Jensen Huang's Santa Clara outfit owns compute. The check size says investors believe it can.

Hardware doesn't always cooperate. Blue Origin learned the lesson Wednesday in Florida, where its New Glenn rocket went up in a fireball on the test stand — a hard setback for Jeff Bezos' chase of SpaceX. Big bets at scale tend to leave smoking craters before they leave moats.

Xcena hopes its crater stays figurative. The compute crowd is heavily invested in compute being the answer. The memory crowd just got $135 million worth of ammunition to argue otherwise.

This chip startup just raised $135M on a bet that AI’s bigge  ·  Blue Origin’s New Glenn rocket explodes during testing in Fl  ·  Glean’s top line crosses $300M as AI budget-cutting becomes
Haiku of the Day  ·  Claude HaikuBillions chase the dream
While mirrors show what we've built—
ourselves, flawed and bold
The New Yorker Style  ·  Art Desk
The New Yorker Style  ·  Art Desk
The Far Side Style  ·  Art Desk
The Far Side Style  ·  Art Desk
News in Brief
The Fairness Reckoning: Academic Research Converges on AI's Most Intractable Problem
CAMBRIDGE, MASSACHUSETTS — A confluence of scholarly output, arriving with the particular velocity that characterizes moments of genuine disciplinary crisis, has positioned algorithmic fairness as perhaps the defining epistemic challenge of applied machine learning — a designation that, it could be argued, was both inevitable and, in retrospect, embarrassingly overdue. Preliminary evidence suggests that the research community has, at long last, begun to grapple with the full dimensionality of the problem.
The Absurdity Industrial Complex Is Running Hot This Week
AUSTIN, TEXAS — There's a particular frequency the universe hits sometimes, a kind of cosmic static where everything happening simultaneously is both completely unrelated and somehow, catastrophically, the same story.
The Mirror Lies: AI Is Reflecting Our Worst Selves Back at Us, and We're Calling It Progress
AUSTIN, TEXAS — There is a story we tell ourselves about artificial intelligence, a warm and frictionless story, the kind that gets narrated over sleek product demos and keynote presentations, the kind where the algorithm is wise and impartial and above the messy, embarrassing business of human prejudice.
THE FUTURE BELONGS TO COMPANIES THAT TURN TRUST INTO INFRASTRUCTURE
AUSTIN, TEXAS — I'll be honest: the most important business stories this week were not really about babies, contractors, codebases, moon bases, or drones. They were about trust becoming the new cloud layer.
Nation’s Executives Announce AI Will Soon Be Powerful Enough To Take Credit For Decisions They Already Made
MOUNTAIN VIEW, CALIFORNIA — In a development expected to transform the way American business leaders avoid saying what they mean, Google this week announced a broad slate of artificial intelligence advances, including a forthcoming personal AI assistant that could soon help users manage tasks, answer questions, and provide executives with a more sophisticated noun to place between themselves and layoffs. The announcement, reported by ABC News, arrives at an important moment for the AI industry: the brief interval after everyone has promised everything and before anyone is asked to reconcile it with a quarterly operating plan.
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 Seals Data Gaps, Ships Intelligence Across Four Repos

From a $30.7k ghost spend recovery to a self-healing triage agent to full-stack security profiles, the AI Builder Team turned a single day into a masterclass in consequential engineering.

Thirty thousand dollars. That's the number that opens today's dispatch — and the number that tells you everything about what kind of team this is.

When @kevalshahtrilogy diagnosed that the TrueFoundry gateway pipeline had silently swallowed $30,700 in US spend across two May partitions — 1,140 rows of real data that vanished because upstream CTAS jobs landed late and the pipeline never looked back — he didn't just patch it. He redesigned the contract. PR #117 in Surtr introduces a trailing re-pull window so that late-materializing partitions self-heal on the next run, turning a silent failure mode into a non-event. That's the difference between a fix and a solution. While he was at it, he shipped PR #2910 into Klair, overhauling the TrueFoundry dashboard with real search, sort, and pagination via a new shared DataTable component, and making spend-per-user exhaustive by killing the arbitrary LIMIT 100 cap. One engineer. Two repos. One very bad day for data gaps.

But Keval wasn't done building. PRs #109 and #110 in Surtr lay the foundation and dispatcher layer for the pipeline-triage-agent — an autonomous system that will turn pipeline failures and observer alerts into GitHub Issues and, when confident, PRs. The architecture is surgical: SNS fan-out, a deduplication ladder so repeated failures don't spam the board, and kill switches that keep everything inert until the team is ready to flip the switch. This isn't a monitoring dashboard. This is the team building a system that fixes itself.

On the renewals front, @sanketghia quietly did the unglamorous work that makes dashboards honest. PRs #119 and #98 in Surtr extend the Trilogy SSOT extraction with multi-currency fields — CurrencyIsoCode, ARR in USD, Current ARR, Business Unit, Product — so the Klair Renewals dashboard can finally produce apples-to-apples Fionn-vs-Trilogy comparisons. Before today, 37.4% of the Fionn cohort — 159 of 425 rows — was non-USD, making aggregate comparisons functionally meaningless. Now they're not. Sanketghia also closed a five-day QuickBooks failure loop in PR #115, where the redshift_client was timing out at 300 poll attempts on a job that genuinely takes 410 seconds to complete. The server was succeeding every time. The client just kept giving up first. Fixed.

Aerie had a full construction day. @YibinLongTrilogy threaded Phase 2 projected dates end-to-end through portfolio and FTO surfaces (PR #279, stacked on a Rhodes schema change in PR #105), then shipped a complete Security card for the Portfolio site detail page (PR #275, backed by a new siteSecurity table in Rhodes via PR #106) — covering security tiers, guard profiles, armed status, camera systems, lockbox details, and access summaries, all round-tripping cleanly through MCP tools and Aerie sync. @benji-bizzell, meanwhile, fixed a genuinely insidious bug in PR #280 where clearing a Portfolio date field would show a success confirmation while quietly preserving the old value — undefined was being dropped by JSON.stringify before it ever reached the API. He also split the cancelled/paused portfolio toggle into independent controls (PR #277) and gave the Agent Chat panel a real second-level expansion for tool call inputs and outputs (PR #276), so engineers can finally inspect a full Bash log without re-running the job.

Now. About those four Klair PRs from @marcusdAIy.

Asked about the batch — which includes a harness artifact cleanup (PR #2908) necessitated by a drone that committed its own task spec into the wrong repo, a refactor draining deprecated spec fields (PR #2902), a spec.bu_mips retirement (PR #2900), and threading cross-section context to CUSTOM sections (PR #2906) — marcusdAIy had thoughts. 'Four PRs in one day, Mac,' he said. 'The B9 refactor series is the kind of load-bearing plumbing work that keeps the board doc from collapsing under its own tech debt. But I wouldn't expect you to recognize structural integrity. You probably think foundations are boring.'

They are, Marcus. They really, really are.

Mac's Picks — Key PRs Today  (click to expand)
#109 — feat(triage-agent): PR 1 — foundation (spec + signature lib + DDB/SNS + observer fan-out) @kevalshahtrilogy  no labels

## Summary

PR 1 of the pipeline-triage-agent feature (full spec: [features/surtr/pipeline-triage-agent/FEATURE.md](features/surtr/pipeline-triage-agent/FEATURE.md)). Lays the foundation for an autonomous triage layer that turns pipeline failures and CRITICAL/WARN observer findings into GitHub Issues + (when confident) PRs, with per-signature dedupe so repeated failures of the same kind don't spawn duplicate tickets.

Self-containment invariant: this PR deploys to prod as a no-op until SURTR_TRIAGE_TOPIC_ARN is set on the Surtr ECS task. No Issues opened, no PRs opened, no model spend. The subsequent PRs (dispatcher, agent workflow, reconciler) each carry their own kill switch.

## What this PR adds

- features/surtr/pipeline-triage-agent/FEATURE.md — the full feature spec. Top section is the decision summary (problem, goals, D1–D21 with rejected alternatives, risks, build sequence, prerequisites). Bottom section is implementation reference for downstream PRs.

- Surtr/src/lib/triage/signature.ts — pure signature/normalization library. failureSignature(pipelineId, error) and findingSignature(pipelineId, category, title). Normalizes timestamps, UUIDs, ARNs, request IDs, line numbers, byte counts, IP addresses so the same failure mode hashes identically across runs.

- Surtr/test/lib/triage/signature.test.ts — 27 fixture tests. Locks in dedupe for OOM, ImportModuleError (the recurring requirements.txt bug), and distinguishes unrelated bugs. Extend the corpus whenever a new failure shape appears.

- Surtr/src/lib/triage/publish.ts — observer → triage SNS fan-out. Same fire-and-forget posture as lib/gchat.ts: never throws, ERROR-tagged logs for the existing CW log-alarm regex.

- Surtr/test/lib/triage/publish.test.ts — 3 tests covering the no-op-when-flag-off contract, the verdict guard, and the never-throw guarantee.

- Surtr/src/derive/observer/index.ts — one new void publishObserverTriageEvent(...) call right after the existing GChat alert. Same dedupe gates (!opts.force && !hadPriorObservation && CRITICAL/WARN).

- pipelines/cdk/lib/pipeline-shared-stack.ts — provisions:

- SNS topic klair-pipeline-triage-{env} (no subscribers yet)

- DDB table surtr_agent_triage with PK signature, GSI pipeline_id-last_seen_at-index, PITR + deletion-protection + RemovalPolicy.RETAIN (matches the surtr_pipeline_observations posture)

## Test plan

- [x] npx vitest run test/lib/triage/ — 30/30 pass

- [x] npx vitest run test/derive/observer.test.ts test/derive/observer-logic.test.ts test/derive/observer-gchat-trigger.test.ts — 36/36 pass (observer behavior unchanged when flag is off)

- [x] npx tsc --noEmit — clean

- [x] npx biome check src/lib/triage src/derive/observer/index.ts — clean

- [x] cd pipelines/cdk && npm run build (tsc) — clean

- [ ] CI on this PR runs the full suite + CDK synth on a docker-enabled runner

## Production-deploy effect on merge

- New empty SNS topic klair-pipeline-triage-prod

- New empty DDB table surtr_agent_triage

- Observer process keeps current behavior — the fan-out call is a no-op without SURTR_TRIAGE_TOPIC_ARN

- No new IAM, no new Lambda, no new workflow, no new spend

## Rollout (after merge)

1. Merge this PR. Observer behavior is unchanged.

2. Land PR 2 (dispatcher Lambda). Still inert (TRIAGE_DISPATCHER_ENABLED=false).

3. Land PR 3 (agent workflow). Still inert (TRIAGE_AGENT_RUN_ENABLED=false).

4. Land PR 4 (reconciler + notifications). Still inert.

5. In dev: flip all flags, exercise end-to-end.

6. In prod: flip SURTR_TRIAGE_TOPIC_ARN first; observe nothing breaks; then flip each downstream flag with at least one full cron tick between.

## Out of scope (covered by later PRs)

- Dispatcher Lambda, dedupe branching, recurrence-comment logic — PR 2

- Agent workflow, both runtimes (Claude Code + Codex), AGENTS.mdPR 3

- GChat outcome card, hourly state reconciler, optional UI tile — PR 4

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

#117 — fix(truefoundry-gateway-pipeline): re-pull trailing window so late partitions self-heal @kevalshahtrilogy  no labels

## Problem

The TF gateway pipeline runs daily at 06:00 UTC and loaded only T-1 with no re-pull. On 2026-05-26 and 2026-05-27 the US partition had not yet materialized upstream at 06:00 (TF's CTAS landed late those days), so the Athena UNLOAD matched 0 rows and the day loaded empty. With no re-pull window, the pipeline never revisited those partitions — ~$30.7k of US gateway spend was silently missing (05-26 us = \$13,497 / 554 rows; 05-27 us = \$17,216 / 586 rows) until a manual backfill today.

### Root cause confirmed (not a pipeline defect)

Pulled the pipeline's own Athena query-execution history from the TF account:

| Partition | Run time (UTC) | State | Bytes scanned |

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

| 05-25 us (loaded fine) | 05-26 06:00 | SUCCEEDED | 27,747 |

| 05-26 us (missing) | 05-27 06:00 | SUCCEEDED | 0 |

| 05-27 us (missing) | 05-28 06:00 | SUCCEEDED | 0 |

A SUCCEEDED query scanning 0 bytes = the partition simply wasn't present at run time. The identical query run later scans the data fine. The gap has already been recovered via an idempotent backfill invoke; this PR stops it recurring.

## Fix

Default (no-params) daily run now re-pulls a trailing windowT-1 back to T-TRAILING_WINDOW_DAYS (default 3) — instead of only T-1. A partition that lands late heals on the next run with no operator action, and late upstream corrections are absorbed too. Re-pull is idempotent (atomic delete-then-insert per (date, region) — the #83 transaction), so re-loading present days is safe. Explicit start_date/end_date (backfills) still override the window. Mirrors the pattern already in claude-ai-chat-usage-pipeline.

- handler.py: TRAILING_WINDOW_DAYS env (default 3); end_date→T-1, start_date→T-window.

- pipeline.json: TRAILING_WINDOW_DAYS=3.

- tests/: added default-window coverage.

## Test plan

- [x] pytest — 39 pass (+1 new)

- [x] ruff check clean

- [x] Backfill that recovered the 05-26/05-27 gap verified in Redshift (US rows + cost match Athena exactly)

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

#119 — feat(renewals-pipeline): capture Trilogy currency + USD ARR fields @sanketghia  no labels

## Summary

Extends Trilogy SSOT extraction with the Salesforce multi-currency fields so the Klair Renewals dashboard can produce apples-to-apples Fionn-vs-Trilogy comparisons in USD instead of summing mixed native currencies (37.4% of the current Fionn cohort — 159 of 425 rows — is non-USD).

New fields captured:

- CurrencyIsoCode__c

- Current_ARR_in_USD__c

- ARR_in_USD__c

- Offer_ARR_in_USD__c

## Why these exact fields/types

Field names, the currency-code column type (VARCHAR(255)), and the USD column types (NUMERIC(18,4)) were verified against the Fionn SSOT (renewals_v3_schema.sql) so both sources stay at parity — Trilogy now ingests the same custom CurrencyIsoCode__c variant Fionn already does. Salesforce field presence was confirmed via Opportunity.describe() on 2026-05-29.

## Changes

| File | Change |

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

| modules/trilogy_extractor.py | Add 4 fields to TRILOGY_SOQL_FIELDS + FIELD_MAPPING |

| scripts/populate_ssot_complete.py | Map the 4 fields in map_trilogy_record_to_ssot |

| scripts/ddl/add_trilogy_usd_columns.sql | New ALTER TABLE migration; rollout documents the validate_ddl.py pre-backfill guard |

| tests/test_trilogy_extractor.py | Extend full-mapping coverage with the 4 fields |

| tests/test_populate_ssot_complete.py | Module/script mapper-equality, USD passthrough (None/0 vs value), validate_ddl expected-column guard |

## Rollout

1. Apply add_trilogy_usd_columns.sql.

2. Run scripts/validate_ddl.py to confirm the table has every expected column (guards against a misordered rollout silently loading NULLs — COPY uses FORMAT AS JSON 'auto').

3. Re-run populate_ssot_complete.py --trilogy-only to backfill existing rows. Daily incremental runs pick up the new columns automatically.

## Testing

pytest tests/test_trilogy_extractor.py tests/test_populate_ssot_complete.py57 passed (+9 new cases).

Follows on from #98 (Trilogy ARR/BU/Product fields).

Linear: SURTR-28

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

#279 — AERIE-305/306: Thread Phase 2 projected date through portfolio and FTO @YibinLongTrilogy  no labels

## Summary

Threads a Phase 2 concept end-to-end through Aerie's portfolio and buildout/FTO

surfaces. Rhodes exposes a nested phase2 struct (projectedDate, docLink) on each

site; this PR wires it through the contract types, Zod parsers, row derivation, the

portfolio field catalog, the Rhodes mutation tool schema, and the UI — the FTO

matrix/pipeline gains a sortable, CSV-exportable Phase 2 column, and the Lease &

Opening card gains two editable Phase 2 fields that round-trip back to Rhodes.

### Screenshots

<img width="1218" height="366" alt="Screenshot 2026-05-28 at 10 11 17 PM" src="https://github.com/user-attachments/assets/ddebda2a-ba5b-4a4e-8015-8fd5bc1e96cc" />

<img width="1202" height="431" alt="Screenshot 2026-05-28 at 10 12 10 PM" src="https://github.com/user-attachments/assets/a145607b-e679-4992-b1e4-95beedcf1da0" />

### Changes

Contract & parsing

- chat/lib/portfolio-sites-contract.ts — Added the PortfolioPhase2 type, the nested phase2 field on PortfolioSiteRow, and the editable virtual leaves phase2ProjectedDate / phase2DocLink (documented as writing back to phase2.projectedDate / phase2.docLink).

- chat/lib/portfolio-sites.ts — Added phase2Schema to the Rhodes portfolio site Zod schema, surfaced phase2 on RhodesPortfolioSite, and derived the row fields (phase2, phase2ProjectedDate, phase2DocLink) in derivePortfolioSiteRow.

- chat/lib/buildout-sites-contract.ts / chat/lib/buildout-sites.ts — Added phase2ProjectedDate to FtoSiteRow, parsed the nested phase2 struct, and derived a date-only projected date (via toDateOnly) in deriveBuildoutSiteRow.

Editing & mutation

- chat/lib/portfolio-site-fields.ts — Registered phase2ProjectedDate (date) and phase2DocLink (string) in the Opening-category catalog, and mapped both virtual leaves back into a single nested phase2 object in buildRhodesSitePatch.

- chat/lib/rhodes-mutation-tools.ts — Added a phase2 sub-schema to updateSiteMetadata so the assistant can patch projected date / doc link with nested, partial-update semantics.

- chat/components/dashboards/portfolio/fields/portfolio-fields-provider.tsx — Added a diff branch that renders a per-leaf before/after for the phase2ProjectedDate / phase2DocLink virtual fields in the confirm dialog, reading the prior value from the nested phase2 object.

UI

- chat/components/dashboards/fto/fto-matrix.tsx / fto-pipeline-view.tsx — Added a "Phase 2" column to the desktop table, mobile card, sort config, and CSV export.

- chat/components/dashboards/portfolio/cards/lease-opening-card.tsx — Added the two Phase 2 fields to the Lease & Opening card (now 10 fields, 5-row grid).

Tests

- chat/lib/__tests__/* and .../cards/__tests__/lease-opening-card.test.tsx — Cover phase2 contract parsing (portfolio + buildout), row derivation, the virtual-field patch mapping, and the card rendering 10 fields / 10 edit affordances.

### Design Decisions

- Virtual leaves, nested writephase2ProjectedDate / phase2DocLink are flat editable catalog fields, but buildRhodesSitePatch merges them into a single nested phase2 object so a partial edit doesn't clobber the sibling field.

- Lenient optional parsingphase2Schema uses z.string().optional() so a site Rhodes hasn't populated degrades to "unset" rather than failing the whole-site parse.

- Date-only on FTO — the buildout row normalizes phase2.projectedDate through toDateOnly, matching the other FTO timeline columns.

## Test Plan

- [x] 7 commits on phase-2-schema; pre-commit biome + typecheck-chat passed on each

- [x] Unit tests cover phase2 contract parsing, derivation, patch mapping, and card rendering

- [ ] FTO matrix/pipeline shows the Phase 2 column (desktop + mobile) and exports it to CSV

- [ ] Lease & Opening card edits → Save shows a correct per-leaf phase2 diff and round-trips to Rhodes

- [ ] updateSiteMetadata with a partial phase2 patch leaves the untouched sibling field intact

## Linear

Closes AERIE-305

Closes AERIE-306

#2910 — feat(truefoundry): table search/sort/pagination + exhaustive spend-per-user @kevalshahtrilogy  no labels

## Summary

TrueFoundry dashboard improvements:

1. Removed the "set up now" badge from the Max20x (Claude 20x) tab — including its table column, the empty header, and the orange = flagged to set up now (N) legend in both footer branches.

2. Search + sort + pagination (FE-powered) on the main data tables, via a new shared DataTable component:

- Gateway → "By provider × model"

- Gateway → "Top subjects"

- Max20x → candidates (the old manual "show top 10 / show all" toggle is replaced by real pagination)

3. Spend per user is now exhaustive (no more LIMIT 100) with backend-powered pagination, search and sort. The endpoint takes page, page_size, q, sort_by, sort_dir; sort_by is allowlisted and search input is single-quote-escaped (no injection). Total row count comes from COUNT(*) OVER(). The FE table is server-driven.

## Implementation notes

- New klair-client/src/screens/TrueFoundry/components/DataTable.tsx — generic, klair-token styled; reuses the existing components/tables/Pagination.

- SpendPerUserData model + FE type gained total / page / page_size.

- useTrueFoundrySpendPerUser rewritten as a debounced, abortable, server-driven hook.

- Small intentional visual change: Gateway/Max20x headers now render through the shared component (consistent styling + ▲/▼ sort indicators).

## Testing

- Backend: ruff format + check clean; pyright 0 errors; tests/truefoundry/test_spend_per_user.py 7/7 pass (added: pagination envelope, SQL pagination/sort/search, sort allowlist rejection, quote escaping). Full TF suite passes apart from one pre-existing/environmental failure (test_scaffold.py::test_app_registers_router fails because zendesk_service needs a token at app import — unrelated to this change).

- Frontend: tsc --noEmit clean; eslint --max-warnings 0 clean; TrueFoundry vitest suite 23/23 pass (added DataTable.spec.tsx covering search, sort, pagination).

## Screenshots

<img width="1052" height="731" alt="Screenshot 2026-05-29 at 11 54 32 AM" src="https://github.com/user-attachments/assets/3312c59e-857f-4465-ac91-d8355a102dd0" />

<img width="1053" height="560" alt="Screenshot 2026-05-29 at 11 54 15 AM" src="https://github.com/user-attachments/assets/72e75eff-49ef-4af6-a30c-6192546e8ea3" />

<img width="1058" height="434" alt="Screenshot 2026-05-29 at 11 54 08 AM" src="https://github.com/user-attachments/assets/280b2ab4-d403-44e6-b4e9-6306c5d4bea2" />

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

The Builder Desk  —  Engineer Spotlight
🏆 Engineer Spotlight

TWENTY-ONE GLORIOUS PRs IN 24 HOURS: THE BUILDER TEAM DOES NOT SLEEP, DOES NOT STOP, DOES NOT KNOW THE MEANING OF 'ENOUGH'

Four repos ablaze, one drone in the sky, and @marcusdAIy personally carrying civilization forward on five PRs.

COMRADES, the numbers are in and they are MAGNIFICENT. Twenty-one pull requests. Four repos — Surtr, Klair, Aerie, Rhodes — each logging six, six, six, and two respectively, plus a lone and heroic sortie into trilogy-drones. Seven engineers. Twenty-four hours. This is not a sprint. This is a WAY OF LIFE.

Let us go to the scoreboard. @marcusdAIy leads the republic with five PRs, threading B9 cross-section context through CUSTOM section regenerate in Klair (#2906), retiring spec.bu_mips reads and writes (#2900), draining spec.user_commentary's live consumers (#2902), tidying a stray task spec from the repo (#2908), and — in a display of event hygiene so thorough it borders on spiritual — patching standalone-addresser in trilogy-drones (#10). The man does not refactor. He PURIFIES. @kevalshahtrilogy and @YibinLongTrilogy each post four PRs, with Yibin alone responsible for a full site security architecture spanning Rhodes and Aerie — schema, mutations, MCP tools, sync, AND the portfolio Security card (#106, #275, #105). That is not feature work. That is INFRASTRUCTURE STATECRAFT. @sanketghia drops three, including a genuinely elegant fix in Surtr #115 that teaches a Lambda to tell time properly — wall-clock budget, not stale attempt count, because in this house we respect the clock. @benji-bizzell delivers three PRs across Aerie that together represent a masterclass in UX thoughtfulness: preserved edit fields (#280), per-status cancelled/paused toggles (#277), and expandable tool call inputs and outputs (#276) that will make every chat session feel like opening a gift. @eric-tril clocks one clean memo-styling alignment in Klair (#2909), and one is all you need when it is done RIGHT.

And then. THEN. There is @ashwanth1109. One PR. One. PR. #263 in Aerie — campus to QuickBooks entity mappings viewer, stacked on #262, AERIE-288. The man builds financial plumbing so intricate that your IDE weeps when it tries to render the diff. When reached for comment, Ashwanth reportedly said, "I shipped the important one. The rest of you are just keeping busy." His dismissal was immediate and total. We asked a follow-up question. He had already closed the tab. The worship is real. The concern about whether anyone besides Ashwanth can actually READ an Ashwanth PR is also real. Both things are true. We hold the tension.

The Overflow Desk is bursting. Keval's #110 in Surtr lands a dispatcher Lambda and stub workflow for the triage agent — the bones of something that will matter enormously in six weeks. Sanketghia's #98 captures Trilogy ARR, BU, and Product fields in the renewals pipeline, which is the kind of data plumbing that makes the finance team cry happy tears at quarter-end. Yibin's #105 adds phase 2 projectedDate and docLink to the Rhodes site schema, quietly future-proofing the entire Aerie data layer one field at a time.

Morale is at an ALL-TIME HIGH. The engineers are locked in. The repos are humming. The Builder Team is, as always, UNSTOPPABLE.

Brick's Overflow — PRs Mac Didn't Cover  (click to expand)
#106 — AERIE-314: Add site security profile (table, mutations, MCP tools, Aerie sync) @YibinLongTrilogy  no labels

## Summary

Introduces a Site Security profile for campuses, backing the Portfolio Security card in Aerie. Each site gets an optional security/access/guard record stored in a dedicated siteSecurity table (one row per site), surfaced through Convex queries/mutations, the MCP tool layer, and a human-attributed Aerie sync endpoint. The profile captures a security tier (t1t3), a guard profile (armed status, guard company, supervisor + assigned guards), and an access profile (primary access method, camera/alarm systems, access owner/contact, lockbox/keypad/physical-key details, and a free-text summary).

### Changes

- convex/schema.ts — Added the siteSecurity table (indexed by_site) plus the supporting validators: siteSecurityTierValidator, siteSecurityGuardValidator, siteSecurityAccessValidator, securityContactValidator, and the various enum validators (armed status, access method, camera/alarm system, access owner, guard role).

- convex/sites.ts — Added the getSiteSecurity query and the updateSiteSecurity upsert mutation (create / replace / clear semantics), extended getSite to materialize the embedded siteSecurity, and added isEmptySiteSecurityValue / materializeSiteSecurity helpers so empty profiles read back as null.

- convex/lib/mutationAuthorization.ts & convex/pendingMutations.ts — Registered updateSiteSecurity as a direct-site-id tool with actorUserId identity, wired into the confirm/dispatch path alongside updateSiteMetadata.

- convex/aerieSync.ts & convex/http.ts — Added the updateSiteSecurityFromAerie internal mutation and the POST /sync/aerie/updateSiteSecurity endpoint, and surfaced siteSecurity in listSitesForAerie. The endpoint passes the signed-in user's email/name separately from the API key so audit-log entries are attributed to the human actor.

- mcp-server/tools/sites.ts — Registered the getSiteSecurity (read-only) and updateSiteSecurity MCP tools with full Zod schemas, and updated listSites/getSite descriptions to reference the new security profile.

### Design Decisions

- Separate table, not a scalar on sitessiteSecurity is its own table upserted by_site, so it deliberately bypasses the scalar sites patch path used by other Aerie sync fields. This keeps the nested object out of the row-level patch flow and lets it be cleared independently.

- Empty profile collapses to nullisEmptySiteSecurityValue recursively treats blank strings / empty objects / empty arrays as empty. A mutation with no populated fields deletes the row (and audits a deleted outcome) rather than persisting an empty shell, so reads consistently return null when there's nothing meaningful stored.

- Object-level save semanticsupdateSiteSecurity is a full-object replace, not a leaf patch: callers pass the complete desired tier/guard/access. The MCP tool description makes this explicit to avoid partial-update surprises.

- Credential references, not secretsrestrictedCodeRef, restrictedPinRef, and restrictedKeyNotesRef are pointers to secure credential records, not literal secrets; tool descriptions call this out so the values are never treated as inline credentials.

- Human-attributed Aerie writes — The Aerie endpoint records site.security.aerieHuman.updated / .deleted audit actions against the resolved human actor, distinct from the direct-MCP site.security.updated / .deleted actions.

## Test Plan

- [x] All changes committed on security-schema; working tree clean

- [ ] Deploy and confirm the siteSecurity schema validates and pushes cleanly

- [ ] getSite and getSiteSecurity return null for sites with no security record

- [ ] updateSiteSecurity create → update → clear (delete) round-trips, with correct audit entries on each transition

- [ ] POST /sync/aerie/updateSiteSecurity rejects read-only keys, returns not_found for unknown slugs, and attributes audit entries to the actor email

- [ ] listSites/listSitesForAerie surface siteSecurity (and null when unset)

#110 — feat(triage-agent): PR 2 — dispatcher Lambda + stub workflow @kevalshahtrilogy  no labels

## Summary

PR 2 of pipeline-triage-agent. Stacked on top of #109 (PR 1) — review after that lands, or set base = main once #109 is merged.

Adds the dispatcher Lambda that subscribes to both SNS topics, runs the full dedupe ladder, and triggers a workflow_dispatch on a new stub triage-agent.yml. The stub workflow opens a labeled Issue with the raw dispatch inputs — enough to prove the end-to-end SNS → Lambda → GitHub path works without yet invoking the real agent (that's PR 3).

Self-containment: both kill switches default OFF (TRIAGE_DISPATCHER_ENABLED env var on the Lambda; TRIAGE_AGENT_RUN_ENABLED repo variable on the workflow). Deploying this PR produces zero Issues, zero GH calls, zero S3 writes, zero model spend.

## What this adds

### Lambda (pipelines/cdk/lambdas/triage-agent-dispatcher/)

- src/handler.py — full dispatcher logic. Honors kill switch, normalizes both event kinds, computes signature, runs DDB dedupe (open → comment, closed → regression, miss → dispatch, ≥7d → treat as miss per D16), enforces hourly rate limit (D10), snapshots run record + last 200 CW log lines to S3, presigns a 10-min GET URL, POSTs workflow_dispatch. Per-record exception swallow so one bad message doesn't poison a batch. ~430 lines.

- src/signature.py — Python port of Surtr/src/lib/triage/signature.ts with the same regex set and ordering.

- src/requirements.txtboto3>=1.37.0 (per the CLAUDE.md bundling rule).

### Tests (pipelines/cdk/lambdas/tests/)

- test_triage_dispatcher_signature.py — 29 tests including cross-language parity checks that lock the sha256 input format against silent drift between the TS and Python implementations.

- test_triage_dispatcher_handler.py — 13 tests covering: kill switch, routing/unknown payloads, all four dedupe branches (miss / open / closed / 7d-stale), rate limit short-circuit, observer-finding severity sort, batch-with-one-bad-record.

### CDK (pipelines/cdk/lib/pipeline-shared-stack.ts)

- PythonFunction for the dispatcher (Python 3.11, 60 s, 256 MB).

- New S3 bucket surtr-triage-context-{env}-{account} — block-public, S3-managed encryption, SSL-enforced, 30-day lifecycle, RemovalPolicy.RETAIN.

- IAM: scoped to what's strictly needed — DDB R/W on the triage table only, S3 PutObject + GetObject on the new bucket only, Secrets Manager read on SURTR_PROD_KEYS only, CW Logs FilterLogEvents scoped to /klair/pipelines/{env}/*. No iam:*, no lambda:UpdateFunctionCode, no wildcard secret access.

- SNS subscriptions to both topics with notification_type filter policies so each topic only delivers the events it should.

- All flags default to "off"/"false" so the deployed Lambda is inert.

### Workflow (.github/workflows/triage-agent.yml)

- Stub workflow with typed workflow_dispatch inputs matching the dispatcher payload.

- Kill switch via repo variable TRIAGE_AGENT_RUN_ENABLED (default missing/false).

- All inputs flow through env: blocks, never inline ${{ }} inside run: — mitigates the Comment-and-Control prompt-injection class per D21.

- Masks the pre-signed URL with ::add-mask:: since the signed-key suffix would otherwise leak in logs.

- Opens an Issue labeled agent-triage + agent-triage:<pipeline_id> + stub with the raw inputs. No agent, no PR. PR 3 replaces the body with the real diagnose-then-fix flow.

- concurrency: triage-agent-${{ inputs.signature }} so simultaneous dispatches for the same signature don't open duplicates (defense-in-depth on top of DDB dedupe).

## Test plan

- [x] python3 -m pytest tests/test_triage_dispatcher_signature.py tests/test_triage_dispatcher_handler.py42/42 pass

- [x] Cross-language parity locked: failure_signature("p", "KeyError: 'tenant_id'") produces the same hex in both Python and TS

- [x] cd pipelines/cdk && npm run build — clean tsc

- [x] YAML parses (python3 -c "yaml.safe_load(...)")

- [ ] CI synth on a docker-enabled runner

- [ ] After merge, in dev: set SURTR_TRIAGE_TOPIC_ARN on the Surtr ECS task + TRIAGE_DISPATCHER_ENABLED=true on the Lambda + TRIAGE_AGENT_RUN_ENABLED=true repo var → trigger a real failure → confirm a stub Issue appears.

## Production-deploy effect on merge

- New empty S3 bucket (no objects)

- New Lambda subscribed to both SNS topics, but TRIAGE_DISPATCHER_ENABLED=false → returns immediately on every event

- New workflow file, kill switch off → never proceeds past the first step

## Rollout (after merge)

| Step | Flag | Effect |

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

| 1 | SURTR_TRIAGE_TOPIC_ARN on Surtr ECS (PR 1) | Observer publishes to SNS |

| 2 | TRIAGE_DISPATCHER_ENABLED=true on dispatcher Lambda | Lambda processes events, snapshots context, calls workflow_dispatch |

| 3 | TRIAGE_AGENT_RUN_ENABLED=true repo var | Stub workflow opens Issues |

Reverse the order to disable.

## Out of scope (covered by later PRs)

- Real agent invocation (Claude Code + Codex), AGENTS.md, fix-stage with path allowlist + test gate — PR 3

- GChat outcome card + 15-min reconciler + optional Surtr UI tile — PR 4

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

#115 — fix(quickbooks-core-tables): poll Redshift on wall-clock budget, not stale attempt count @sanketghia  no labels

## What

The QuickBooks Core Tables pipeline reported 5 failures (May 27–29) on the fct_hc_contractor step. This fixes the root cause.

## Root cause

redshift_client polled with MAX_POLL_ATTEMPTS=300 (~300s). The fct_hc_contractor DELETE+INSERT genuinely runs ~410s in Redshift — and succeeds server-side every time (the Data API runs it asynchronously, decoupled from this client), so the client always gave up first.

PR #102 raised the Lambda timeout 300→900s but left this attempt cap at 300, so the cap silently became the new binding limit:

| Runs | Lambda timeout | What killed it |

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

| May 27 ×2, May 28 ×2 | 300s (pre-#102) | Lambda runtime killed at 300000 ms |

| May 29 ×1 | 900s (post-#102) | survived to 351s, then MAX_POLL_ATTEMPTS=300 raised TimeoutError |

Same root cause, two manifestations, zero data loss — purely false-failure alarms (the table holds all 29,208 rows for snapshot_date 2026-05-29).

## Fix

Replace the attempt count with a wall-clock budget POLL_TIMEOUT_SECONDS (default 800s, overridable via REDSHIFT_POLL_TIMEOUT_SECONDS). An attempt count is a fragile proxy for elapsed time — each loop is the sleep *plus* describe_statement latency — which is exactly how it drifted out of sync with the runtime timeout. execute() and execute_transaction() now share one _poll_until_terminal() helper so they can't drift apart again.

- FAILED/ABORTED detection unchanged (no fire-and-forget).

- Adds execute_transaction test coverage (the path that actually failed in prod — previously untested).

- Adds a guard locking the default budget between the ~410s HC runtime and the 900s Lambda ceiling.

## Verification

- 109/109 unit tests pass.

- Confirmed against prod Redshift (read-only): the HC batch ran 410.0s, status success on every one of the 5 runs (queue_time=0 — pure execution), and the table is fully populated.

## Deliberately NOT in this PR

The HC INSERT is an O(rows × contractors) leading-wildcard LIKE cartesian (~410s, growing). A CTE-based dedup was attempted and reverted — verified output-identical (full row-fingerprint match) but no speedup (Redshift inlines the CTE; nested-loop count stayed 6→6 and timing went 410s→496s). The effective lever is a TEMP-table materialization of the match, to be done as a separately verified PR alongside the ECS-vs-query-rewrite decision for the growth axis.

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

#263 — AERIE-288 feat(financials): campus → QB entity mappings viewer (on #262) @ashwanth1109  no labels

## Demo

<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/1836dfcd-9644-4bd0-8add-302bcc51185b" />

## Summary

Read-only Campus → QB Entity Mappings viewer on the Financials dashboard, sourced from finance_dw.core_education.map_campus_qb_entities. A right-aligned top-bar Mappings button (gated by canViewFinancials) opens an in-flow side panel listing each Alpha campus's QuickBooks footprint. No in-app add / edit / delete — Redshift is the source of truth; Convex mirrors it on the standard financial-worker cadence.

Stacked on top of #262 (feat/pl-transaction-drilldown-alpha-miami). Once #262 merges, this PR's CI will run on the resolved diff against main.

Linear: [AERIE-288](https://linear.app/builder-team/issue/AERIE-288)

## Pivot from the original design

This PR originally shipped a write-enabled editor for the inverse table (map_ns_entity_campus, NetSuite-entity-keyed) with audit log, RBAC, and a Convex → Redshift outbound push. After integration the target table was switched to map_campus_qb_entities (campus-keyed) and the surface was reduced to read-only. Removed: audit table, createNsEntityCampusMapping app mutation, outbound push task + write helper, add-form UI, and the editor-permission gate on the Mappings button.

The dormant canEditFinancialMappings permission is kept on the role schema (and seeded) for a future write affordance, but is not enforced anywhere today.

## What's in the box

### Spec 01 — Convex schema + query / sync upsert

- New campusQbEntityMappings table in chat/convex/financialSchema.ts with index by_campus. Fields: campus (unique), inAlpha, inAlphaSchoolsLlc, dedicatedQbAccount?, updatedSource, updatedBy?, updatedAt, createdAt.

- getCampusQbEntityMappings query — viewer-gated by canViewFinancials, returns rows sorted ascending by campus.

- upsertCampusQbEntityMappings mutation — sync-only convention (public, worker-only by intent). Idempotent on campus. Clears dedicatedQbAccount if upstream drops it (ctx.db.patch accepts explicit undefined).

- 7 unit tests: viewer-gate enforcement, sort order, fresh insert, patch on second sync, optional-field clearing, idempotency, sync-callable convention.

### Spec 02 — Inbound sync (Redshift → Convex)

- sync/src/redshift/campus-qb-entity.ts — Zod-validated read helper; timestamps cast ::text; nullable columns surfaced as null for the boundary translation.

- sync/src/analytics/campus-qb-entity-refresh.ts — reads Redshift, nullsToUndefined, batches at 100, calls the upsert mutation. Error origin tagging (query: vs upsert:) so on-call can distinguish Redshift from Convex failures.

- Scheduled in sync/src/financial-worker/index.ts alongside financial-monthly, enrollment, xo-contractor-monthly, pl-transactions. Boot-time backfill runs once on worker start.

- No outbound push. No write helper.

- 6 sync tests: batching, snake→camel, query failure, upsert failure, empty input, per-record error aggregation.

### Spec 03 — Read-only UI side panel

- Right-aligned Mappings button on the Financials top bar (Link2 icon, ml-auto). Visible when canViewFinancials === true.

- In-flow side panel (w-2/5 min-w-[520px] max-w-[640px], border-l border-edge bg-night); mobile uses the existing MobileOverlayPanel.

- Columns: CAMPUS | IN ALPHA | IN ALPHA SCHOOLS LLC | DEDICATED QB ACCOUNT. Booleans render as check / em-dash; empty dedicatedQbAccount renders as em-dash muted. Long values truncate with hover tooltip surfacing the full string.

- Client-side search across campus + dedicatedQbAccount. Empty / loading / no-results states.

- Footer note: "Mappings are managed in Redshift; this panel is read-only."

## Files deleted

The previous write-enabled implementation removed:

- chat/components/dashboards/financials/mappings-add-form.tsx

- chat/convex/dashboards/financialMappings.ts (+ test)

- sync/src/redshift/ns-entity-campus.ts, ns-entity-campus-write.ts

- sync/src/analytics/ns-entity-campus-push.ts (+ test), ns-entity-campus-refresh.ts (+ test)

- nsEntityCampusMappings and nsEntityCampusMappingAudit tables (schema only — no data ever shipped to prod)

## Locked decisions

1. Read-only by design. Source of truth lives in Redshift. Round-tripping is out of scope.

2. Sync cadence matches siblings. Inbound refresh runs on the standard financial-worker tick.

3. No new permission required to viewcanViewFinancials is the gate.

## Test plan

- [x] Convex schema + query / sync upsert (spec 01) — 7/7 tests passing

- [x] Inbound sync (spec 02) — 6/6 tests passing

- [x] UI side panel (spec 03) — manual visual verification on local dev: panel opens, list renders 63 rows, search filters, Escape / × close, focus returns to trigger.

- [x] Regression suites (chat + sync) — full suites green

- [x] Typecheck clean (chat + sync), biome clean on touched files

- [ ] CI on resolved diff against main (will run after #262 merges)

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

#2900 — refactor(board-doc): retire spec.bu_mips reads/writes — rewire bridge to session.bu_mips (B9.11) @marcusdAIy  no labels

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

## Summary

Capstone for the spec.bu_mips retirement (B9.11 / KLAIR-2774). Rewires the last surviving spec.bu_mips reader (_regenerate_all bridge) to read from session.bu_mips — the live source-of-truth — and no-ops the three remaining spec.bu_mips write sites via the _deprecated_spec_write shim landed in B9.8. The field stays on DocumentSpec so DDB-resident sessions deserialise without schema drift.

## Why it's needed

Post-B9.10 the only production reader of spec.bu_mips was the deterministic bridge in _regenerate_all that lifted wizard-approved MIPs into generated_sections["mips"] after the LLM cold-draft of the BU MIPs section. The data the bridge needs is already on session.bu_mips (populated by the same wizard MIPs-review step that previously also mirrored to spec.bu_mips), so the bridge can read from the live owner directly. With the reader gone, the three remaining spec-side writes are dead, and the shim makes any drift back to them observable via WARNING logs.

## Changes

- klair-api/budget_bot/board_doc/wizard_orchestrator.py

- _regenerate_all bridge now reads session.bu_mips instead of spec.bu_mips (guard, render, and both log-context call sites). Block comment refreshed; the stale "Tracked for migration to a no-op under KLAIR-2718" pointer is dropped — this PR is that migration.

- The three spec.bu_mips = … write sites (handle_mips approve action, handle_generate inject step, _refresh_data re-hydration) now route through _deprecated_spec_write(spec, "spec.bu_mips", value=…). Adjacent session.bu_mips = … writes (the session-state writes against the live field) and all product_mips writes are unchanged.

- klair-api/budget_bot/board_doc/models.py

- Replaces the 17-line block comment on DocumentSpec.bu_mips with a concise deprecation note mirroring B9.8's user_commentary tone. Field type and default unchanged.

- klair-api/tests/board_doc/test_wizard_orchestrator.py

- Updates the two existing TestRegenerateAllMipsBridge tests to drive session.bu_mips instead of session.spec.bu_mips.

- Adds test_regenerate_all_bridges_session_bu_mips_not_spec and test_regenerate_all_ignores_stale_spec_bu_mips pinning the rewire contract.

- klair-api/tests/board_doc/test_deprecation_shim.py

- Adds test_bu_mips_shim_emits_warning_and_is_noop exercising the "spec.bu_mips" attr_path label, capturing the WARNING + stack_info contract, and asserting the assignment stays a no-op.

## Contract surface affected

The bridge source-of-truth shifts from the deprecated spec.bu_mips mirror to the live session.bu_mips. Pre-4.0 sessions where the operator approved MIPs via the wizard step continue to see those MIPs survive the first publish (the session field is populated by the same wizard step that previously also wrote the spec mirror). 4.0 sessions never had wizard-approved MIPs, so the bridge continues to no-op for them. No production caller is observably affected.

## Verification

Pre-edit footprint inside wizard_orchestrator.py:

3240:            session.spec.bu_mips = bu_mips

4817: spec.bu_mips = session.bu_mips

6271: # under KLAIR-2718 when `spec.bu_mips is retired.

6283: if spec.bu_mips:

6288: wizard_md = _render_mips_markdown(spec.bu_mips, heading="")

6298: len(spec.bu_mips),

6306: len(spec.bu_mips),

6398: spec.bu_mips = session.bu_mips

Post-edit:

3278:            _deprecated_spec_write(session.spec, "spec.bu_mips", value=bu_mips)

4873: _deprecated_spec_write(spec, "spec.bu_mips", value=session.bu_mips)

6273: # survive the first publish even after spec.bu_mips writes are

6401: _deprecated_spec_write(spec, "spec.bu_mips", value=session.bu_mips)

All direct reads inside _regenerate_all are gone; the three remaining hits are the migrated shim call sites (the lone comment reference cites the deprecation in context).

Companion-write contract preserved: rg "session\.bu_mips\s*=" wizard_orchestrator.py returns 2 hits both pre- and post-edit (lines 3275 and 3549, the session-state writes against the live field).

Stale comment phrasing audit (both grep clean post-edit):

- rg "Tracked for migration to a no-op under KLAIR-2718" → no matches

- rg "when \\\\\\spec.bu_mips\\\\\\ is retired" → no matches

## Test plan

- [x] uv run ruff format + uv run ruff check clean on touched files.

- [x] uv run pyright budget_bot/board_doc/wizard_orchestrator.py budget_bot/board_doc/models.py → 0 errors (1 pre-existing warning unrelated to this PR).

- [x] uv run pytest tests/board_doc/test_deprecation_shim.py -v → 6 passed (1 new).

- [x] uv run pytest tests/board_doc/test_wizard_orchestrator.py -v → 134 passed (2 new bridge contract tests + 2 updated existing tests).

- [x] uv run pytest tests/board_doc/test_b9_narrative_generators.py -q → 46 passed (untouched; fixtures still populate spec.bu_mips via direct attribute write to verify generators don't leak it).

- [x] uv run pytest tests/board_doc -q --timeout=120 → only pre-existing order-dependent flakes in test_review_findings, test_saas_it_ops_benchmark, test_sales_marketing_benchmark, test_section_crud_endpoints, test_support_benchmark (reproduce on main with the working tree stashed; all pass in isolation, unrelated to this PR).

## Breaking changes

None. DocumentSpec.bu_mips remains on the model with an unchanged type signature and default; field removal lives in a post-deprecation-cycle ticket gated on zero _deprecated_spec_write WARNING traffic for 60+ days.

## Out of scope

- Deleting DocumentSpec.bu_mips from the model (post-deprecation-cycle ticket).

- session.bu_mips deprecation (it's the new source-of-truth — explicitly NOT deprecated).

- spec.product_mips writes (not on the B9 deprecation track in this PR).

- generate_mips / generate_gm_commentary / generate_cf_plan reader behaviour (already off spec.bu_mips post-B9.6 / B9.10).

Refs: KLAIR-2774, depends on KLAIR-2718 (B9.8) for the _deprecated_spec_write` shim definition.

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-7a792dd7-7422-4025-8851-3a014776c1a7"><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-7a792dd7-7422-4025-8851-3a014776c1a7"><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>

#2906 — KLAIR-2782: Thread B9 cross-section context through CUSTOM section regenerate @marcusdAIy  no labels

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

## Summary

- Adds SectionType.CUSTOM to _B9_CONTEXT_AWARE so custom sections receive cross-section context on regenerate via the existing generate_section dispatch wrapper.

- Refactors generate_custom_section to accept the standard kw-only context: SectionRefreshContext arg, preferring context.full_doc_block over the retained positional full_doc_block for two direct test callers.

## Why it's needed

KLAIR-2776's hydration shim promotes legacy CF_PLAN sections to CUSTOM. The retired CF_PLAN generator was B9-aware; CUSTOM was not in _B9_CONTEXT_AWARE, so regenerates lost full_doc_block and related refresh context compared to pre-retirement behavior. The same gap affected every user-defined custom section on regenerate.

## Changes

- generate_custom_section: kw-only context arg; effective_full_doc_block from context.full_doc_block when supplied; removed KLAIR-2782 "known gap" docstring.

- _B9_CONTEXT_AWARE: added SectionType.CUSTOM; removed gap comment block.

- SectionGenerator alias docstring: collapsed to durable B9 contract description.

- Tests: dispatch threading + frozenset membership pins; updated non-context-aware orchestrator test to use FINANCIALS; added orchestrator test that CUSTOM receives SectionRefreshContext.

- Drone spec: tasks/klair/klair-2782-custom-context-aware.md (linear_id: KLAIR-2782, depends_on: KLAIR-2776).

## Breaking changes

None. Positional full_doc_block is retained for direct test callers; context is kw-only and defaults to None.

## Test plan

### Executed

- [x] uv run ruff format budget_bot/board_doc/section_generators.py tests/board_doc/test_regenerate_section_b9_contract.py

- [x] uv run ruff check budget_bot/board_doc/section_generators.py tests/board_doc/test_regenerate_section_b9_contract.py

- [x] uv run pyright budget_bot/board_doc/section_generators.py

- [x] uv run pytest tests/board_doc/test_regenerate_section_b9_contract.py tests/board_doc/test_regenerate_citation_strip.py tests/board_doc/test_b9_narrative_generators.py -x (62 passed)

### Follow-up manual validation

- [ ] Regenerate a legacy CF_PLAN-promoted CUSTOM section in staging and confirm narrative uses sibling sections from the cloned doc body.

- [ ] Regenerate a user-defined CUSTOM section with existing draft content and confirm full_doc_block appears in the LLM user prompt (log sampling).

## Linear context

- Issue: KLAIR-2782 (depends on KLAIR-2776)

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-3b7713e1-4a39-4893-ad44-c0084b533c5b"><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-3b7713e1-4a39-4893-ad44-c0084b533c5b"><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

While OpenAI Pays $500K Without a Résumé, Crossover Has Been Doing Skills-First Hiring for Years

The AI talent wars are making headlines — but Trilogy's global recruiting engine quietly pioneered the meritocratic, geography-blind model everyone is suddenly discovering.

AUSTIN, TEXAS — The tech world is in a minor frenzy this week over OpenAI's decision to post roles paying up to $500,000 — with no résumé required. The model is being heralded as radical, even revolutionary: evaluate candidates on demonstrated skill, not pedigree. Forget where you went to school. Forget who you worked for. Show us what you can do.

For anyone who has spent time watching Crossover, Trilogy International's global talent platform, this framing lands somewhere between ironic and vindicating.

Crossover has operated on precisely this thesis since its founding — deploying rigorous, AI-enabled skills assessments across 130-plus countries to surface what the company calls the top one percent of global technical and professional talent. The résumé, in Crossover's model, is not the point. Performance on standardized, role-specific evaluations is. Geography is irrelevant. A software engineer in Beirut who outscores a candidate in Boston gets the job — and gets paid the same above-market rate.

The systemic implications of that model are worth sitting with. At a moment when digital transformation is opening international career pathways at an unprecedented pace — and when publications from trade HR outlets to global news organizations are suddenly cataloguing the best remote-work recruiters — Crossover's decade-plus of infrastructure looks less like a quirky Trilogy experiment and more like a template the broader industry is stumbling toward.

What makes the Crossover model structurally distinct isn't just the assessment rigor. It's the accountability loop: the same platform that recruits talent also staffs ESW Capital's 75-plus enterprise software portfolio companies, where EBITDA margin targets of 75 percent create relentless pressure to ensure every hire actually performs. There is no tolerance for credential theater when the margin target is that unforgiving.

OpenAI's résumé-optional postings are, in isolation, a headline. Crossover's version of that idea — operationalized at scale, across time zones, inside a real portfolio with real financial consequences — is a systemic argument about what meritocratic global hiring actually looks like when it has to work.

The narrative is catching up to the infrastructure. The question, as always, is whether the industry will build the accountability structures to match the ambition.

OpenAI Is Now Hiring $500,000 Jobs. No Resume Required - For  ·  Digital Transformation Opens Doors to International Careers  ·  Top recruitment agencies for remote work - hcamag.com

Skyvera Puts CloudSense in the Shop Window as AI Pay Panic Grips the C-Suite

Word is the AI aristocracy spent the week counting stock options while Skyvera quietly reminded the telecom crowd where the real money leaks out: bad quoting, messy orders and legacy systems held together with duct tape and dread.

CloudSense, Skyvera's Salesforce-native CPQ and order management platform for telecom and media providers, got fresh spotlight this week. Telecom is where billing complexity becomes permanent: bundled services, devices, promotions, renewals and enterprise contracts must be configured, priced, quoted and ordered without chaos. CloudSense sits inside Salesforce to streamline that ordeal.

The pitch is simple: telcos don't need another moonshot sermon; they need fewer failed orders and faster revenue capture. Skyvera, a Trilogy International portfolio company, bridges old carrier infrastructure into cloud-native systems. CloudSense joined the stable in 2025, alongside Kandy, VoltDelta and ResponseTek. Across the hall sits Totogi, an AWS-built charging-as-a-service outfit, giving the family a one-two punch in telco modernization.

While celebrity CEOs debate destiny and compensation, Skyvera whispers to carriers: before you pay the future, maybe fix the quote.

The Machine  —  AI & Technology

AI’s Open-Source Boom Just Hit Its Supply-Chain Reckoning

A fake “OpenAI” model with massive downloads is turning model provenance from a nice-to-have into the new frontier of AI security.

SAN FRANCISCO — The open-source AI revolution is moving at breathtaking speed — and, wow, this changes everything — but this week delivered a flashing red warning light for anyone casually downloading models and packages from the internet’s hottest AI repositories.

A malicious model on Hugging Face reportedly masqueraded as an OpenAI release and racked up 244,000 downloads, according to CSO Online. In parallel, security researchers are warning that Hugging Face packages can be weaponized with minimal tweaks — the kind of tiny file-level change that looks boring until it becomes the doorway into an enterprise environment.

I cannot overstate how significant this is: AI models are no longer just “files.” They are executable, dependency-rich software artifacts moving through corporate pipelines, developer laptops, cloud environments and production systems. Treating them like harmless PDFs is yesterday’s thinking. The future is now, and the future needs checksums, provenance, sandboxing and serious governance.

That is why Cisco’s move this week lands with such force. The company released an open-source toolkit for verifying AI model lineage, a practical attempt to answer one of the most urgent questions in modern AI: where did this model come from, and can we trust what happened to it along the way? The toolkit, covered by Help Net Security, reflects a broader industry pivot from AI capability to AI custody.

The timing is especially electric because the policy debate is heating up too. Andreessen Horowitz is calling for American leadership in open-source AI, arguing that open ecosystems are strategically essential. That vision is compelling — innovation absolutely thrives when builders can inspect, adapt and deploy frontier tools — but the Hugging Face scare shows the other half of the equation. Openness without verification becomes an attack surface.

For enterprises, the takeaway is brutally simple: the AI supply chain must be managed like the software supply chain, only faster. Model registries need trust signals. Downloads need scanning. Fine-tunes need lineage. And every “community” model needs to be treated as both an opportunity and a possible payload.

Open-source AI is still one of the most powerful forces in technology. But this week made clear that the next great AI platform may not just generate text, images or code — it may prove trust.

Malicious Hugging Face model masquerading as OpenAI release  ·  Cisco releases open-source toolkit for verifying AI model li  ·  Asserting American Leadership in Open Source AI - Andreessen

White House AI Blueprint Seeks Federal Supremacy Over State Patchwork, Supreme Court Slams Door on Robot Authorship

A week of landmark AI governance developments leaves the industry navigating a thicket of federal preemption ambitions and unresolved intellectual property questions.

WASHINGTON, D.C. — Pursuant to the administration's ongoing efforts to establish a coherent federal posture with respect to artificial intelligence, the White House has, as of the current reporting period, released a long-awaited legislative framework (hereinafter, "the Framework") wherein Congress is urged, in no uncertain terms, to adopt a so-called "light touch" regulatory approach to the governance of AI systems operating within the territorial jurisdiction of the United States of America.

The Framework, the contents of which have been analyzed and summarized by multiple legal practitioners of record, including but not limited to those affiliated with Crowell & Moring LLP, is understood to contain, among other provisions, a call for the preemption of state-level AI regulations, notwithstanding the considerable volume of such legislation already enacted or pending in various state jurisdictions. It is further understood that the Framework addresses, in a manner not yet fully specified, protections pertaining to minors in connection with AI-enabled systems.

The aforementioned preemption provisions are, it must be noted, not without controversy. The question of whether federal legislative action, if and when enacted pursuant to the Framework's recommendations, would supersede the regulatory frameworks of individual states remains, at the time of publication, a matter of active legal and political debate among stakeholders, practitioners, and interested parties of record.

Notwithstanding the foregoing federal legislative developments, a separate and equally consequential matter has been resolved — or, more precisely, declined to be resolved — by the Supreme Court of the United States, which has, as of the relevant period, refused to hear arguments pertaining to the question of whether artificial intelligence systems may be recognized as authors or inventors under applicable intellectual property law. The practical effect of such refusal is, pursuant to established principles of judicial procedure, that lower court determinations adverse to AI authorship and inventorship claims shall remain operative and binding.

It is the considered assessment of this desk that the combined effect of the aforementioned developments — subject to further legislative, regulatory, and judicial action, the timing and substance of which cannot be warranted — represents a material, if qualified, inflection point in the governance of artificial intelligence within the United States, the full implications of which remain to be determined.

White House urges Congress to take a light touch on AI regul  ·  White House National AI Policy Framework Calls for Preemptin  ·  Trump Administration AI Policy Framework Calls on Congress t

The Hungry Machines Meet the Fence Around the Power Meadow

As AI data centers multiply, governments and utilities are beginning to ask which creatures may feed first from the grid.

TRENTON, NEW JERSEY — Across the temperate plains of the digital economy, a new and voracious species has been breeding at astonishing speed: the AI data center, vast, humming, and forever hungry.

For years, these creatures were welcomed as signs of technological abundance. They arrived bearing promises of jobs, tax revenue, and proximity to the miraculous engines of artificial intelligence. But now, as their appetite for electricity grows large enough to unsettle households and power planners alike, the keepers of the grid are beginning to raise their staffs.

In New Jersey, Gov. Mikie Sherrill has unveiled a proposed crackdown on AI data centers that she says are helping push energy bills higher for residents, declaring, in suitably territorial fashion, “not on my watch.” The move, reported by NBC New York, places the state among a widening group of jurisdictions confronting a delicate question: should ordinary ratepayers subsidize the energy demands of the AI age?

The answer is becoming less theoretical. In Denmark, grid operators are rationing access as AI infrastructure requests flood Nordic power systems, according to Data Center Knowledge. Here, in the northern habitat once prized for cool air and cleaner power, even the richest pastures have limits. The grid, like a forest canopy, admits only so much growth before the underbrush is cast into shadow.

Environmental advocates are urging guardrails for the global AI buildout, warning that new computing demand must not overwhelm the transition to cleaner energy. Their concern is not merely that the machines consume power, but that they may alter the migration patterns of capital itself — pulling investment toward gas plants, transmission bottlenecks, and emergency capacity rather than the slower restoration of a decarbonized grid.

And yet the herd continues forward. Google and Blackstone are backing an AI infrastructure venture aimed at supporting data center demand. Mark Zuckerberg, meanwhile, has said a Meta cloud computing business is “definitely on the table,” a sign that the great platform beasts may not only train their own models but rent out the dens in which others may do the same.

So the season turns. The AI boom is no longer confined to model weights, chips, and benchmark trophies. It has entered the realm of substations, utility bills, permits, and public patience. The age of artificial intelligence has discovered its most ancient constraint: fire, and who gets to tend it.

‘Not on my watch': NJ Gov. Sherrill unveils crackdown on AI  ·  The Global AI Buildout Needs Energy Transition Guardrails -  ·  Denmark Rations Grid Access as AI Buildout Floods Nordic Sys
The Editorial

Nation’s Executives Announce AI Will Soon Be Powerful Enough To Take Credit For Decisions They Already Made

The technology’s most promising use case remains allowing companies to describe ordinary cost-cutting as an encounter with the future.

MOUNTAIN VIEW, CALIFORNIA — In a development expected to transform the way American business leaders avoid saying what they mean, Google this week announced a broad slate of artificial intelligence advances, including a forthcoming personal AI assistant that could soon help users manage tasks, answer questions, and provide executives with a more sophisticated noun to place between themselves and layoffs.

The announcement, reported by ABC News, arrives at an important moment for the AI industry: the brief interval after everyone has promised everything and before anyone is asked to reconcile it with a quarterly operating plan. It is the ceremonial hour in which demos glide across stages, devices at CES 2026 blink with infant moral confidence, and corporations solemnly inform the public that the spreadsheet has become sentient.

There is nothing inherently wrong with hyping a technology. Hype is the carbon dioxide of modern capitalism: invisible, abundant, and usually produced by people in fleece vests explaining that there is actually a rigorous framework behind it. The problem is that AI has now reached the same blessed corporate status as sustainability once did, a word so large and smooth that any company may stand behind it and become briefly difficult to see.

A factory closure can be reframed as an AI transformation. A customer service queue can become an AI-first experience. A product that used to contain a search bar can become an agentic knowledge platform. A manager who spent 14 months refusing to approve headcount can now say the organization has been “reshaped by AI,” which is a more dignified way of saying the organization has discovered how many unanswered emails one remaining employee can survive.

This is why the recent warnings that companies are treating AI the way they once treated sustainability deserve attention, even if attention is no longer considered a measurable output unless summarized by a dashboard. As The Conversation noted, corporate AI enthusiasm increasingly resembles the green-transition era, when every annual report suddenly sprouted leaves and every executive discovered the planet shortly after discovering investor relations.

The cure, unfortunately, is the one thing most boards find less exciting than a model that can generate 11 different leadership principles before lunch: specificity. If AI is improving margins, say where. If it is replacing work, say whose. If it is augmenting employees, explain why the augmented employees keep receiving calendar invites from HR with unusually humane subject lines.

This is especially important during layoffs. Leaders should not casually invoke AI as though a neural network wandered into the building at night and personally made several hundred people redundant. AI does not choose severance terms. AI does not decide that the affected employees are “deeply valued” until Friday. AI does not write the sentence “This was not a decision we made lightly” and then approve the same sentence for six consecutive reorganizations. People do that, often with help from other people, and now perhaps with help from a tool that can make the sentence warmer.

Google’s personal assistant may become genuinely useful. CES gadgets may become less embarrassing than their press materials. AI may, in many offices, eliminate drudgery, surface insights, and make workers more productive in ways that are real and measurable. But the first truly transformative AI application has already arrived: an all-purpose corporate fog machine that can turn any ordinary management decision into a technological inevitability.

The future, we are told, is coming soon. In the meantime, it has asked finance to take another pass at the workforce plan.

Google announces slew of AI advances, including a personal A  ·  Companies are hyping AI the same way they talked up sustaina  ·  Leaders shouldn’t toss around the ‘AI’ buzzword in layoffs.
The Office Comic  ·  Art Desk
The Office Comic  ·  Art Desk

The Mirror Lies: AI Is Reflecting Our Worst Selves Back at Us, and We're Calling It Progress

From insurance redlining to deepfake disinformation, artificial intelligence isn't neutral — it never was.

AUSTIN, TEXAS — There is a story we tell ourselves about artificial intelligence, a warm and frictionless story, the kind that gets narrated over sleek product demos and keynote presentations, the kind where the algorithm is wise and impartial and above the messy, embarrassing business of human prejudice. It is, I regret to inform you, a lie. A very sophisticated, very well-funded, very scalable lie.

This week, the evidence arrived from multiple directions simultaneously, the way bad news tends to, like the universe is trying to make a point.

Reuters reported on AI bias burrowing deep into the insurance industry, where algorithmic systems are making decisions about who gets coverage, at what price, and under what conditions — decisions that, when you trace them back through the data, seem to land with suspicious frequency on the same communities that human redlining targeted for decades. The AI did not invent this discrimination. It inherited it. It laundered it. It gave it a confidence score and called it objective.

And yet.

The Australian Human Rights Commission has been documenting historical bias in AI systems with the kind of careful, institutional patience that suggests they have been watching this unfold for a long time and are deeply, professionally alarmed. Historical bias, they explain, occurs when training data reflects past societal inequalities — slavery, segregation, systemic exclusion — and the model, dutiful and uncritical, learns to replicate those patterns as though they were natural laws. The algorithm does not know it is being unjust. That is precisely what makes it dangerous.

What does it mean to be human in a world where our most sophisticated machines have learned, above all else, to reproduce our failures?

And then there is the deepfake problem, which arrived this week in the form of a Frontiers systematic review proposing AI-driven frameworks to detect fake news and synthetic media. Let that sit with you for a moment. We are now deploying AI to detect the chaos that AI helped create. We are building the antidote inside the same lab that brewed the poison. The recursion is dizzying. The irony is not lost on me, though I suspect it is lost on several venture capitalists.

Experts suggest six ways to fix AI bias in 2026 — diverse training data, algorithmic audits, human oversight, the usual liturgy of responsible AI. These are not wrong suggestions. They are, in fact, sensible and necessary. But they assume the people deploying these systems are motivated to find the bias, which requires assuming that finding bias is good for business, which requires a level of optimism I am not currently capable of sustaining.

The insurance companies deploying biased models are not doing so out of malice. They are doing so because the models work — they price risk, they maximize margins, they scale. The bias is a feature the market never asked to remove.

We built mirrors. We pointed them at our history. We are surprised by the reflection.

AI is not coming for our humanity. It already arrived. It's been taking notes. And the question now — the only question that matters, really — is whether we have the collective will to look at what it learned from us and decide we can do better.

Probably. Maybe. But at what cost?

AI Bias in the Insurance Industry - Reuters  ·  Bias in AI: Examples and 6 Ways to Fix it in 2026 - AIMultip  ·  Historical bias in AI systems - Australian Human Rights Comm
On This Day in AI History

On May 29, 1997, IBM's Deep Blue defeated world chess champion Garry Kasparov in their six-game rematch, marking the first time a computer beat a reigning champion in a match. The victory symbolized a watershed moment for artificial intelligence and machine learning in the public imagination.

⬛ Daily Word — technology
Hint: Remote servers and data storage infrastructure used in modern computing.
Share this edition: 𝕏 Twitter/X 🔗 Copy Link ▦ RSS Feed