The provider sandbox never ran. bubblewrap 0.9.0 stops parsing an `--args` file at the first non-option and never hands the remainder back, so the command written into that file was silently dropped: bwrap printed its usage text, exited 1, and the provider produced no evidence at all. The options still travel in the args file — that is what keeps host paths and credentials out of `/proc/<pid>/cmdline` — but the command now rides on real argv, and `encodeProviderBwrapInput` refuses a `--` so the drop cannot come back. The scope wrapper then could not exit. It read the supervisor's liveness pipe through `fs`, which runs a blocking `read(2)` on a threadpool thread; the supervisor holds that pipe open for the scope's whole life, so the read never returned and closing the descriptor did not interrupt it. Once bubblewrap finished the wrapper deadlocked in `process.exit`, the scope outlived the provider, and a completed run was reported as a timeout kill. The channel is now read through the event loop, so teardown is observable and terminal. Creation modes were left to the ambient umask. `mkdir(mode)` and `open(mode)` are requests the kernel subtracts the umask from, so a runner exporting a restrictive umask produced directories it could not enter and handed `tar` a file it could not re-open. Private modes are pinned instead of inherited. Promotion cleanup deleted before it checked. Removals run through a pinned descriptor, so a leaf substituted after validation had this promotion's exact five destroyed first and the substitution reported afterwards, leaving a half-emptied directory a retry could not tell from a completed one. The name is re-bound to the inode before anything is removed, so the failure is total. Separately, release coherence proved the artifacts agreed with each other but never that they belonged where they were going: a build whose runtime document said `APP_ENV: local`, `AUTH_MODE: demo` and a loopback API is coherent with itself and passed every gate. `public/` is copied verbatim into `dist/`, so that local document shipped with every build regardless of what the build was for. Runtime configuration now comes from a declared profile, and FE-GATE-027 refuses to admit an artifact to an environment it does not match — including refusing an undeclared destination, so nothing is admitted by omission. `REQUEST_TIMEOUT_MS` and `VITE_ROUTER_BASE_PATH` were validated and then dropped: the V3 executor ran every operation on its contract's own deadline, and Vite emitted root-absolute assets for a sub-path deployment. The timeout is now a ceiling that may tighten a contract but never loosen one, and one base path feeds the router, the Service Worker scope and the asset base together. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Clean Architecture Frontend Template
A React/Vite reference implementation where architecture boundaries, integration behavior, release coherence, accessibility, performance, and operations are executable contracts rather than conventions.
Start locally
Requirements: the exact Node.js version in .nvmrc (currently 24.14.0) and
Corepack. The repository pins pnpm in package.json.
Product source, tests, build/quality scripts, and supported tool configuration
are TypeScript/TSX. allowJs is disabled. Node-side .ts scripts run directly
on the pinned Node 24 runtime and are checked with NodeNext resolution plus
erasable-syntax enforcement. Project-owned executable source contains no
JavaScript-family files; negative architecture, security, and type-compatibility
fixtures are TypeScript/TSX as well.
corepack pnpm install --frozen-lockfile
corepack pnpm dev
Runtime-public settings live in public/config.json and are validated before
the product tree mounts. Client secrets are forbidden.
Included starter experience
The default build mounts a domain-neutral application shell with a header,
responsive sidebar, route focus management, session integration status, and a
persistent system / light / dark theme selector.
| Route | Purpose |
|---|---|
/ |
implementation readiness and starter links |
/examples/ui |
buttons, fields, cards, alerts, badges, modal, and tokens |
/examples/states |
loading, refresh, empty, error, auth, forbidden, and not-found states |
/examples/auth |
reactive external-auth integration seam |
/examples/reference-resources |
removable, session-required reference feature |
AUTH_MODE=demo is credential-free and accepted only in local/development
environments. Deployments use AUTH_MODE=external and provide the opaque auth
owner described in
docs/architecture/starter-experience.md.
The client route policy is user experience only; server authorization remains
authoritative.
Architecture
Dependencies point inward:
presentation -> application -> domain
adapters -----^
bootstrap composes concrete adapters
contracts own cross-cutting registries
See docs/architecture/overview.md, docs/architecture/layers.md, and
docs/architecture/starter-experience.md. The removable vertical slice is
under src/features/reference-feature; its domain, application input, HTTP
adapter, contracts, route runtime, and presentation are installed through the
feature contribution files in src/features. The generic starter routes
continue to typecheck, test, and build after that contribution is removed.
Platform capability review
The starter shell is implemented, but the repository review also records the remaining work required before feature teams can use every declared contract through one end-to-end application path:
- platform capability review
- ports, adapters, and feature boundaries
- REST, GraphQL, Connect/gRPC-Web, Schema, Mapper, and Server State
- Protobuf browser transports and REST Gateway
- backend API and Server State handoff contract
- TypeScript, state ownership, and data flow
- routing, page templates, and reusable patterns
- browser data capability completion ledger
- browser file and origin-storage platform
- client cache and storage
- realtime events, Web Push, and bounded polling
- presigned transfer, resumable upload, streaming download, and Image CDN
- server file capability infrastructure
- design-system platform
- frontend platform testing strategy
- implementation roadmap
These documents distinguish repository defaults from opt-in adapters and project-owned integrations. They are target designs and review findings; a capability is not treated as implemented until its branch acceptance criteria and executable gates pass.
Verification
Common local checks:
corepack pnpm lint
corepack pnpm check:types
corepack pnpm check:types:app
corepack pnpm check:types:node
corepack pnpm check:types:test
corepack pnpm check:architecture
corepack pnpm test:all
corepack pnpm test:e2e
corepack pnpm test:a11y
corepack pnpm build
corepack pnpm check:bundle
corepack pnpm test:performance
corepack pnpm verify:compatibility
corepack pnpm verify:release
corepack pnpm check:registries
corepack pnpm drill:runbooks
corepack pnpm check:ci
check:types는 source, Node scripts/config와 tests를 분리된 TypeScript
project로 모두 검사한다. type/architecture/security/registry의 invalid
fixture는 config/ci/gates.json에서 “실패해야 통과”하는 negative gate로
실행된다. 도구 호환성 결정은
VD-01에 기록돼
있다.
Application feature input은 module augmentation으로 닫힌 ID와 정확한 input
shape를 제공하며, 공통 Result<Value, Failure = AppFailure>는 error registry의
failure kind만 application/presentation 경계를 통과시킨다. Architecture gate는
TypeScript/TSX의 static, dynamic, type import를 별도 정적 그래프로 분석하고
runtime/source 영역의 JavaScript 재유입도 거절한다. 해석되지 않은 import,
parse failure, 금지 계층 edge와 순환 의존은 모두 fail-closed이며 전용
TypeScript/TSX negative fixture로도 검증된다.
Install the pinned Playwright browser engines before the first cross-browser run:
corepack pnpm exec playwright install --with-deps chromium firefox webkit
Two gates intentionally need external evidence:
review:a11y-manualneeds a signed human keyboard/focus/screen-reader review for all six registered routes.collect:web-vitals-evidencestaysFAIL_UNVERIFIEDuntil a reviewed minimum eligible-sample threshold and 28 days of production data exist.
Live release verification additionally requires HOSTING_BASE_URL.
CI and evidence
The 26-gate registry is config/ci/gates.json; the Gitea workflow is
.gitea/workflows/quality-gates.yml. It follows:
MERGE_READY -> RELEASE_READY -> PROD_PROMOTION_READY -> FIELD_SLO_READY
DOCUMENTATION_READY is independent. No gate is downgraded to a warning.
Machine-readable evidence is written below artifacts/; generated evidence is
ignored by Git while .gitkeep files preserve the taxonomy.
Operational details are in docs/operations/, with incident procedures in
docs/runbooks/.