NAC3 v2.4 / Conduit closure
← spec home  ·  600-run benchmark  ·  migration paper  ·  2026-05-22 closure
Conduit closure · cheap-model unlock + cross-language transfer + NAC3 strict resolution

574 / 600 at N=10.
Four models × five languages.

We pushed the community Conduit fork -- 47 React components, Express + Sequelize backend, real Medium-clone surface -- through a paper-grade matrix: 4 models × 5 languages × 3 flows × N=10 = 600 dispatched flows. Sonnet 4.6 scores 150 / 150. Haiku 4.5 scores 148 / 150 at half the cost. Gemini 2.5 Flash Lite (the default) scores 144 / 150 at $0.0007 per flow -- 40× cheaper than Sonnet. The matrix held across English, Spanish, Chinese, Hindi (transliterated), Arabic. Total cost to run the experiment: $7.31.

Total trials600 (N=10 × 4 models × 5 langs × 3 flows).
Aggregate pass-rate95.7% (574 / 600).
Default modelgemini-2.5-flash-lite -- $0.0007 / flow, 96.0% N=10 cross-lang.
Closure cost$7.31 to run the full matrix. Reproducible.
Paper-grade N=10 matrix
574 / 600
95.7% aggregate across 4 models × 5 langs × 3 flows. See closure matrix below.
Cheap-model unlock
40×
Flash Lite at $0.0007/flow hits 96.0% N=10 cross-lang vs Sonnet at $0.028/flow at 100%. Cheap default lands.
NAC3 strict-resolution lift
+12 pts
12 of 18 prior "model failures" on Haiku were runtime damage (silent indexOf fallback). Haiku reclassified 3/9 lenient → 10/10 strict.
gen-tests closure (structural)
91.1%
51 / 56 peak Cypress pass-rate. Median 89.3%, floor 85.7%. Net lift from 30.7% baseline: +60.4 pts over the journey.
00 / Closure -- the matrix that ends the experiment VERIFIED

Four models, five languages, three flows, thirty trials each cell.

The headline N=10 paper-grade matrix. Same 3 flows from prior phases (login, post_comment, favorite_article) × 5 languages (en / es / zh / hi-Latin / ar) × 4 models × N=10 trials per cell = 600 dispatched flows. Strict-resolution NAC3 runtime (v2.4) throughout -- no lenient fallbacks, no silent indexOf matching. Pilot drives the cockpit per turn; harness captures result + cost + tokens + latency.

Langflash-litegpt-5-minihaiku-4-5sonnet-4-6Lang total
en27 / 3027 / 3030 / 3030 / 30114 / 120 (95.0%)
es29 / 3026 / 3030 / 3030 / 30115 / 120 (95.8%)
zh29 / 3029 / 3030 / 3030 / 30118 / 120 (98.3%)
hi (Latin)29 / 3022 / 30 ⚠28 / 3030 / 30109 / 120 (90.8%) ⚠
ar30 / 3028 / 3030 / 3030 / 30118 / 120 (98.3%)
Model total144 / 150 (96.0%)132 / 150 (88.0%)148 / 150 (98.7%)150 / 150 (100%)574 / 600 (95.7%)

Headline reads:

Hindi is an OPEN question, not a settled finding. The Hindi prompts ran in Latin transliteration (ASCII), not native Devanagari, so we cannot attribute the 109/120 = 90.8% gap to script handling. Candidate hypotheses (none ruled in or out by this matrix): (1) transliteration friction -- Latin Hindi may be off-distribution for models trained on native-script web text; (2) training-data sparsity; (3) tokenizer fragmentation under transliteration; (4) verb-final syntax + loaned English nouns; (5) sample-size artefact (N=30 per cell is paper-grade but a 2-point gap can still be coin-flip without N=50+). A follow-up running Devanagari + Latin side-by-side would isolate hypothesis (1). The paper reports the observation + hypothesis set; it does not claim causation.

Cost summary, full experiment (N=10 cross-language):

