The identifier signal is the ONLY thing that withholds a response after #143 (claim wording is penalty-only, deliberately — parsing English to make a publish/withhold decision failed three times in that PR). That makes the signal's coverage load-bearing, and it currently exempts most of the public API surface.
The gap
packages/outpost/ai/src/groundedness.ts filters candidate identifiers with a /copilotkit/i guard. Anything that does not contain the literal string copilotkit is never considered — so a fabricated useCopilotAction, CopilotChat, CopilotSidebar, CopilotTextarea, or useCopilotReadable is invisible to the gate, no matter how many are invented or whether any source mentions them.
Verified against the merged code:
extractCopilotKitIdentifiers('Use `.copilotKitGhostA` and `.copilotKitGhostB`')
→ ['copilotKitGhostA', 'copilotKitGhostB'] → suppress: true
extractCopilotKitIdentifiers('Call `useCopilotFabricated()` and `<CopilotInvented />`')
→ [] → suppress: false
The second line is the more likely fabrication in practice: the docs are full of useCopilotAction / CopilotChat, so a model inventing a neighbour of a real hook is a much more natural failure than inventing a .copilotKit* CSS class.
Two narrower related gaps
- TLD allowlist.
BARE_HOST_PATTERN strips scheme-less hosts using a 9-TLD list (ai|app|co|com|dev|io|net|org|sh). A citation on another TLD (.cloud, .help) still leaks a phantom copilotkit identifier; conversely a genuine identifier that happens to end in one of those TLDs gets blanked as a host. Both directions verified.
- Extraction shape coverage. Nested parens and some JSX/prose forms are not matched, so an invented name in those shapes is not extracted.
Why this is filed rather than fixed in #143
Widening the guard changes what gets withheld, which needs its own review round and its own corpus rows (there is now a table-driven corpus in groundedness.test.ts keyed by response shape — the natural home). Doing it inside #143 would have meant a fifth review round on a PR that had already converged on the design.
Direction, when picked up: match on a CopilotKit-ish shape (Copilot* / useCopilot* / .copilotKit*) rather than the literal substring, and pin the widened surface with corpus rows in both directions — invented names suppress, documented names do not.
Found by the CR loop on #143 (round 3), reproduced against the merged code.
The identifier signal is the ONLY thing that withholds a response after #143 (claim wording is penalty-only, deliberately — parsing English to make a publish/withhold decision failed three times in that PR). That makes the signal's coverage load-bearing, and it currently exempts most of the public API surface.
The gap
packages/outpost/ai/src/groundedness.tsfilters candidate identifiers with a/copilotkit/iguard. Anything that does not contain the literal stringcopilotkitis never considered — so a fabricateduseCopilotAction,CopilotChat,CopilotSidebar,CopilotTextarea, oruseCopilotReadableis invisible to the gate, no matter how many are invented or whether any source mentions them.Verified against the merged code:
The second line is the more likely fabrication in practice: the docs are full of
useCopilotAction/CopilotChat, so a model inventing a neighbour of a real hook is a much more natural failure than inventing a.copilotKit*CSS class.Two narrower related gaps
BARE_HOST_PATTERNstrips scheme-less hosts using a 9-TLD list (ai|app|co|com|dev|io|net|org|sh). A citation on another TLD (.cloud,.help) still leaks a phantomcopilotkitidentifier; conversely a genuine identifier that happens to end in one of those TLDs gets blanked as a host. Both directions verified.Why this is filed rather than fixed in #143
Widening the guard changes what gets withheld, which needs its own review round and its own corpus rows (there is now a table-driven corpus in
groundedness.test.tskeyed by response shape — the natural home). Doing it inside #143 would have meant a fifth review round on a PR that had already converged on the design.Direction, when picked up: match on a CopilotKit-ish shape (
Copilot*/useCopilot*/.copilotKit*) rather than the literal substring, and pin the widened surface with corpus rows in both directions — invented names suppress, documented names do not.Found by the CR loop on #143 (round 3), reproduced against the merged code.