Everything TRIF changes, and why.
If you've written Selenium or Playwright, you already know most of this — under different names, with different trade-offs. Here's each TRIF concept, the traditional idea it maps to, and the benefit of the change.
At a glance
| TRIF concept | Traditionally | Why it's better |
|---|---|---|
| Recipe | a test script / test case | human- and agent-readable, engine-portable, runs from ~400 tokens |
| Cookbook | a test project / suite | one versioned artifact; knowledge captured once, reused at O(1-test) |
| Anchor | a selector / locator | resilient semantic resolution; drift is named, not a mystery break |
| Oracle | assertions in the script | the success criterion is explicit and gradeable by anyone |
| Four verdicts | pass / fail | separates a real bug from drift from "couldn't run" |
| Binding & graduation | a compiled test script | pay to learn the app once, then rerun at $0 — script is disposable |
| Disclosure levels | load the whole framework | a test costs ~1,500 tokens no matter how big the app is |
| Freshness ledger | — (a wiki that rots) | the cookbook tells you what's stale before a run lies |
| Healing | manual maintenance / silent self-heal | repair is explicit and reviewable — never masks a regression |
| Four doors | framework / language lock-in | same tests from any agent, any CI, or by hand — no rewrite |
| Evidence & report | a report + screenshot-on-fail | native-grade, uniform evidence for every verdict and lane |
| IA map | — (tribal knowledge) | see exactly what's covered and how the app is modeled |
In detail
Recipe
maps to → a test script / test caseA single test written as human-readable intent: a setup line, ordered steps in a small fixed verb grammar (goto · click · fill · read · wait_for …), and an explicit oracle. It refers to elements by anchor, never by raw selector, and lives in one small markdown file.
.spec.ts (or Java/Python) file: selectors, waits, and assertions interleaved in code, tied to one engine and one language, only a programmer can read.recipes/TC-01.md: steps + oracle in plain language, engine-agnostic, ≤400 tokens — a person, an agent, or a compiled script can all execute it.Cookbook
maps to → a test project / suiteThe versioned bundle of everything known about testing one app: its recipes, the app map + anchor registry, a healing playbook, and a freshness ledger — a directory <app>.trif/ with a semantic version.
Anchor
maps to → a selector / locatorA semantic reference to a UI element — role + accessible name + a stable hint + a note on the non-obvious bits — resolved at run time by a ladder: engine hint first, then role/name, then an agentic fallback. Stored in map/anchors.json.
#firstHeading, an XPath, a CSS chain — hardcoded in the test. When markup changes it breaks with a bare "element not found".locator(...) when a recipe graduates — so you get flexible resolution at author time and a fast selector at run time.Oracle
maps to → assertions inside the scriptThe test's success condition, made first-class and explicit: deterministic checks (equals · contains · count · matches) are preferred; "judged" (model-graded) oracles are second-class and can never auto-file a bug.
expect(...) calls buried among the actions, implicit and engine-specific — you have to read the code to know what "pass" even means.oracle: block anyone (human, agent, compiled script) grades the same way — and deterministic is the path of least resistance.Four verdicts
maps to → pass / failPASS · FAIL-BUG (real defect, evidence-quoted) · FAIL-STALE (the app drifted — an anchor miss) · BLOCKED (couldn't run: missing capability, unreachable app, auth).
Binding & graduation
maps to → a compiled test scriptWhen a recipe passes on the intent lane and is deterministic-ready, its steps + anchors + oracle compile into a real script (Playwright .spec.ts, Katalon .groovy) that reruns with no model. See exactly how in the infographic.
Disclosure levels
maps to → loading the whole frameworkThe cookbook is layered (router → recipe → healing → map → ledger) so an executor loads only what one test needs: the router (≤1000 tokens) + one recipe (≤400). The repair layers load only on failure or authoring.
Freshness ledger
maps to → (nothing — a wiki that rots)A dated coverage record (coverage.json) that tracks what's exercised and fingerprints each recipe + its resolved anchors, so staleness is detectable before a run.
stale reports per-surface freshness; a binding retires automatically the moment its recipe or anchors change.Healing
maps to → manual maintenance / silent self-healWhen a run drifts, it emits a machine-readable patch proposal (anchor-fix, new-quirk, …). A maintainer — the only writer — applies it, bumps the version, and the recipe re-graduates. Executors stay read-only.
Four doors
maps to → framework / language lock-inOne cookbook, four ways in: an Agent Skill (SKILL.md), an MCP server, the CLI, or the raw files. Each is a thin wrapper over the same files; results flow back into the same schema.
Evidence & report
maps to → a report + screenshot-on-failEvery run leaves a native bundle — Playwright trace, video, console + network logs, screenshots — and a self-contained HTML report that shows the verdict, the resolved lane, the step trace, the oracle checks, and the evidence.
IA map
maps to → (tribal knowledge)A generated, browsable map of the app's information architecture — surfaces × anchors × recipes, color-coded by freshness, with a detail drawer.