docs: finalize TypeScript migration documentation
Some checks failed
CI / check (push) Failing after 5m5s
Some checks failed
CI / check (push) Failing after 5m5s
The migration is done and the documentation had not caught up. Two files,
no source changes.
README.md. Twenty-seven references still named modules by their old
extension — `main.jsx`, `krowHooks.js`, `AuthContext.jsx` and the rest.
Every one was checked to resolve under its new extension before being
touched. `store.js` is deliberately NOT among them: that file does not
exist under any extension, having been deleted when the transport moved
to HTTP, so "correcting" it to `.ts` would have replaced a visibly stale
reference with a plausible-looking false one. It stays as it is, with the
rest of that architecture section, for a separate pass.
Also: the assertion count 1691 -> 1693, since recapturing the baselines
replaced one check with three; and the Owliver skill count 18 -> 19,
which had been wrong since `create-employee-role` was added.
The "Known-failing checks" section is now "Check status", and the
rewrite is the part worth reading. It claimed two failures that no longer
exist, and my first attempt at replacing it merged two unrelated
histories into one sentence. They are now separate, because they are:
- The 834/835 suite failure was `the seeded overtime climb is found`.
It asserted against the live calendar — the oldest week in the window
thinned as the week wore on and inflated the baseline every later
week was compared against — so the climb was reported Sunday through
Thursday and vanished on Friday and Saturday. That is a product
defect, not a flaky assertion, and it was fixed in
`src/lib/attendance.ts` at `88c412f` by dropping a leading week
rostered well below the usual, only from the front so that a genuine
collapse in the middle is still a finding.
- The 59 type errors were resolved by this migration.
- `the backend fixture is in step with this seed` failed for its own
reasons and is recorded because it is easy to confuse with the first.
Fixed at `3ddacf2` by teaching the generator to emit the `users`
array the Go seeder reads, rather than by overwriting the fixture.
All three pass. The heading is kept rather than deleted so the absence of
failures is stated rather than merely implied.
MIGRATION_BASELINE.md is appended to, never edited: 68 lines added, zero
removed, and its first 141 lines are byte-identical to the previous
commit. The 2026-09-11 measurements — 71 errors, 1641/1642, 302 files
linted — are the thing the migration was checked against, so bringing
them up to date would destroy the comparison rather than update it. The
new dated entry is the other end of it, and records how the three items
that document left open were each closed.
typecheck 0 errors
lint exit 0, 0 errors, 289 warnings
npm test 1693/1693
build exit 0, bundle 74d17e2d… unchanged
seed:check in step
owliver matches the baseline
No file under `src/` changed, which is why the bundle hash cannot move.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
This commit is contained in:
@@ -139,3 +139,71 @@ node scripts/owliver-baseline.mjs
|
||||
npm run build
|
||||
git diff --stat -M
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-20 — closing addendum: the migration is complete
|
||||
|
||||
Everything above this line is the record as measured on 2026-09-11 and is left
|
||||
exactly as it was written. The numbers in it describe `main` before the first
|
||||
rename; they are the thing the migration was checked against, so correcting them
|
||||
to today's figures would destroy the comparison rather than update it. What
|
||||
follows is the other end of that comparison.
|
||||
|
||||
### Final state, measured on the `ts-migration` branch
|
||||
|
||||
| Check | Command | 2026-09-11 baseline | Now |
|
||||
|---|---|---|---|
|
||||
| Types | `npm run typecheck` | FAILS — 71 errors / 27 files | **0 errors**, 321 files in the program |
|
||||
| Lint | `npm run lint` | PASSES, exit 0 | PASSES, exit 0 |
|
||||
| Lint (with warnings) | `npx eslint .` | 0 errors, 289 warnings | 0 errors, 289 warnings |
|
||||
| Behaviour | `npm test` | 1641 / 1642 | **1693 / 1693** |
|
||||
| Build | `npm run build` | succeeds | succeeds |
|
||||
| Bundle | `dist/assets/index-*.js` | — | `74d17e2d5cafdd6f88eaf6d89ffdab11` |
|
||||
| Owliver, standalone | `node scripts/owliver-baseline.mjs` | FAILS — pre-existing | **matches the baseline** |
|
||||
| Backend fixture | `npm run seed:check` | FAILS — stale | **in step** |
|
||||
|
||||
No `.js` or `.jsx` remains under `src/`: 103 `.ts`, 216 `.tsx` and 2 `.d.ts`.
|
||||
`src/agents/**/*.md` and `src/skills/**/*.md` are untouched, as promised.
|
||||
|
||||
### The three items this document left open, and where they were closed
|
||||
|
||||
**The standalone Owliver script.** Recorded above as failing before any of this
|
||||
began, verified by running it on a clean `main`. The byte-exact comparison was
|
||||
reporting one real difference: the baseline held 23 skills and the runtime
|
||||
resolved 24, because `create-employee-role` was added after the baseline was
|
||||
last written and nobody recaptured it. `npm test` tolerated it — its check
|
||||
asserts only that nothing was *removed*, and read "23 kept, 1 added since" — so
|
||||
the drift was visible only to the stricter script. Refreshed in `34505d7`:
|
||||
three inserted lines, no deletions, routes byte-identical at 18 and all eleven
|
||||
contexts unchanged. The check now reads "24 kept, 0 added since".
|
||||
|
||||
**The backend seed fixture.** Recorded above as predating the migration and
|
||||
deliberately left alone. It stayed that way for good reason: the generator was a
|
||||
version behind the seeder and emitted no `users` key, so regenerating would have
|
||||
dropped `employer@krow.app` from every fresh seed and left nobody to sign in as
|
||||
to reach the employer console. Fixed in `3ddacf2` by teaching the generator to
|
||||
emit the key, not by overwriting the fixture — with that change the generator
|
||||
reproduces the committed fixture byte for byte, so `seed.json` in the sibling
|
||||
repository was never written to at all.
|
||||
|
||||
**The HTML render baselines.** Recorded above as read-only for the duration of
|
||||
the migration, and that held: they were untouched through every phase. Three of
|
||||
them — Hired History, Analytics and Candidates — were recaptured in `878a235`,
|
||||
after the migration, because a parallel feature removed demo data those files had
|
||||
captured while it was still in effect. They are renamed `*.render.html`, since a
|
||||
file called `pre-migration` holding post-feature markup is a lie in the filename.
|
||||
The other five still hold genuine pre-migration markup, still pass, and keep the
|
||||
name. One check that could no longer be satisfied was replaced by three that read
|
||||
the render directly; `scripts/__baseline__/README.md` has the detail.
|
||||
|
||||
### Commits
|
||||
|
||||
3ddacf2 fix(seed): emit the users array the backend seeder reads
|
||||
878a235 test(baseline): recapture the three HTML baselines that held invented people
|
||||
34505d7 chore: refresh owliver baseline
|
||||
|
||||
Strictness remains as debt rather than a blocker: `strict: true` reports 4438
|
||||
errors, `noImplicitAny` 3317 and `strictNullChecks` 1794, while the committed
|
||||
configuration reports none. None of it affects emitted output — the production
|
||||
bundle hash is unchanged — so it is hardening work, not migration work.
|
||||
|
||||
88
README.md
88
README.md
@@ -19,22 +19,22 @@ Recharts + MUI X Charts · react-hot-toast.
|
||||
|
||||
```
|
||||
src/
|
||||
main.jsx entry — mounts <App/>, imports index.css
|
||||
App.jsx providers + the entire route table
|
||||
main.tsx entry — mounts <App/>, imports index.css
|
||||
App.tsx providers + the entire route table
|
||||
index.css design tokens (HSL CSS variables) + utility layers
|
||||
|
||||
api/ the backend seam — see below
|
||||
base44Client.js the contract the production app talks to
|
||||
base44Client.ts the contract the production app talks to
|
||||
store.js in-memory entity store, mirrored to localStorage
|
||||
aiEngine.js local, deterministic InvokeLLM
|
||||
seed.js demo dataset
|
||||
attendanceSeed.js shift/attendance dataset
|
||||
aiEngine.ts local, deterministic InvokeLLM
|
||||
seed.ts demo dataset
|
||||
attendanceSeed.ts shift/attendance dataset
|
||||
|
||||
lib/ domain logic and data hooks
|
||||
krowHooks.js React Query hooks over the entity store
|
||||
krowAi.js AI workflows
|
||||
krowScore.js score engine
|
||||
AuthContext.jsx auth provider
|
||||
krowHooks.ts React Query hooks over the entity store
|
||||
krowAi.ts AI workflows
|
||||
krowScore.ts score engine
|
||||
AuthContext.tsx auth provider
|
||||
admin/ admin session, permissions, position insights
|
||||
skills/ the Owliver skill system (registry, resolver, flows)
|
||||
agents/ the agent system (registry, runtime, lifecycle)
|
||||
@@ -79,37 +79,37 @@ The app opens on **`/admin/login`**. Everything else lives under `/admin/*` behi
|
||||
| `/admin/workspace/skills`, `skills/new`, `skills/:id` | UI skill list and editor |
|
||||
| `/admin/workspace/skills/owliver/new`, `owliver/:id` | Owliver skill editor |
|
||||
| `/admin/workspace/skill-development` | Skill Development |
|
||||
| `*` | `lib/PageNotFound.jsx` |
|
||||
| `*` | `lib/PageNotFound.tsx` |
|
||||
|
||||
Legacy top-level paths (`/overview`, `/positions`, `/candidates`, `/hired`, `/talent-pool`,
|
||||
`/university`, `/analytics`, `/activity`, `/tracking`) all `Navigate` into their `/admin/*`
|
||||
equivalent, id preserved. Static route segments are declared before dynamic ones so
|
||||
`workspace/agents/new` cannot be read as an agent whose id is `"new"`.
|
||||
|
||||
> **Note.** `App.jsx` still imports a set of pre-redesign Employer/Talent pages
|
||||
> **Note.** `App.tsx` still imports a set of pre-redesign Employer/Talent pages
|
||||
> (`Overview`, `Apply`, `WorkerProfile`, `KrowIdentity`, `EmployeeDashboard`, `DesignSystem`, …)
|
||||
> and `layouts/Layout.jsx`. None of them are mounted on a route — they are unreachable at runtime
|
||||
> and `layouts/Layout.tsx`. None of them are mounted on a route — they are unreachable at runtime
|
||||
> and retained pending a decision on whether to re-route or remove them.
|
||||
|
||||
## The backend seam
|
||||
|
||||
The production app talks to a Base44 backend through `src/api/base44Client.js`. This demo keeps that
|
||||
The production app talks to a Base44 backend through `src/api/base44Client.ts`. This demo keeps that
|
||||
module path, export name and full method contract, and swaps only the transport:
|
||||
|
||||
| Contract | Demo implementation |
|
||||
| --- | --- |
|
||||
| `base44.entities.<Name>.list/filter/get/create/update/delete` | `api/store.js` — in-memory records, mirrored to `localStorage` |
|
||||
| `base44.integrations.Core.InvokeLLM` | `api/aiEngine.js` — local, deterministic |
|
||||
| `base44.integrations.Core.InvokeLLM` | `api/aiEngine.ts` — local, deterministic |
|
||||
| `base44.integrations.Core.UploadFile` | blob URLs, session-scoped |
|
||||
| `base44.auth.*` | seeded employer/admin user, always signed in |
|
||||
|
||||
Because the seam did not move, everything above it — `lib/krowHooks.js`, `lib/krowAi.js`,
|
||||
`lib/krowScore.js`, every page and component — is unchanged from the reference implementation.
|
||||
Because the seam did not move, everything above it — `lib/krowHooks.ts`, `lib/krowAi.ts`,
|
||||
`lib/krowScore.ts`, every page and component — is unchanged from the reference implementation.
|
||||
|
||||
## The AI engine
|
||||
|
||||
Every AI workflow funnels through one call, `InvokeLLM({ prompt, response_json_schema })`.
|
||||
`api/aiEngine.js` reimplements it locally: it recognises each workflow by the phrase its prompt opens
|
||||
`api/aiEngine.ts` reimplements it locally: it recognises each workflow by the phrase its prompt opens
|
||||
with, reads the structured fields the prompt already carries (`Years Experience: 6`,
|
||||
`Required Certifications: …`, the talent-pool JSON block) and scores them deterministically.
|
||||
|
||||
@@ -124,8 +124,8 @@ Two registries discover their definitions from markdown at build time:
|
||||
|
||||
| Registry | Glob | Files |
|
||||
| --- | --- | --- |
|
||||
| `lib/skills/registry.js` | `import.meta.glob('/src/skills/**/*.md')` | 18 Owliver skills, 5 workforce training skills |
|
||||
| `lib/agents/registry.js` | `import.meta.glob('/src/agents/**/*.md')` | 9 agent definitions |
|
||||
| `lib/skills/registry.ts` | `import.meta.glob('/src/skills/**/*.md')` | 19 Owliver skills, 5 workforce training skills |
|
||||
| `lib/agents/registry.ts` | `import.meta.glob('/src/agents/**/*.md')` | 9 agent definitions |
|
||||
|
||||
**These globs are absolute paths.** Moving or renaming `src/skills/` or `src/agents/` makes the
|
||||
registry silently return nothing — no build error, no import failure, just an empty registry. Add
|
||||
@@ -133,9 +133,9 @@ definitions by dropping a new `.md` file into the right folder; nothing else nee
|
||||
|
||||
## Demo data
|
||||
|
||||
Seeded in `src/api/seed.js` — positions, applicants, AI-scored candidates, interviews, hires,
|
||||
Seeded in `src/api/seed.ts` — positions, applicants, AI-scored candidates, interviews, hires,
|
||||
talent-pool profiles, Proving Ground courses and an activity log; shift data in
|
||||
`src/api/attendanceSeed.js`.
|
||||
`src/api/attendanceSeed.ts`.
|
||||
|
||||
Edits persist to `localStorage`. To restore the shipped dataset:
|
||||
|
||||
@@ -163,12 +163,12 @@ Tokens live in `src/index.css` as HSL CSS variables consumed by `tailwind.config
|
||||
| Body | Inter |
|
||||
|
||||
`src/components/ds/` is the vocabulary the app actually writes in — `Surface`, `KpiCard`,
|
||||
`DataTable`, `PageHeader`, `Modal`, `toast` and the rest, exported through `ds/index.js`.
|
||||
`DataTable`, `PageHeader`, `Modal`, `toast` and the rest, exported through `ds/index.ts`.
|
||||
`src/components/ui/` holds the shadcn primitives those are built on. Surfaces use `glass` and
|
||||
`glass-card`; the page background is the `gradient-mesh` utility.
|
||||
|
||||
Toasts go through `ds/toast` (a wrapper over `react-hot-toast`), rendered by `<HotToaster>` in
|
||||
`App.jsx`.
|
||||
`App.tsx`.
|
||||
|
||||
## Scripts
|
||||
|
||||
@@ -179,7 +179,7 @@ Toasts go through `ds/toast` (a wrapper over `react-hot-toast`), rendered by `<H
|
||||
| `npm run preview` | Serve the build |
|
||||
| `npm run lint` | ESLint — currently clean |
|
||||
| `npm run lint:fix` | ESLint with `--fix` |
|
||||
| `npm test` | `scripts/skill-check.mjs` — 1691 assertions over the skill and agent systems |
|
||||
| `npm test` | `scripts/skill-check.mjs` — 1693 assertions over the skill and agent systems |
|
||||
| `npm run typecheck` | `tsc -p ./tsconfig.json` — 0 errors across 321 TypeScript files |
|
||||
|
||||
### The test harness
|
||||
@@ -191,17 +191,41 @@ mocks. It also diffs Owliver's behaviour across eleven page contexts against a c
|
||||
`node scripts/owliver-baseline.mjs --write`, never to turn a red check green.
|
||||
|
||||
Because it loads modules by absolute path, the harness pins the locations of `src/api/`, `src/lib/`,
|
||||
`src/lib/skills/`, `src/lib/agents/`, `src/components/ai-assistant/`, `src/App.jsx`,
|
||||
`src/layouts/AdminLayout.jsx` and a handful of agent files. Move any of them and update
|
||||
`src/lib/skills/`, `src/lib/agents/`, `src/components/ai-assistant/`, `src/App.tsx`,
|
||||
`src/layouts/AdminLayout.tsx` and a handful of agent files. Move any of them and update
|
||||
`scripts/owliver-capture.mjs` and `scripts/skill-check.mjs` in the same change.
|
||||
|
||||
### Known-failing checks
|
||||
### Check status
|
||||
|
||||
Two checks fail on a clean checkout and are tracked as separate work, not regressions:
|
||||
Everything above passes on a clean checkout: `npm test` is 1693/1693 and
|
||||
`npm run typecheck` reports no errors.
|
||||
|
||||
- `npm test` — 834/835 pass; `the seeded overtime climb is found` fails.
|
||||
- `npm run typecheck` — 59 errors, all pre-existing JSDoc/inference gaps in `lib/krowAi.js`,
|
||||
`lib/skills/*`, `lib/positionModel.js` and a few components.
|
||||
This section used to list two known failures — 834/835 on the suite, and 59 type
|
||||
errors across `lib/krowAi`, `lib/skills/*` and `lib/positionModel`. Both are
|
||||
gone, and they were unrelated to each other.
|
||||
|
||||
The suite failure was `the seeded overtime climb is found`. It asserted against
|
||||
the live calendar: the shifts are generated by counting back from the day the
|
||||
suite runs, so the oldest week in the window thinned as the week wore on and
|
||||
inflated the baseline every later week was compared against. The climb was
|
||||
reported Sunday through Thursday and vanished on Friday and Saturday. That was a
|
||||
product defect rather than a flaky assertion, and it was fixed in
|
||||
`src/lib/attendance.ts` (commit `88c412f`) by dropping a leading week rostered
|
||||
well below the usual — only from the front, so a genuine collapse in the middle
|
||||
is still a finding. `the seeded overtime climb is detectable on every day of the
|
||||
week` re-runs the detector against 28 consecutive anchors and is what keeps it
|
||||
fixed.
|
||||
|
||||
The type errors were resolved by the TypeScript migration.
|
||||
|
||||
A third check, `the backend fixture is in step with this seed`, failed for its
|
||||
own reasons and is recorded here because it is easily confused with the above:
|
||||
`seed.json` in the sibling backend had drifted from this seed module. Fixed in
|
||||
commit `3ddacf2` by teaching the generator to emit the `users` array the Go
|
||||
seeder reads, rather than by overwriting the fixture. All three pass.
|
||||
|
||||
The heading is kept rather than deleted so that the absence of failures is
|
||||
stated rather than merely implied.
|
||||
|
||||
## Deployment
|
||||
|
||||
|
||||
Reference in New Issue
Block a user