ModelCost / flowTotal trialsTrials costPass-rate$ per pass
gemini-2.5-flash-lite$0.0007150$0.10596.0%$0.00073
claude-haiku-4-5$0.0131150$1.9798.7%$0.0133
claude-sonnet-4-6$0.0279150$4.19100%$0.0279
gpt-5-mini~$0.007150$1.0588.0%$0.0080
Matrix total600$7.3195.7%

The unlock: for the assistive-tech use case where 100% is not mandatory, you drive a Conduit-equivalent app cross-language with $0.001/flow Flash Lite at 96% reliability, then escalate to Sonnet at 40× cost only for the cells where 100% is required. The contract is model-agnostic in 4 of 5 languages and survives reframing of the 5th as an open question rather than a limit.

00c / Structural closure -- gen-tests Cypress final VERIFIED

From 30.7% baseline to 91.1% peak on the structural metric.

Parallel to the operational closure above, the structural metric -- the Cypress test suite auto-generated by yf gen-tests, one test per (nac_id, role, verb) tuple -- closed at peak 51 / 56 = 91.1%, median 50 / 56 = 89.3%, floor 48 / 56 = 85.7% across 3 consecutive runs. Net lift: 30.7% → 91.1% = +60.4 points. Both metrics are reported. Both are real. They answer different questions of the same manifest.

LayerWhat landedCumulative pass-rate
BaselineH1.v3 route-aware fixtures only23 / 75 = 30.7%
Overnight closerouter_kind + heuristic routes + FormFieldset prop-forwarding + qualifier wiring + token rehydrate44 / 59 = 74.6%
H5 manifest re-genparent-child id-prefix continuity in ai-apply prompt44 / 56 = 78.6%
+ multi-user fixture + route-aware seeding + NavItem prop forwarding + @-prefix rewrite + follow_button heuristicstructural unlocks for follow/favorite/profile flows49 / 56 = 87.5%
+ seed-data (12 articles + tags)paginate + filter have real DOM to anchor against51 / 56 = 91.1% peak

Two metrics, two lifts, one closure. The operational track (Pilot driving Conduit cross-lang) reaches 95.7% at N=10. The structural track (Cypress suite over every nac_id) reaches 91.1% peak / 89.3% median. The variance from 85.7% to 91.1% across runs is a known race in the multi-user fixture's cy.request ordering -- 1-3 secondary-author follow/favorite tests flake. Pinning the order should stabilise above 90%. Until then the page reports median + peak + floor honestly, not the high-water mark in isolation. The detailed trajectory of how each fix landed is in "Cómo llegamos hasta aquí".

00b / What these four numbers prove together VERIFIED

From "Forge migrates a React app" to "agents drive it cross-language at $0.001 a flow."

ClaimEvidence
Forge emits sound tests on real apps51 / 56 = 91.1% peak Cypress pass-rate, 89.3% median, 85.7% floor (see §00c and §04h)
The contract holds under natural-language input3 / 3 byte-deterministic flow replay at temp=0 (see §04f)
The contract is model-agnostic4 of 6 models score 30 / 30 on N=10 EN at the cheap end of the roster
The contract is language-agnostic (4 of 5)469 / 480 across en / es / zh / ar at N=10 (≥95%); Hindi 109 / 120 (90.8%) flagged as open question
The runtime is not the bottleneck for cheap modelsNAC3 v2.4 strict resolution: 12 of 18 "model failures" on Haiku were runtime damage; Haiku reclassifies 3 / 9 → 10 / 10

The closure thesis: A model that costs $0.0007 per flow hits 96.0% across 5 languages on a non-trivial real app under a strict-resolution runtime. Premium Sonnet hits 100%. The gap between cheap and premium is 4 points and 40× cost. For agent-driven UI work over assistive-tech surfaces, this is the inflection point.


Cómo llegamos hasta aquí · how we got here

From 30.7% baseline to 91.1% structural + 95.7% operational.

The journey took ~3 weeks across three parallel layers: Forge product (--ai-apply emitter + gen-tests + qualifier inference), Conduit fixture (multi-user seed, route-aware fixtures, NavItem prop-forwarding), NAC3 runtime (strict resolution, qualifier opt, click_by_verb / tab fallback). Every fix below is tagged with the layer it landed in + the metric it moved. The full chronological story, with the honest decomposition of which lift came from which layer:

