From e73929f47efcd27ed9138b57cfcf457c6a889d96 Mon Sep 17 00:00:00 2001 From: Aravind Date: Fri, 18 Sep 2026 13:55:59 +0530 Subject: [PATCH] =?UTF-8?q?refactor(ts-migration):=20Phase=2011=20batch=20?= =?UTF-8?q?2=20=E2=80=94=20the=20skills-layer=20leaves?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eight modules under `src/lib/skills/` that import nothing from their own layer, plus `uiConfig`, which imports only `surfaces`. Renamed and annotated; no logic touched. All eight emit byte-identical minified JavaScript, and the production bundle still hashes to `74d17e2d…`. Four of them are R100 — not one character changed beyond the extension. The annotations are four fixes of the same two kinds: - `Object.entries` / `Object.values` at three sites. Passing an `any` value to either yields `unknown`, not `any`, because inference into the union parameter of their signatures does not distribute — so `weightsOf`'s entries arrived unsortable and two `reduce` accumulators arrived un-addable. The explicit type argument restores what JavaScript had. No cast, no runtime change. - `FlowReply` as `assignmentPreview`'s return type. Two of its five branches genuinely return no `followUp` — "already fully staffed" and "nobody is both qualified and free" are answers with nothing to offer next — so `followUp` is optional, which is what `headcountSet` has always passed through. One inert `/** @param {any} */` in `saveFeedback` became a real annotation. Left as a comment it would have read as if it still did something. Measured against `eaa677f`, all unchanged: typecheck 20 errors, same files lint exit 0, 0 errors, 289 warnings npm test 1684/1691, the same 7 failures verbatim build exit 0, identical bundle hash emitted JS 8/8 byte-identical One number moved and it is a reporting artifact, recorded here so it is not misread next time: ESLint's file count went 269 -> 261. `src/lib/**` is in `ignores` for both config blocks and always has been, so no rule has ever run on these files. A `.js` file there is still walked by ESLint's default `**/*.js` glob and then ignored, which produces an entry with zero messages; a `.ts` file matches no `files` pattern, so it is never walked and produces no entry at all. Confirmed directly: linting `registry.js` reports nothing, linting `yaml.ts` reports "File ignored because no matching configuration was supplied." Zero rules applied before, zero after. The counts that carry signal — 0 errors, 289 warnings — did not move. No baseline artifact touched. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8 --- ...onversationFlow.js => conversationFlow.ts} | 0 src/lib/skills/{draftFlow.js => draftFlow.ts} | 4 ++-- .../{saveFeedback.js => saveFeedback.ts} | 3 +-- ...verSuggestions.js => serverSuggestions.ts} | 0 src/lib/skills/{surfaces.js => surfaces.ts} | 0 src/lib/skills/{uiConfig.js => uiConfig.ts} | 2 +- .../{workforceFlow.js => workforceFlow.ts} | 19 ++++++++++++++++++- src/lib/skills/{yaml.js => yaml.ts} | 0 8 files changed, 22 insertions(+), 6 deletions(-) rename src/lib/skills/{conversationFlow.js => conversationFlow.ts} (100%) rename src/lib/skills/{draftFlow.js => draftFlow.ts} (98%) rename src/lib/skills/{saveFeedback.js => saveFeedback.ts} (95%) rename src/lib/skills/{serverSuggestions.js => serverSuggestions.ts} (100%) rename src/lib/skills/{surfaces.js => surfaces.ts} (100%) rename src/lib/skills/{uiConfig.js => uiConfig.ts} (99%) rename src/lib/skills/{workforceFlow.js => workforceFlow.ts} (98%) rename src/lib/skills/{yaml.js => yaml.ts} (100%) diff --git a/src/lib/skills/conversationFlow.js b/src/lib/skills/conversationFlow.ts similarity index 100% rename from src/lib/skills/conversationFlow.js rename to src/lib/skills/conversationFlow.ts diff --git a/src/lib/skills/draftFlow.js b/src/lib/skills/draftFlow.ts similarity index 98% rename from src/lib/skills/draftFlow.js rename to src/lib/skills/draftFlow.ts index 566ae74..d9f3462 100644 --- a/src/lib/skills/draftFlow.js +++ b/src/lib/skills/draftFlow.ts @@ -228,7 +228,7 @@ export const noDraftReply = () => doc( /** The weights this position actually carries, never a default dressed as one. */ export function weightsOf(position) { const criteria = position?.vetting_criteria || {}; - const entries = Object.entries(criteria).filter(([, value]) => Number.isFinite(Number(value))); + const entries = Object.entries(criteria).filter(([, value]) => Number.isFinite(Number(value))); return { entries, total: entries.reduce((sum, [, value]) => sum + Number(value), 0), @@ -298,7 +298,7 @@ export function weightsFromQuestion(question, position) { } export const weightsSetReply = (position, next) => { - const total = Object.values(next).reduce((sum, value) => sum + Number(value), 0); + const total = Object.values(next).reduce((sum, value) => sum + Number(value), 0); return doc( heading('Vetting weights updated', position.title), diff --git a/src/lib/skills/saveFeedback.js b/src/lib/skills/saveFeedback.ts similarity index 95% rename from src/lib/skills/saveFeedback.js rename to src/lib/skills/saveFeedback.ts index 7aab46e..389a200 100644 --- a/src/lib/skills/saveFeedback.js +++ b/src/lib/skills/saveFeedback.ts @@ -16,8 +16,7 @@ import { toast } from '@/components/ds'; */ export function reportSave(message) { return { - /** @param {any} result */ - onSuccess: (result) => { + onSuccess: (result: any) => { if (result?.persisted === false) { toast.error( `${message} — but this browser would not store it, so it will be gone on reload. ` diff --git a/src/lib/skills/serverSuggestions.js b/src/lib/skills/serverSuggestions.ts similarity index 100% rename from src/lib/skills/serverSuggestions.js rename to src/lib/skills/serverSuggestions.ts diff --git a/src/lib/skills/surfaces.js b/src/lib/skills/surfaces.ts similarity index 100% rename from src/lib/skills/surfaces.js rename to src/lib/skills/surfaces.ts diff --git a/src/lib/skills/uiConfig.js b/src/lib/skills/uiConfig.ts similarity index 99% rename from src/lib/skills/uiConfig.js rename to src/lib/skills/uiConfig.ts index 330d7a3..bfca3d8 100644 --- a/src/lib/skills/uiConfig.js +++ b/src/lib/skills/uiConfig.ts @@ -394,4 +394,4 @@ export const sectionsForPage = (skill, page) => { /** How many UI sections a definition registers, across every page. */ export const countSections = (skill) => - Object.values(skill?.ui || {}).reduce((n, page) => n + (page.sections?.length || 0), 0); + Object.values(skill?.ui || {}).reduce((n, page) => n + (page.sections?.length || 0), 0); diff --git a/src/lib/skills/workforceFlow.js b/src/lib/skills/workforceFlow.ts similarity index 98% rename from src/lib/skills/workforceFlow.js rename to src/lib/skills/workforceFlow.ts index 6c2bc8f..9339210 100644 --- a/src/lib/skills/workforceFlow.js +++ b/src/lib/skills/workforceFlow.ts @@ -580,7 +580,24 @@ export function headcountFailed(position) { * position title, so accepting it goes back through the same resolution path a * typed sentence would — and re-checks the data before writing. */ -export function assignmentPreview(position, context) { +/** + * A reply from this module: a document, and sometimes chips to offer next. + * + * `followUp` is optional because two of the five branches genuinely omit it — + * "already fully staffed" and "nobody is both qualified and free" are answers + * with nothing to offer after them. Callers that spread it on, like + * `headcountSet`, therefore pass `undefined` through in those cases, which is + * what this has always done at run time. + * + * Both fields are `any`: the blocks are the document format's own structures + * and describing them belongs to that format, not here. + */ +export interface FlowReply { + doc: any; + followUp?: any; +} + +export function assignmentPreview(position, context): FlowReply { const plan = prepareAssignment(position, context); const demand = demandFor(position, context); diff --git a/src/lib/skills/yaml.js b/src/lib/skills/yaml.ts similarity index 100% rename from src/lib/skills/yaml.js rename to src/lib/skills/yaml.ts