Parcourir la source

Merge latest origin/master into codex/simplify-agent-identity-plumbing

Tianyi Cui il y a 2 mois
Parent
commit
3cd73ec4b8

+ 2 - 2
docs/config-catalog.md

@@ -99,7 +99,7 @@ export interface Config {
 }
 ```
 
-Depends on: [`AgentOptions`](../packages/core/agent/src/index.ts) · [`SessionId`](../packages/core/session/src/index.ts)
+Depends on: [`AgentOptions`](core-data-structures/core.md) · [`SessionId`](core-data-structures/core.md)
 
 Source: [`packages/core/agent-loop/src/index.ts:369`](../packages/core/agent-loop/src/index.ts)
 
@@ -1144,7 +1144,7 @@ export interface Config {
 }
 ```
 
-Depends on: [`AgentOptions`](../packages/core/agent/src/index.ts)
+Depends on: [`AgentOptions`](core-data-structures/core.md)
 
 Source: [`packages/subagent/tool-subagent/src/index.ts:23`](../packages/subagent/tool-subagent/src/index.ts)
 

+ 48 - 20
docs/cordis-catalog/events.md

@@ -31,7 +31,7 @@ A fully configured agent and live session were published. Setup is composition-o
 'agent/created'(this: Scoped<Agent>, agent: Agent): void
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:141`](../../packages/core/agent/src/types.ts)
 
@@ -51,7 +51,7 @@ An agent left the registry; AgentLoop emits this after driver quiescence but bef
 'agent/disposed'(this: Scoped<Agent>, agent: Agent): void
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:150`](../../packages/core/agent/src/types.ts)
 
@@ -73,7 +73,7 @@ A step or turn errored. The loop reports a failure here (plus the logger) even w
 'agent/error'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, error: Error): void
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:285`](../../packages/core/agent/src/types.ts)
 
@@ -101,7 +101,7 @@ Awaited serial checkpoint for session-surface mutation after prompt assembly and
 'agent/pre-step'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal): Promise<void> | void
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:204`](../../packages/core/agent/src/types.ts)
 
@@ -122,7 +122,7 @@ Allow, rewrite, or block one drained prompt before it becomes a user message. Ca
 'agent/prompt-submit'(this: Scoped<Agent>, agent: Agent, content: ContentBlock[], source: MessageSource, next: () => Promise<PromptDecision>): Promise<PromptDecision>
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md) · [PromptDecision](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:214`](../../packages/core/agent/src/types.ts)
 
@@ -143,7 +143,7 @@ Detached, frozen content entered the agent's inbox. Source defaults have already
 'agent/queued'(this: Scoped<Agent>, agent: Agent, content: ContentBlock[], info: { source: MessageSource; steering: boolean }): void
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:169`](../../packages/core/agent/src/types.ts)
 
