The fixture generator was a version behind the seeder, and the gap was
the `users` key.
`internal/seeder` unmarshals `seed.json` into `{demoUser, users,
entities}` and writes every account in `users`, falling back to
`demoUser` alone when the key is absent. `fixtureFrom` never emitted it —
its comment still claimed the Go loader "ignores the rest", which stopped
being true when the seeder gained the field. So `npm run seed:check`
reported stale on every run, and that is the seventh suite failure, the
one that pre-dates the TypeScript migration.
What made this worth investigating rather than regenerating: the
committed fixture was NOT wrong. It carries two accounts — the demo
administrator and `employer@krow.app` — and running `npm run seed:fixture`
against the old generator would have written a fixture without them.
`krow-backend/docs/deploy-9d3192a.md` says so in as many words, and tells
anyone deploying not to run it.
The accounts are not deleted from a live database by that — the only
DELETE in the seeder is the shift-record prune, and `upsertUser`'s ON
CONFLICT deliberately leaves `password_hash` alone. The damage lands on
the next fresh environment, where `user_employer` would simply never be
created, leaving nobody to sign in as to reach the employer console —
which is the exact gap `seeder.go` records the account as having been
added to close.
The matching frontend half already existed, unmerged, on
`feat/krow-employee-pages` (7a4b61d). That branch is a 53-file console
restructure that renames the same files this migration renamed, so it is
not mergeable here. Only the three files that carry the contract are
taken: `EMPLOYER_USER`, `seedData.User` naming both accounts, and the
generator emitting `users`.
The proof is that nothing had to be written. With the generator corrected
its output is byte-identical to the fixture already committed in
krow-backend — 168,293 bytes, `cmp` clean — so `seed.json` was never
opened for writing, and its md5 and mtime are untouched.
typecheck 0 errors
seed:check "seed.json is in step with src/api/seed.js", exit 0
npm test 1685/1691, up from 1684 — the fixture check now reads
"24 applications, byte-identical". The remaining 6 are
exactly the documented dca1842 baseline failures.
lint exit 0, 0 errors, 289 warnings
build exit 0, bundle 74d17e2d… unchanged
The bundle being unchanged is itself a check: `demoUser.ts` IS in the
production bundle, and `EMPLOYER_USER` is a new export of it. Nothing in
the app imports it, so it is tree-shaken out and not one byte reaches the
shipped code.
No baseline artifact touched. krow-backend not modified.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
Phase 4a: `demoUser` and `httpClient`. Type-only. The production bundle is
byte-identical - built from this commit's parent and from this commit, all six
chunk hashes match.
`httpClient` is the contract boundary, so the annotations are deliberately
conservative:
- `KrowApiError` is a CAST, not a class. The three error sites still build a
plain `Error` and assign `.name`, `.status`, `.code` and `.details` onto it
exactly as before. `class KrowApiError extends Error` would have read
better and changed three things that callers depend on: the prototype
chain, `instanceof`, and how `name` comes to be set.
- `RESOURCE_PATHS` becomes `Record<EntityName, EntityResourcePath>`. That is
the first thing in the repo to check the eighteen entity names against the
eighteen in `ENTITY_NAMES`; until now the two lists agreed only by habit,
and a divergence would have surfaced as `base44.entities.Whatever` being
undefined with nothing to say why.
- `createEntity`'s parameter stays `string` and its return stays inferred.
Annotating the return `EntityClient<any>` was tried and reverted: it makes
`list()` return `Promise<any[]>` where inference gives `Promise<any>`, and
`agentStore.js` does `qc.getQueryData(KEY) || (await ...list(...))`. React
Query types `getQueryData` as `unknown`; `unknown || any` collapses to
`any`, `unknown || any[]` stays `unknown`, and `.find` on the next line
stopped compiling. Two new errors in a file this phase does not migrate,
for no gain. `EntityClientFor<K>` is ready for the phase that migrates
those consumers.
Unchanged and verified in the emitted output: `credentials: 'include'`, both
header branches on `body === undefined`, the URLSearchParams query encoding with
its repeated-array and undefined-omission rules, the `payload.data` unwrap that
drops `meta`, the verbatim server message, `status: 0` / `code: 'unreachable'`
for a transport failure, the `-created_date` and `limit` defaults, path
construction through `encodeURIComponent`, and `bulkCreate`'s sequential
`this.create` loop.
`DEMO_USER` is annotated `User`, which does real work: unannotated,
`role: 'admin'` widens to `string` and the default shape did not satisfy the
type the app uses for the thing it defaults.
Verified in isolation from the parallel feature work (d1425f9 plus these two
files): tsc 64 -> 53, the eleven removed being exactly this file's, and a
set-difference against the baseline showing none added. skill-check 1641/1642
with only the known stale-fixture failure, Owliver baseline 59/59, lint 0
errors, build succeeds with the API origin inlined.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8