Skip to content

docs(spec): KnowledgeSource docblock says runtime registration, not governed metadata - #17649

Closed
os-bill wants to merge 1 commit into
mainfrom
claude/issue-17464-knowledge-source-docblock
Closed

docs(spec): KnowledgeSource docblock says runtime registration, not governed metadata#17649
os-bill wants to merge 1 commit into
mainfrom
claude/issue-17464-knowledge-source-docblock

Conversation

@os-bill

@os-bill os-bill commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Part of #17464

  • Clause-②: no

The docblock above KnowledgeSourceSchema claimed, verbatim:

Canonical KnowledgeSource. Stored as metadata, versioned, and
environment-scoped exactly like a view or a flow.

None of the three is true. This PR corrects the prose. No schema, no registry entry, no key — the diff is one docblock plus its changeset.

Fork (a) vs (b) — the measurements support (a): the PROSE is wrong

The card allowed for the possibility that the registry, not the sentence, is the defect. It is not, on three independent grounds measured on this tree:

  1. No ruling exists that KnowledgeSource ought to be governed metadata. grep -rln "KnowledgeSource\|knowledge source" docs/adr/ returns zero files — no ADR in this repo mentions it at all.
  2. The rest of the contract already says service-level, consistently. IKnowledgeService (packages/spec/src/contracts/knowledge-service.ts) declares registerSource / unregisterSource / listSources / getSource; KnowledgeServicePlugin takes a sources option and calls registerSource for each at init(); KnowledgeService holds them in a plain process-lifetime Map.
  3. The liveness ledger says the same from the other side. packages/spec/liveness/agent.json, row props/knowledge, status dead: "restrict retrieval at the knowledge-service/source level; describe grounding in instructions".

So the sentence was the outlier, and the sentence is what moves. ⛔ Nothing here assumes (b) will happen later — the new text describes only what is true today.

The three prerequisite readings (re-taken on origin/main, ⛔ not inherited from the card)

The card's counts were taken on the installed @objectstack/spec 17.4.0. These were re-taken against the tree under test, with the import resolution proven to the worktree build (import.meta.resolve reported file:///home/user/objectstack-issue-17464/packages/spec/dist/kernel/index.mjs), base bc2bf01c8a.

1 · The docblock still carried the sentence. Anchored by content, ⛔ not by line. The sentence wraps across a line break, so a contiguous grep reads 0 — a mistyped anchor, not an absence. Whitespace-flattened first, then counted by occurrence:

naive contiguous grep                                        -> 0   (MISTYPED ANCHOR)
flattened, "Stored as metadata, versioned, and
            environment-scoped exactly like a view or a flow." -> 1
LIT  CONTROL "Canonical KnowledgeSource."                     -> 1
DARK CONTROL nonsense variant of the same sentence            -> 0

Census over tracked files only (git ls-tree, so the built dist/ cannot pollute it): the phrase exactly like a view or a flow occurs in exactly 1 tracked file — the target.

2 · Registry read, with the card's own control reproduced.

COUNT listMetadataTypeSchemaTypes() = 26
knowledge-shaped (/know/i)          = []
CONTROL view  => true      CONTROL flow  => true      CONTROL skill => true
CONTROL agent => true      CONTROL tool  => true
DARK CONTROL zzz_nonsense => false

3 · No stack-authoring route — with a LIT control.

ObjectStackDefinitionSchema top-level key COUNT = 44
knowledge-shaped keys                           = []
controls present: skills, agents, tools, views, flows  => all true

PROBE base only (additive control)          => ACCEPTED
PROBE LIT CONTROL skills:[valid skill]      => ACCEPTED     <- the probe DOES find an
                                                               authoring route for a type
                                                               that has one
PROBE knowledgeSources:[KS]                 => REJECTED: Unrecognized key(s) ...
PROBE knowledge:[KS] / knowledge_sources    => REJECTED: Unrecognized key(s) ...
PROBE DARK CONTROL zzz_nonsense:1           => REJECTED: Unrecognized key(s) ...  (identical text)