01 / The fixture

Conduit -- the industry's benchmark Medium clone.

Conduit is what the RealWorld project ships as the canonical app for comparing frameworks: a Medium-style blogging site with user auth, articles, comments, follow/favorite, tags, profile + settings pages. Real surface, real complexity, used to evaluate ~24 frontend frameworks in head-to-head form. We picked the community fork that comes with both a React/Vite frontend AND a hand-written Cypress test suite, so the comparison Forge-vs-manual was apples-to-apples in the same codebase.

PropertyValue
FrontendReact 18 + Vite + SWC. 47 .jsx files in src/.
BackendExpress + Sequelize + PostgreSQL. (We swapped to SQLite via the Sequelize dialect knob for zero-setup reproducibility.)
Existing tests14 Cypress cases across 3 page flows (editor / login / register).
LicenseMIT. Thinkster / RealWorld attribution preserved in the fork.
02 / Migration phase VERIFIED

Forge --ai-apply decorates 47 files in 70 seconds.

--ai-apply is the JSX counterpart to --ai-silent. Walks every .jsx / .tsx under <repo>/src, sends each to Claude Sonnet 4.6 in parallel (concurrency 4 by default, max 8), receives back the decorated JSX plus a manifest fragment listing what was decorated. Forge aggregates fragments into a single manifest.json at the project root.

# From a fresh clone of the Conduit fork
yf migrate ./conduit-forge-ai \
  --ai-apply \
  --ai-plugin-slug conduit \
  --subdir src \
  --ai-out ./conduit-forge-ai \
  --ai-concurrency 4

# Output:
AI apply complete.
  Files scanned:   47
  Files decorated: 34
  Manifest elements: 59
  Plugin slug:     conduit
  Tokens in/out:   43428 / 22192
  Total cost:      $0.4632
  Total LLM time:  262s wall (across 47 files, divided by concurrency = ~70s real)

Per-role breakdown of the 59-element manifest:

RoleCountExample IDs
action14conduit.action.publish, conduit.action.follow, conduit.action.favorite
navigation19conduit.navigation.login, conduit.navigation.author_avatar
field11conduit.field.title, conduit.field.body, conduit.field.comment_body
tab6conduit.tab.your_feed, conduit.tab.global_feed, conduit.tab.tag_feed
region9conduit.region.popular_tags, conduit.region.feed_toggler

Quality assessment: IDs are semantic (not ordinal like btn_3), verbs are imperative (publish, follow, favorite, delete), roles match content (display/history-style fields as field, navigation links as navigation, feed switchers as tab).

03 / Test-corpus generation VERIFIED

One command, four frameworks, 66 test cases.

yf gen-tests takes the Forge-aggregated manifest and emits an e2e suite in whichever test framework the user's project carries. Multi-framework on purpose: most adoptions already have Playwright or Cypress or Vitest installed -- Forge does not mandate a choice.

yf gen-tests ./conduit-forge-ai --framework all --base-url "http://localhost:3000"

# Output:
Manifest elements:  59
Test cases:         66                          # some elements have multiple verbs
Frameworks:         playwright, cypress, vitest, wdio

playwright: + tests/forge-e2e/conduit.spec.ts
cypress:    + cypress/e2e/forge/conduit.cy.js
vitest:     + tests/forge-e2e/conduit.test.ts
wdio:       + test/specs/forge-e2e/conduit.test.ts

Coverage: 59 / 59 manifest elements exercised.

The coverage metric is "agent-relevant surface coverage" -- one test case per (nac_id, role, verb) tuple in the manifest. This is the honest claim; we do not report this as line-coverage (which the manifest alone cannot guarantee).

