# ADR-0048: The Angular tier stays source-only until it meets the published-tier bar ## Status **Accepted** (2026-08-10). Governs `@metaobjectsdev/angular` (`client/web/packages/angular/`) and `@metaobjectsdev/codegen-ts-angular` (`server/typescript/packages/codegen-ts-angular/`). Enforced by `scripts/check-publish-intent.sh` (the `SOURCE_ONLY` list). ## Context The two Angular packages were authored as a second universal browser tier (runtime + codegen pair, mirroring React/TanStack) and versioned on their own `0.6.x` line. `docs/RELEASING.md` defined the lockstep publish set as "every non-`private` package at the previous version" — a non-private package on its own version line matched neither branch, so **every release silently skipped them and neither was ever published**, while the README, four port docs and a full recipe described them as installable. The 0.21.5 cut corrected the docs to "source-only" and added `check-publish-intent.sh` so the gap cannot recur silently. That left the actual decision open: publish the tier, or keep it source-only on purpose. A code assessment settled it. The tier is real — the `CurrencyInputComponent` genuinely mirrors the React `` semantics with a behavioral test suite, the DI fetcher token is clean, and the three generators emit plausible standalone-component output against the cross-port REST grammar. But it is **well below the published tier's bar**, on several independent axes: 1. **Runtime grid is not at parity.** `EntityGridComponent` renders a string-coercing table with a row-click callback. The TanStack `` it claims to mirror has controlled sorting, pagination controls, and working cell-renderer dispatch; the Angular component's `CellRendererRegistry` lookup is computed and then **discarded** (the registry is decorative), and its doc comment describes sort/pagination callbacks that do not exist. 2. **Form codegen predates two shipped feature lines.** Control dispatch stops at text/checkbox/currency — no enum ``, `view.textarea`, `view.checkbox`/`view.radio` dispatch (image support may be explicitly scoped out), and validation semantics reconciled with FR-035/036. 3. Generator parity with the other UI tiers: TPH handling, read-only service surface for projections (no write methods against routes that do not exist), and generated services importing the DB-free `.meta` descriptor — gated by a browser-bundle test over generated output. 4. A test runner that actually executes the runtime behavioral suite (Angular linker toolchain), wired into CI, plus a compile gate over generated output against `@angular/core`. 5. Peer ranges covering only tested Angular majors. 6. A real consumer asking for the npm package. Then, mechanically: bump both to the lockstep version, remove them from `SOURCE_ONLY`, add them to the `docs/RELEASING.md` tier table (codegen in tier 2, runtime in tier 3), and flip the "source-only" notes in README.md, CLAUDE.md, `docs/ports/typescript-client.md`, the three backend port docs and `docs/recipes/csharp-angular18.md`. ## Consequences - Nothing an adopter can install is promised and unowned: the docs say source-only, the registry says 404, and both statements agree. - The tier keeps riding the repo's mechanical gates (build, typecheck, browser-bundle, peer-range, publish-intent) for free, so it stays buildable without pretending its suite is green. - The feature-drift cost is accepted and visible: sweeps (accessor discipline, peer ranges) reach it; feature lines (view kinds, meta descriptors, TPH) are not required to, until someone picks up the promotion bar. - Anyone proposing to publish it has a checklist instead of an argument.