⚠️ One run was discarded and is reported rather than silently retried. The first lit-control attempt used a malformed skill payload and came back REJECTED (3 issues). Reading the full message showed field-level errors inside skills.0 (label / tools required) — a recognized key failing its element schema, not an unrecognized-key refusal. The probe was re-run with a valid skill, which is the ACCEPTED line above.

The correction

The replacement docblock states what the schema actually is — the shape of a runtime registration — names both routes a source arrives by, and records that retrieval is restricted per-source at the service level. It explicitly contrasts against view / flow / skill / agent / tool so the next reader does not have to re-derive the measurement above.

Changeset: patch on @objectstack/spec, graded honestly

⛔ Not skip-changeset: this text is published twice over. files[] ships dist and src/**/*.zod.ts.

BEFORE (dist built from old src):  "exactly like a view or a flow"  -> 1x .d.ts + 1x .d.mts
AFTER  (dist rebuilt):             same phrase                      -> 0
                                   new phrase                       -> 2  (.d.ts + .d.mts)
                                   LIT CONTROL "Canonical KnowledgeSource" -> 2

Measured over 126 built declaration files. The changeset is committed, not a working-tree edit, so the gate that reads it out of git can see it.

Generators

gen:schema and gen:docs were run; both produced no artefact change. content/docs/references/ai/knowledge-source.mdx mirrors the file-level header docblock, not this per-schema one — consistent with the 1-file census above. ⛔ Nothing generated was hand-edited.

Verification — all at 7bd20c60ea

Gate families derived mechanically with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (it takes its own change set from the merge base), then reconciled with --ran carrying a recorded exit code per family:

Run reconciliation — 75 derived, 73 run, 2 NOT-MEASURED, 0 UNRUN.
  • 73 green. Includes check:docs, check:api-surface, check:authorable-surface, check:llms-txt, check:liveness, check:nul-bytes, check:published-files, check:changeset-no-major, check:empty-changeset, check:spec-docblock-symbol-anchors.
  • 2 NOT MEASURED (exit 3), declared: check:dual-build-cjs-loads and check:lean-entry-closure both refuse their own prerequisite — they read built output and 83 workspace packages have no dist/ in this worktree. Clearing them needs a repo-wide pnpm build; that is CI's Build Core. ⛔ Recorded as NOT MEASURED, ⛔ not as green.
  • 6 gates were discarded and re-run, not silently retried. check:doc-formula-expressions, check:api-surface, check:browser-reachable-entries, check:dual-source-exports, check:entry-nameability, check:exported-any first returned a prerequisite refusal (dist stale against the edited src; one at exit 3, five at exit 1 — a refusal does not always arrive as exit 3). After rebuilding @objectstack/spec, @objectstack/formula and @objectstack/lint, all six are green. The whole @objectstack/spec check family (17 gates) was additionally re-run on the rebuilt tree, since a green taken against a stale dist is a false green.

Tests / typecheck (affected package is @objectstack/spec; the published surface is byte-unchanged apart from TSDoc, so no consumer owes a test):

pnpm --filter @objectstack/spec typecheck  -> exit 0
   check:test-typecheck: OK — 54 file(s) / 259 error(s) / 144 pinned signature(s) held
pnpm --filter @objectstack/spec test       -> exit 0
   Test Files  473 passed (473)
   Tests       13429 passed (13429)

Both ran through scripts/pm/os-verify-lock.sh; verdicts read from the printed VERDICT command-exit line, ⛔ never from a bare status after a pipe.

