chore: close TECH-TS-PORTAL-TSC — apps/portal vue-tsc at zero

Brings apps/portal from 729 vue-tsc errors (≈22 own-code, of which
18 were TS2339 downstream of tiptap; ≈707 in node_modules/@tiptap/)
to zero. Tiptap fix-route: Option A — patch upgrade @tiptap/* from
2.27.1 to 2.27.2 to fix tiptap's dist/index.d.ts re-export paths.

Sprint commits (this work package, 3 total):
  - f7bb864 fix(portal-deps): upgrade @tiptap/* 2.27.1 → 2.27.2
            to fix dist resolution (cleared 707 + 18 errors)
  - a7ccd2b fix(portal-types): clear residual long-tail tsc errors
            (cleared the 4 tiptap-independent stragglers:
             vite.config.ts componentName param,
             LayoutConfig.title Lowercase<string> over-constraint,
             @iconify/types missing dev-dep, casl.ts meta string cast)
  - this commit: close BACKLOG entry; correct the misleading "+4 in
                 tiptap" framing in the original entry (was the
                 ts-reset delta, not the absolute pre-existing count
                 of ~707); seed TECH-PORTAL-TSC-CI-GATE follow-up.

apps/portal `pnpm exec vue-tsc --noEmit` exits clean.
Vitest: 113/113 passing. Build: 8.52s, succeeded.

Pre-commit hook gate not added — the project has no husky/lefthook/
simple-git-hooks setup. Captured as TECH-PORTAL-TSC-CI-GATE follow-
up; without that gate the zero state has no enforcement and can
drift back. Should land before S3b organizer UI work to keep the
"new code introduces no new errors" discipline mechanically
enforceable.

S3b form-builder organizer UI can now land on top of a verified
TypeScript baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 04:35:43 +02:00
parent a7ccd2b97e
commit 81b20ecbea

View File

@@ -987,54 +987,77 @@ tamperbaar door lokale users, dus dit is ook een kleine security
verbetering.
**Prioriteit:** Laag — defensive hardening, geen user-impact.
### TECH-TS-PORTAL-TSC — `tsc --noEmit` baseline reduction (apps/portal)
### ~~TECH-TS-PORTAL-TSC — `tsc --noEmit` baseline reduction (apps/portal)~~
**Priority:** medium → **high before S3b organizer UI lands.**
**Scope:** 22 pre-existing TypeScript errors in `apps/portal/src/`
own code surfaced by foundation-tooling commit 3 (ts-reset install).
**Status: closed 2026-04-25**`pnpm exec vue-tsc --noEmit` exits
clean in `apps/portal/`. Sprint commits: `f7bb864` (tiptap 2.27.2
upgrade) + `a7ccd2b` (4 long-tail fixes).
**Trigger to upgrade priority to "must-fix-now":** any S3b
form-builder organizer UI commit. Launching new TypeScript code on
top of an unverified existing-error baseline produces unactionable
compile output ("which errors are mine?"). Reduce to zero before
S3b starts.
**Correction to the original framing:** the entry initially read
"22 pre-existing tsc errors in own code + 4 in tiptap node_modules".
The "4" was the **delta** that ts-reset added in foundation-tooling
commit 3 (ts-reset's `JSON.parse → unknown` tightening surfaced 4
new tiptap errors), **not** the absolute pre-existing tiptap baseline.
The actual absolute count was **~707 tiptap node_modules errors**,
silently invisible because the project's CI runs build + vitest only,
not `vue-tsc`.
**Triage approach (mirror Larastan reduction pattern):**
1. `cd apps/portal && pnpm exec vue-tsc --noEmit 2>&1 | grep "src/" > /tmp/tsc-errors.txt`
2. Group by error code (TS2339 property-not-found, TS2345 argument
type, TS18047 possibly null, TS2322 not-assignable, etc.) —
typical top categories on a Vue-3 + Pinia codebase. Foundation-
tooling triage already noted clusters in TiptapEditor/
ProductDescriptionEditor commands, a `@iconify/types` missing
import, and a themeConfig `Lowercase<string>` mismatch
3. Fix per-category in scoped commits (mirror Larastan reduction
sprints — one category per PR if >5 occurrences, combine if <=5)
4. Add `pnpm exec vue-tsc --noEmit` to a pre-commit hook or CI as
blocking gate once own-code errors hit zero (CI integration is
tracked separately; the gate enforcement is what closes the
"new code introduces no new errors" discipline gap)
**Root cause of the 707:** tiptap 2.27.1's `dist/index.d.ts`
re-exported from `'../src/CommandManager.js'` and ~22 similar lines
that referenced `.js` files which did not exist (only `.ts` source).
With `moduleResolution: "Bundler"`, vue-tsc fell through and pulled
tiptap's entire uncompiled source tree into the program. Tiptap
2.27.2 (a patch release) fixed the dist exports to use sibling-
relative paths (`./CommandManager.js`) that resolve correctly to
the existing `dist/*.d.ts` siblings.
**Tiptap upstream errors (4 in node_modules):**
`skipLibCheck: true` is **already set** in both SPAs' `tsconfig.json`
(only one tsconfig variant exists per SPA; no `tsconfig.app.json`
or `tsconfig.node.json` split). Despite that, the 4 errors persist
because **tiptap ships uncompiled `.ts` source files** in
`node_modules/.../@tiptap/core/src/`, not `.d.ts` declaration
files. `skipLibCheck` only suppresses checking of `.d.ts` files;
it does **not** apply to raw `.ts` files that vue-tsc pulls in
through the import graph. Real options, in order of preference:
(a) upgrade `@tiptap/*` to a release that ships only `.d.ts`
(check upstream — the policy may already have changed in newer
majors); (b) add a focused `exclude` glob for tiptap's
`node_modules/.../src/**/*.ts` if the upgrade is blocked. Avoid
blanket `node_modules` excludes — they can break import resolution
in vue-tsc.
**Why `skipLibCheck` did not help:** `skipLibCheck: true` was
already set in `apps/portal/tsconfig.json` (and `apps/app/`)
**but only suppresses checking of `.d.ts` declaration files**.
Tiptap's uncompiled `.ts` source files in `node_modules/.../src/`
were raw `.ts`, not `.d.ts`, so they bypassed `skipLibCheck` once
the import graph reached them. The 2.27.2 packaging fix made the
import graph stop there, no exclusion needed.
**Out of scope:** runtime fixes for behaviors that surface as type
errors but aren't actually broken at runtime. If a fix requires
reasoning about runtime behavior (not just type narrowing), surface
it as a separate ticket — TypeScript-correctness is this sprint's
remit, runtime-correctness is a different concern.
**Final error tally:**
- Pre: 729 vue-tsc errors (~22 own-code, of which 18 were TS2339
downstream of tiptap's broken types; ~707 in node_modules/@tiptap)
- Post-tiptap-upgrade: 4 own-code (the tiptap-independent stragglers:
`vite.config.ts` TS7006, `themeConfig.ts` TS2322 via
`LayoutConfig.title` `Lowercase<string>` over-constraint,
`build-icons.ts` TS2307 missing `@iconify/types`,
`casl.ts` TS2345 vue-router meta cast)
- Post-long-tail-fixes: 0 own-code, 0 node_modules
**Aftermath:**
- The S3b form-builder organizer UI now lands on a verified
zero-error baseline.
- The "new code introduces no new errors" discipline still depends
on a CI gate — see TECH-PORTAL-TSC-CI-GATE follow-up.
### TECH-PORTAL-TSC-CI-GATE — vue-tsc as a blocking gate for apps/portal
**Aanleiding:** TECH-TS-PORTAL-TSC reached zero in commits `f7bb864`
+ `a7ccd2b`, but the project has no pre-commit infrastructure
(no husky, lefthook, or simple-git-hooks) and CI does not run
`vue-tsc` either. Without a blocking gate, the baseline can drift
back to non-zero between commits — exactly the discipline gap
that produced the 22 pre-existing errors in the first place.
**Wat:**
- Add `pnpm exec vue-tsc --noEmit` as a CI step in the workflow that
runs portal build/vitest (most natural location).
- OR introduce a pre-commit infrastructure (lefthook is lighter than
husky for monorepos) and run vue-tsc on portal-touching commits.
- Either path: the gate must fail the run on any new vue-tsc error
in `apps/portal/`.
**Out of scope:** extending the same gate to `apps/app/` — that
SPA still has a different mix of errors and would be a separate
sprint (out of scope today, would land alongside TECH-APP-VITEST or
later).
**Prioriteit:** Middel — without the gate, TECH-TS-PORTAL-TSC's
zero state has no enforcement. Should land before S3b organizer UI
work to keep that sprint's "new code introduces no new errors"
discipline mechanically enforceable.
### TECH-APP-VITEST — apps/app Vitest setup