@indexnetwork/protocol 20.0.0-rc.484.1 → 20.0.1-rc.485.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/mcp/elicitation.builder.d.ts +1 -1
  3. package/dist/mcp/elicitation.dispatcher.d.ts +1 -1
  4. package/dist/questions/index.d.ts +37 -8
  5. package/dist/questions/index.js +38 -2
  6. package/dist/questions/{application/question.agent.d.ts → question.agent.d.ts} +2 -2
  7. package/dist/questions/{application/question.agent.js → question.agent.js} +6 -9
  8. package/dist/questions/{application/question.ask.tool.d.ts → question.ask.tool.d.ts} +2 -2
  9. package/dist/questions/{application/question.ask.tool.js → question.ask.tool.js} +4 -7
  10. package/dist/questions/{application/question.env.d.ts → question.env.d.ts} +1 -4
  11. package/dist/questions/{application/question.env.js → question.env.js} +1 -4
  12. package/dist/questions/{application/question.input.d.ts → question.input.d.ts} +4 -7
  13. package/dist/questions/{application/question.input.js → question.input.js} +1 -1
  14. package/dist/questions/{ports/question.persistence.port.d.ts → question.persistence.port.d.ts} +2 -4
  15. package/dist/questions/{application/question.presets.d.ts → question.presets.d.ts} +2 -5
  16. package/dist/questions/{application/question.presets.js → question.presets.js} +12 -2
  17. package/dist/questions/{domain/question.schema.d.ts → question.schema.d.ts} +43 -47
  18. package/dist/questions/{domain/question.schema.js → question.schema.js} +32 -32
  19. package/dist/questions/{application/question.tools.d.ts → question.tools.d.ts} +2 -2
  20. package/dist/questions/{application/question.tools.js → question.tools.js} +4 -7
  21. package/dist/questions/{ports/question.tools.port.d.ts → question.tools.port.d.ts} +2 -4
  22. package/dist/shared/agent/tool.helpers.d.ts +3 -3
  23. package/dist/shared/schemas/pending-question.schema.d.ts +1 -1
  24. package/dist/shared/schemas/underspecification.schema.d.ts +1 -1
  25. package/dist/shared/schemas/underspecification.schema.js +1 -1
  26. package/package.json +1 -1
  27. package/dist/questions/application/index.d.ts +0 -39
  28. package/dist/questions/application/index.js +0 -41
  29. package/dist/questions/application/question.qud.d.ts +0 -12
  30. package/dist/questions/application/question.qud.js +0 -16
  31. package/dist/questions/domain/index.d.ts +0 -24
  32. package/dist/questions/domain/index.js +0 -24
  33. package/dist/questions/ports/index.d.ts +0 -27
  34. package/dist/questions/ports/index.js +0 -26
  35. /package/dist/questions/{ports/question.persistence.port.js → question.persistence.port.js} +0 -0
  36. /package/dist/questions/{ports/question.tools.port.js → question.tools.port.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -20,6 +20,30 @@ went 6.7.1 → 8.0.2 with no 7.x in between because the whole 7.x line shipped a
20
20
  prereleases between the two promotions. To track every change, read `rc`; to
21
21
  pin a supported release, use `latest`.
22
22
 
23
+ ## 20.0.1 - 2026-08-17
24
+
25
+ ### Changed
26
+
27
+ - Flatten `src/questions/` from four directories to one, matching the same move
28
+ already made in `intents/` and `networks/`, and the flat layout of `chat/`,
29
+ `discovery/`, and `premises/`. The `domain/`, `ports/`, and `application/`
30
+ directories held two,
31
+ two, and six files behind 206 lines of re-export barrel; the three sub-barrels
32
+ re-exported roughly twenty symbols no consumer outside the capability ever
33
+ imported. Files now sit flat and are named for what they are
34
+ (`question.schema`, `question.input`, `question.agent`, `question.presets`,
35
+ `question.env`, `question.tools`, `question.ask.tool`, and the two ports), with
36
+ a single `index.ts` as the capability barrel.
37
+ - Fold the QUD taxonomy constant into `question.presets.ts`, its only consumer,
38
+ retiring the 16-line `question.qud.ts`.
39
+ - Share the negotiation candidate/provenance field shape and their identical
40
+ counterparty-eligibility refinement instead of declaring both twice. The two
41
+ `superRefine` blocks stated the same uptake-only rule in different words; they
42
+ now delegate to one helper, so the invariant has a single definition.
43
+
44
+ The package's exported surface is unchanged — `questions/index.ts` exports the
45
+ same 44 names as before. Only paths private to the capability moved.
46
+
23
47
  ## 20.0.0 - 2026-08-17
24
48
 
25
49
  ### Changed
@@ -1,4 +1,4 @@
1
- import type { Question } from "../questions/domain/question.schema.js";
1
+ import type { Question } from "../questions/question.schema.js";
2
2
  type SingleChoiceSchema = {
3
3
  type: "string";
4
4
  enum: string[];
@@ -1,4 +1,4 @@
1
- import type { Question } from "../questions/domain/question.schema.js";
1
+ import type { Question } from "../questions/question.schema.js";
2
2
  import type { ChatMessageWriter } from "../shared/interfaces/chat-message-writer.interface.js";
3
3
  import { buildElicitationCreate } from "./elicitation.builder.js";
4
4
  export type ElicitResultLike = {
@@ -2,12 +2,41 @@
2
2
  * questions — the capability's sole cross-capability surface.
3
3
  *
4
4
  * Anything outside this capability imports from here and nowhere else.
5
- * Supersedes the capabilities/*.facade.ts + questions/public/ pair; the export
6
- * list is the union of the facades it replaces, so the contract is unchanged.
5
+ *
6
+ * ## What lives in the capability
7
+ *
8
+ * - **question.schema** — Zod schemas and derived types for the whole question
9
+ * vocabulary: the public Question shape, generator envelopes, and the
10
+ * detection/provenance/pool/recovery persistence sub-schemas.
11
+ * - **question.input** — per-mode context types, the discriminated
12
+ * QuestionerInput union, and `isValidQuestionerInputContract`, the runtime
13
+ * mirror of that discriminant enforced at queue boundaries.
14
+ * - **question.agent** — QuestionerAgent: stateless, mode-driven generation.
15
+ * - **question.presets** — system prompts and user-message builders per mode.
16
+ * - **question.env** — the QUESTIONER_* env accessors. All reads go through it.
17
+ * - **question.tools** / **question.ask.tool** — foreground adapters: the
18
+ * authenticated MCP read/answer tools, and the blocking chat
19
+ * `ask_user_question` tool.
20
+ * - **question.persistence.port** / **question.tools.port** — the injected
21
+ * host contracts (question CRUD, chat host bridge, tool host capabilities).
22
+ *
23
+ * Ambient generation (recovery, pool, uptake, inflight, push) is scheduled via
24
+ * the backend QuestionerQueue, which consumes the {@link QuestionerEnqueueFn}
25
+ * injected from the composition root.
26
+ *
27
+ * ## Boundary
28
+ *
29
+ * The capability imports from shared/ infrastructure and the negotiations
30
+ * barrel — never from runtime/, host implementations, or other capability
31
+ * internals.
7
32
  */
8
- export type { QuestionerEnqueueFn, } from "./application/question.input.js";
9
- export { createAskUserQuestionTools, createQuestionerTools, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, isValidQuestionerInputContract, QuestionerAgent, uptakeAuthorityThreshold, } from "./application/index.js";
10
- export type { InflightQuestionerInput, PoolDiscoveryContext, PostStallQuestionerInput, QuestionerEnqueuePayload, QuestionerInput, RecoveryQuestionerInput, UptakeQuestionerInput, } from "./application/index.js";
11
- export type { AskUserQuestionToolDeps, ChatQuestionsHost, PersistableQuestion, PersistedQuestion, QuestionerDatabase, QuestionerToolDeps, QuestionFilters, } from "./ports/index.js";
12
- export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./domain/index.js";
13
- export type { NegotiationQuestionCandidate, QuestionOption, NegotiationQuestionProvenance, NegotiationQuestionPurpose, Question, QuestionGenerationResult, QuestionPoolDiscriminator, QuestionPoolPush, QuestionPoolPushRequestReason, QuestionPoolPushRequestStatus, QuestionPoolSnapshot, QuestionPurpose, QuestionRecoverySnapshot, QuestionStrategy, QuestionVoidedReason, UnderspecificationType, } from "./domain/index.js";
33
+ export { QuestionerAgent } from "./question.agent.js";
34
+ export { createAskUserQuestionTools } from "./question.ask.tool.js";
35
+ export { createQuestionerTools } from "./question.tools.js";
36
+ export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, } from "./question.env.js";
37
+ export { isValidQuestionerInputContract } from "./question.input.js";
38
+ export type { InflightQuestionerInput, PoolDiscoveryContext, PostStallQuestionerInput, QuestionerEnqueueFn, QuestionerEnqueuePayload, QuestionerInput, RecoveryQuestionerInput, UptakeQuestionerInput, } from "./question.input.js";
39
+ export type { ChatQuestionsHost, PersistableQuestion, PersistedQuestion, QuestionerDatabase, QuestionFilters, } from "./question.persistence.port.js";
40
+ export type { AskUserQuestionToolDeps, QuestionerToolDeps } from "./question.tools.port.js";
41
+ export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./question.schema.js";
42
+ export type { NegotiationQuestionCandidate, NegotiationQuestionProvenance, NegotiationQuestionPurpose, Question, QuestionGenerationResult, QuestionOption, QuestionPoolDiscriminator, QuestionPoolPush, QuestionPoolPushRequestReason, QuestionPoolPushRequestStatus, QuestionPoolSnapshot, QuestionPurpose, QuestionRecoverySnapshot, QuestionStrategy, QuestionVoidedReason, UnderspecificationType, } from "./question.schema.js";
@@ -1,2 +1,38 @@
1
- export { createAskUserQuestionTools, createQuestionerTools, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, isValidQuestionerInputContract, QuestionerAgent, uptakeAuthorityThreshold, } from "./application/index.js";
2
- export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./domain/index.js";
1
+ /**
2
+ * questions the capability's sole cross-capability surface.
3
+ *
4
+ * Anything outside this capability imports from here and nowhere else.
5
+ *
6
+ * ## What lives in the capability
7
+ *
8
+ * - **question.schema** — Zod schemas and derived types for the whole question
9
+ * vocabulary: the public Question shape, generator envelopes, and the
10
+ * detection/provenance/pool/recovery persistence sub-schemas.
11
+ * - **question.input** — per-mode context types, the discriminated
12
+ * QuestionerInput union, and `isValidQuestionerInputContract`, the runtime
13
+ * mirror of that discriminant enforced at queue boundaries.
14
+ * - **question.agent** — QuestionerAgent: stateless, mode-driven generation.
15
+ * - **question.presets** — system prompts and user-message builders per mode.
16
+ * - **question.env** — the QUESTIONER_* env accessors. All reads go through it.
17
+ * - **question.tools** / **question.ask.tool** — foreground adapters: the
18
+ * authenticated MCP read/answer tools, and the blocking chat
19
+ * `ask_user_question` tool.
20
+ * - **question.persistence.port** / **question.tools.port** — the injected
21
+ * host contracts (question CRUD, chat host bridge, tool host capabilities).
22
+ *
23
+ * Ambient generation (recovery, pool, uptake, inflight, push) is scheduled via
24
+ * the backend QuestionerQueue, which consumes the {@link QuestionerEnqueueFn}
25
+ * injected from the composition root.
26
+ *
27
+ * ## Boundary
28
+ *
29
+ * The capability imports from shared/ infrastructure and the negotiations
30
+ * barrel — never from runtime/, host implementations, or other capability
31
+ * internals.
32
+ */
33
+ export { QuestionerAgent } from "./question.agent.js";
34
+ export { createAskUserQuestionTools } from "./question.ask.tool.js";
35
+ export { createQuestionerTools } from "./question.tools.js";
36
+ export { INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, intentQuestionDailyCap, isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, } from "./question.env.js";
37
+ export { isValidQuestionerInputContract } from "./question.input.js";
38
+ export { NegotiationQuestionCandidateSchema, NegotiationQuestionProvenanceSchema, UnderspecificationTypeSchema, } from "./question.schema.js";
@@ -1,5 +1,5 @@
1
- import { type QuestionGenerationResult } from "../domain/question.schema.js";
2
- import { createStructuredModel } from "../../shared/agent/model.config.js";
1
+ import { type QuestionGenerationResult } from "./question.schema.js";
2
+ import { createStructuredModel } from "../shared/agent/model.config.js";
3
3
  import { type QuestionerInput } from "./question.input.js";
4
4
  export interface QuestionerAgentConfig {
5
5
  /** Optional model config override. */
@@ -8,7 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
10
  /**
11
- * questions/application/question.agent — QuestionerAgent.
11
+ * questions/question.agent — QuestionerAgent.
12
12
  *
13
13
  * Stateless, mode-driven agent that generates structured decision questions
14
14
  * from arbitrary protocol contexts.
@@ -17,16 +17,13 @@ var __metadata = (this && this.__metadata) || function (k, v) {
17
17
  * single public `invoke()` method receives the full context per call.
18
18
  * The LLM model is bound once at construction; the preset (system prompt +
19
19
  * builder) is selected per invocation based on `input.mode`.
20
- *
21
- * IND-547: canonical home — previously questioner/questioner.agent.ts.
22
- * Legacy path is a thin compatibility shim pointing here.
23
20
  */
24
21
  import { HumanMessage, SystemMessage } from "@langchain/core/messages";
25
- import { QuestionGeneratorResponseSchema } from "../domain/question.schema.js";
26
- import { createStructuredModel } from "../../shared/agent/model.config.js";
27
- import { invokeWithAbortSignal } from "../../shared/agent/model-signal.js";
28
- import { protocolLogger } from "../../shared/observability/protocol.logger.js";
29
- import { Timed } from "../../shared/observability/performance.js";
22
+ import { QuestionGeneratorResponseSchema } from "./question.schema.js";
23
+ import { createStructuredModel } from "../shared/agent/model.config.js";
24
+ import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
25
+ import { protocolLogger } from "../shared/observability/protocol.logger.js";
26
+ import { Timed } from "../shared/observability/performance.js";
30
27
  import { getPreset } from "./question.presets.js";
31
28
  import { isValidQuestionerInputContract } from "./question.input.js";
32
29
  const logger = protocolLogger("QuestionerAgent");
@@ -1,5 +1,5 @@
1
- import type { DefineTool } from "../../shared/agent/tool.helpers.js";
2
- import type { AskUserQuestionToolDeps } from "../ports/question.tools.port.js";
1
+ import type { DefineTool } from "../shared/agent/tool.helpers.js";
2
+ import type { AskUserQuestionToolDeps } from "./question.tools.port.js";
3
3
  import { QuestionerAgent } from "./question.agent.js";
4
4
  /** Test seam: replace or reset the module-level QuestionerAgent singleton. */
5
5
  export declare function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * questions/application/question.ask.tool — foreground adapter: chat ask_user_question tool.
2
+ * questions/question.ask.tool — foreground adapter: chat ask_user_question tool.
3
3
  *
4
4
  * Blocking mid-conversation questions for the chat orchestrator
5
5
  * (AskUserQuestion-style human-in-the-loop).
@@ -26,14 +26,11 @@
26
26
  * Foreground adapter: registered by `createChatTools` only when
27
27
  * `deps.chatQuestions` is provided — never part of the MCP tool registry
28
28
  * (MCP clients have their own elicitation surface).
29
- *
30
- * IND-547: canonical home — previously questioner/questioner.ask.tool.ts.
31
- * Legacy path is a thin compatibility shim pointing here.
32
29
  */
33
30
  import { z } from "zod";
34
- import { error, success } from "../../shared/agent/tool.helpers.js";
35
- import { requestContext } from "../../shared/observability/request-context.js";
36
- import { protocolLogger } from "../../shared/observability/protocol.logger.js";
31
+ import { error, success } from "../shared/agent/tool.helpers.js";
32
+ import { requestContext } from "../shared/observability/request-context.js";
33
+ import { protocolLogger } from "../shared/observability/protocol.logger.js";
37
34
  import { QuestionerAgent } from "./question.agent.js";
38
35
  import { chatQuestionWaitTimeoutMs } from "./question.env.js";
39
36
  const logger = protocolLogger("AskUserQuestionTool");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * questions/application/question.env — centralized question-generation env accessors.
2
+ * questions/question.env — centralized question-generation env accessors.
3
3
  *
4
4
  * Naming scheme (one prefix, hierarchical):
5
5
  *
@@ -18,9 +18,6 @@
18
18
  * All reads go through this module — do not read these variables via
19
19
  * `process.env` elsewhere. Values are read on every call (no caching) so tests
20
20
  * and long-lived processes observe changes.
21
- *
22
- * IND-547: canonical home — previously questioner/questioner.env.ts.
23
- * Legacy path is a thin compatibility shim pointing here.
24
21
  */
25
22
  export declare const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
26
23
  export declare const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * questions/application/question.env — centralized question-generation env accessors.
2
+ * questions/question.env — centralized question-generation env accessors.
3
3
  *
4
4
  * Naming scheme (one prefix, hierarchical):
5
5
  *
@@ -18,9 +18,6 @@
18
18
  * All reads go through this module — do not read these variables via
19
19
  * `process.env` elsewhere. Values are read on every call (no caching) so tests
20
20
  * and long-lived processes observe changes.
21
- *
22
- * IND-547: canonical home — previously questioner/questioner.env.ts.
23
- * Legacy path is a thin compatibility shim pointing here.
24
21
  */
25
22
  export const CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT = 240000;
26
23
  export const UPTAKE_AUTHORITY_THRESHOLD_DEFAULT = 70;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * questions/application/question.input — QuestionerAgent input envelope.
2
+ * questions/question.input — QuestionerAgent input envelope.
3
3
  *
4
4
  * Defines per-mode context types (IntentContext, NegotiationContext, …),
5
5
  * the discriminated QuestionerInput union, and the runtime validation guard
@@ -13,13 +13,10 @@
13
13
  * Foreground and ambient adapter entry points inject a `QuestionerEnqueueFn`
14
14
  * (defined here as a port alias) to schedule async generation without
15
15
  * importing the queue implementation.
16
- *
17
- * IND-547: canonical home — previously questioner/questioner.types.ts.
18
- * Legacy path is a thin compatibility shim pointing here.
19
16
  */
20
- import type { ToolScopeType } from "../../shared/agent/tool.scope.js";
21
- import type { NegotiationQuestionCandidate, QuestionMode, QuestionPoolDiscriminator } from "../domain/question.schema.js";
22
- import type { NegotiationConsultationReason } from "../../negotiations/index.js";
17
+ import type { ToolScopeType } from "../shared/agent/tool.scope.js";
18
+ import type { NegotiationQuestionCandidate, QuestionMode, QuestionPoolDiscriminator } from "./question.schema.js";
19
+ import type { NegotiationConsultationReason } from "../negotiations/index.js";
23
20
  /** Intent context — data needed to generate questions about an intent. */
24
21
  export interface IntentContext {
25
22
  intentId: string;
@@ -1,4 +1,4 @@
1
- import { NEGOTIATION_QUESTION_GENERIC_COUNTERPARTY, NEGOTIATION_QUESTION_GENERIC_NETWORK, NEGOTIATION_QUESTION_GENERIC_UPTAKE_ACTIVITY } from "../../negotiations/index.js";
1
+ import { NEGOTIATION_QUESTION_GENERIC_COUNTERPARTY, NEGOTIATION_QUESTION_GENERIC_NETWORK, NEGOTIATION_QUESTION_GENERIC_UPTAKE_ACTIVITY } from "../negotiations/index.js";
2
2
  /** Runtime mirror of the mode/purpose/context discriminant used at queue boundaries. */
3
3
  export function isValidQuestionerInputContract(input) {
4
4
  if (input.purpose === 'recovery') {
@@ -1,13 +1,11 @@
1
1
  /**
2
- * questions/ports/question.persistence.port — question persistence contracts.
2
+ * questions/question.persistence.port — question persistence contracts.
3
3
  *
4
4
  * Protocol-level persistence contract for structured questions generated by
5
5
  * QuestionerAgent. Implementations live in the backend and are injected into
6
6
  * ProtocolDeps.
7
- *
8
- * IND-547: canonical question persistence port.
9
7
  */
10
- import type { Question, QuestionMode, QuestionPurpose, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer, UnderspecificationType } from "../domain/question.schema.js";
8
+ import type { Question, QuestionMode, QuestionPurpose, QuestionStrategy, QuestionDetection, QuestionActor, QuestionAnswer, UnderspecificationType } from "./question.schema.js";
11
9
  /** Shape accepted by `persist()` — everything needed to insert a question row. */
12
10
  export interface PersistableQuestion {
13
11
  detection: QuestionDetection;
@@ -1,13 +1,10 @@
1
1
  /**
2
- * questions/application/question.presets — mode presets for QuestionerAgent.
2
+ * questions/question.presets — mode presets for QuestionerAgent.
3
3
  *
4
4
  * Each preset provides a system prompt and a buildPrompt function that assembles
5
5
  * the user message from a typed context object.
6
- *
7
- * IND-547: canonical home — previously questioner/questioner.presets.ts.
8
- * Legacy path is a thin compatibility shim pointing here.
9
6
  */
10
- import type { QuestionMode, QuestionPurpose } from "../domain/question.schema.js";
7
+ import type { QuestionMode, QuestionPurpose } from "./question.schema.js";
11
8
  export interface QuestionerPreset {
12
9
  /** The LLM system prompt for this mode. */
13
10
  systemPrompt: string;
@@ -1,5 +1,15 @@
1
- import { QUD_UNDERSPECIFICATION_RULES } from "./question.qud.js";
2
- import { consultationPromptFor } from "../../negotiations/index.js";
1
+ import { consultationPromptFor } from "../negotiations/index.js";
2
+ /**
3
+ * Questions Under Discussion taxonomy, appended to every preset's system prompt.
4
+ * Every mode carries it because the structured output schema requires the
5
+ * internal `underspecificationType` field; intent and discovery are the primary
6
+ * consumers of non-null classifications.
7
+ */
8
+ const QUD_UNDERSPECIFICATION_RULES = `QUD underspecification taxonomy. For every structured question, emit a required \`underspecificationType\` field. Use exactly one category only when the question repairs that kind of underspecification:
9
+ - missing_constituent: an absent core participant, entity, or outcome (who/what).
10
+ - missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).
11
+ - open_alternative_set: an unresolved choice among materially different interpretations or scopes.
12
+ Use null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: \`strategy\` describes the conversational move; \`underspecificationType\` describes the QUD defect repaired. Never infer one mechanically from the other.`;
3
13
  /**
4
14
  * Shared rule block appended to every questioner system prompt. Enforces that
5
15
  * the generated `prompt` resolves on its own — no demonstratives/anaphora that
@@ -1,14 +1,12 @@
1
1
  /**
2
- * questions/domain/question.schema — canonical home for question value types and schemas.
2
+ * questions/question.schema — canonical home for question value types and schemas.
3
3
  *
4
4
  * Defines the public structured shape consumed by frontend renderers and MCP
5
5
  * elicitation dispatch, plus internal generator, persistence, and delivery
6
6
  * envelopes used across the questions capability.
7
- *
8
- * IND-547: canonical question schema in the questions domain layer.
9
7
  */
10
8
  import { z } from "zod";
11
- import { UnderspecificationTypeSchema, type UnderspecificationType } from "../../shared/schemas/underspecification.schema.js";
9
+ import { UnderspecificationTypeSchema, type UnderspecificationType } from "../shared/schemas/underspecification.schema.js";
12
10
  export { UnderspecificationTypeSchema };
13
11
  export declare const QuestionOptionSchema: z.ZodObject<{
14
12
  /** Display text. Suffix " (Recommended)" on the safest path; list it first. */
@@ -256,24 +254,24 @@ export declare const QuestionPurposeSchema: z.ZodEnum<["uptake", "recovery", "st
256
254
  * authoritative rows before generation; callers cannot mint provenance.
257
255
  */
258
256
  export declare const NegotiationQuestionCandidateSchema: z.ZodEffects<z.ZodObject<{
259
- purpose: z.ZodEnum<["uptake", "stalled_followup", "inflight_consultation"]>;
260
- recipientUserId: z.ZodString;
261
- recipientIntentId: z.ZodString;
262
- opportunityId: z.ZodString;
263
- taskId: z.ZodOptional<z.ZodString>;
264
- networkId: z.ZodString;
257
+ readonly purpose: z.ZodEnum<["uptake", "stalled_followup", "inflight_consultation"]>;
258
+ readonly recipientUserId: z.ZodString;
259
+ readonly recipientIntentId: z.ZodString;
260
+ readonly opportunityId: z.ZodString;
261
+ readonly taskId: z.ZodOptional<z.ZodString>;
262
+ readonly networkId: z.ZodString;
265
263
  /** Uptake only: exact low-authority counterparty eligibility binding. */
266
- counterpartyUserId: z.ZodOptional<z.ZodString>;
267
- counterpartyIntentId: z.ZodOptional<z.ZodString>;
268
- counterpartyFelicityAuthority: z.ZodOptional<z.ZodNumber>;
264
+ readonly counterpartyUserId: z.ZodOptional<z.ZodString>;
265
+ readonly counterpartyIntentId: z.ZodOptional<z.ZodString>;
266
+ readonly counterpartyFelicityAuthority: z.ZodOptional<z.ZodNumber>;
269
267
  }, "strip", z.ZodTypeAny, {
270
268
  networkId: string;
271
269
  purpose: "uptake" | "stalled_followup" | "inflight_consultation";
272
270
  recipientUserId: string;
273
271
  recipientIntentId: string;
274
272
  opportunityId: string;
275
- taskId?: string | undefined;
276
273
  counterpartyUserId?: string | undefined;
274
+ taskId?: string | undefined;
277
275
  counterpartyIntentId?: string | undefined;
278
276
  counterpartyFelicityAuthority?: number | undefined;
279
277
  }, {
@@ -282,8 +280,8 @@ export declare const NegotiationQuestionCandidateSchema: z.ZodEffects<z.ZodObjec
282
280
  recipientUserId: string;
283
281
  recipientIntentId: string;
284
282
  opportunityId: string;
285
- taskId?: string | undefined;
286
283
  counterpartyUserId?: string | undefined;
284
+ taskId?: string | undefined;
287
285
  counterpartyIntentId?: string | undefined;
288
286
  counterpartyFelicityAuthority?: number | undefined;
289
287
  }>, {
@@ -292,8 +290,8 @@ export declare const NegotiationQuestionCandidateSchema: z.ZodEffects<z.ZodObjec
292
290
  recipientUserId: string;
293
291
  recipientIntentId: string;
294
292
  opportunityId: string;
295
- taskId?: string | undefined;
296
293
  counterpartyUserId?: string | undefined;
294
+ taskId?: string | undefined;
297
295
  counterpartyIntentId?: string | undefined;
298
296
  counterpartyFelicityAuthority?: number | undefined;
299
297
  }, {
@@ -302,8 +300,8 @@ export declare const NegotiationQuestionCandidateSchema: z.ZodEffects<z.ZodObjec
302
300
  recipientUserId: string;
303
301
  recipientIntentId: string;
304
302
  opportunityId: string;
305
- taskId?: string | undefined;
306
303
  counterpartyUserId?: string | undefined;
304
+ taskId?: string | undefined;
307
305
  counterpartyIntentId?: string | undefined;
308
306
  counterpartyFelicityAuthority?: number | undefined;
309
307
  }>;
@@ -312,24 +310,23 @@ export declare const NegotiationQuestionCandidateSchema: z.ZodEffects<z.ZodObjec
312
310
  * questions. This object is stripped from every REST/MCP projection.
313
311
  */
314
312
  export declare const NegotiationQuestionProvenanceSchema: z.ZodEffects<z.ZodObject<{
315
- version: z.ZodLiteral<1>;
313
+ intentFingerprint: z.ZodString;
314
+ opportunityStatus: z.ZodEnum<["latent", "draft", "negotiating", "pending", "stalled", "accepted", "rejected", "expired"]>;
315
+ opportunityUpdatedAt: z.ZodString;
316
+ taskState: z.ZodOptional<z.ZodEnum<["submitted", "working", "input_required", "completed", "canceled", "failed", "rejected", "auth_required", "waiting_for_agent", "claimed"]>>;
317
+ taskUpdatedAt: z.ZodOptional<z.ZodString>;
318
+ /** Stable per-generation position so retries dedupe without reducing cardinality. */
319
+ questionOrdinal: z.ZodNumber;
316
320
  purpose: z.ZodEnum<["uptake", "stalled_followup", "inflight_consultation"]>;
317
321
  recipientUserId: z.ZodString;
318
322
  recipientIntentId: z.ZodString;
319
323
  opportunityId: z.ZodString;
320
324
  taskId: z.ZodOptional<z.ZodString>;
321
325
  networkId: z.ZodString;
322
- intentFingerprint: z.ZodString;
323
- opportunityStatus: z.ZodEnum<["latent", "draft", "negotiating", "pending", "stalled", "accepted", "rejected", "expired"]>;
324
- opportunityUpdatedAt: z.ZodString;
325
- taskState: z.ZodOptional<z.ZodEnum<["submitted", "working", "input_required", "completed", "canceled", "failed", "rejected", "auth_required", "waiting_for_agent", "claimed"]>>;
326
- taskUpdatedAt: z.ZodOptional<z.ZodString>;
327
- /** Uptake only: exact low-authority counterparty eligibility binding. */
328
326
  counterpartyUserId: z.ZodOptional<z.ZodString>;
329
327
  counterpartyIntentId: z.ZodOptional<z.ZodString>;
330
328
  counterpartyFelicityAuthority: z.ZodOptional<z.ZodNumber>;
331
- /** Stable per-generation position so retries dedupe without reducing cardinality. */
332
- questionOrdinal: z.ZodNumber;
329
+ version: z.ZodLiteral<1>;
333
330
  }, "strip", z.ZodTypeAny, {
334
331
  networkId: string;
335
332
  purpose: "uptake" | "stalled_followup" | "inflight_consultation";
@@ -341,8 +338,8 @@ export declare const NegotiationQuestionProvenanceSchema: z.ZodEffects<z.ZodObje
341
338
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
342
339
  opportunityUpdatedAt: string;
343
340
  questionOrdinal: number;
344
- taskId?: string | undefined;
345
341
  counterpartyUserId?: string | undefined;
342
+ taskId?: string | undefined;
346
343
  counterpartyIntentId?: string | undefined;
347
344
  counterpartyFelicityAuthority?: number | undefined;
348
345
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -358,8 +355,8 @@ export declare const NegotiationQuestionProvenanceSchema: z.ZodEffects<z.ZodObje
358
355
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
359
356
  opportunityUpdatedAt: string;
360
357
  questionOrdinal: number;
361
- taskId?: string | undefined;
362
358
  counterpartyUserId?: string | undefined;
359
+ taskId?: string | undefined;
363
360
  counterpartyIntentId?: string | undefined;
364
361
  counterpartyFelicityAuthority?: number | undefined;
365
362
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -375,8 +372,8 @@ export declare const NegotiationQuestionProvenanceSchema: z.ZodEffects<z.ZodObje
375
372
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
376
373
  opportunityUpdatedAt: string;
377
374
  questionOrdinal: number;
378
- taskId?: string | undefined;
379
375
  counterpartyUserId?: string | undefined;
376
+ taskId?: string | undefined;
380
377
  counterpartyIntentId?: string | undefined;
381
378
  counterpartyFelicityAuthority?: number | undefined;
382
379
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -392,8 +389,8 @@ export declare const NegotiationQuestionProvenanceSchema: z.ZodEffects<z.ZodObje
392
389
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
393
390
  opportunityUpdatedAt: string;
394
391
  questionOrdinal: number;
395
- taskId?: string | undefined;
396
392
  counterpartyUserId?: string | undefined;
393
+ taskId?: string | undefined;
397
394
  counterpartyIntentId?: string | undefined;
398
395
  counterpartyFelicityAuthority?: number | undefined;
399
396
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -740,24 +737,23 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
740
737
  purpose: z.ZodOptional<z.ZodEnum<["uptake", "recovery", "stalled_followup", "inflight_consultation"]>>;
741
738
  /** Exact negotiation recipient/intent/task routing provenance. Internal only. */
742
739
  negotiation: z.ZodOptional<z.ZodEffects<z.ZodObject<{
743
- version: z.ZodLiteral<1>;
740
+ intentFingerprint: z.ZodString;
741
+ opportunityStatus: z.ZodEnum<["latent", "draft", "negotiating", "pending", "stalled", "accepted", "rejected", "expired"]>;
742
+ opportunityUpdatedAt: z.ZodString;
743
+ taskState: z.ZodOptional<z.ZodEnum<["submitted", "working", "input_required", "completed", "canceled", "failed", "rejected", "auth_required", "waiting_for_agent", "claimed"]>>;
744
+ taskUpdatedAt: z.ZodOptional<z.ZodString>;
745
+ /** Stable per-generation position so retries dedupe without reducing cardinality. */
746
+ questionOrdinal: z.ZodNumber;
744
747
  purpose: z.ZodEnum<["uptake", "stalled_followup", "inflight_consultation"]>;
745
748
  recipientUserId: z.ZodString;
746
749
  recipientIntentId: z.ZodString;
747
750
  opportunityId: z.ZodString;
748
751
  taskId: z.ZodOptional<z.ZodString>;
749
752
  networkId: z.ZodString;
750
- intentFingerprint: z.ZodString;
751
- opportunityStatus: z.ZodEnum<["latent", "draft", "negotiating", "pending", "stalled", "accepted", "rejected", "expired"]>;
752
- opportunityUpdatedAt: z.ZodString;
753
- taskState: z.ZodOptional<z.ZodEnum<["submitted", "working", "input_required", "completed", "canceled", "failed", "rejected", "auth_required", "waiting_for_agent", "claimed"]>>;
754
- taskUpdatedAt: z.ZodOptional<z.ZodString>;
755
- /** Uptake only: exact low-authority counterparty eligibility binding. */
756
753
  counterpartyUserId: z.ZodOptional<z.ZodString>;
757
754
  counterpartyIntentId: z.ZodOptional<z.ZodString>;
758
755
  counterpartyFelicityAuthority: z.ZodOptional<z.ZodNumber>;
759
- /** Stable per-generation position so retries dedupe without reducing cardinality. */
760
- questionOrdinal: z.ZodNumber;
756
+ version: z.ZodLiteral<1>;
761
757
  }, "strip", z.ZodTypeAny, {
762
758
  networkId: string;
763
759
  purpose: "uptake" | "stalled_followup" | "inflight_consultation";
@@ -769,8 +765,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
769
765
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
770
766
  opportunityUpdatedAt: string;
771
767
  questionOrdinal: number;
772
- taskId?: string | undefined;
773
768
  counterpartyUserId?: string | undefined;
769
+ taskId?: string | undefined;
774
770
  counterpartyIntentId?: string | undefined;
775
771
  counterpartyFelicityAuthority?: number | undefined;
776
772
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -786,8 +782,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
786
782
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
787
783
  opportunityUpdatedAt: string;
788
784
  questionOrdinal: number;
789
- taskId?: string | undefined;
790
785
  counterpartyUserId?: string | undefined;
786
+ taskId?: string | undefined;
791
787
  counterpartyIntentId?: string | undefined;
792
788
  counterpartyFelicityAuthority?: number | undefined;
793
789
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -803,8 +799,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
803
799
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
804
800
  opportunityUpdatedAt: string;
805
801
  questionOrdinal: number;
806
- taskId?: string | undefined;
807
802
  counterpartyUserId?: string | undefined;
803
+ taskId?: string | undefined;
808
804
  counterpartyIntentId?: string | undefined;
809
805
  counterpartyFelicityAuthority?: number | undefined;
810
806
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -820,8 +816,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
820
816
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
821
817
  opportunityUpdatedAt: string;
822
818
  questionOrdinal: number;
823
- taskId?: string | undefined;
824
819
  counterpartyUserId?: string | undefined;
820
+ taskId?: string | undefined;
825
821
  counterpartyIntentId?: string | undefined;
826
822
  counterpartyFelicityAuthority?: number | undefined;
827
823
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -1161,8 +1157,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
1161
1157
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
1162
1158
  opportunityUpdatedAt: string;
1163
1159
  questionOrdinal: number;
1164
- taskId?: string | undefined;
1165
1160
  counterpartyUserId?: string | undefined;
1161
+ taskId?: string | undefined;
1166
1162
  counterpartyIntentId?: string | undefined;
1167
1163
  counterpartyFelicityAuthority?: number | undefined;
1168
1164
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -1255,8 +1251,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
1255
1251
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
1256
1252
  opportunityUpdatedAt: string;
1257
1253
  questionOrdinal: number;
1258
- taskId?: string | undefined;
1259
1254
  counterpartyUserId?: string | undefined;
1255
+ taskId?: string | undefined;
1260
1256
  counterpartyIntentId?: string | undefined;
1261
1257
  counterpartyFelicityAuthority?: number | undefined;
1262
1258
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -1349,8 +1345,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
1349
1345
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
1350
1346
  opportunityUpdatedAt: string;
1351
1347
  questionOrdinal: number;
1352
- taskId?: string | undefined;
1353
1348
  counterpartyUserId?: string | undefined;
1349
+ taskId?: string | undefined;
1354
1350
  counterpartyIntentId?: string | undefined;
1355
1351
  counterpartyFelicityAuthority?: number | undefined;
1356
1352
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -1443,8 +1439,8 @@ export declare const QuestionDetectionSchema: z.ZodEffects<z.ZodObject<{
1443
1439
  opportunityStatus: "latent" | "draft" | "negotiating" | "pending" | "stalled" | "accepted" | "rejected" | "expired";
1444
1440
  opportunityUpdatedAt: string;
1445
1441
  questionOrdinal: number;
1446
- taskId?: string | undefined;
1447
1442
  counterpartyUserId?: string | undefined;
1443
+ taskId?: string | undefined;
1448
1444
  counterpartyIntentId?: string | undefined;
1449
1445
  counterpartyFelicityAuthority?: number | undefined;
1450
1446
  taskState?: "rejected" | "waiting_for_agent" | "input_required" | "completed" | "failed" | "submitted" | "working" | "canceled" | "auth_required" | "claimed" | undefined;
@@ -1,14 +1,12 @@
1
1
  /**
2
- * questions/domain/question.schema — canonical home for question value types and schemas.
2
+ * questions/question.schema — canonical home for question value types and schemas.
3
3
  *
4
4
  * Defines the public structured shape consumed by frontend renderers and MCP
5
5
  * elicitation dispatch, plus internal generator, persistence, and delivery
6
6
  * envelopes used across the questions capability.
7
- *
8
- * IND-547: canonical question schema in the questions domain layer.
9
7
  */
10
8
  import { z } from "zod";
11
- import { UnderspecificationTypeSchema } from "../../shared/schemas/underspecification.schema.js";
9
+ import { UnderspecificationTypeSchema } from "../shared/schemas/underspecification.schema.js";
12
10
  export { UnderspecificationTypeSchema };
13
11
  export const QuestionOptionSchema = z.object({
14
12
  /** Display text. Suffix " (Recommended)" on the safest path; list it first. */
@@ -71,10 +69,11 @@ export const QuestionPurposeSchema = z.enum([
71
69
  "inflight_consultation",
72
70
  ]);
73
71
  /**
74
- * Producer-supplied candidate binding. The API re-resolves every field from
75
- * authoritative rows before generation; callers cannot mint provenance.
72
+ * Routing fields every negotiation-family binding carries. The provenance
73
+ * envelope extends this with freshness and ordinal fields; the candidate is
74
+ * exactly this shape.
76
75
  */
77
- export const NegotiationQuestionCandidateSchema = z.object({
76
+ const negotiationQuestionBinding = {
78
77
  purpose: NegotiationQuestionPurposeSchema,
79
78
  recipientUserId: z.string().min(1),
80
79
  recipientIntentId: z.string().min(1),
@@ -85,7 +84,29 @@ export const NegotiationQuestionCandidateSchema = z.object({
85
84
  counterpartyUserId: z.string().min(1).optional(),
86
85
  counterpartyIntentId: z.string().min(1).optional(),
87
86
  counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),
88
- }).superRefine((candidate, ctx) => {
87
+ };
88
+ /**
89
+ * Counterparty eligibility is carried by uptake bindings and ONLY by uptake
90
+ * bindings — exactly present on uptake, entirely absent otherwise. Identical on
91
+ * the candidate and the provenance envelope, so both delegate here.
92
+ */
93
+ function refineCounterpartyEligibility(binding, ctx) {
94
+ const path = ["counterpartyUserId"];
95
+ if (binding.purpose === "uptake") {
96
+ if (!binding.counterpartyUserId || !binding.counterpartyIntentId || binding.counterpartyFelicityAuthority === undefined) {
97
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path, message: "uptake bindings require exact counterparty eligibility" });
98
+ }
99
+ return;
100
+ }
101
+ if (binding.counterpartyUserId || binding.counterpartyIntentId || binding.counterpartyFelicityAuthority !== undefined) {
102
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path, message: "only uptake bindings carry counterparty eligibility" });
103
+ }
104
+ }
105
+ /**
106
+ * Producer-supplied candidate binding. The API re-resolves every field from
107
+ * authoritative rows before generation; callers cannot mint provenance.
108
+ */
109
+ export const NegotiationQuestionCandidateSchema = z.object(negotiationQuestionBinding).superRefine((candidate, ctx) => {
89
110
  const taskRequired = candidate.purpose !== "uptake";
90
111
  if (taskRequired !== Boolean(candidate.taskId)) {
91
112
  ctx.addIssue({
@@ -96,13 +117,7 @@ export const NegotiationQuestionCandidateSchema = z.object({
96
117
  : "uptake questions must not carry a synthetic taskId",
97
118
  });
98
119
  }
99
- const hasCounterparty = Boolean(candidate.counterpartyUserId) || Boolean(candidate.counterpartyIntentId);
100
- if (candidate.purpose === "uptake" && (!candidate.counterpartyUserId || !candidate.counterpartyIntentId || candidate.counterpartyFelicityAuthority === undefined)) {
101
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["counterpartyUserId"], message: "uptake questions require exact counterparty provenance" });
102
- }
103
- if (candidate.purpose !== "uptake" && (hasCounterparty || candidate.counterpartyFelicityAuthority !== undefined)) {
104
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["counterpartyUserId"], message: "only uptake questions carry counterparty provenance" });
105
- }
120
+ refineCounterpartyEligibility(candidate, ctx);
106
121
  });
107
122
  /**
108
123
  * Durable server-only routing and freshness envelope for negotiation-family
@@ -110,21 +125,12 @@ export const NegotiationQuestionCandidateSchema = z.object({
110
125
  */
111
126
  export const NegotiationQuestionProvenanceSchema = z.object({
112
127
  version: z.literal(1),
113
- purpose: NegotiationQuestionPurposeSchema,
114
- recipientUserId: z.string().min(1),
115
- recipientIntentId: z.string().min(1),
116
- opportunityId: z.string().min(1),
117
- taskId: z.string().min(1).optional(),
118
- networkId: z.string().min(1),
128
+ ...negotiationQuestionBinding,
119
129
  intentFingerprint: z.string().min(1),
120
130
  opportunityStatus: z.enum(["latent", "draft", "negotiating", "pending", "stalled", "accepted", "rejected", "expired"]),
121
131
  opportunityUpdatedAt: z.string().datetime(),
122
132
  taskState: z.enum(["submitted", "working", "input_required", "completed", "canceled", "failed", "rejected", "auth_required", "waiting_for_agent", "claimed"]).optional(),
123
133
  taskUpdatedAt: z.string().datetime().optional(),
124
- /** Uptake only: exact low-authority counterparty eligibility binding. */
125
- counterpartyUserId: z.string().min(1).optional(),
126
- counterpartyIntentId: z.string().min(1).optional(),
127
- counterpartyFelicityAuthority: z.number().min(0).max(100).optional(),
128
134
  /** Stable per-generation position so retries dedupe without reducing cardinality. */
129
135
  questionOrdinal: z.number().int().min(0).max(2),
130
136
  }).superRefine((provenance, ctx) => {
@@ -149,13 +155,7 @@ export const NegotiationQuestionProvenanceSchema = z.object({
149
155
  if (provenance.purpose === "inflight_consultation" && provenance.taskState !== "input_required") {
150
156
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["taskState"], message: "inflight task must be input_required" });
151
157
  }
152
- const hasCounterparty = Boolean(provenance.counterpartyUserId) || Boolean(provenance.counterpartyIntentId);
153
- if (provenance.purpose === "uptake" && (!provenance.counterpartyUserId || !provenance.counterpartyIntentId || provenance.counterpartyFelicityAuthority === undefined)) {
154
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["counterpartyUserId"], message: "uptake provenance requires exact counterparty eligibility" });
155
- }
156
- if (provenance.purpose !== "uptake" && (hasCounterparty || provenance.counterpartyFelicityAuthority !== undefined)) {
157
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["counterpartyUserId"], message: "only uptake provenance carries counterparty eligibility" });
158
- }
158
+ refineCounterpartyEligibility(provenance, ctx);
159
159
  });
160
160
  export const QuestionModeSchema = z.enum([
161
161
  "intent",
@@ -1,5 +1,5 @@
1
- import type { DefineTool } from "../../shared/agent/tool.helpers.js";
2
- import type { QuestionerToolDeps } from "../ports/question.tools.port.js";
1
+ import type { DefineTool } from "../shared/agent/tool.helpers.js";
2
+ import type { QuestionerToolDeps } from "./question.tools.port.js";
3
3
  /**
4
4
  * Creates MCP tool definitions for the questioner domain.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * questions/application/question.tools — foreground adapter: MCP question tools.
2
+ * questions/question.tools — foreground adapter: MCP question tools.
3
3
  *
4
4
  * Creates MCP tool definitions for the questions domain. Exposes
5
5
  * `read_pending_questions` and `answer_pending_question` for retrieving and
@@ -9,14 +9,11 @@
9
9
  * Foreground adapter: these tools respond to authenticated user actions
10
10
  * (read, answer, dismiss). Ambient delivery adapters are handled separately
11
11
  * via the QuestionerQueue.
12
- *
13
- * IND-547: canonical home — previously questioner/questioner.tools.ts.
14
- * Legacy path is a thin compatibility shim pointing here.
15
12
  */
16
13
  import { z } from "zod";
17
- import { error, success } from "../../shared/agent/tool.helpers.js";
18
- import { focusedIntentId, focusedNetworkId, focusedNetworkLabel } from "../../shared/agent/tool.scope.js";
19
- import { callerMayAccessQuestionMode } from "../../shared/agent/activity-projection.js";
14
+ import { error, success } from "../shared/agent/tool.helpers.js";
15
+ import { focusedIntentId, focusedNetworkId, focusedNetworkLabel } from "../shared/agent/tool.scope.js";
16
+ import { callerMayAccessQuestionMode } from "../shared/agent/activity-projection.js";
20
17
  /**
21
18
  * Detection modes whose questions derive solely from the caller's own data
22
19
  * (profile gaps, own intents, own discovery sessions). Negotiation-mode
@@ -1,13 +1,11 @@
1
1
  /**
2
- * questions/ports/question.tools.port — host capabilities injected into question tools.
2
+ * questions/question.tools.port — host capabilities injected into question tools.
3
3
  *
4
4
  * Declares the narrow port types consumed by the foreground adapter tools
5
5
  * (question delivery and chat-inline ask_user_question) without importing
6
6
  * the full ToolRegistryCompositionDeps interface.
7
- *
8
- * IND-547: canonical tool-host port.
9
7
  */
10
- import type { ToolRegistryCompositionDeps } from "../../shared/agent/tool.helpers.js";
8
+ import type { ToolRegistryCompositionDeps } from "../shared/agent/tool.helpers.js";
11
9
  /** Host capabilities consumed by asynchronous question delivery tools. */
12
10
  export type QuestionerToolDeps = Pick<ToolRegistryCompositionDeps, "answerPendingQuestion" | "findPendingQuestions" | "reportToolError">;
13
11
  /** Host capabilities consumed by the blocking, chat-only question tool. */
@@ -20,11 +20,11 @@ import type { AgentDatabase } from "../../agents/ports/index.js";
20
20
  import type { NegotiationTimeoutQueue } from "../interfaces/negotiation-events.interface.js";
21
21
  import type { AgentDispatcher } from "../interfaces/agent-dispatcher.interface.js";
22
22
  import type { DeliveryLedger } from "../interfaces/delivery-ledger.interface.js";
23
- import type { ChatQuestionsHost, QuestionerDatabase } from "../../questions/ports/index.js";
23
+ import type { ChatQuestionsHost, QuestionerDatabase } from "../../questions/question.persistence.port.js";
24
24
  import type { NegotiatorMemoryToolsHost } from "../interfaces/negotiator-memory.interface.js";
25
- import type { QuestionerEnqueueFn } from "../../questions/application/question.input.js";
25
+ import type { QuestionerEnqueueFn } from "../../questions/question.input.js";
26
26
  import type { PendingQuestionSummary } from "../schemas/pending-question.schema.js";
27
- import type { QuestionMode, QuestionPurpose } from "../../questions/domain/question.schema.js";
27
+ import type { QuestionMode, QuestionPurpose } from "../../questions/question.schema.js";
28
28
  import type { EnrichmentRunQueue, EnrichmentRunStore } from "../interfaces/enrichment-run.interface.js";
29
29
  import type { McpActivityCaller } from "./activity-projection.js";
30
30
  export type IdentityContext = UserIdentity | null;
@@ -3,7 +3,7 @@
3
3
  * in tool results. Omits internal fields (actors, answer, status) that
4
4
  * are not needed by the chat agent or MCP client.
5
5
  */
6
- import type { QuestionMode, QuestionPurpose } from "../../questions/domain/question.schema.js";
6
+ import type { QuestionMode, QuestionPurpose } from "../../questions/question.schema.js";
7
7
  export interface PendingQuestionSummary {
8
8
  id: string;
9
9
  title: string;
@@ -5,7 +5,7 @@ import { z } from "zod";
5
5
  * Shared between signals (the intent clarifier decides whether an utterance is
6
6
  * underspecified) and questions (which records the category on the question it
7
7
  * raises). It lives here rather than inside either capability because both need
8
- * it: filing it under `questions/domain` meant the signals clarifier had to
8
+ * it: filing it under `questions/` meant the signals clarifier had to
9
9
  * import the whole questions capability — LLM agents and tools included — to
10
10
  * reach a three-value enum.
11
11
  */
@@ -5,7 +5,7 @@ import { z } from "zod";
5
5
  * Shared between signals (the intent clarifier decides whether an utterance is
6
6
  * underspecified) and questions (which records the category on the question it
7
7
  * raises). It lives here rather than inside either capability because both need
8
- * it: filing it under `questions/domain` meant the signals clarifier had to
8
+ * it: filing it under `questions/` meant the signals clarifier had to
9
9
  * import the whole questions capability — LLM agents and tools included — to
10
10
  * reach a three-value enum.
11
11
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/protocol",
3
- "version": "20.0.0-rc.484.1",
3
+ "version": "20.0.1-rc.485.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,39 +0,0 @@
1
- /**
2
- * questions/application — orchestrators, agents, env, tools, and presets.
3
- *
4
- * Re-exports the orchestration tier of the questions capability: the
5
- * QuestionerAgent, env accessors, generation presets, and adapter tool
6
- * factories.
7
- *
8
- * ## Foreground adapters (participant-directed, authenticated)
9
- *
10
- * - {@link createQuestionerTools} — `read_pending_questions` and
11
- * `answer_pending_question` MCP tools for authenticated answer/dismiss paths.
12
- * - {@link createAskUserQuestionTools} — blocking chat `ask_user_question`
13
- * tool for inline chat orchestrator questions.
14
- *
15
- * ## Ambient adapters (background generation)
16
- *
17
- * Recovery, pool, uptake, inflight, and push generation are scheduled via
18
- * the QuestionerQueue (backend). They consume {@link QuestionerEnqueueFn}
19
- * injected from the composition root and call QuestionerAgent.invoke() with
20
- * the appropriate mode context. The ports for these adapters are declared in
21
- * `questions/ports/question.persistence.port.ts`.
22
- *
23
- * ## Boundary
24
- *
25
- * Imports from questions/domain, questions/ports, shared/ infrastructure,
26
- * and narrow capability facades (negotiation.questions.facade) — never from
27
- * runtime/, host implementations, or other capability internals.
28
- *
29
- * IND-547: canonical application layer for the questions capability.
30
- */
31
- export { isValidQuestionerInputContract, } from "./question.input.js";
32
- export type { QuestionerInput, QuestionerContext, QuestionerEnqueuePayload, QuestionerEnqueueFn, IntentContext, RecoveryIntentContext, NegotiationContext, PostStallNegotiationContext, UptakeNegotiationContext, NegotiationInflightContext, ChatContext, PoolDiscoveryContext, PostStallQuestionerInput, InflightQuestionerInput, UptakeQuestionerInput, RecoveryQuestionerInput, } from "./question.input.js";
33
- export { QuestionerAgent } from "./question.agent.js";
34
- export type { QuestionerAgentConfig } from "./question.agent.js";
35
- export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
36
- export { getPreset } from "./question.presets.js";
37
- export type { QuestionerPreset } from "./question.presets.js";
38
- export { createQuestionerTools } from "./question.tools.js";
39
- export { createAskUserQuestionTools, setQuestionerAgentForTesting } from "./question.ask.tool.js";
@@ -1,41 +0,0 @@
1
- /**
2
- * questions/application — orchestrators, agents, env, tools, and presets.
3
- *
4
- * Re-exports the orchestration tier of the questions capability: the
5
- * QuestionerAgent, env accessors, generation presets, and adapter tool
6
- * factories.
7
- *
8
- * ## Foreground adapters (participant-directed, authenticated)
9
- *
10
- * - {@link createQuestionerTools} — `read_pending_questions` and
11
- * `answer_pending_question` MCP tools for authenticated answer/dismiss paths.
12
- * - {@link createAskUserQuestionTools} — blocking chat `ask_user_question`
13
- * tool for inline chat orchestrator questions.
14
- *
15
- * ## Ambient adapters (background generation)
16
- *
17
- * Recovery, pool, uptake, inflight, and push generation are scheduled via
18
- * the QuestionerQueue (backend). They consume {@link QuestionerEnqueueFn}
19
- * injected from the composition root and call QuestionerAgent.invoke() with
20
- * the appropriate mode context. The ports for these adapters are declared in
21
- * `questions/ports/question.persistence.port.ts`.
22
- *
23
- * ## Boundary
24
- *
25
- * Imports from questions/domain, questions/ports, shared/ infrastructure,
26
- * and narrow capability facades (negotiation.questions.facade) — never from
27
- * runtime/, host implementations, or other capability internals.
28
- *
29
- * IND-547: canonical application layer for the questions capability.
30
- */
31
- // ── Domain input types + validation ──────────────────────────────────────────
32
- export { isValidQuestionerInputContract, } from "./question.input.js";
33
- // ── Agent ─────────────────────────────────────────────────────────────────────
34
- export { QuestionerAgent } from "./question.agent.js";
35
- // ── Env ───────────────────────────────────────────────────────────────────────
36
- export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
37
- // ── Presets ───────────────────────────────────────────────────────────────────
38
- export { getPreset } from "./question.presets.js";
39
- // ── Foreground adapter tools ──────────────────────────────────────────────────
40
- export { createQuestionerTools } from "./question.tools.js";
41
- export { createAskUserQuestionTools, setQuestionerAgentForTesting } from "./question.ask.tool.js";
@@ -1,12 +0,0 @@
1
- /**
2
- * questions/application/question.qud — Questions Under Discussion taxonomy.
3
- *
4
- * Shared QUD taxonomy contract for structured question-generation prompts.
5
- * Every Questioner mode uses this block because the structured output schema
6
- * requires the internal metadata field; intent and discovery are the primary
7
- * consumers of non-null classifications.
8
- *
9
- * IND-547: canonical home — previously questioner/questioner.qud.ts.
10
- * Legacy path is a thin compatibility shim pointing here.
11
- */
12
- export declare const QUD_UNDERSPECIFICATION_RULES = "QUD underspecification taxonomy. For every structured question, emit a required `underspecificationType` field. Use exactly one category only when the question repairs that kind of underspecification:\n- missing_constituent: an absent core participant, entity, or outcome (who/what).\n- missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).\n- open_alternative_set: an unresolved choice among materially different interpretations or scopes.\nUse null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: `strategy` describes the conversational move; `underspecificationType` describes the QUD defect repaired. Never infer one mechanically from the other.";
@@ -1,16 +0,0 @@
1
- /**
2
- * questions/application/question.qud — Questions Under Discussion taxonomy.
3
- *
4
- * Shared QUD taxonomy contract for structured question-generation prompts.
5
- * Every Questioner mode uses this block because the structured output schema
6
- * requires the internal metadata field; intent and discovery are the primary
7
- * consumers of non-null classifications.
8
- *
9
- * IND-547: canonical home — previously questioner/questioner.qud.ts.
10
- * Legacy path is a thin compatibility shim pointing here.
11
- */
12
- export const QUD_UNDERSPECIFICATION_RULES = `QUD underspecification taxonomy. For every structured question, emit a required \`underspecificationType\` field. Use exactly one category only when the question repairs that kind of underspecification:
13
- - missing_constituent: an absent core participant, entity, or outcome (who/what).
14
- - missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).
15
- - open_alternative_set: an unresolved choice among materially different interpretations or scopes.
16
- Use null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: \`strategy\` describes the conversational move; \`underspecificationType\` describes the QUD defect repaired. Never infer one mechanically from the other.`;
@@ -1,24 +0,0 @@
1
- /**
2
- * questions/domain — pure question value types and schemas.
3
- *
4
- * Contains Zod schemas and TypeScript types that define the questions
5
- * capability's domain language. No LLM calls, no agents, no cross-capability
6
- * imports beyond zod.
7
- *
8
- * ## What lives here
9
- *
10
- * - **question.schema** — Question, QuestionWithStrategy, QuestionDetection,
11
- * QuestionMode, QuestionPurpose, NegotiationQuestionCandidate,
12
- * NegotiationQuestionProvenance, pool/push/recovery sub-schemas, and all
13
- * derived TypeScript types.
14
- *
15
- * ## What does NOT live here
16
- *
17
- * - QuestionerInput/QuestionerContext: they reference capability facades
18
- * (negotiation question-safety) and belong in questions/application.
19
- * - QuestionerAgent and tool factories: application layer.
20
- * - Persistence/generator ports: questions/ports.
21
- *
22
- * IND-547: canonical home for question domain types.
23
- */
24
- export * from "./question.schema.js";
@@ -1,24 +0,0 @@
1
- /**
2
- * questions/domain — pure question value types and schemas.
3
- *
4
- * Contains Zod schemas and TypeScript types that define the questions
5
- * capability's domain language. No LLM calls, no agents, no cross-capability
6
- * imports beyond zod.
7
- *
8
- * ## What lives here
9
- *
10
- * - **question.schema** — Question, QuestionWithStrategy, QuestionDetection,
11
- * QuestionMode, QuestionPurpose, NegotiationQuestionCandidate,
12
- * NegotiationQuestionProvenance, pool/push/recovery sub-schemas, and all
13
- * derived TypeScript types.
14
- *
15
- * ## What does NOT live here
16
- *
17
- * - QuestionerInput/QuestionerContext: they reference capability facades
18
- * (negotiation question-safety) and belong in questions/application.
19
- * - QuestionerAgent and tool factories: application layer.
20
- * - Persistence/generator ports: questions/ports.
21
- *
22
- * IND-547: canonical home for question domain types.
23
- */
24
- export * from "./question.schema.js";
@@ -1,27 +0,0 @@
1
- /**
2
- * questions/ports — injected dependency contracts for the questions capability.
3
- *
4
- * Re-exports the narrow port types that the questions module declares as explicit
5
- * injected boundaries. Consumers import these to wire host implementations
6
- * without depending on the application layer.
7
- *
8
- * ## Port groups
9
- *
10
- * ### Persistence ports
11
- * - QuestionerDatabase — question CRUD (persist, findPending, answer, dismiss).
12
- * - PersistableQuestion, PersistedQuestion, QuestionFilters — persistence shapes.
13
- *
14
- * ### Chat host port
15
- * - ChatQuestionsHost — blocking inline ask_user_question host bridge.
16
- * - ChatQuestionAnswerOutcome — resolution shape for awaited answers.
17
- *
18
- * ### Generator port (deprecated)
19
- *
20
- * ### Tool host ports
21
- * - QuestionerToolDeps — host capabilities for async question delivery tools.
22
- * - AskUserQuestionToolDeps — host capabilities for the chat ask_user_question tool.
23
- *
24
- * IND-547: canonical ports surface for the questions capability.
25
- */
26
- export type { PersistableQuestion, PersistedQuestion, QuestionFilters, ChatQuestionAnswerOutcome, ChatQuestionsHost, QuestionerDatabase, } from "./question.persistence.port.js";
27
- export type { QuestionerToolDeps, AskUserQuestionToolDeps } from "./question.tools.port.js";
@@ -1,26 +0,0 @@
1
- /**
2
- * questions/ports — injected dependency contracts for the questions capability.
3
- *
4
- * Re-exports the narrow port types that the questions module declares as explicit
5
- * injected boundaries. Consumers import these to wire host implementations
6
- * without depending on the application layer.
7
- *
8
- * ## Port groups
9
- *
10
- * ### Persistence ports
11
- * - QuestionerDatabase — question CRUD (persist, findPending, answer, dismiss).
12
- * - PersistableQuestion, PersistedQuestion, QuestionFilters — persistence shapes.
13
- *
14
- * ### Chat host port
15
- * - ChatQuestionsHost — blocking inline ask_user_question host bridge.
16
- * - ChatQuestionAnswerOutcome — resolution shape for awaited answers.
17
- *
18
- * ### Generator port (deprecated)
19
- *
20
- * ### Tool host ports
21
- * - QuestionerToolDeps — host capabilities for async question delivery tools.
22
- * - AskUserQuestionToolDeps — host capabilities for the chat ask_user_question tool.
23
- *
24
- * IND-547: canonical ports surface for the questions capability.
25
- */
26
- export {};