Lint — a declared narrowing, with its three readings. pnpm lint is a repo-wide scan CI owns; this PR ran the narrowed set and proves the narrowing excluded nothing:

  1. Population, read from eslint's own config via ESLint#isPathIgnored over git ls-files: 6615 files are under lint.
  2. Files actually linted, counted from --format json: 2packages/spec/src/ai/knowledge-source.zod.ts (0 errors, 0 warnings) and the changeset .md, whose only message is File ignored because no matching configuration was supplied. eslint --no-inline-config exited 0.
  3. Invariance for the other 6613. This repo runs one eslint.config.mjs and it never enables type-aware linting for any file — no parserOptions.project, no typed @typescript-eslint rules. The config states this in its own words at eslint.config.mjs:326-329, with a positive control recorded there. A TSDoc edit inside one file therefore cannot move any untouched file's verdict.

Acceptance notes (out of scope, ⛔ not filed)

⚠️ Landing note — one advisory check is RED and no author action clears it

Part-of PR must not also close its card (check:partof-closing-keyword, RULE 2) is red, and it is my error: the single commit on this branch carries Part of #17464 in its message, while the contract puts the card relation in the PR body only. Reproduced locally, verbatim:

commit `7bd20c60e` ... carries `Part of #17464` in its message.

The branch was already pushed when this surfaced, and the gate's own header is explicit that the repair is not a history rewrite: "Amend, rebase and force-push are forbidden in this repository and this gate never asks for one." On a pushed branch a new commit on top only joins the commit list. So ⛔ I did not amend, rebase or force-push, and ⛔ I did not push a cosmetic commit to paper over it.

Three facts from the gate's own output, so this can be read rather than acted on:

  1. The check is advisory at the branch-protection layer — absent from the required-context registry, and its workflow subscribes to no merge_group event.
  2. The squash message is assembled from the commit messages, not the body.
  3. The card relation is safe either way: the body's Part of #17464 is what acts, and Part of lands as a reference that moves no card — the lowest-cost of the three spellings the rule refuses.

What discharges it is the merge, and only a merge whose squash message is the PR body. That is the lander's call under the rules that bind them, ⛔ not mine and ⛔ not this gate's.


Generated by Claude Code

…overned metadata

The docblock above `KnowledgeSourceSchema` claimed it is "Stored as
metadata, versioned, and environment-scoped exactly like a view or a
flow". Measured on this tree: `listMetadataTypeSchemaTypes()` returns 26
governed types with none knowledge-shaped (controls `view`, `flow`,
`skill`, `agent`, `tool` all present), `ObjectStackDefinitionSchema` has
44 top-level keys with none knowledge-shaped, and
`defineStack({ knowledgeSources: [...] })` is refused with the generic
unrecognized-key message — identical to a `zzz_nonsense` dark control —
while `defineStack({ skills: [<valid skill>] })` is accepted as the lit
control.

No ADR says it ought to be a governed metadata type; the rest of the
contract already says the opposite (`IKnowledgeService.registerSource`,
`KnowledgeServicePlugin({ sources })`, the process-lifetime source Map,
and the `agent.knowledge` liveness row). The prose was the outlier, so
the prose is what moves: the replacement states the schema is the shape
of a runtime registration, names both routes a source arrives by, and
says retrieval is restricted per-source at the service level.

Prose only — no schema, no registry, no key. `gen:schema` and `gen:docs`
produced no artefact change.

Part of #17464

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/ai/knowledge-source.zod.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/ai/knowledge-source.zod.ts) — pages documenting those are invisible to this run
  • 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 — 135 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 1f0b5659e430717645877f01c4128be567731e35packageMentionDocs.

os-bill commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #17653 — same content, byte-identical on both paths, on a fresh branch off current main.

The reason is this PR's commit message: it carries the card relation, which the contract puts in the PR body only (check:partof-closing-keyword, RULE 2). On an already-pushed branch nothing clears that red, and amend / rebase / force-push stay forbidden — so the remedy was a new branch, ⛔ not a rewrite. Closing this one; ⛔ its branch claude/issue-17464-knowledge-source-docblock is left in place.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ai size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants