TL;DR: The engines move to the public API. Turbo-Cat (the ~200-format knowledge base) and the bench engine join scoring and the 6Ws Interview as composed, single-source engines — every FAF MCP imports them through the bridge instead of carrying its own drifting copy. And a same-day patch proves the doctrine polices itself.

One Engine Each. Composed Everywhere.

Before this release, the real Turbo-Cat lived only inside the CLI — so each MCP server ran its own smaller, hand-maintained format map. Same for the bench engine. That's how drift happens: five copies, five trajectories, one truth slowly forking.

import {
  turboCatScan,      // ~200-format detection — per-format breakdown + stack signature
  deriveQuestionSet, // the bench engine — your .faf is the answer key
  publicQuestions,   // questions WITHOUT the answer key (see below)
  gradeAnswers,      // mechanical grading — no judge, no rubric drift
  buildReceipt,      // the ✪ receipt — sha256, third-party re-derivable
} from 'faf-cli';

The servers don't adapt to these — they delete their local copies. Detection sourced-only and order-independent. Grading byte-identical across the CLI and every server. The receipt is now one convention across parity, trust, and bench: sha256 over a canonical projection, re-derivable by anyone.

The Answer Key Stays Locked

The bench export came with one integrity-critical clause: deriveQuestionSet returns the answer key (your .faf's values) so grading can be mechanical. A tool that printed that key would make the benchmark a lie. So the API makes the mistake unmakeable — publicQuestions(qset) is the only shape a "give me the questions" surface hands out. Version, hash, questions. Never answers.

The Same-Day Patch — Doctrine Policing Itself

Hours after 6.10.0 shipped, the first consumer caught something: Turbo-Cat's knowledge base asserted a full Chrome Extension stack — JavaScript, Chrome Web Store, the lot — from the filename manifest.json alone. But manifest.json is one of the most overloaded names in software: chrome extension, MCP bundle manifest, PWA, plain config. Asserting a stack from the name is a guess. Sourced-only forbids guessing. The release that shipped the doctrine was violating it.

TS project + an mcpb manifest.json
  6.10.0:  JavaScript · Chrome Extension   ✗ guessed
  6.10.1:  TypeScript · (none)             ✓ sourced

v6.10.1 fixes it the right way: content decides, never the filename. Chrome asserts only when manifest_version is a number and a chrome field is present — real extensions still detect, v2 and v3. MCP manifests, PWAs, and anything ambiguous assert nothing. An honest empty beats a guessed stack.

That's the part worth reading twice: the consumer that caught it verified the fix independently before it shipped. Single-source engines mean one bug, one fix, every surface healed at once — that's the entire argument for composing.

Try It

Or bunx faf, or brew install faf-cli. Building on the formats? The engines are right there on the import.

The Numbers

  • v6.10.0 + v6.10.1 — Released June 12, 2026
  • 843 tests, 0 fail — 2,746 assertions
  • 🏆 100% — Trophy score
  • 4 composed engines — scoring · 6Ws Interview · Turbo-Cat · bench
  • 23 new contract tests — populated-not-present · answer-key-not-leaked · content-not-filename