@@ -166,7 +166,7 @@ Replace the frozen call configuration. Model-visible content must use logged cha
 'agent/request'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, config: LlmCallConfig, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [LlmCallConfig](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [LlmCallConfig](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:226`](../../packages/core/agent/src/types.ts)
 
@@ -192,7 +192,7 @@ Compose request-only messages placed before derived history. The frozen result i
 'agent/session-prefix'(this: Scoped<Agent>, agent: Agent, prefix: Message[], signal: AbortSignal, next: () => Promise<Message[]>): Promise<Message[]>
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:241`](../../packages/core/agent/src/types.ts)
 
@@ -214,7 +214,7 @@ The session lifecycle began, once before the first turn. Use `agent.inject()` to
 'agent/session-start'(this: Scoped<Agent>, agent: Agent, source: SessionStartSource): void
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [SessionStartSource](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md) · [SessionStartSource](../core-data-structures/core.md)
 
 Source: [`packages/core/agent/src/types.ts:182`](../../packages/core/agent/src/types.ts)
 
@@ -234,7 +234,7 @@ Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does no
 'agent/status'(this: Scoped<Agent>, agent: Agent, status: AgentStatus): void
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [AgentStatus](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:159`](../../packages/core/agent/src/types.ts)
 
@@ -256,7 +256,7 @@ Waterfall: post-process the assembled assistant Message before tool dispatch (va
 'agent/step-result'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, message: Message, next: () => Promise<Message>): Promise<Message>
 ```
 
-Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:252`](../../packages/core/agent/src/types.ts)
 
@@ -277,7 +277,7 @@ Override whether the turn continues. The default continues after tool calls or s
 'agent/turn-continuation'(this: Scoped<Agent>, agent: Agent, turn: number, defaultDecision: ContinuationDecision, next: () => Promise<ContinuationDecision>): Promise<ContinuationDecision>
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [ContinuationDecision](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:262`](../../packages/core/agent/src/types.ts)
 
@@ -298,7 +298,7 @@ Monotonic terminal-stop checkpoint after continuation and steering are folded; a
 'agent/turn-stop'(this: Scoped<Agent>, agent: Agent, turn: number): ContinuationStop | undefined
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [ContinuationStop](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/core/agent/src/types.ts:272`](../../packages/core/agent/src/types.ts)
 
@@ -321,6 +321,8 @@ A declarative agent entry failed before it could publish a live agent. Consumers
 'agent-loop/config-start-failed'(sessionId: SessionId, error: unknown): void
 ```
 
+Types: [SessionId](../core-data-structures/core.md)
+
 Source: [`packages/core/agent-loop/src/index.ts:362`](../../packages/core/agent-loop/src/index.ts)
 
 ## `approval/*`
@@ -340,7 +342,7 @@ Ask composed answerers for one decision. Return an outcome to claim the request
 'approval/request'(this: Scoped<ApprovalService>, req: ApprovalRequest, next: () => Promise<ApprovalOutcome>): Promise<ApprovalOutcome>
 ```
 
-Types: [ApprovalOutcome](../core-data-structures/approval.md) · [ApprovalRequest](../core-data-structures/approval.md)
+Types: [ApprovalOutcome](../core-data-structures/approval.md) · [ApprovalRequest](../core-data-structures/approval.md) · [ApprovalService](../core-data-structures/approval.md) · [Scoped](../core-data-structures/scope.md)
 
 Source: [`packages/ui/user-approval/src/index.ts:31`](../../packages/ui/user-approval/src/index.ts)
 
@@ -426,7 +428,7 @@ Waterfall around every streaming model call (retry, replay, routing). Bound to t
 'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable<StreamChunk>): AsyncIterable<StreamChunk>
 ```
 
-Types: [GenerateOptions](../core-data-structures/core.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
+Types: [GenerateOptions](../core-data-structures/core.md) · [LlmService](../core-data-structures/llm-streaming.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
 
 Source: [`packages/llm/llm/src/index.ts:40`](../../packages/llm/llm/src/index.ts)
 
@@ -451,6 +453,8 @@ Creation announcement during session publication. A synchronous throw vetoes and
 'session/created'(this: Scoped<Session>, session: Session): void
 ```
 
+Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
+
 Source: [`packages/core/session/src/index.ts:47`](../../packages/core/session/src/index.ts)
 
 ### `session/disposed` — emit
@@ -470,6 +474,8 @@ Emitted once when an announced session leaves the store, including publication r
 'session/disposed'(this: Scoped<Session>, session: Session): void
 ```
 
+Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
+
 Source: [`packages/core/session/src/index.ts:57`](../../packages/core/session/src/index.ts)
 
 ### `session/event` — emit
@@ -491,7 +497,7 @@ Post-commit, fire-and-forget append feed. The listener snapshot resolves before
 'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void
 ```
 
-Types: [SessionEvent](../core-data-structures/core.md)
+Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md) · [SessionEvent](../core-data-structures/core.md)
 
 Source: [`packages/core/session/src/index.ts:69`](../../packages/core/session/src/index.ts)
 
@@ -512,6 +518,8 @@ Awaited parallel durability checkpoint: every listener runs and the caller await
 'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void
 ```
 
+Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
+
 Source: [`packages/core/session/src/index.ts:79`](../../packages/core/session/src/index.ts)
 
 ## `subagent/*`
@@ -532,6 +540,8 @@ A ready child settled. Scope-filtered dispatch uses the same delegating parent c
 'subagent/end'(this: Scoped<SubagentService>, info: SubagentRunEndInfo): void
 ```
 
+Types: [Scoped](../core-data-structures/scope.md) · [SubagentService](../core-data-structures/subagent.md)
+
 Source: [`packages/subagent/subagent/src/index.ts:112`](../../packages/subagent/subagent/src/index.ts)
 
 ### `subagent/provider-added` — emit
@@ -547,6 +557,8 @@ A provider became resolvable in the registry.
 'subagent/provider-added'(provider: SubagentProvider): void
 ```
 
+Types: [SubagentProvider](../core-data-structures/subagent.md)
+
 Source: [`packages/subagent/subagent/src/index.ts:86`](../../packages/subagent/subagent/src/index.ts)
 
 ### `subagent/provider-removed` — emit
@@ -582,6 +594,8 @@ A provider established a ready child. For in-process providers, `ctx.agents.get(
 'subagent/start'(this: Scoped<SubagentService>, info: SubagentRunInfo): void
 ```
 
+Types: [Scoped](../core-data-structures/scope.md) · [SubagentService](../core-data-structures/subagent.md)
+
 Source: [`packages/subagent/subagent/src/index.ts:103`](../../packages/subagent/subagent/src/index.ts)
 
 ## `system-prompt/*`
@@ -602,6 +616,8 @@ Expert waterfall over the assembled sections, tools, and variables. Scope-filter
 'system-prompt/assemble'(this: Scoped<SystemPrompt>, assembly: PromptAssembly, context: AssembleContext, next: () => Promise<PromptAssembly>): Promise<PromptAssembly>
 ```
 
+Types: [AssembleContext](../core-data-structures/system-prompt.md) · [Scoped](../core-data-structures/scope.md) · [SystemPrompt](../core-data-structures/system-prompt.md)
+
 Source: [`packages/core/system-prompt/src/index.ts:27`](../../packages/core/system-prompt/src/index.ts)
 
 ### `system-prompt/change` — emit
@@ -656,7 +672,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor
 'tools/execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult>
 ```
 
-Types: [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
+Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
 
 Source: [`packages/core/tools/src/index.ts:89`](../../packages/core/tools/src/index.ts)
 
@@ -676,7 +692,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts
 'tools/post-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, result: Readonly<ToolExecutionResult>, next: () => Promise<PostToolDecision>): Promise<PostToolDecision>
 ```
 
-Types: [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
+Types: [PostToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
 
 Source: [`packages/core/tools/src/index.ts:98`](../../packages/core/tools/src/index.ts)
 
@@ -695,7 +711,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv
 'tools/pre-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>
 ```
 
-Types: [ToolExecution](../core-data-structures/tools.md)
+Types: [PreToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
 
 Source: [`packages/core/tools/src/index.ts:80`](../../packages/core/tools/src/index.ts)
 
@@ -714,7 +730,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained
 'tools/result'(this: Scoped<ToolRegistry>, exec: Readonly<ToolExecution>, result: Readonly<ToolExecutionResult>): undefined
 ```
 
-Types: [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
+Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
 
 Source: [`packages/core/tools/src/index.ts:106`](../../packages/core/tools/src/index.ts)
 
@@ -738,6 +754,8 @@ One `agent()` call settled (clean result, child failure, or run cancellation). P
 'workflow/agent-end'(info: WorkflowRunInfo, agent: WorkflowAgentEndInfo): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:81`](../../packages/workflow/workflow/src/index.ts)
 
 ### `workflow/agent-start` — emit
@@ -757,6 +775,8 @@ One `agent()` call established a ready child run. Paired with Events['workflow/a
 'workflow/agent-start'(info: WorkflowRunInfo, agent: WorkflowAgentInfo): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:70`](../../packages/workflow/workflow/src/index.ts)
 
 ### `workflow/end` — emit
@@ -776,6 +796,8 @@ A workflow run settled (any stop reason). Fired when WorkflowRun.result resolves
 'workflow/end'(info: WorkflowRunInfo, result: WorkflowResultInfo): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:91`](../../packages/workflow/workflow/src/index.ts)
 
 ### `workflow/log` — emit
@@ -792,6 +814,8 @@ The script emitted a narration line (a `log(message)` call).
 'workflow/log'(info: WorkflowRunInfo, message: string): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:60`](../../packages/workflow/workflow/src/index.ts)
 
 ### `workflow/phase` — emit
@@ -809,6 +833,8 @@ The script entered a phase (a `phase(title)` call) — progress grouping for obs
 'workflow/phase'(info: WorkflowRunInfo, title: string): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:53`](../../packages/workflow/workflow/src/index.ts)
 
 ### `workflow/start` — emit
@@ -825,6 +851,8 @@ A workflow run started — the script's meta block validated, the body about to
 'workflow/start'(info: WorkflowRunInfo): void
 ```
 
+Types: [WorkflowRunInfo](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:45`](../../packages/workflow/workflow/src/index.ts)
 
 ## Inherited events (cordis core + loader/hmr/timer)

+ 30 - 12
docs/cordis-catalog/services.md

@@ -42,7 +42,7 @@ async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<Agent
 async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [AgentOptions](../core-data-structures/core.md) · [SessionHeader](../core-data-structures/persistence.md) · [SessionId](../core-data-structures/core.md)
 
 Source: [`packages/core/agent-loop/src/index.ts:407`](../../packages/core/agent-loop/src/index.ts)
 
@@ -214,7 +214,7 @@ list(): Agent[]
 roots(): Agent[]
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [SessionId](../core-data-structures/core.md)
 
 Source: [`packages/core/agent/src/index.ts:217`](../../packages/core/agent/src/index.ts)
 
@@ -284,7 +284,7 @@ abstract run(spec: BashExecSpec): Promise<BashRunResult>
 abstract start(spec: BashExecSpec): BashProcess
 ```
 
-Types: [BashExecRequest](../core-data-structures/bash.md) · [BashExecSpec](../core-data-structures/bash.md) · [BashRunResult](../core-data-structures/bash.md)
+Types: [BashExecRequest](../core-data-structures/bash.md) · [BashExecSpec](../core-data-structures/bash.md) · [BashProcess](../core-data-structures/bash.md) · [BashRunResult](../core-data-structures/bash.md)
 
 Source: [`packages/bash/bash/src/index.ts:49`](../../packages/bash/bash/src/index.ts)
 
@@ -315,7 +315,7 @@ collect(execution: ToolExecution): DshEnvironment
 list(): BashEnvVariableInfo[]
 ```
 
-Types: [ToolExecution](../core-data-structures/tools.md)
+Types: [DshEnvironment](../core-data-structures/bash.md) · [ToolExecution](../core-data-structures/tools.md)
 
 Source: [`packages/bash/tool-bash/src/index.ts:102`](../../packages/bash/tool-bash/src/index.ts)
 
@@ -382,7 +382,7 @@ abstract compactIfNeeded( agent: CompactAgentContext, fullSystemPrompt: string,
 abstract compactRegion( start: number, end: number, agent: CompactAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>
 ```
 
-Types: [Message](../core-data-structures/core.md)
+Types: [CompactionResult](../core-data-structures/compaction.md) · [Message](../core-data-structures/core.md)
 
 Source: [`packages/compact/compact/src/index.ts:38`](../../packages/compact/compact/src/index.ts)
 
@@ -478,7 +478,7 @@ abstract writeText(target: FsTarget, content: string, expected?: FsWriteIntent,
 abstract editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome>
 ```
 
-Types: [FsEditOutcome](../core-data-structures/filesystem.md) · [FsEditRequest](../core-data-structures/filesystem.md) · [FsInfo](../core-data-structures/filesystem.md) · [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md) · [FsWriteIntent](../core-data-structures/filesystem.md) · [FsWriteOutcome](../core-data-structures/filesystem.md)
+Types: [FsDirEntry](../core-data-structures/filesystem.md) · [FsEditOutcome](../core-data-structures/filesystem.md) · [FsEditRequest](../core-data-structures/filesystem.md) · [FsInfo](../core-data-structures/filesystem.md) · [FsPathInfo](../core-data-structures/filesystem.md) · [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md) · [FsWriteIntent](../core-data-structures/filesystem.md) · [FsWriteOutcome](../core-data-structures/filesystem.md)
 
 Source: [`packages/fs/fs/src/index.ts:80`](../../packages/fs/fs/src/index.ts)
 
@@ -523,7 +523,7 @@ async listModels(provider: string): Promise<LlmModelInfo[]>
 stream(options: GenerateOptions): AsyncIterable<StreamChunk>
 ```
 
-Types: [GenerateOptions](../core-data-structures/core.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
+Types: [GenerateOptions](../core-data-structures/core.md) · [LlmAdapter](../core-data-structures/llm-streaming.md) · [LlmModelInfo](../core-data-structures/core.md) · [LlmProviderInfo](../core-data-structures/core.md) · [StreamChunk](../core-data-structures/llm-streaming.md)
 
 Source: [`packages/llm/llm/src/index.ts:94`](../../packages/llm/llm/src/index.ts)
 
@@ -567,7 +567,7 @@ optionOf(name: string): PresetOption
 set(session: Session, name: string): void
 ```
 
-Types: [SessionEvent](../core-data-structures/core.md)
+Types: [Session](../core-data-structures/session.md) · [SessionEvent](../core-data-structures/core.md)
 
 Source: [`packages/ui/permission/src/index.ts:94`](../../packages/ui/permission/src/index.ts)
 
@@ -645,7 +645,7 @@ abstract load(id: SessionId): Promise<{ meta: SessionHeader; events: SessionEven
 abstract list(): Promise<SessionHeader[]>
 ```
 
-Types: [SessionEvent](../core-data-structures/core.md)
+Types: [SessionEvent](../core-data-structures/core.md) · [SessionHeader](../core-data-structures/persistence.md) · [SessionId](../core-data-structures/core.md) · [SessionLocation](../core-data-structures/persistence.md)
 
 Source: [`packages/session-persistence/session-persistence/src/index.ts:42`](../../packages/session-persistence/session-persistence/src/index.ts)
 
@@ -691,6 +691,8 @@ async traceEvent(request: SessionEventTraceRequest): Promise<SessionEventTrace>
 async readEvent(request: SessionEventReadRequest): Promise<SessionEventWindow>
 ```
 
+Types: [SessionEventReadRequest](../core-data-structures/session-query.md) · [SessionEventRecord](../core-data-structures/session-query.md) · [SessionEventTrace](../core-data-structures/session-query.md) · [SessionEventTraceRequest](../core-data-structures/session-query.md) · [SessionEventWindow](../core-data-structures/session-query.md) · [SessionId](../core-data-structures/core.md) · [SessionLineageTrace](../core-data-structures/session-query.md) · [SessionRecord](../core-data-structures/session-query.md)
+
 Source: [`packages/session-query/session-query/src/index.ts:38`](../../packages/session-query/session-query/src/index.ts)
 
 ## `ctx.sessions` — `SessionStore`
@@ -816,6 +818,8 @@ list(): Session[]
 fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session
 ```
 
+Types: [CreateSessionOptions](../core-data-structures/persistence.md) · [Session](../core-data-structures/session.md) · [SessionId](../core-data-structures/core.md)
+
 Source: [`packages/core/session/src/index.ts:577`](../../packages/core/session/src/index.ts)
 
 ## `ctx.skills` — `SkillService`
@@ -862,6 +866,8 @@ async list(options: SkillLookupOptions = {}): Promise<SkillSummary[]>
 async get(name: string, options: SkillLookupOptions = {}): Promise<SkillDefinition | undefined>
 ```
 
+Types: [SkillDefinition](../core-data-structures/skills.md) · [SkillLookupOptions](../core-data-structures/skills.md) · [SkillProvider](../core-data-structures/skills.md) · [SkillRegistration](../core-data-structures/skills.md) · [SkillSummary](../core-data-structures/skills.md)
+
 Source: [`packages/skill/skill/src/index.ts:141`](../../packages/skill/skill/src/index.ts)
 
 ## `ctx.spillStore` — `SpillStore` (abstract seam)
@@ -883,6 +889,8 @@ Semantics every implementation must honor:
 abstract saveText(input: SaveTextSpill): Promise<SpillRef>
 ```
 
+Types: [SaveTextSpill](../core-data-structures/spill.md) · [SpillRef](../core-data-structures/spill.md)
+
 Source: [`packages/spill/spill/src/index.ts:45`](../../packages/spill/spill/src/index.ts)
 
 ## `ctx.subagents` — `SubagentService`
@@ -924,6 +932,8 @@ list(): string[]
 async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
 ```
 
+Types: [SubagentProvider](../core-data-structures/subagent.md) · [SubagentRun](../core-data-structures/subagent.md) · [SubagentStartRequest](../core-data-structures/subagent.md)
+
 Source: [`packages/subagent/subagent/src/index.ts:153`](../../packages/subagent/subagent/src/index.ts)
 
 ## `ctx.systemPrompt` — `SystemPrompt`
@@ -970,6 +980,8 @@ variable(name: string, provider: (context: AssembleContext) => string | undefine
 async assemble(context: AssembleContext = {}): Promise<PromptAssembly>
 ```
 
+Types: [AssembleContext](../core-data-structures/system-prompt.md) · [PromptSection](../core-data-structures/system-prompt.md) · [ToolProviderResult](../core-data-structures/system-prompt.md)
+
 Source: [`packages/core/system-prompt/src/index.ts:209`](../../packages/core/system-prompt/src/index.ts)
 
 ## `ctx.tasks` — `TaskService`
@@ -1057,7 +1069,7 @@ onTaskDone(listener: TaskDoneListener): () => void
 attachSurface(name: string): () => void
 ```
 
-Types: [Agent](../core-data-structures/core.md)
+Types: [Agent](../core-data-structures/core.md) · [TaskDoneListener](../core-data-structures/tasks.md) · [TaskId](../core-data-structures/tasks.md) · [TaskRead](../core-data-structures/tasks.md) · [TaskSnapshot](../core-data-structures/tasks.md) · [TaskStart](../core-data-structures/tasks.md)
 
 Source: [`packages/tasks/tasks/src/index.ts:76`](../../packages/tasks/tasks/src/index.ts)
 
@@ -1092,7 +1104,7 @@ measure(session: Session, requestHeader?: EpochHeader): TokenMeasurement
 estimateMessage(message: Message): number
 ```
 
-Types: [Message](../core-data-structures/core.md)
+Types: [EpochHeader](../core-data-structures/session.md) · [Message](../core-data-structures/core.md) · [Session](../core-data-structures/session.md) · [TokenMeasurement](../core-data-structures/token-meter.md)
 
 Source: [`packages/llm/token-meter/src/index.ts:106`](../../packages/llm/token-meter/src/index.ts)
 
@@ -1170,7 +1182,7 @@ executionMode(exec: ToolExecutionInput): ToolExecutionMode
 async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
 ```
 
-Types: [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
+Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md)
 
 Source: [`packages/core/tools/src/index.ts:438`](../../packages/core/tools/src/index.ts)
 
@@ -1196,6 +1208,8 @@ registerProvider(provider: UserInteractionProvider): () => void
 async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
 ```
 
+Types: [AskUserQuestionAnswer](../core-data-structures/user-interaction.md) · [AskUserQuestionRequest](../core-data-structures/user-interaction.md) · [UserInteractionProvider](../core-data-structures/user-interaction.md)
+
 Source: [`packages/ui/user-interaction/src/index.ts:82`](../../packages/ui/user-interaction/src/index.ts)
 
 ## `ctx.web` — `WebService`
@@ -1252,6 +1266,8 @@ async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearch
 async fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>
 ```
 
+Types: [WebFetchProvider](../core-data-structures/web.md) · [WebFetchRequest](../core-data-structures/web.md) · [WebFetchResult](../core-data-structures/web.md) · [WebSearchProvider](../core-data-structures/web.md) · [WebSearchRequest](../core-data-structures/web.md) · [WebSearchResult](../core-data-structures/web.md)
+
 Source: [`packages/web/web/src/index.ts:74`](../../packages/web/web/src/index.ts)
 
 ## `ctx.workflows` — `WorkflowService` (abstract seam)
@@ -1268,6 +1284,8 @@ Workflow execution seam. Invalid requests throw before publication; a live run i
 abstract start(request: WorkflowStartRequest): WorkflowRun
 ```
 
+Types: [WorkflowRun](../core-data-structures/workflow.md) · [WorkflowStartRequest](../core-data-structures/workflow.md)
+
 Source: [`packages/workflow/workflow/src/index.ts:159`](../../packages/workflow/workflow/src/index.ts)
 
 ## Inherited `ctx` members (cordis core + loader/hmr/timer)

+ 3 - 3
docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md

@@ -20,7 +20,7 @@ Specific choices:
 
 - **`@mode` tag, cross-checked.** Each harness event's JSDoc carries an explicit `@mode emit|waterfall|parallel|serial` tag; the generator hard-errors on a missing tag. Where the signature shape is conclusive — a trailing `next: () => …` parameter is structurally a waterfall — it asserts the tag agrees and hard-errors on a contradiction. The emit/parallel/serial distinction is not structurally visible (`session/flush` returns `Promise<void> | void` with no `next`, as does the ordered `agent/pre-step` checkpoint), so it is trusted from the tag. The authoring rule lives in [AGENTS.md](../../../../AGENTS.md).
 - **Tiered scope.** The harness tier (the 8 `@deepseek-ai/dsh-*` services + their events) is rendered in full from source. The inherited tier (cordis-core `ctx.on/emit/effect/provide/…` + the `internal/*` events + loader/hmr/timer) is pinned vendor source a plugin also sees; it is rendered tersely (name + one-line + source pointer) from a curated table in the generator, NOT walked from the vendor AST — the cordis-core `Context` mixes true ctx members with non-service fields (`root`, `baseUrl`, `logger`), and the vendor surface changes only on a deliberate vendor sync.
-- **Cross-links to the data-structure catalog.** A type name in a signature (`GenerateOptions`, `StreamChunk`, `ToolDefinition`, …) links to the core-data-structures page that documents it. The map is a small hand-curated const in the generator — NOT `type-equiv.manifest.json`, which documents the `…Map` symbols while signatures reference the derived union names, and lists a few symbols on two pages.
+- **Cross-links to the data-structure catalog.** Every repository-owned type name in a signature (`GenerateOptions`, `StreamChunk`, `ToolDefinition`, …) links to its primary core-data-structures page through a curated map. The AST walk is fail-closed: each parameter, generic constraint/default, and return-type reference must be mapped, be the signature's own type parameter, be a named TypeScript/Cordis foundation type, or carry a named exception with its non-catalog documentation owner. Violations aggregate with source pointers and name the appropriate owning lists. The map does NOT reuse `type-equiv.manifest.json`, which documents `…Map` symbols while signatures reference derived union names and lists some symbols on multiple pages.
 - **A dedicated fence.** Signature blocks use a ` ```ts cordis-catalog ` info string and place the original event or public-method JSDoc immediately before its declaration. `doc-typecheck` recognizes and skips the bare fragments, excluding them from the opt-out ratio — the same treatment `type-equiv` blocks get.
 
 This **supersedes the event-taxonomy half** of [doc-sync enforcement](2026-06-11-doc-sync-enforcement.md): `verify-event-taxonomy` and its `docs/architecture.md` table are retired (the architecture.md heading stays, its body now points at the catalog; the Service-map role table stays as curated prose). doc-typecheck, verify-md-wrap, verify-md-links, and verify-type-equiv are unchanged.
@@ -29,11 +29,11 @@ This **supersedes the event-taxonomy half** of [doc-sync enforcement](2026-06-11
 
 - **Verify-don't-generate, as the retired taxonomy check did** — reversed *for this surface only*: the data here is mechanically complete, so generation is strictly stronger (full signatures, cannot drift, catches undocumented events) than a name-set check of a hand-maintained table.
 - **Walking the vendor AST for the inherited tier** — rejected for the curated table: the cordis-core `Context` mixes true ctx members with non-service fields, and the pinned vendor surface changes only on a deliberate sync.
-- **Reusing `type-equiv.manifest.json` as the signature cross-link map** — rejected for a small hand-curated const: the manifest documents the `…Map` symbols while signatures reference the derived union names, and it lists a few symbols on two pages.
+- **Reusing `type-equiv.manifest.json` as the signature cross-link map** — rejected for a complete curated const plus fail-closed coverage: the manifest documents `…Map` symbols while signatures reference derived union names, and it lists some symbols on multiple pages. The explicit map makes each rendered destination and each non-catalog exception a reviewable decision.
 
 ## Consequences
 
-- The catalog cannot drift: a source change that the committed file doesn't reflect fails `verify-cordis-catalog` in the pre-push hook and CI. A new event with no `@mode` tag, or a tag that contradicts its signature, fails the generator outright.
+- The catalog cannot drift: a source change that the committed file doesn't reflect fails `verify-cordis-catalog` in the pre-push hook and CI. A new event with no `@mode` tag, a tag that contradicts its signature, or an unclassified signature type fails the generator outright.
 - Event and service-method contracts have a single home — the JSDoc at the declaration. The catalog repeats that original JSDoc inside its generated signature block and uses its description portion as entry prose, so thin source documentation yields a thin catalog entry.
 - The inherited tier is hand-summarized, so a vendor sync that adds/renames a cordis-core event or `ctx` member needs a matching edit to the curated table in `gen-cordis-catalog.ts`. This is the deliberate cost of not walking pinned vendor source; it changes rarely and is called out in the generator.
 - `verify-event-taxonomy.ts` is deleted and the `docs/architecture.md` event table is gone; anyone who linked to a specific table row now lands on the generated catalog instead.

+ 35 - 1
packages/core/agent/tests/gen-cordis-catalog.spec.ts

@@ -1,5 +1,6 @@
 /**
- * Negative-path tests for the cordis catalog generator (`scripts/gen-cordis-catalog.ts`).
+ * Contract and negative-path tests for the cordis catalog generator
+ * (`scripts/gen-cordis-catalog.ts`).
  */
 
 import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
@@ -76,6 +77,33 @@ describe('gen-cordis-catalog collectEvents', () => {
     expect(events[0]?.mode).toBe('parallel')
   })
 
+  it('accepts linked, foundation, generic-parameter, and explicitly exempt signature types', () => {
+    const events = collectEvents(make(
+      '    /**\n     * Carry linked and foundation types.\n     * @param value - the linked value.\n     * @param preset - deployment metadata outside the core catalog.\n     * @param signal - cancellation.\n     * @mode parallel\n     */\n    \'fix/typed\'<T extends SessionEvent>(value: Readonly<T>, preset: PresetSpec, signal: AbortSignal): Promise<T>',
+    ))
+    expect(events).toHaveLength(1)
+    expect(renderEvents(events)).toContain('Types: [SessionEvent](../core-data-structures/core.md)')
+    expect(renderEvents(events)).not.toContain('[PresetSpec]')
+  })
+
+  it('aggregates every unclassified signature type with its source and remediation', () => {
+    const expected = new RegExp([
+      '2 signature type-link coverage violation\\(s\\)',
+      'fix/one',
+      'packages/group/fix/src/index.ts',
+      'MissingOne',
+      'fix/two',
+      'packages/group/fix/src/index.ts',
+      'missingTwo',
+      'Add it to LINK_MAP',
+      'FOUNDATION_TYPE_NAMES',
+      'TYPE_LINK_EXEMPTIONS',
+    ].join('[\\s\\S]*'))
+    expect(() => collectEvents(make(
+      '    /**\n     * First.\n     * @param value - first value.\n     * @mode emit\n     */\n    \'fix/one\'(value: MissingOne): void\n    /**\n     * Second.\n     * @param value - second value.\n     * @mode emit\n     */\n    \'fix/two\'(value: missingTwo): void',
+    ))).toThrow(expected)
+  })
+
   it('hard-errors when an event is missing its @mode tag', () => {
     expect(() => collectEvents(make(
       '    /** No mode here. */\n    \'fix/untagged\'(): void',
@@ -167,6 +195,12 @@ export class FixService {
     expect(renderServices(services)).toContain('```ts cordis-catalog\n/**\n * Do the thing.\n * @param id - which thing to do.\n * @returns the outcome of doing it.\n */\nrun(id: string): string\n\n/** Fire and forget (void needs no @returns). */\npoke(): void')
   })
 
+  it('hard-errors on an unclassified service-method signature type', () => {
+    expect(() => collectServices(makeService(
+      '/** Fixture service. */\nexport class FixService {\n  /**\n   * Use an unknown value.\n   * @param value - the value.\n   */\n  run(value: MissingServiceType): void {}\n}',
+    ))).toThrow(/service method ctx\.fix\.run .* references unclassified type 'MissingServiceType'/)
+  })
+
   it('hard-errors on a public method with no JSDoc at all', () => {
     expect(() => collectServices(makeService(
       '/** Fixture service. */\nexport class FixService {\n  run(id: string): string { return id }\n}',

+ 176 - 22
scripts/gen-cordis-catalog.ts

@@ -1,8 +1,8 @@
 /**
  * Generate the Cordis event and service catalogs from static declarations.
- * The walk enforces event modes plus JSDoc parameter/return completeness;
- * inherited Cordis services come from the curated table below. `--check`
- * verifies both committed artifacts.
+ * The walk enforces event modes, JSDoc parameter/return completeness, and
+ * signature type-link coverage; inherited Cordis services come from the
+ * curated table below. `--check` verifies both committed artifacts.
  */
 
 import { globSync, readFileSync, writeFileSync } from 'node:fs'
@@ -20,48 +20,196 @@ const OUT_SERVICES = 'docs/cordis-catalog/services.md'
 const FENCE = 'ts cordis-catalog'
 
 /**
- * One primary core-data-structures page per signature type, shared by the
- * Cordis and config catalogs; union names intentionally do not reuse the
- * type-equivalence manifest's map-symbol entries.
+ * One primary core-data-structures page per project type used by a generated
+ * signature. This stays curated because union names intentionally do not
+ * reuse the type-equivalence manifest's map-symbol entries and some symbols
+ * appear on more than one page.
  */
-// TODO(catalog-type-links): verify or generate link-map coverage.
 export const LINK_MAP: Record<string, string> = {
   Agent: 'core.md',
+  AgentOptions: 'core.md',
+  AgentStatus: 'core.md',
   ContentBlock: 'core.md',
-  Message: 'core.md',
-  MessageSource: 'core.md',
+  ContinuationDecision: 'core.md',
+  ContinuationStop: 'core.md',
   GenerateOptions: 'core.md',
   LlmCallConfig: 'core.md',
+  LlmModelInfo: 'core.md',
+  LlmProviderInfo: 'core.md',
+  Message: 'core.md',
+  MessageSource: 'core.md',
+  PromptDecision: 'core.md',
   SessionEvent: 'core.md',
+  SessionId: 'core.md',
   SessionStartSource: 'core.md',
-  StreamChunk: 'llm-streaming.md',
-  TurnEndReason: 'session.md',
-  ToolDefinition: 'tools.md',
-  ToolExecution: 'tools.md',
-  ToolExecutionMode: 'tools.md',
-  ToolExecutionInput: 'tools.md',
-  ToolExecutionResult: 'tools.md',
-  ToolExecutionToken: 'tools.md',
   ApprovalOutcome: 'approval.md',
   ApprovalPolicy: 'approval.md',
   ApprovalRequest: 'approval.md',
+  ApprovalService: 'approval.md',
   BashExecRequest: 'bash.md',
   BashExecSpec: 'bash.md',
+  BashProcess: 'bash.md',
   BashRunResult: 'bash.md',
-  ConfinedArgv: 'sandbox.md',
-  SandboxMode: 'sandbox.md',
-  SandboxPolicy: 'sandbox.md',
+  DshEnvironment: 'bash.md',
   CodeRunRequest: 'code-runtime.md',
   CodeRunResult: 'code-runtime.md',
+  CompactionResult: 'compaction.md',
+  FileReadOutcome: 'filesystem.md',
+  FsDirEntry: 'filesystem.md',
   FsEditOutcome: 'filesystem.md',
   FsEditRequest: 'filesystem.md',
   FsInfo: 'filesystem.md',
+  FsPathInfo: 'filesystem.md',
+  FsPolicyExec: 'filesystem.md',
   FsTarget: 'filesystem.md',
   FsVersion: 'filesystem.md',
   FsWriteIntent: 'filesystem.md',
   FsWriteOutcome: 'filesystem.md',
-  FsPolicyExec: 'filesystem.md',
-  FileReadOutcome: 'filesystem.md',
+  LlmAdapter: 'llm-streaming.md',
+  LlmService: 'llm-streaming.md',
+  StreamChunk: 'llm-streaming.md',
+  CreateSessionOptions: 'persistence.md',
+  SessionHeader: 'persistence.md',
+  SessionLocation: 'persistence.md',
+  ConfinedArgv: 'sandbox.md',
+  SandboxMode: 'sandbox.md',
+  SandboxPolicy: 'sandbox.md',
+  ScopeKey: 'scope.md',
+  Scoped: 'scope.md',
+  EpochHeader: 'session.md',
+  Session: 'session.md',
+  TurnEndReason: 'session.md',
+  SessionEventReadRequest: 'session-query.md',
+  SessionEventRecord: 'session-query.md',
+  SessionEventTrace: 'session-query.md',
+  SessionEventTraceRequest: 'session-query.md',
+  SessionEventWindow: 'session-query.md',
+  SessionLineageTrace: 'session-query.md',
+  SessionRecord: 'session-query.md',
+  SkillDefinition: 'skills.md',
+  SkillLookupOptions: 'skills.md',
+  SkillProvider: 'skills.md',
+  SkillRegistration: 'skills.md',
+  SkillSummary: 'skills.md',
+  SaveTextSpill: 'spill.md',
+  SpillRef: 'spill.md',
+  SubagentProvider: 'subagent.md',
+  SubagentRun: 'subagent.md',
+  SubagentService: 'subagent.md',
+  SubagentStartRequest: 'subagent.md',
+  AssembleContext: 'system-prompt.md',
+  PromptSection: 'system-prompt.md',
+  SystemPrompt: 'system-prompt.md',
+  ToolProviderResult: 'system-prompt.md',
+  TaskDoneListener: 'tasks.md',
+  TaskId: 'tasks.md',
+  TaskRead: 'tasks.md',
+  TaskSnapshot: 'tasks.md',
+  TaskStart: 'tasks.md',
+  TokenMeasurement: 'token-meter.md',
+  PostToolDecision: 'tools.md',
+  PreToolDecision: 'tools.md',
+  ToolDefinition: 'tools.md',
+  ToolExecution: 'tools.md',
+  ToolExecutionInput: 'tools.md',
+  ToolExecutionMode: 'tools.md',
+  ToolExecutionResult: 'tools.md',
+  ToolExecutionToken: 'tools.md',
+  ToolGuard: 'tools.md',
+  ToolRegistry: 'tools.md',
+  ToolRestriction: 'tools.md',
+  ToolSchema: 'tools.md',
+  AskUserQuestionAnswer: 'user-interaction.md',
+  AskUserQuestionRequest: 'user-interaction.md',
+  UserInteractionProvider: 'user-interaction.md',
+  WebFetchProvider: 'web.md',
+  WebFetchRequest: 'web.md',
+  WebFetchResult: 'web.md',
+  WebSearchProvider: 'web.md',
+  WebSearchRequest: 'web.md',
+  WebSearchResult: 'web.md',
+  WorkflowRun: 'workflow.md',
+  WorkflowRunInfo: 'workflow.md',
+  WorkflowStartRequest: 'workflow.md',
+}
+
+/** TypeScript lib and pinned framework types that have no repository-owned data page. */
+const FOUNDATION_TYPE_NAMES = new Set([
+  'AbortSignal',
+  'AsyncIterable',
+  'Context',
+  'Error',
+  'Pick',
+  'Promise',
+  'Readonly',
+])
+
+/** Project types deliberately documented outside the core-data catalog. */
+const TYPE_LINK_EXEMPTIONS: Readonly<Record<string, string>> = {
+  AgentFactory: 'agent creation seam is owned by packages/core/agent/README.md',
+  AgentHandle: 'agent ownership handle is owned by packages/core/agent/README.md',
+  BashEnvContributor: 'service-local extension type is owned by packages/bash/tool-bash/src/index.ts',
+  BashEnvVariableInfo: 'service-local metadata type is owned by packages/bash/tool-bash/src/index.ts',
+  CompactAgentContext: 'compaction service input is owned by packages/compact/compact/src/index.ts',
+  CreateAgentOptions: 'agent creation contract is owned by packages/core/agent/README.md',
+  PresetOption: 'deployment menu metadata is owned by packages/ui/permission/README.md',
+  PresetSpec: 'deployment preset composition is owned by packages/ui/permission/README.md',
+  PromptAssembly: 'assembly result is owned by packages/core/system-prompt/README.md',
+  ResumeAgentOptions: 'agent resume contract is owned by packages/core/agent/README.md',
+  SessionForkSource: 'service-local fork input is owned by packages/core/session/src/index.ts',
+  SubagentRunEndInfo: 'event-local snapshot is owned by packages/subagent/subagent/src/index.ts',
+  SubagentRunInfo: 'event-local snapshot is owned by packages/subagent/subagent/src/index.ts',
+  WorkflowAgentEndInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
+  WorkflowAgentInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
+  WorkflowResultInfo: 'event-local snapshot is owned by packages/workflow/workflow/src/index.ts',
+}
+
+/** Collect named references from parameter, generic-constraint/default, and return types. */
+function signatureTypeNames(member: ts.MethodSignature | ts.MethodDeclaration, sf: ts.SourceFile): string[] {
+  const declared = new Set(member.typeParameters?.map(parameter => parameter.name.text) ?? [])
+  const referenced = new Set<string>()
+  const visit = (node: ts.Node): void => {
+    if (ts.isTypeReferenceNode(node)) referenced.add(node.typeName.getText(sf))
+    if (ts.isTypeQueryNode(node)) referenced.add(node.exprName.getText(sf))
+    ts.forEachChild(node, visit)
+  }
+  for (const parameter of member.typeParameters ?? []) {
+    if (parameter.constraint) visit(parameter.constraint)
+    if (parameter.default) visit(parameter.default)
+  }
+  for (const parameter of member.parameters) {
+    if (parameter.type) visit(parameter.type)
+  }
+  if (member.type) visit(member.type)
+  return [...referenced].filter(name => !declared.has(name)).sort()
+}
+
+/** Append fail-closed signature type-link violations with actionable ownership choices. */
+function checkTypeLinks(
+  where: string,
+  member: ts.MethodSignature | ts.MethodDeclaration,
+  sf: ts.SourceFile,
+  violations: string[],
+): void {
+  for (const name of signatureTypeNames(member, sf)) {
+    if (Object.hasOwn(LINK_MAP, name)
+      || FOUNDATION_TYPE_NAMES.has(name)
+      || Object.hasOwn(TYPE_LINK_EXEMPTIONS, name)) continue
+    violations.push(
+      `${where} references unclassified type '${name}'. Add it to LINK_MAP with its core-data-structures page, `
+      + 'to FOUNDATION_TYPE_NAMES if TypeScript or Cordis owns it, or to TYPE_LINK_EXEMPTIONS with '
+      + 'the non-catalog documentation owner.',
+    )
+  }
+}
+
+/** Throw one aggregated diagnostic for every unclassified signature type. */
+function reportTypeLinkViolations(gate: string, violations: string[]): void {
+  if (violations.length === 0) return
+  throw new Error(
+    `${gate}: ${violations.length} signature type-link coverage violation(s):\n`
+    + violations.map(violation => `  ${violation}`).join('\n'),
+  )
 }
 
 /** One harness event, extracted from an `interface Events` block. */
@@ -148,6 +296,7 @@ function jsDocText(text: string, sf: ts.SourceFile, node: ts.Node): string {
 export function collectEvents(scanRoot: string = root): EventEntry[] {
   const entries: EventEntry[] = []
   const violations: string[] = []
+  const typeLinkViolations: string[] = []
   for (const rel of globSync('packages/*/*/src/*.ts', { cwd: scanRoot }).map(s => s.split(sep).join('/')).sort()) {
     const abs = resolve(scanRoot, rel)
     const text = readFileSync(abs, 'utf8')
@@ -161,6 +310,7 @@ export function collectEvents(scanRoot: string = root): EventEntry[] {
       const { doc, mode } = parseJsDoc(raw)
       const src = pointer(rel, sf, member)
       const where = `event '${name}' (${src})`
+      checkTypeLinks(where, member, sf, typeLinkViolations)
       if (!mode) {
         violations.push(`${where} is missing an @mode tag. Add '@mode emit|waterfall|parallel|serial' to its JSDoc (see AGENTS.md).`)
       }
@@ -185,6 +335,7 @@ export function collectEvents(scanRoot: string = root): EventEntry[] {
     }
   }
   reportViolations('gen-cordis-catalog', violations)
+  reportTypeLinkViolations('gen-cordis-catalog', typeLinkViolations)
   return entries
 }
 
@@ -197,6 +348,7 @@ export function collectEvents(scanRoot: string = root): EventEntry[] {
 export function collectServices(scanRoot: string = root): ServiceEntry[] {
   const entries: ServiceEntry[] = []
   const violations: string[] = []
+  const typeLinkViolations: string[] = []
   for (const rel of globSync('packages/*/*/src/index.ts', { cwd: scanRoot }).map(s => s.split(sep).join('/')).sort()) {
     const abs = resolve(scanRoot, rel)
     const text = readFileSync(abs, 'utf8')
@@ -220,6 +372,7 @@ export function collectServices(scanRoot: string = root): ServiceEntry[] {
         const memberName = member.name.getText(sf)
         if (memberName.startsWith('[')) continue // computed/symbol members
         const where = `service method ctx.${key}.${memberName} (${pointer(rel, sf, member)})`
+        checkTypeLinks(where, member, sf, typeLinkViolations)
         const raw = rawJsDoc(text, member)
         methods.push({ signature: memberSignature(member, sf), jsDoc: jsDocText(text, sf, member) })
         if (!raw) { violations.push(`${where} has no JSDoc.`); continue }
@@ -243,6 +396,7 @@ export function collectServices(scanRoot: string = root): ServiceEntry[] {
     }
   }
   reportViolations('gen-cordis-catalog', violations)
+  reportTypeLinkViolations('gen-cordis-catalog', typeLinkViolations)
   return entries.sort((a, b) => a.key.localeCompare(b.key))
 }