FrameworkFile emittedPattern
Playwrighttests/forge-e2e/conduit.spec.tsOne test(...) per case, navigates + waits for NAC.register, then dispatches via NAC.click_by_verb
Cypresscypress/e2e/forge/conduit.cy.jsOne it(...) per case inside a top describe, uses cy.window().then((win) => win.NAC.click_by_verb(...))
Vitest + jsdomtests/forge-e2e/conduit.test.tsStructural tests: manifest plugin_slug matches, every element id is present in the loaded HTML's data-nac-id attributes
WebdriverIOtest/specs/forge-e2e/conduit.test.tsAsync-await pattern with browser.execute for NAC calls
04 / Comparison vs hand-written Cypress VERIFIED (structural)

Forge: 4.7× more cases, full surface.

The fork's testAutomation/ directory carries 14 hand-written Cypress cases across 3 .cy.js files. Forge's emitter produces 66 cases in one .cy.js. The comparison is structural here -- counting cases + verifying surface coverage -- because operational pass-rate validation requires running both suites against a live backend.

Forge auto (Cypress emitter)Hand-written Cypress (in same fork)
Test cases6614
Surface coverage59 / 59 manifest elements (100%)3 page flows (editor / login / register)
Time to author~30 seconds (one command)Days-person (assumed; not measured for this fork)
BrittlenessSelectors are data-nac-id attrs -- stable across CSS/HTML refactorsMostly text/class selectors -- break when designers move things
Maintenance after refactorRe-run yf gen-testsManual update of every broken selector
04b / Operational run -- starting point CHECKPOINT 1 of 4

Quantity is not quality. SPA-naive gen-tests need flow awareness.

Read this section as "the starting baseline", not "the final state". The 1.5% pass-rate below is the v1 SPA-naive Cypress emitter on day one. The journey that follows lifts gen-tests through five checkpoints to a final median 50/56 = 89.3%, peak 51/56 = 91.1% (see §04h). The parallel Pilot operational track reaches 574/600 = 95.7% N=10 cross-language (see §00 Closure). The gen-tests structural metric and the Pilot operational metric are two distinct consumers of the same manifest; both are reported.

We stood up the Conduit backend (SQLite via Sequelize dialect swap), brought up the migrated Vite frontend, and ran both Cypress suites end-to-end. The structural delta (66 vs 14) holds; the operational delta tells a different story we publish unsoftened.

SuiteTotalPassingPass rateWhy
Hand-written Cypress (3 page flows)11 (1 pending)545%Tests are flow-aware (navigate to /editor before testing editor). One test had a pre-existing cy.type(undefined) bug from a faker reuse issue. The remaining 5 failures are likely env-specific (SQLite vs the prod DB the suite was tuned against).
Forge auto Cypress (SPA-naive, v1)6611.5%Each test calls cy.visit(BASE_URL) (home page) then dispatches one verb. For an SPA where 80% of action elements only mount under specific routes (editor / login / register / profile), most dispatches don't find the element. This is a real gap in gen-tests v1.
The honest read. Forge gen-tests v1 covers every manifest element with 1 test apiece. That's structurally complete but operationally naive for SPAs -- it doesn't know that conduit.action.publish only exists under /editor, or that conduit.action.follow requires being on a profile page. v2 of gen-tests needs route-awareness: per-element navigation hints derived from React Router config or from a Pilot dispatch simulation. Until then the suite is best read as a checklist of decorated elements, not as a runnable acceptance suite.

Two structural conclusions hold despite the operational gap:

  1. Forge's 59-element manifest is correct: NAC3 attached, plugin registered, every decorated element discoverable via NAC.click_by_verb when its containing route is mounted.
  2. The SPA-aware nac-bridge (MutationObserver) works: late-mounted action/navigation/tab elements get bound automatically as routes change.
04c / Component reuse finding CHECKPOINT 2 of 4

One JSX component, many DOM instances, same nac_id.

Ran a Pilot-style operational demo: tell Sonnet 4.6 "log in as sumi@yujin.app", give it the live manifest, let it pick verbs turn by turn, dispatch via NAC.click_by_verb. Every dispatch returned OK (the bridge fires the contract event), but the URL never changed. The model picked conduit.navigation.nav_item verb navigate six turns in a row -- each click hit the same DOM element (the first NavItem) which happened to be the Home link, not the SignIn link.

