Skip to content

Commit 6ba6f24

Browse files
feat(spike): thin-wrapper cost probe — admission walls ARE the finding
Spike C (nts-t004, partial-by-design): both candidates license-clean at pin. Walls before measurement: frozen React adapter refuses ejected-CRA trees (no react-scripts/Vite declaration — a React-side admission boundary class); operator migrate materializes an entry document, not an installable tree (the full pipeline is fixture-code — the exact owner-named automation gap); node-sass 4.x has no arm64 binding at any Node (era cells are a host architecture requirement). Ledger: 37s machine / ~22min operator / 0 builds / 0 witness. threeUnitsCredible: false — unreached, not refuted; per-app averages are over a filtered population. Freeze 27741d9c intact. Claude-Session: https://claude.ai/code/session_01HEVhWgWk9AXTiFMysQNB5r
1 parent b76d72e commit 6ba6f24

3 files changed

Lines changed: 494 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# SPIKE C — the real per-application cost, measured on a never-completed application
2+
3+
Unit `nts-t004/spike-c-thin-wrapper-cost`. Measured 2026-08-14 on one host
4+
(darwin-arm64, Node v24.15.0, npm 12.0.1). Machine record:
5+
`evidence/spikes/thin-wrapper-cost/verdict.json`.
6+
7+
The spike was sent to price the post-industrialization per-application cost by
8+
taking a never-completed application through the frozen React adapter and
9+
witnessing it through the thin-wrapper path. It did not get there. What follows
10+
is what it did measure, and where it stopped.
11+
12+
## Gate zero — license text at the pin
13+
14+
Both candidates pass, read out of the consented archive already on disk after
15+
that archive was re-verified against the digest its ingest recorded.
16+
17+
| application | pinned commit | license file | sha256 | gate |
18+
|---|---|---|---|---|
19+
| react-shlink-web-client | `44aca4ae` | `LICENSE` (MIT License) | `249a81967c48177d9fa4672adbfdecd356aba715101780e05d54fcbd744d699c` | pass |
20+
| react-sqlpad-v5-5-0 | `5c259dd7` | `LICENSE.md` (#The MIT License) | `93dec0b7b1f9775cdcb15603a6c1d8829164ac72fa01a4679845c85ee76421da` | pass |
21+
22+
The primary passed, so no license fallback was taken. `react-sqlpad-v5-5-0` was
23+
read only as a comparator.
24+
25+
## Where it stopped
26+
27+
Two walls, both before the stage the ~3u estimate describes.
28+
29+
**The frozen React adapter refuses the application.** `analyze` reads it as React
30+
with builder `unknown`; `plan` and `migrate` both refuse:
31+
32+
> React plan: this tree declares neither react-scripts nor a Vite configuration, so no frozen React adapter claims it. This flow refuses rather than guessing an origin toolchain.
33+
34+
shlink-web-client v2.3.0 is an ejected create-react-app: it carries its own
35+
webpack 4 configuration under `config/` and does not declare `react-scripts`.
36+
This is a named gap. No frozen subtree was edited.
37+
38+
**The era cell refuses the baseline.** With one Node era cell installed on this
39+
host, webpack 4 fails first on hashing —
40+
`error:0308010C:digital envelope routines::unsupported` — which
41+
`NODE_OPTIONS=--openssl-legacy-provider` answers, and then the build stops for
42+
good on the native dependency:
43+
44+
> ./src/common/react-tagsinput.scss — Error: Node Sass does not yet support your current environment: OS X Unsupported architecture (arm64) with Unsupported runtime (137)
45+
46+
The corpus source is immutable, so swapping node-sass for dart-sass is not
47+
available, and no second era cell is installed.
48+
49+
## The ledger
50+
51+
| stage | machine | operator | outcome |
52+
|---|---|---|---|
53+
| license pre-screen (both) | 3 s | ~10 min | pass |
54+
| ingest completion (both) | 2 s | ~2 min | source complete both; no dependency closure for the primary |
55+
| baseline install | 20 s over 2 attempts | ~3 min | installed after one refusal (`EALLOWREMOTE`) and one operator decision (`--allow-remote all`) |
56+
| baseline production build | 10 s over 2 attempts | ~4 min | not built |
57+
| migrate under the frozen adapter | 1.04 s | ~2 min | refused |
58+
| migrate, admitted comparator (sqlpad client) | 0.95 s | ~1 min | materialised: 1 file written, 167 copied |
59+
| witness, thin-wrapper path | 0 | 0 | not executed |
60+
| **total** | **37 s** | **~22 min** | **0 builds, 0 witness passes, 0 new TypeScript lines** |
61+
62+
Machine seconds are wall clock around the awaited command and nothing else.
63+
Operator seconds are the acts between commands — reading a refusal, choosing a
64+
remedy — and are never folded into machine time.
65+
66+
## What this says about ~3u per application
67+
68+
`threeUnitsCredible: false`, and the reason matters more than the flag: the
69+
claim was not reached rather than refuted. An application drawn from the
70+
never-completed set spent its whole budget on the stages *before* the one the
71+
estimate covers. Any per-application average that quotes only the applications
72+
that made it through is quoting a filtered population.
73+
74+
Four costs remain manual, and this run priced the first three:
75+
76+
1. **Era-cell provisioning** — two failed builds, ~4 minutes, no remedy on this host.
77+
2. **Install policy** (remote tarballs, install scripts) — one failed install, ~3 minutes; both mechanisable as policy, both judgment today.
78+
3. **Adapter admission** for trees outside the react-scripts/Vite declaration — ~2 minutes, then the application leaves the pipeline.
79+
4. **The migrated tree is not yet installable from the CLI.** On the admitted comparator, `migrate --materialize` wrote one file (the entry document) and copied 167; the lane's `package.json` still declares `react-scripts ^3.4.1` and carries no Vite configuration. The Vite-era rewrite for the applications already completed lives in per-application fixture code (18 to 318 lines each).
80+
81+
Witness journey authoring and calibration were not touched here, so T002's
82+
reading of that stage stands unrevised.
83+
84+
## The thin-wrapper floor, as inventory
85+
86+
The pattern this spike was sent to price is real on disk — `react-dejavu-run.ts`
87+
is 61 lines and `angular-fuxa-run.ts` 67, over the 7,453-line generic harness,
88+
against 235 to 436 lines for the earlier per-application wrappers. That is
89+
inventory of work already done. It is not evidence that a new application
90+
reaches that floor, because no new application here reached the stage where the
91+
wrapper is written.
92+
93+
## Not established
94+
95+
- No build ran to completion, so nothing here establishes that either application builds on any era cell.
96+
- No witness pass ran, so nothing here establishes browser behaviour, parity, locality, or a bounded witness outcome.
97+
- The thin-wrapper line counts are inventory of previously completed applications, not a measurement of a new one.
98+
- Operator timings are single-run wall clock on one host, not a distribution.
99+
- The refusals are readings of this host and this pin; a different architecture, era cell, or npm would refuse differently, and none was tested.
100+
- Nothing here revises the frozen adapters, the supported matrix, or any capability status; no coverage or matrix artifact was regenerated.

0 commit comments

Comments
 (0)