fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding - #15147

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck
Sep 4, 2026
Merged

fix(service-knowledge): put the test layer in front of tsc, and repair the four defects it was hiding#15147
os-sales merged 1 commit into
mainfrom
claude/issue-15049-service-knowledge-typecheck

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#15049

Clause-②: no

The gap, and which exemplar this is copied from

packages/services/service-knowledge had no typecheck script at all
its scripts were build and test — so no tsc program anywhere read this
package. Turbo/CI typecheck lanes skipped it silently (a zero-matching filter
run exits 0); tsup transpiles with esbuild and vitest runs through esbuild
type-stripping; neither type-checks. Errors were carried instead as a
DEBT entry of 10 in scripts/check-type-check-coverage.mjs.

Copied from @objectstack/service-cluster (#14181 / PR #15032), the
worked example this card names — not from plugin-auth / plugin-sharing /
core, whose tsconfig.jsonexcludes tests, because AGENTS.md forbids
adding such an exclusion. service-knowledge's tsconfig.json does not
exclude tests (include: ["src"], no **/*.test.ts exclusion) and never
did — the same shape as service-cluster and plugin-webhooks — so the
program that would have read them already existed and was simply never
invoked. tsconfig.json is therefore untouched; the sibling
tsconfig.test.json is the family's uniform instrument over the same files.

Measured error count, before and after

Dependency closure built first (pnpm --filter '@objectstack/service-knowledge^...' build),
measured at merge-base 2cc4610304:

programbeforeafter
BUILD semantics (tsc --noEmit -p tsconfig.json, undivided)100
test layer (tsc --noEmit -p tsconfig.test.json, the split)40

409 files in the test program (441 in the build program — the gap is dist
declaration-variant granularity for the same three workspace deps under
NodeNext vs bundler resolution, .d.ts/.d.cts chunk files vs .d.mts, not
a difference in which of this package's own src/test files are read),
covering all 4 of the package's src/__tests__/*.test.ts.

The undivided 10 matched the DEBT entry this PR deletes exactly — 3 TS2835
(config-tier: three relative test imports missing .js, required by
moduleResolution: NodeNext) + 4 TS7006 (noise: the unresolved imports make
KnowledgeService resolve to any, cascading into every
out.map((h) => h.documentId) callback over its search results) + 3 code-tier
the ledger's note itemised (TS2339/TS2352/TS2493).

The split did NOT confirm the ledger's 3-code-tier guess — it read 4. This
is the same "a tier split read off an unrepaired config is a guess about what
is UNDER it" lesson scripts/check-type-check-coverage.mjs already states for
@objectstack/metadata and @objectstack/service-storage: fixing the 3
TS2835 removed the any cascade, and doing so re-enabled a TypeScript
excess-property check the cascade had been silently suppressing —
uncovering a 4th real error the undivided reading had masked completely.

The four code-tier defects — all in the test file's own typing, src/ untouched

  1. A stale field name.executionContext: { userId: 'u1', roles: ['member'], permissions: [], isSystem: false }
    roles was renamed to positions (execution-context.zod.ts:
    "Position names held by the user … Formerly roles"). Every other
    executionContext literal in this file already used positions; this one
    simply had never been read by a type checker before, so nothing ever
    caught it. TS2353 (excess property) once the excess-property check could
    see it. Fixed by renaming the field — ExecutionContext itself is correct
    and untouched.
  2. An under-typed mock.buildSetup's vi.fn() stand-in for
    IDataEngine.find typed its second parameter as
    { context: { isSystem?: boolean } }, omitting the where field the real
    call site (knowledge-service.ts's RLS re-check) actually passes.
    expect(opts.where).toEqual(...) then read a property TypeScript correctly
    said did not exist (TS2339). Fixed by widening the mock's parameter type to
    match the call it stubs — where and fields added — never by loosening
    the assertion.
  3. Two more mocks with no parameter type at all. A find = vi.fn(async () => [...])
    in the reindex test had zero declared parameters, so TypeScript inferred a
    0-arity implementation and typed .mock.calls as an array of empty
    tuples
    . find.mock.calls[0][1] then indexed past a fixed-length-0 tuple
    — a genuine TS2493 — and the as { context: {...} } cast off the resulting
    undefined compounded into TS2352. Fixed by typing the mock's parameters
    to match the real reindexSource call site (where, limit, context);
    the assertion no longer needs its as cast at all.

Why these and not a widened ExecutionContext or a looser IDataEngine
stub: the spec contract is correct in both cases (the field really was
renamed; find really is called with where/fields/limit) — the defect
was in the test's typing of its own doubles, so the test is where it is
fixed. This is the same contract-first call PR #15032 made for
service-cluster's TS2322 (fix the test, not the contract it stubs).

The three TS2835 — repaired directly, not routed around

.js added to the three relative specifiers
(../knowledge-service-plugin../knowledge-service-plugin.js,
../knowledge-service../knowledge-service.js ×2). Unlike
service-cluster, whose test files already carried the extension (undivided
and split agreed at 1 both times), this package's did not — and because
tsconfig.json genuinely includes the tests and stays untouched (excluding
them is the one thing AGENTS.md forbids), the package's own typecheck
script's bare tsc --noEmit tsconfig.json step reads these same files under
NodeNext regardless of the new sibling config. They needed fixing either way;
the fix is exactly what TS2835's own message names (Did you mean '../knowledge-service.js'?), not a config change.

tsconfig.test.json

Module semantics only — module: esnext, moduleResolution: bundler,
lib: ["ES2022"] — matching how vitest actually executes these files.
Strictness is inherited and untouched, and it declares no paths (a child's
paths would REPLACE the parent map rather than merge). package.json gains
typecheck / check:test-typecheck, both scripts checked against the
required spellings check-type-check-coverage.mjs and
check-test-typecheck.mts --self-test/--project name.

No test-typecheck-debt.json is created — its absence is the zero: the
gate reads a missing ledger as no entries, so any error in any file here
would be red immediately with nothing to add an entry to.

Ledger consequences

  • DEBT entry deleted, not lowered.check-type-check-coverage.mjs
    carried '@objectstack/service-knowledge': { errors: 10, note: '...' }.
    That gate's own invariant — covered packages must not also sit in the
    ledger — makes this a structural requirement, not a courtesy. Deleted, with
    the graduation and its real composition recorded in the file's prose (the
    same convention service-cluster's graduation used).
  • No test-typecheck-debt.json — see above.

⚠️check:type-source-resolution — an onboarding re-baseline, please review it as one

Went red on my diff, same shape PR #15032 hit for service-cluster:
onboarding tsconfig.test.json moves the package's tsc PROGRAM SET, and the
gate's doc-block opens an explicit onboarding limb for exactly this.

Term 1 — provenance, all three deps annotated via tsconfig.test.json by
the gate's own failure text; the BUILD program (tsconfig.json) carries zero
dist-resolved workspace type imports both before and after this PR (confirmed
by direct measurement, not inferred), so the exposure is only reachable
through the onboarded program.

Term 2 — numbers, --list before/after on the same checkout (before at
the service-cluster merge, 2cc4610304; after with this card applied):

packagesprogramspairsclean
before58 of 7811929020
after59 of 7812029319

+1 package, +1 program, +3 pairs — this entry (@objectstack/core,
@objectstack/objectql, @objectstack/spec) and nothing else.

Term 3 — why the entry and not paths, measured both ways. Redirecting
the three deps to source takes this package's test layer from 0 errors to
487
, all TS6059 (not under rootDir) and every one in another
package's
source (packages/spec/src/**, packages/core/src/**,
packages/objectql/src/**) — billed to a package that cannot pay them down.
Same shape as service-cluster's own 0 → 435 and #12570's +5 for rest, at a
larger scale here because three workspace deps are pulled rather than two.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands
on the rebased head 2969cef816, plus the roster-silent families this diff's
paths sit inside (check:error-code-casing, check:filter-alias-parity,
check:i18n-stale-fill, check:published-readme-exports,
check:published-list-mirrors, check:swallow-census-controls,
check:authz-resolver, check:console-injection) — silent verdicts read
against a roster, not against these paths, so run rather than trusted.
Exit codes captured redirect-then-read, never across a pipe.

73 gates run: 70 exit 0, 2 exit 3 (NOT MEASURED), 1 exit 1 that is also NOT
MEASURED in substance
(below) , 0 red.

NOT MEASURED, quoting each gate's own verdict:

  • check:dual-build-cjs-loads — exit 3: "PREREQUISITE NOT MET — this
    gate reads built output, and some package has no dist/."
    Zero mentions of
    service-knowledge in its output.
  • check:type-check-debt — exit 3: "check-type-check-coverage:
    PREREQUISITE NOT MET … --re-measure cannot run: 18 workspace
    dependenc(ies) of the ledgered packages have no built type entry point on
    disk."
    service-knowledge graduated out of this ledger in this PR, so it
    is not among the 18.
  • check:published-readme-exports — exit 1 (a genuine finding, not this
    gate's own NOT-MEASURED code), but its 84 findings are every OTHER
    unbuilt workspace package's README pointing at a missing dist/. It
    named service-knowledge twice before I built this package's own dist
    (pnpm --filter @objectstack/service-knowledge build); re-run after that
    build: 0service-knowledge mentions, 84 remain for packages this
    card does not touch. None of the three above is evidence about this
    diff — building the other ~60 unbuilt packages is CI's pnpm build step,
    not a scoped card's local obligation.

Package-level, on the final head: pnpm --filter @objectstack/service-knowledge typecheck
exit 0, and pnpm --filter @objectstack/service-knowledge test — 4 files / 40
tests passed.

Declined, with reasons

Changeset

.changeset/service-knowledge-test-tsc-program.md, patch on
@objectstack/service-knowledge. No runtime code changed — src/**
excluding tests is byte-identical, verified — so no shipped behaviour moves;
the level reflects the published package.json gaining typecheck /
check:test-typecheck scripts and a tsx devDependency.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8


Generated by Claude Code

…r the four defects it was hiding (#15049)
packages/services/service-knowledge had no typecheck script at all, so no
tsc program anywhere read this package. Undivided (existing tsconfig.json)
measured 10 raw errors, matching the DEBT entry this PR deletes; the correct
split (new tsconfig.test.json) measured 4 -- not the ledger's own 3-code-tier
guess, because fixing the 3 TS2835 config-tier imports re-enabled an
excess-property check the resulting `any` cascade had been suppressing,
uncovering a 4th real error (a stale `roles` field, renamed to `positions`).
All 4 code-tier defects and the 3 TS2835 are repaired in the test files; both
readings are now 0.
DEBT entry deleted (not lowered). check:type-source-resolution gains an
onboarding-limb registry entry for the 3 workspace deps now reached only
through tsconfig.test.json (paths was measured and rejected: 0 -> 487
TS6059, all billed to other packages' source).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUF1NoViznQK32gqpK8wS8
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1876d5dfd8f309483ef424e7ddd69919409a06dcpackageMentionDocs.

@github-actionsgithub-actionsBot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling labels Sep 4, 2026
@os-sales
os-sales marked this pull request as ready for review September 4, 2026 04:14
@os-sales
os-sales added this pull request to the merge queueSep 4, 2026
Merged via the queue into main with commit 8422acdSep 4, 2026
36 checks passed
@os-sales
os-sales deleted the claude/issue-15049-service-knowledge-typecheck branch September 4, 2026 04:41
os-warren pushed a commit that referenced this pull request Sep 4, 2026
Resolves the third and last conflict of the #14062 family. Both siblings
have landed on main (#15147 service-knowledge, #15152 service-automation)
and all three touch the same two gate scripts.
Resolution is "keep every entry" -- the three cards do not disagree:
* scripts/check-type-check-coverage.mjs: all three graduation paragraphs
kept above `DEBT` (service-storage first, so the service-knowledge
paragraph's "the paragraph above ... for `metadata` and `service-storage`"
back-reference still resolves), and all three DEBT entries deleted. The
ledger summary line is computed at runtime from DEBT/TEST_DEBT, so no
hand-edited total exists there to reconcile.
* scripts/check-type-source-resolution.mjs: auto-merged; all three new
registry entries present, service-cluster / service-i18n untouched.
* pnpm-lock.yaml: not hand-merged. `pnpm install` over the merged manifest
set leaves the auto-merged file byte-identical (hash 000bb7d...) and
`pnpm install --frozen-lockfile` exits 0.
The diff against main is unchanged from the reviewed one: same 20 files,
same +307/-133.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tooling(services): service-knowledge has no typecheck script — its test layer is compiled by no tsc program (#14062 family, sibling of #14181)

2 participants

@os-sales@claude