Diagnosis: Conduit's Navbar uses a <NavItem> component reused for Home, SignIn, SignUp, Settings, Profile. --ai-apply sees the component once, decorates the JSX with data-nac-id="conduit.navigation.nav_item", and that single ID propagates to every rendered instance. The manifest deduplicates by ID, so the 5+ DOM instances collapse into 1 manifest entry. NAC.click_by_verb then matches the first DOM occurrence -- always the same one, regardless of which the user actually wanted.

FindingWhat to do
Component reuse generates duplicate nac_idsPer-component-instance suffixing (e.g. conduit.navigation.nav_item[home], nav_item[sign_in]) derived from the prop / children text. Next iteration of --ai-apply.
Manifest dedup hides this from the agentSurface duplicate-id warnings during apply. Optionally: emit one manifest entry per occurrence rather than per declaration.
Model needs disambiguation contextSystem prompt extension: when multiple manifest entries share a verb, ask Pilot to use additional payload like child-text or aria-label.
Why this matters. This is the most actionable finding in the case study. It's a clean architectural gap with three independent fixes, all small. Once landed, the Pilot demo above goes from "every click hits the first NavItem" to "Sonnet picks the SignIn link, clicks it, fills email + password, submits". That's the unlock for true SPA operation.
04d / H2 fix: per-instance disambiguation CHECKPOINT 2 closed

Per-instance disambiguation shipped + verified.

Closed finding 04c at the architectural level. --ai-apply now infers per-instance qualifiers from JSX props (label, name, to, slug, etc), bakes them into data-nac-id as a __qualifier suffix, and emits N manifest entries per known instance (or instance_pattern for runtime-dynamic qualifiers). The NAC3 runtime's click_by_verb now accepts { qualifier } and { qualifier_ordinal } in opts for explicit instance targeting.

LayerWhat changed
Forge --ai-apply promptSTATIC / DYNAMIC / UNINFERRABLE doctrine. Per-instance suffix baked into JSX. Warning emitted when reusable component cannot be qualified.
Manifest schemaNew optional fields: instance_pattern, qualifier_source, warning.
NAC3 runtime (nac.browser.js)click_by_verb(plugin, verb, { qualifier, qualifier_ordinal }). Backward compatible (no qualifier = old behavior).
Pilot system promptDoctrine explained: when entries share verb but differ in suffix, pass qualifier in payload.

Verification on Conduit v2 (re-decorated post-H2):

MetricPre-H2Post-H2
Manifest size59 elements61 elements (NavItem 1 -> 4 instances, FeedToggler 1 -> 2, DropdownItem 1 -> 3)
Elements with __qualifier09 (static enumerated)
Elements with instance_pattern031 (dynamic templates)
Warnings (uninferrable reusables)hidden12 surfaced with file + suggestion
Pilot demo dispatchloops on Home foreverSonnet picks navigate + qualifier="login", URL changes to /login, then continues to fill form_fieldset__email
Decoration cost$0.46$0.66 (+41%, prompt denser; one-shot per project)
The Pilot demo now reaches the login form and starts filling email -- a step the pre-H2 demo never reached (it was stuck looping clicks against the first NavItem). The remaining gap to complete login end-to-end is no longer architectural: it's that the turn-to-turn state probe shown to the model needs to include "this field already has value X" so it doesn't loop on the same fill. That's a Pilot improvement, scheduled separately. The structural unlock is in.
04e / H1 fix: route-aware gen-tests CHECKPOINT 3 of 4 -- 22× lift

Route-aware emitter lifts pass-rate 22×.

Closed Hallazgo 1 at the architectural level. --ai-apply now extracts a route_map from any file that is a React Router root, and each manifest element carries mounted_at: string[] + requires_auth: boolean. The Cypress emitter consumes both: every test does cy.visit(mounted_at[0]) before dispatch, and auth-gated tests insert a loginViaApi() pre-step (drops a JWT in localStorage, no UI navigation needed).

MetricPre-H1 (v1)Post-H1 (v3)
Cypress test count6670 (manifest grew by 4 elements post-H2)
Cypress pass-rate1 / 66 = 1.5%23 / 70 = 33%
Liftbaseline22×
Elements with mounted_at042 / 62
Elements marked requires_auth015 / 62
Route distributionn/a'*' x19, '/' x3, /article/:slug x5, /editor* x5, /login x3, /profile/:username x2, /register x1, /settings x4
Why 33% and not 70% (target). The remaining failures are no longer about navigation -- they're about fixture state. Tests for favorite_article need an article to exist; tests for follow_author need a second user. The dynamic routes (/article/:slug, /profile/:username) need fixture seed data in the SQLite before cy.visit. Next iteration of gen-tests: emit beforeEach blocks with Faker-style seed data per dynamic-route test. Per the brief: "Si queda por debajo de 70%, investigar antes de declarar v2 listo." -- investigated and reported. The route-awareness piece IS shipped; the fixture-awareness piece is the next slice.

Per the brief's communication discipline: gen-tests is not communicated publicly as a finished product until pass-rate is ≥70% sustained. This case study documents the H1 architectural unlock + the honest 22× lift, NOT a sales claim. The "agent-relevant surface coverage" metric (every (nac_id, role, verb) tuple) remains the only quantitative claim safe to publish; the test-pass-rate is documented as an honest WIP signal here.

04f / Pilot end-to-end login CHECKPOINT operational unlock

Sonnet drives Conduit login end-to-end. 4 turns. $0.022.

Two fixes that together destrabaron el demo Pilot end-to-end:

  1. Pilot per-turn state probe now includes the current value of every visible input/textarea (keyed by data-nac-id + fallbacks), plus the navbar text snapshot, plus the last 5 action_history entries. System prompt got a STATE AWARENESS section: "before you emit a fill, check if the field already has the target value -- if it does, ADVANCE."
  2. NAC.fill is now React-safe. The previous implementation set el.value = newVal directly. React silently reverts that on the next render because its synthetic event system tracks the original property descriptor on HTMLInputElement.prototype. The fix: use Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(el, newVal). Same pattern for textarea / select / checkbox. Plain DOM behavior unchanged. (Committed in rpaforce-crm@c1bd8dc5.)
MetricPre-H4.prePost-H4.pre
Login flow completionnever (loops on fill-email forever)success=true in 4 turns
Turns used6 (cap) without success4 (navigate, fill email, fill password, click submit)
Determinism (3 runs, temp=0)n/a (didn\'t complete)3 / 3 byte-identical (same tokens, turns, cost)
Cost per run$0.038+ wasted$0.0222
Tokens (in / out per run)9781 / 6646136 / 252
The 5 items of "Conduit listo para caso de exito" -- updated.
  • [x] H2 cerrado -- per-instance qualifiers across all 3 layers.
  • [~] H1 cerrado at architecture; 33% pass rate (was 1.5%, 22× lift); 70% target needs fixture-state next.
  • [x] End-to-end Sonnet demo: login flow completes deterministically at $0.0222.
  • [ ] H4 (cheap-model validation across {Gemini Flash Lite, GPT-4o-mini, Haiku, Sonnet} × N≥5) is now unblocked -- the field-state + React-safe fill that gated it both shipped.
  • [ ] Public reproducer repo with MIT attribution -- next step.
04g / Two metrics, not one CHECKPOINT 4 of 5

Operational vs structural: two distinct consumers of the same manifest.

Conduit gen-tests (Cypress) and the Pilot agent (Sonnet / Haiku / Flash-Lite / gpt-5-mini) read the same manifest but ask different questions of it. gen-tests asks "is every element reachable?". Pilot asks "can a model drive a multi-step flow?". The numbers split. The closure-to-90 work (§04h below) is what brings gen-tests from the 33% checkpoint to a final 91.1% peak / 89.3% median.

Re-corri la suite Cypress generada por Forge contra la Conduit live despues de H4.pre + el fix de React-safe NAC.fill, esperando un lift sobre el 33% pre-H4. El numero quedo en 23/70 = 33%. Dos fixes que parecian deberian moverlo no lo movieron, y la razon es clara + honesta:

Fix probadoEsperadoRealPor que
React-safe NAC.fillfield_write tests subiriansin cambioLos field_write tests de Forge no asertan que el valor persiste -- solo dispatchan. Pilot (multi-step flow) SI depende del valor real para el siguiente paso; por eso el demo login paso de 0% a 100% con el mismo fix. Distintos consumidores, distinto efecto.
Auth localStorage key fix (jwtToken -> loggedUser shape)auth-gated tests subiriansin cambioEl bloqueo principal de los 47 failing no es auth -- es fixture-state. Tests sobre /article/:slug y /profile/:username necesitan un articulo / usuario seedeado en la SQLite ANTES del cy.visit. Sin contenido en esas rutas, el elemento target no monta.
Dos metricas que no se confunden -- estado intermedio (pre-closure-to-90).
  • Forge gen-tests v2 (Cypress estructural): en este checkpoint 23 / 70 = 33% pass. Cada test es una "checklist entry" por elemento del manifest. Mide cobertura de superficie. El cierre que sigue (§04h) lleva esto a 51/56 = 91.1% peak / 50/56 = 89.3% median.
  • Pilot end-to-end (operational): 3 / 3 = 100% pass, $0.0222, 4 turns, byte-deterministic. Sonnet drives the SPA through a real multi-step flow. La extension multi-modelo + multi-lang llega a 574/600 = 95.7% N=10 (ver §00 Closure).
Son metricas distintas que se publican por separado. Una mide "cuantos elementos del manifest tienen un test que pasa contra una suite Cypress agnostica de fixture" -- cobertura. La otra mide "cuanto cuesta que un agente IA opere la app cross-language" -- caso comercial.
04h / Closure-to-90 -- gen-tests final CHECKPOINT 5 of 5

The structural metric closes at 91.1% peak / 89.3% median.

The 33% checkpoint at §04e was the H1 route-aware unlock. Closure-to-90 bundled a series of layered fixes that lifted the structural pass-rate from there to median 50 / 56 = 89.3%, with peak 51 / 56 = 91.1% and floor 48 / 56 = 85.7% across 3 consecutive runs. Net lift on the structural metric: 30.7% → 91.1% peak, +60.4 points. Trajectory:

StagePatches landedBest run
baseline (pre-overnight)H1.v3 fixtures only23 / 75 = 30.7%
overnight closerouter_kind + heuristic routes + FormFieldset + qualifier wiring + token rehydrate44 / 59 = 74.6%
H5 manifest re-genparent-child id-prefix continuity in ai-apply prompt44 / 56 = 78.6%
+ onBeforeLoad rehydratelocalStorage seeded BEFORE module-init44 / 56 = 78.6%
+ cy.get wait gateretries before click44 / 56 = 78.6%
+ multi-user fixture (USER2 authors)follow_author can now mount (viewer ≠ author)45 / 56 = 80.4%
+ route-aware seedingskip localStorage on /login + /register48 / 56 = 85.7%
+ NavItem prop forwardingprofile tabs land on real DOM elements49 / 56 = 87.5%
+ @-prefix → /profile/ rewriteconventional route preferred49 / 56 = 87.5%
+ follow_button → /article heuristictop-level follow / unfollow tests visit article49 / 56 = 87.5%
+ seed-data (12 articles + tags)paginate + filter have content51 / 56 = 91.1% peak

Determinism across 3 consecutive runs of the full close-to-90 lot: 51/56 (91.07%) / 50/56 (89.28%) / 48/56 (85.71%). Median 50/56 = 89.3%. The 90% threshold is touched but not stably cleared. Variance source: the multi-user fixture's USER1 / USER2 login race in cy.request resolution timing -- 1-3 secondary-author follow / favorite tests flake when Cypress.env hasn't yet swapped to USER1 when the it() body runs.

DecompositionWhat it isHonest framing
Forge product winsH1.v4 router_kind + H1.v5 id-keyword route inference + H1.v6 qualifier opt + H5 parent-child id-prefix continuity + NAC runtime click_by_verb / tab fallbackThe emitter generates valid cases that previously couldn't pass.
Emitter dropping invalid testsSkip region_present + field_read + tab_switch on template-only entries; skip credential field writes; skip session-mutating verbs (logout / signup / save)The denominator shrinks from 68 to 56 manifest-derived tests. ~+5-6 points of the lift is "dropping bad tests" not "generating better ones". Documented as such.
Fixture sanolocalStorage rehydrate via cy.visit onBeforeLoad; route-aware localStorage skip; stale-article purge in suite-level before(); multi-user fixture; minimal home-feed seed (12 articles + tags)Test harness wins, not product wins. Required for any honest acceptance suite.
What remains on the gen-tests structural metric. The variance from 85.7% to 91.1% across consecutive runs is a known race in the multi-user fixture's loginAs / cy.request ordering. Pinning the order with cy.wrap().as() + explicit cy.then() chains should stabilise the 90% threshold. Until then, the page reports median + peak + floor honestly. The Pilot operational metric (95.7% N=10 cross-language at §00) is independent and not subject to this fixture race.
05 / What's verified vs what's next CLOSURE

The honest picture at closure (2026-05-22).

ItemStatus
Forge migrates Conduit's 47 JSX files end-to-endverified
Manifest quality (semantic IDs, imperative verbs, correct roles)verified
Forge auto-generates 66 e2e cases in 4 frameworks (v1) → 70 cases (v3 route-aware)verified
SPA-aware nac-bridge (MutationObserver re-binds on route change)verified (live probe on running Conduit)
NAC3 runtime registers the 59-element manifest (v1) → 61 (post-H2) → 62 (post-strict)verified (Playwright probe)
Pass-rate of the Forge-generated Cypress suite against live Conduitverified -- 30.7% baseline → 51/56 = 91.1% peak / 50/56 = 89.3% median at closure-to-90 (see §00c + §04h)
Pass-rate of the hand-written Cypress suite against live Conduitverified -- 5/11 (45%), incl. pre-existing flake
Pilot-style operational demo (Sonnet drives the migrated app)verified -- login flow 4 turns / $0.022 / 3×3 byte-deterministic
Operational testing N=10 ES default + multi-modelverified -- 60/60 default + 4 winners advanced to N=10
NAC3 strict resolution -- eliminate silent fallbacks + reclassify Haikuverified -- +12 pts on H4; Haiku 3/9 lenient → 10/10 strict
Cross-language transfer N=10 (paper-grade)verified -- 574 / 600 = 95.7% across 4 models × 5 langs
Conduit-NAC3 fork (BYOK Pilot + i18n 10 langs + WAL + race fix)verified -- production codepath validated nativ. Deploy postponed.
Hindi (Latin transliteration) as open question, not settled limitdocumented -- 5 hypotheses listed; follow-up Devanagari vs Latin experiment scoped
Public reproducer repo with MIT attribution to Thinksterpending push -- NOTICE.md + README_NAC3.md ready
Robustness test: refactor CSS, re-run both suites -- which survives?pending
gen-tests v4: fixture-aware emission (lift 33% → ≥70% target)pending -- 2-3h dev + $0.50 regen
06 / Reproduce

Three commands to repeat this on your machine.

# 1. Clone Conduit + install
git clone https://github.com/digitalinnovationone/conduit-realworld-example-app-with-cypress-automation conduit
cd conduit
npm install

# 2. Decorate with Forge (you need a paid seat + ANTHROPIC_API_KEY)
export ANTHROPIC_API_KEY=sk-ant-...
cp -r ./frontend ./frontend-forge-ai
yf migrate ./frontend-forge-ai \
  --ai-apply --ai-plugin-slug conduit --subdir src --ai-out ./frontend-forge-ai

# 3. Generate the test corpus in whatever framework you want
yf gen-tests ./frontend-forge-ai --framework cypress
# or --framework playwright,vitest,wdio,all

Total cost to reproduce: ~$0.50 in Anthropic tokens. Total wall time: ~3 minutes including npm install.

07 / The tools

Forge + Pilot. Build once, drive forever.

Everything in this case study runs on three pieces of open infrastructure: NAC3 v2.3.1 (the protocol, Apache-2.0), Yujin Forge (the build tool, paid seat), and Yujin Pilot (the embedded driver, open core). All three ship today.