@productbrain/mcp 0.0.1-beta.6290 → 0.0.1-beta.6296

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.
@@ -17,7 +17,6 @@ import {
17
17
  kernelMutation,
18
18
  kernelQuery,
19
19
  recordSessionActivity,
20
- refreshWorkspaceGovernanceMode,
21
20
  requireActiveSession,
22
21
  requireVendorTriageAccess,
23
22
  requireWriteAccess,
@@ -42,7 +41,7 @@ import {
42
41
  trackSessionCaptureRate,
43
42
  trackWriteBackHintServed,
44
43
  trackZeroCaptureAuditFired
45
- } from "./chunk-OT4PU7IF.js";
44
+ } from "./chunk-Q2BQSINV.js";
46
45
 
47
46
  // src/server.ts
48
47
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -815,65 +814,6 @@ var ScopedCache = class {
815
814
  };
816
815
  var COLLECTION_CACHE_TTL_MS = 6e4;
817
816
 
818
- // src/tools/coherency-refusal.ts
819
- function asDescription(value) {
820
- if (typeof value !== "string") return void 0;
821
- const trimmed = value.trim();
822
- return trimmed.length > 0 ? trimmed : void 0;
823
- }
824
- var GENERIC_RECOVERY_LINE = "Respond and retry: link the entry to the strategic spine, pass `coherencyAcknowledgement`, or supply a typed `steeringOverrideReason`.";
825
- function coherencyRefusedResult(toolName, entryId, refusal, options) {
826
- const headingLevel = options?.headingLevel ?? 1;
827
- const heading = "#".repeat(headingLevel);
828
- const lines = [
829
- `${heading} Write refused by the coherency gate`,
830
- "",
831
- refusal.reason ?? `The coherency gate refused this write on ${entryId}.`
832
- ];
833
- if (refusal.subject?.name) {
834
- lines.push(`On: ${refusal.subject.name}`);
835
- }
836
- if (refusal.mode) {
837
- lines.push("", `Mode: ${refusal.mode}`);
838
- }
839
- const routes = refusal.routes;
840
- const routeKeys = routes ? Object.keys(routes) : [];
841
- if (routeKeys.length > 0) {
842
- lines.push("", `${"#".repeat(headingLevel + 1)} Recovery routes`);
843
- const beforeRoutes = lines.length;
844
- if (routes && typeof routes.link === "object" && routes.link !== null) {
845
- const link = routes.link;
846
- lines.push(`- **link:** ${asDescription(link.description) ?? "Link the entry to the strategic spine."}`);
847
- }
848
- if (routes && typeof routes.acknowledge === "object" && routes.acknowledge !== null) {
849
- const ack = routes.acknowledge;
850
- const responses = ack.responses?.join(" | ") ?? "linked | accepted-fix | diverged";
851
- lines.push(
852
- `- **acknowledge** (\`${ack.param ?? "coherencyAcknowledgement"}\`): ${responses}${ack.minReasonChars ? ` (\u2265${ack.minReasonChars} chars for diverged)` : ""}. ${asDescription(ack.description) ?? ""}`.trim()
853
- );
854
- }
855
- if (routes && typeof routes.override === "object" && routes.override !== null) {
856
- const ov = routes.override;
857
- lines.push(
858
- `- **override** (\`${ov.param ?? "steeringOverrideReason"}\`): \u2265${ov.minChars ?? 12} chars. ${asDescription(ov.description) ?? ""}`.trim()
859
- );
860
- }
861
- if (lines.length === beforeRoutes) {
862
- lines.push(GENERIC_RECOVERY_LINE);
863
- }
864
- } else {
865
- lines.push("", GENERIC_RECOVERY_LINE);
866
- }
867
- return failureResult(
868
- lines.join("\n"),
869
- "COHERENCY_REFUSED",
870
- `Coherency gate refused ${toolName} on ${entryId}.`,
871
- "Use one of the refusal's routes (link / coherencyAcknowledgement / steeringOverrideReason), then retry.",
872
- void 0,
873
- { entryId, refusal }
874
- );
875
- }
876
-
877
817
  // src/lib/resolveCollection.ts
878
818
  async function resolveCollection(params) {
879
819
  const { name, description, typeHint, allowReviewRouting } = params;
@@ -1116,10 +1056,10 @@ var batchCaptureRealOutputSchema = z4.object({
1116
1056
  entryId: z4.string(),
1117
1057
  collection: z4.string(),
1118
1058
  name: z4.string(),
1119
- // "draft_on_failure" is the status emitted when an auto-commit is REFUSED/failed (the entry
1120
- // stays a draft) — the same path that now also emits coherencyRefusal. The strict schema must
1121
- // accept it or a refused response fails to validate on `status` (codex review, completing the
1122
- // coherencyRefusal contract fix).
1059
+ // WP-751 M3a-1b (TASK-189, DEC-1700): "proposed" and "draft_on_failure" are never emitted
1060
+ // by `buildBatchEntryFailure` or the create loop anymore — both were statuses the deleted
1061
+ // client-side auto-commit attempt could produce. Left in the enum (not narrowed) since this
1062
+ // is a shared output-contract schema; narrowing it is a separate, independently-scoped change.
1123
1063
  status: z4.enum(["draft", "committed", "proposed", "draft_on_failure", "draft_spine_floor"]),
1124
1064
  spineFloor: z4.object({ relationType: z4.string(), parentKind: z4.string(), exempt: z4.boolean() }).optional(),
1125
1065
  classifiedBy: z4.enum(["llm", "heuristic", "explicit"]).optional(),
@@ -1131,14 +1071,11 @@ var batchCaptureRealOutputSchema = z4.object({
1131
1071
  rejected: z4.array(z4.string()).optional()
1132
1072
  }).optional(),
1133
1073
  // TEN-2365: capture-time authority-domain proposal slug (PENDING ratification), when filed.
1134
- domain: z4.string().optional(),
1135
- // WP-465 surface parity: structured coherency refusal for a gate-refused auto-commit (batch
1136
- // shape). Loose record — same single-source rationale as captureSuccessOutputSchema.
1137
- coherencyRefusal: z4.record(z4.unknown()).optional(),
1138
- // WP-485 Slice 2b round 4 (Codex P2, FEAT-1370): per-entry contradiction advisory, emitted
1139
- // into structuredContent but previously undeclared here. Not `.strict()` so this one was
1140
- // silently stripped rather than rejected — declared anyway so batch consumers actually see it.
1141
- contradictionAdvisory: z4.record(z4.unknown()).optional()
1074
+ domain: z4.string().optional()
1075
+ // WP-751 M3a-1b (TASK-189, DEC-1700): `coherencyRefusal` and `contradictionAdvisory` are
1076
+ // deleted — both were only ever populated by the client-side auto-commit attempt
1077
+ // (smart-capture.ts), deleted entirely. Role is the only governance mode a reader honors
1078
+ // now, and role never attempted a client-side commit.
1142
1079
  })),
1143
1080
  total: z4.number(),
1144
1081
  failed: z4.number(),
@@ -1828,7 +1765,6 @@ var captureSchema = z6.object({
1828
1765
  to: z6.string().describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
1829
1766
  type: z6.string().describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
1830
1767
  })).optional().describe("Relations to create after capture. Skips auto-link discovery when provided."),
1831
- autoCommit: z6.boolean().optional().describe("If true, commits the entry immediately after capture + linking. If omitted, Open mode workspaces auto-commit by default and consensus/role modes stay draft-first."),
1832
1768
  sourceRef: z6.string().optional().describe("URI or path of the source document backing this entry (e.g. 'meeting-2026-03-28.md', 'import://batch-5'). Stored as top-level entry field, not in data."),
1833
1769
  sourceExcerpt: z6.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data."),
1834
1770
  // WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
@@ -1863,9 +1799,6 @@ var batchCaptureSchema = z6.object({
1863
1799
  // ownerTeamEntryId deleted — team derives from the role's own placement.
1864
1800
  ownerRoleEntryId: z6.string().max(200).optional().describe("Owning role entry ID/ref (rung 2); its home team is derived automatically.")
1865
1801
  })).min(1).max(50).describe("Array of entries to capture"),
1866
- autoCommit: z6.boolean().optional().describe(
1867
- "If true, commits created entries immediately after linking. If omitted, Open mode workspaces commit by default and consensus/role modes stay draft-first."
1868
- ),
1869
1802
  // WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
1870
1803
  preview: z6.boolean().optional().describe("If true, validates all captures without writing. Returns what would happen. Default false.")
1871
1804
  });
@@ -2149,14 +2082,10 @@ var captureSuccessOutputSchema = z6.object({
2149
2082
  }).optional(),
2150
2083
  // TASK-160: the server's birth-floor verdict must survive the strict output contract.
2151
2084
  spineFloor: z6.object({ relationType: z6.string(), parentKind: z6.string(), exempt: z6.boolean() }).optional(),
2152
- // WP-465 surface parity: structured coherency refusal when an auto-commit is gate-refused.
2153
- // Loose record — the CoherencyRefusal contract is authored in
2154
- // convex/lib/gates/coherencyControls.ts; re-declaring it here would be a second SSOT.
2155
- coherencyRefusal: z6.record(z6.unknown()).optional(),
2156
- // WP-485 Slice 2b round 4 (Codex P2, FEAT-1370): the server's contradiction advisory is emitted
2157
- // into structuredContent but was missing here — since this schema is `.strict()`, a real capture
2158
- // response carrying it failed validation with `unrecognized_keys`. Loose record, same rationale as coherencyRefusal above.
2159
- contradictionAdvisory: z6.record(z6.unknown()).optional(),
2085
+ // WP-751 M3a-1b (TASK-189, DEC-1700): `coherencyRefusal` and `contradictionAdvisory` are
2086
+ // deleted — both were only ever populated by the client-side auto-commit attempt (surfacing
2087
+ // its own gate refusal, or the commit response's contradiction advisory), and that attempt is
2088
+ // deleted entirely. Neither field is set anywhere in this file anymore.
2160
2089
  fallbackApplied: z6.boolean().optional()
2161
2090
  // round 2 (PRRT_kwDORS4ils6cTNbF): classifier field above still names the original (pre-substitution) prediction
2162
2091
  }).strict();
@@ -2168,10 +2097,6 @@ var captureOutputSchema = z6.union([
2168
2097
  captureSinglePreviewOutputSchema,
2169
2098
  captureClassifierOnlyOutputSchema
2170
2099
  ]);
2171
- function shouldAutoCommitCapture(autoCommit, governanceMode) {
2172
- if (governanceMode !== "open") return false;
2173
- return autoCommit === true || autoCommit === void 0;
2174
- }
2175
2100
  function buildDataFromFields(fields, descriptionField, descriptionValue) {
2176
2101
  const data = {};
2177
2102
  for (const field of fields) {
@@ -2199,7 +2124,6 @@ var captureCompoundSchema = z6.object({
2199
2124
  to: z6.string().max(200).describe("Target entry ID (e.g. '<PREFIX>-<n>')"),
2200
2125
  type: z6.string().max(200).describe("Relation type (e.g. 'governs', 'related_to', 'informs')")
2201
2126
  })).max(20).optional().describe("For 'capture': relations to create after capture. Skips auto-link discovery when provided."),
2202
- autoCommit: z6.boolean().optional().describe("For 'capture'/'batch': if true, commits immediately after capture + linking."),
2203
2127
  sourceRef: z6.string().max(2e3).optional().describe("For 'capture': URI or path of the source document backing this entry."),
2204
2128
  sourceExcerpt: z6.string().max(5e3).optional().describe("For 'capture': verbatim excerpt from the source backing this entry's claims."),
2205
2129
  preview: z6.boolean().optional().describe("For 'capture'/'batch': if true, validates without writing."),
@@ -2215,7 +2139,6 @@ var captureSingleVariant = captureSchema.extend({ action: z6.literal("capture")
2215
2139
  var captureBatchVariant = z6.object({
2216
2140
  action: z6.literal("batch"),
2217
2141
  items: z6.array(captureItemSchema).min(1).max(50),
2218
- autoCommit: z6.boolean().optional(),
2219
2142
  preview: z6.boolean().optional()
2220
2143
  });
2221
2144
  var captureActionUnion = z6.discriminatedUnion("action", [
@@ -2224,21 +2147,21 @@ var captureActionUnion = z6.discriminatedUnion("action", [
2224
2147
  ]);
2225
2148
  var CAPTURE_ACTION_SPECS = {
2226
2149
  capture: {
2227
- params: ["collection", "name", "description", "context", "entryId", "canonicalKey", "data", "links", "autoCommit", "sourceRef", "sourceExcerpt", "preview", "suggestOnly", "format"],
2150
+ params: ["collection", "name", "description", "context", "entryId", "canonicalKey", "data", "links", "sourceRef", "sourceExcerpt", "preview", "suggestOnly", "format"],
2228
2151
  description: "name and description are required."
2229
2152
  },
2230
- batch: { params: ["items", "autoCommit", "preview"], description: "items (1-50, each may carry inline relations) is required." }
2153
+ batch: { params: ["items", "preview"], description: "items (1-50, each may carry inline relations) is required." }
2231
2154
  };
2232
2155
  function registerSmartCaptureTools(server) {
2233
2156
  const captureHandlers = {
2234
2157
  capture: (data) => handleCapture(server, data),
2235
- batch: (data) => handleBatchCapture(server, { entries: data.items, autoCommit: data.autoCommit, preview: data.preview })
2158
+ batch: (data) => handleBatchCapture(server, { entries: data.items, preview: data.preview })
2236
2159
  };
2237
2160
  server.registerTool(
2238
2161
  "capture",
2239
2162
  {
2240
2163
  title: "Capture",
2241
- description: "The tool for creating knowledge entries \u2014 single or batch. Two actions:\n\n- **capture**: Create a single entry. Creates an entry, auto-links related entries, and returns a quality scorecard \u2014 all in one call. Provide a name and description; `collection` is optional \u2014 the classifier auto-routes when omitted.\n- **batch**: Create multiple entries in one call via `items[]` (absorbs batch-capture). Each item may carry inline `relations` created right after that entry is captured.\n\n**action=capture details:**\nSupported collections with smart profiles: tensions, business-rules, glossary, decisions, features, audiences, strategy, standards, chains, insights, principles.\nAll other collections get an ENT-{random} ID and sensible defaults.\n\n**Explicit data:** When you know the schema, pass `data: { field: value }` to set fields directly. Top-level `name` and `description` always win for those fields. `data` wins over inference for all other fields.\n\n**Compound capture:** Pass `links` to create relations in the same call (skips auto-link discovery). In Open mode, entries commit by default when `autoCommit` is omitted. Pass `autoCommit: true` to promote the entry from draft to SSOT immediately after linking when you want to be explicit. Governed collections (glossary, business-rules, principles, standards, strategy, features, architecture) will warn but still commit \u2014 use only when you're certain. An objective, key result or work package is always born draft first \u2014 `autoCommit: true` has no effect on that first birth even with a complete spine; commit it explicitly afterward.\n\nEntries are created as `draft` first, then may publish immediately depending on governance and `autoCommit`. Use `entries action=update` for post-creation adjustments.",
2164
+ description: "The tool for creating knowledge entries \u2014 single or batch. Two actions:\n\n- **capture**: Create a single entry. Creates an entry, auto-links related entries, and returns a quality scorecard \u2014 all in one call. Provide a name and description; `collection` is optional \u2014 the classifier auto-routes when omitted.\n- **batch**: Create multiple entries in one call via `items[]` (absorbs batch-capture). Each item may carry inline `relations` created right after that entry is captured.\n\n**action=capture details:**\nSupported collections with smart profiles: tensions, business-rules, glossary, decisions, features, audiences, strategy, standards, chains, insights, principles.\nAll other collections get an ENT-{random} ID and sensible defaults.\n\n**Explicit data:** When you know the schema, pass `data: { field: value }` to set fields directly. Top-level `name` and `description` always win for those fields. `data` wins over inference for all other fields.\n\n**Compound capture:** Pass `links` to create relations in the same call (skips auto-link discovery). Entries are always created as `draft` \u2014 use `entries action=commit` to promote when ready.",
2242
2165
  inputSchema: captureCompoundSchema,
2243
2166
  annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
2244
2167
  },
@@ -2253,7 +2176,7 @@ function registerSmartCaptureTools(server) {
2253
2176
  })
2254
2177
  );
2255
2178
  }
2256
- async function handleCapture(server, { collection, name, description, context, entryId, canonicalKey, data: userData, links, autoCommit, sourceRef, sourceExcerpt, preview, suggestOnly, format, ownerRoleEntryId }) {
2179
+ async function handleCapture(server, { collection, name, description, context, entryId, canonicalKey, data: userData, links, sourceRef, sourceExcerpt, preview, suggestOnly, format, ownerRoleEntryId }) {
2257
2180
  requireWriteAccess();
2258
2181
  const timingStart = Date.now();
2259
2182
  const wsCtx = await getWorkspaceContext();
@@ -2403,7 +2326,6 @@ ${groundingReport.governance.map((g) => `- **${g.entryId}** ${g.name} [${g.colle
2403
2326
  canonicalKey,
2404
2327
  data: userData,
2405
2328
  links,
2406
- autoCommit,
2407
2329
  sourceRef,
2408
2330
  sourceExcerpt,
2409
2331
  ownerRoleEntryId
@@ -2553,7 +2475,6 @@ ${groundingReport.governance.map((g) => `- **${g.entryId}** ${g.name} [${g.colle
2553
2475
  canonicalKey,
2554
2476
  data: userData,
2555
2477
  links,
2556
- autoCommit,
2557
2478
  sourceRef,
2558
2479
  sourceExcerpt,
2559
2480
  ownerRoleEntryId
@@ -2632,7 +2553,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2632
2553
  const linksSuggested = [];
2633
2554
  const userLinkResults = [];
2634
2555
  const advisedLinks = [];
2635
- const conflictCandidates = groundingReport.duplicates.filter((candidate) => candidate.matchType === "possible_duplicate" && candidate.entryId !== finalEntryId).slice(0, 3).map((candidate) => ({ entryId: candidate.entryId, name: candidate.name, collection: candidate.collectionSlug }));
2636
2556
  const pendingRelations = [];
2637
2557
  const skipAutoDiscovery = links && links.length > 0;
2638
2558
  const searchQuery = extractSearchTerms(name, description);
@@ -2829,12 +2749,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2829
2749
  } catch {
2830
2750
  }
2831
2751
  }
2832
- const freshGovernanceMode = await refreshWorkspaceGovernanceMode();
2833
- const shouldAutoCommit = !spineFloor && shouldAutoCommitCapture(autoCommit, freshGovernanceMode);
2834
2752
  let finalStatus = "draft";
2835
- let commitError = null;
2836
- let commitRefusal = null;
2837
- let contradictionAdvisory = null;
2838
2753
  if (wasAutoCommittedServerSide) {
2839
2754
  finalStatus = "committed";
2840
2755
  await recordSessionActivity({ entryModified: internalId });
@@ -2844,38 +2759,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2844
2759
  commit_method: "auto",
2845
2760
  surface: "mcp_capture"
2846
2761
  });
2847
- } else if (shouldAutoCommit && finalEntryId) {
2848
- try {
2849
- const semanticConflicts = await discoverSemanticConflicts(name, description, resolvedCollection);
2850
- const commitResult = await kernelMutation("chain.commitEntry", {
2851
- entryId: finalEntryId,
2852
- author: agentId ? `agent:${agentId}` : void 0,
2853
- sessionId: agentId ?? void 0,
2854
- ...semanticConflicts.length > 0 ? { conflicts: semanticConflicts } : {}
2855
- });
2856
- const refusalReason = coherencyRefusalReason(commitResult);
2857
- if (refusalReason) {
2858
- commitError = `coherency gate refused this accept \u2014 ${refusalReason}`;
2859
- commitRefusal = commitResultField(commitResult, "refusal") ?? null;
2860
- finalStatus = "draft_on_failure";
2861
- } else {
2862
- finalStatus = commitResultField(commitResult, "status") === "proposal_created" ? "proposed" : "committed";
2863
- contradictionAdvisory = commitResultField(commitResult, "contradictionAdvisory") ?? null;
2864
- if (finalStatus === "committed") {
2865
- await recordSessionActivity({ entryModified: internalId });
2866
- trackChainEntryCommitted(wsCtx.workspaceId, {
2867
- entry_id: finalEntryId,
2868
- collection: resolvedCollection,
2869
- commit_method: "auto",
2870
- surface: "mcp_capture"
2871
- });
2872
- }
2873
- }
2874
- } catch (e) {
2875
- commitError = e instanceof Error ? e.message : "unknown error";
2876
- finalStatus = "draft_on_failure";
2877
- await recordCommitFailure({ entryId: finalEntryId, error: e, sessionId: agentId, server });
2878
- }
2879
2762
  }
2880
2763
  const lines = [
2881
2764
  `# Captured: ${finalEntryId || name}`,
@@ -2928,54 +2811,18 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2928
2811
  for (const r of userLinkResults) lines.push(`- ${r.label}`);
2929
2812
  }
2930
2813
  if (finalStatus === "committed") {
2931
- const wasAutoCommitted = autoCommit === void 0 && freshGovernanceMode === "open";
2932
2814
  lines.push("");
2933
2815
  lines.push(`## Accepted: ${finalEntryId}`);
2934
- if (wasAutoCommitted) {
2935
- lines.push(`**${name}** added to your knowledge base.`);
2936
- } else {
2937
- lines.push(`**${name}** promoted to SSOT on the Chain.`);
2938
- }
2816
+ lines.push(`**${name}** added to your knowledge base.`);
2939
2817
  if (await isGoverned(resolvedCollection)) {
2940
2818
  lines.push(`_Note: \`${resolvedCollection}\` is a governed collection \u2014 ensure this entry has been reviewed._`);
2941
2819
  }
2942
- if (contradictionAdvisory) {
2943
- lines.push("");
2944
- lines.push("## Contradiction advisory");
2945
- lines.push(contradictionAdvisory.reason);
2946
- for (const c of contradictionAdvisory.conflictDetails) {
2947
- lines.push(`- \`${c.chainEntryId}\` ${c.chainEntryName}: ${c.explanation}`);
2948
- }
2949
- }
2950
- } else if (finalStatus === "proposed") {
2951
- lines.push("");
2952
- lines.push(`## Proposal created: ${finalEntryId}`);
2953
- lines.push(`**${name}** requires consent before it can be accepted, so a proposal was created instead of accepting directly.`);
2954
- } else if (commitError) {
2955
- lines.push("");
2956
- lines.push("## Accept failed");
2957
- if (commitRefusal) {
2958
- const refusalText = coherencyRefusedResult("capture", finalEntryId, commitRefusal, { headingLevel: 3 }).content[0].text;
2959
- lines.push(...refusalText.split("\n"));
2960
- lines.push(`Entry saved as draft \u2014 use \`entries action=commit entryId="${finalEntryId}"\` to promote when ready.`);
2961
- } else {
2962
- lines.push(`Error: ${commitError}. Entry saved as draft \u2014 use \`entries action=commit entryId="${finalEntryId}"\` to promote when ready.`);
2963
- }
2964
2820
  } else if (spineFloor) {
2965
2821
  lines.push("");
2966
2822
  lines.push("## Saved as draft");
2967
2823
  lines.push(`**${name}** ${spineFloor.exempt ? SPINE_FLOOR_EXEMPT_SENTENCE : SPINE_FLOOR_SENTENCE}`);
2968
2824
  lines.push(`Next: \`entries action=commit entryId="${finalEntryId}"\`.`);
2969
2825
  }
2970
- if (shouldAutoCommit && conflictCandidates.length > 0) {
2971
- lines.push("");
2972
- lines.push("## Potential Overlaps");
2973
- lines.push(`Auto-accepted with advisory: ${conflictCandidates.length} similar ${conflictCandidates.length === 1 ? "entry" : "entries"} found.`);
2974
- for (const c of conflictCandidates) {
2975
- lines.push(`- \`${c.entryId}\`: ${c.name} [${c.collection}]`);
2976
- }
2977
- lines.push("Consider reviewing for duplicates.");
2978
- }
2979
2826
  if (linksSuggested.length > 0) {
2980
2827
  lines.push("");
2981
2828
  lines.push("## Suggested links (review and use `relations action=create`)");
@@ -3088,11 +2935,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
3088
2935
  if (hasQualityGaps) {
3089
2936
  lines.push(`2. **Improve quality:** \`entries action=update entryId="${eid}"\` \u2014 fill missing fields`);
3090
2937
  }
3091
- } else if (finalStatus === "proposed") {
3092
- lines.push(`1. **Connect it:** \`relations action=suggest entryId="${eid}"\` \u2014 discover additional links to support the proposal`);
3093
- if (hasQualityGaps) {
3094
- lines.push(`2. **Improve quality:** \`entries action=update entryId="${eid}"\` \u2014 strengthen the entry before approval`);
3095
- }
3096
2938
  } else {
3097
2939
  if (userLinkResults.length === 0) {
3098
2940
  lines.push(`1. **Connect it:** \`relations action=suggest entryId="${eid}"\` \u2014 discover what this should link to`);
@@ -3117,7 +2959,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
3117
2959
  } catch {
3118
2960
  }
3119
2961
  const next = [];
3120
- if (finalStatus === "committed" || finalStatus === "proposed") {
2962
+ if (finalStatus === "committed") {
3121
2963
  next.push({ tool: "relations", description: "Discover connections", parameters: { action: "suggest", entryId: finalEntryId } });
3122
2964
  } else {
3123
2965
  if (userLinkResults.length === 0) {
@@ -3127,7 +2969,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
3127
2969
  next.push({ tool: "entries", description: "Accept onto Chain", parameters: { action: "commit", entryId: finalEntryId } });
3128
2970
  }
3129
2971
  const qualityPhrase = verdictQualityPhrase(verdictResult);
3130
- const summary = finalStatus === "committed" ? `Captured and accepted ${finalEntryId} (${name}) onto ${resolvedCollection}. ${qualityPhrase}` : finalStatus === "proposed" ? `Captured ${finalEntryId} (${name}) in ${resolvedCollection} and created a proposal for acceptance. ${qualityPhrase}` : `Captured ${finalEntryId} (${name}) as draft in ${resolvedCollection}. ${qualityPhrase}`;
2972
+ const summary = finalStatus === "committed" ? `Captured and accepted ${finalEntryId} (${name}) onto ${resolvedCollection}. ${qualityPhrase}` : `Captured ${finalEntryId} (${name}) as draft in ${resolvedCollection}. ${qualityPhrase}`;
3131
2973
  const expectedFields = (col.fields ?? []).map((f) => ({
3132
2974
  key: f.key,
3133
2975
  type: f.type,
@@ -3161,14 +3003,6 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
3161
3003
  collection: resolvedCollection,
3162
3004
  name,
3163
3005
  status: finalStatus,
3164
- // WP-465 surface parity: thread full refusal (routes + mode) for coherency-refused auto-commits.
3165
- ...commitRefusal ? { coherencyRefusal: commitRefusal } : {},
3166
- // WP-485 Slice 2b round 3 (Codex P2, FEAT-1370): mirror the server's contradiction
3167
- // advisory into the structured payload — it was rendered in the human text (the
3168
- // "## Contradiction advisory" section above) but silently absent from
3169
- // structuredContent, so a structured-only MCP consumer saw a committed capture
3170
- // with no warning even though the text response carried one.
3171
- ...contradictionAdvisory ? { contradictionAdvisory } : {},
3172
3006
  // WP-480 S1: the server verdict rides `qualityVerdict` (named breaking
3173
3007
  // output-contract change, pre-launch).
3174
3008
  qualityVerdict: verdictResult?.verdict ? { ...verdictResult.verdict, source: verdictResult.source ?? "heuristic" } : void 0,
@@ -3203,14 +3037,12 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
3203
3037
  };
3204
3038
  return toolResult;
3205
3039
  }
3206
- async function handleBatchCapture(server, { entries, autoCommit, preview }) {
3040
+ async function handleBatchCapture(server, { entries, preview }) {
3207
3041
  requireWriteAccess();
3208
3042
  const batchTimingStart = Date.now();
3209
3043
  const agentId = getAgentSessionId();
3210
3044
  const createdBy = agentId ? `agent:${agentId}` : "capture";
3211
3045
  const wsCtx = await getWorkspaceContext();
3212
- const freshGovernanceModeForBatch = await refreshWorkspaceGovernanceMode();
3213
- const shouldAutoCommitBatch = shouldAutoCommitCapture(autoCommit, freshGovernanceModeForBatch);
3214
3046
  let autoCommitApplied = false;
3215
3047
  const needsClassification = entries.map((e, i) => ({ ...e, index: i })).filter((e) => !e.collection);
3216
3048
  let classificationMap = /* @__PURE__ */ new Map();
@@ -3465,10 +3297,7 @@ async function handleBatchCapture(server, { entries, autoCommit, preview }) {
3465
3297
  if (!preview) resolveGapsForEntry(entry.name, result2.entryId);
3466
3298
  const batchWasAutoCommittedServerSide = result2.status === "active";
3467
3299
  const batchSpineFloor = result2.spineFloor;
3468
- let finalStatus = batchWasAutoCommittedServerSide ? "committed" : batchSpineFloor ? "draft_spine_floor" : "draft";
3469
- let commitError;
3470
- let commitRefusal;
3471
- let contradictionAdvisory;
3300
+ const finalStatus = batchWasAutoCommittedServerSide ? "committed" : batchSpineFloor ? "draft_spine_floor" : "draft";
3472
3301
  if (batchWasAutoCommittedServerSide) {
3473
3302
  if (!preview) autoCommitApplied = true;
3474
3303
  await recordSessionActivity({ entryModified: internalId });
@@ -3565,40 +3394,6 @@ async function handleBatchCapture(server, { entries, autoCommit, preview }) {
3565
3394
  if (relationsProposedCount > 0) {
3566
3395
  batchEntryWarnings.push(`${relationsProposedCount} inline relation(s) converted to an agent proposal (misuse pattern) \u2014 review in Cortex UI.`);
3567
3396
  }
3568
- if (!preview && shouldAutoCommitBatch && !batchWasAutoCommittedServerSide && !batchSpineFloor) {
3569
- try {
3570
- const semanticConflicts = await discoverSemanticConflicts(entry.name, entry.description, resolvedSlug);
3571
- autoCommitApplied = true;
3572
- const commitResult = await kernelMutation("chain.commitEntry", {
3573
- entryId: finalEntryId,
3574
- author: agentId ? `agent:${agentId}` : void 0,
3575
- sessionId: agentId ?? void 0,
3576
- ...semanticConflicts.length > 0 ? { conflicts: semanticConflicts } : {}
3577
- });
3578
- const refusalReason = coherencyRefusalReason(commitResult);
3579
- if (refusalReason) {
3580
- commitError = `coherency gate refused this accept \u2014 ${refusalReason}`;
3581
- commitRefusal = commitResultField(commitResult, "refusal") ?? void 0;
3582
- finalStatus = "draft_on_failure";
3583
- } else {
3584
- finalStatus = commitResultField(commitResult, "status") === "proposal_created" ? "proposed" : "committed";
3585
- contradictionAdvisory = commitResultField(commitResult, "contradictionAdvisory") ?? void 0;
3586
- if (finalStatus === "committed") {
3587
- await recordSessionActivity({ entryModified: internalId });
3588
- trackChainEntryCommitted(wsCtx.workspaceId, {
3589
- entry_id: finalEntryId,
3590
- collection: resolvedSlug ?? void 0,
3591
- commit_method: "auto",
3592
- surface: "mcp_capture"
3593
- });
3594
- }
3595
- }
3596
- } catch (error) {
3597
- commitError = error instanceof Error ? error.message : String(error);
3598
- finalStatus = "draft_on_failure";
3599
- await recordCommitFailure({ entryId: finalEntryId, error, sessionId: agentId, server });
3600
- }
3601
- }
3602
3397
  const entryNorm = result2.normalization;
3603
3398
  results.push({
3604
3399
  entryIdx,
@@ -3620,14 +3415,8 @@ async function handleBatchCapture(server, { entries, autoCommit, preview }) {
3620
3415
  // Fix 1 (TEN-2918 follow-up): not caller-supplied — the preview projection
3621
3416
  // must not report this predicted-but-duplicable ID as concrete.
3622
3417
  ...!entry.entryId ? { entryIdAssignedAtCapture: true } : {},
3623
- ...commitError ? { commitError } : {},
3624
- // WP-465 surface parity: thread full refusal payload for coherency-refused batch entries.
3625
- ...commitRefusal ? { commitRefusal } : {},
3626
3418
  ...batchSpineFloor ? { spineFloor: batchSpineFloor } : {},
3627
3419
  // WP-745 TASK-160: read by the render below.
3628
- // WP-485 Slice 2b (R2, FEAT-1370): the server's contradiction advisory (DEC-1321 —
3629
- // advisory only, never blocking) — visible, never a silent success.
3630
- ...contradictionAdvisory ? { contradictionAdvisory } : {},
3631
3420
  ...batchEntryWarnings.length > 0 ? { warnings: batchEntryWarnings } : {},
3632
3421
  ...entryNorm && (Object.keys(entryNorm.remapped).length > 0 || entryNorm.rejected.length > 0) && {
3633
3422
  normalization: { remapped: entryNorm.remapped, rejected: entryNorm.rejected }
@@ -3672,7 +3461,7 @@ async function handleBatchCapture(server, { entries, autoCommit, preview }) {
3672
3461
  logger: "product-brain"
3673
3462
  });
3674
3463
  if (preview) {
3675
- return buildBatchPreviewFromResults(created, failed, skippedLowConfidence, entries.length, entries, autoCommit);
3464
+ return buildBatchPreviewFromResults(created, failed, skippedLowConfidence, entries.length, entries);
3676
3465
  }
3677
3466
  const totalAutoLinks = created.reduce((sum, r) => sum + r.autoLinks, 0);
3678
3467
  const totalAdvisedLinks = created.reduce((sum, r) => sum + r.advisedLinks, 0);
@@ -3738,41 +3527,20 @@ _Use \`entries action=move\` to correct any misclassified entries._`);
3738
3527
  lines.push("");
3739
3528
  lines.push("_Re-capture these with an explicit `collection` or use the suggested collection._");
3740
3529
  }
3741
- if (commitFailed.length > 0 || spineFloored.length > 0) {
3530
+ if (spineFloored.length > 0) {
3742
3531
  lines.push("");
3743
3532
  lines.push("## Saved as draft");
3744
- for (const r of [...spineFloored, ...commitFailed]) {
3745
- if (r.spineFloor) {
3746
- lines.push(`- **${r.entryId}**: ${r.name} [${r.collection}] \u2014 ${r.spineFloor.exempt ? SPINE_FLOOR_EXEMPT_SENTENCE : SPINE_FLOOR_SENTENCE} Next: \`entries action=commit entryId="${r.entryId}"\`.`);
3747
- } else if (r.commitRefusal) {
3748
- lines.push(`- **${r.entryId}**: ${r.name} [${r.collection}]`);
3749
- const refusalText = coherencyRefusedResult("batch-capture", r.entryId ?? "", r.commitRefusal, { headingLevel: 3 }).content[0].text;
3750
- lines.push(...refusalText.split("\n"));
3751
- } else {
3752
- lines.push(`- **${r.entryId}**: ${r.name} [${r.collection}] \u2014 ${r.commitError}`);
3753
- }
3533
+ for (const r of spineFloored) {
3534
+ lines.push(`- **${r.entryId}**: ${r.name} [${r.collection}] \u2014 ${r.spineFloor.exempt ? SPINE_FLOOR_EXEMPT_SENTENCE : SPINE_FLOOR_SENTENCE} Next: \`entries action=commit entryId="${r.entryId}"\`.`);
3754
3535
  }
3755
3536
  }
3756
- const entriesWithContradictionAdvisory = created.filter((r) => r.contradictionAdvisory);
3757
- if (entriesWithContradictionAdvisory.length > 0) {
3537
+ const entriesWithOverlaps = created.filter((r) => r.overlapCount && r.overlapCount > 0);
3538
+ if (entriesWithOverlaps.length > 0) {
3758
3539
  lines.push("");
3759
- lines.push("## Contradiction Advisories");
3760
- for (const r of entriesWithContradictionAdvisory) {
3761
- lines.push(`- **${r.entryId}**: ${r.name} \u2014 ${r.contradictionAdvisory.reason}`);
3762
- for (const c of r.contradictionAdvisory.conflictDetails) {
3763
- lines.push(` - \`${c.chainEntryId}\` ${c.chainEntryName}: ${c.explanation}`);
3764
- }
3765
- }
3766
- }
3767
- if (autoCommitApplied) {
3768
- const entriesWithOverlaps = created.filter((r) => r.overlapCount && r.overlapCount > 0);
3769
- if (entriesWithOverlaps.length > 0) {
3770
- lines.push("");
3771
- lines.push("## Related-entry Suggestions");
3772
- lines.push(`${entriesWithOverlaps.length} ${entriesWithOverlaps.length === 1 ? "entry has" : "entries have"} link candidates. Review their relevance before linking:`);
3773
- for (const r of entriesWithOverlaps) {
3774
- lines.push(`- **${r.entryId}**: ${r.name} \u2014 ${r.overlapCount} link ${r.overlapCount === 1 ? "candidate" : "candidates"}`);
3775
- }
3540
+ lines.push("## Related-entry Suggestions");
3541
+ lines.push(`${entriesWithOverlaps.length} ${entriesWithOverlaps.length === 1 ? "entry has" : "entries have"} link candidates. Review their relevance before linking:`);
3542
+ for (const r of entriesWithOverlaps) {
3543
+ lines.push(`- **${r.entryId}**: ${r.name} \u2014 ${r.overlapCount} link ${r.overlapCount === 1 ? "candidate" : "candidates"}`);
3776
3544
  }
3777
3545
  }
3778
3546
  const entriesWithWarnings = created.filter((r) => r.warnings && r.warnings.length > 0);
@@ -3848,20 +3616,16 @@ _Use \`entries action=move\` to correct any misclassified entries._`);
3848
3616
  ...r.confidenceTier ? { confidenceTier: r.confidenceTier } : {},
3849
3617
  ...r.warnings?.length ? { warnings: r.warnings } : {},
3850
3618
  ...r.normalization ? { normalization: r.normalization } : {},
3851
- ...r.commitError ? { commitError: r.commitError } : {},
3852
- // WP-465 surface parity: thread full refusal payload into batch structured output.
3853
- ...r.commitRefusal ? { coherencyRefusal: r.commitRefusal } : {},
3619
+ // WP-751 M3a-1b (TASK-189, DEC-1700): `commitError`, `coherencyRefusal` (from
3620
+ // `r.commitRefusal`), and `contradictionAdvisory` are deleted — all three were
3621
+ // only ever populated by the client-side auto-commit attempt, deleted entirely.
3854
3622
  ...r.spineFloor ? { spineFloor: r.spineFloor } : {},
3855
3623
  // WP-745 TASK-160: the projection a machine consumer receives; was human-render only (Copilot review, PR #901).
3856
3624
  ...r.authorityDomain ? { domain: r.authorityDomain.slug } : {},
3857
3625
  // TEN-957 (WP-484 S2): inline relations created for this entry.
3858
3626
  ...r.relationsCreated ? { relationsCreated: r.relationsCreated } : {},
3859
3627
  // Finding #14: proposal outcomes are distinct from writes — never folded in.
3860
- ...r.relationsProposed ? { relationsProposed: r.relationsProposed } : {},
3861
- // WP-485 Slice 2b round 2 (Codex P1): the server's per-entry contradiction
3862
- // advisory — was reaching `results` but dropped here, the final projection the
3863
- // caller actually receives. Visible, never a silent success.
3864
- ...r.contradictionAdvisory ? { contradictionAdvisory: r.contradictionAdvisory } : {}
3628
+ ...r.relationsProposed ? { relationsProposed: r.relationsProposed } : {}
3865
3629
  })),
3866
3630
  total: created.length,
3867
3631
  failed: failed.length,
@@ -3903,46 +3667,6 @@ _Use \`entries action=move\` to correct any misclassified entries._`);
3903
3667
  }
3904
3668
  };
3905
3669
  }
3906
- function coherencyRefusalReason(commitResult) {
3907
- if (!commitResult || typeof commitResult !== "object" || !("status" in commitResult) || commitResult.status !== "coherency_refused") {
3908
- return null;
3909
- }
3910
- const refusal = "refusal" in commitResult ? commitResult.refusal : void 0;
3911
- return refusal?.reason ?? "refused by the coherency gate";
3912
- }
3913
- function commitResultField(commitResult, field) {
3914
- if (!commitResult || typeof commitResult !== "object" || !(field in commitResult)) return void 0;
3915
- return commitResult[field];
3916
- }
3917
- async function recordCommitFailure({
3918
- entryId,
3919
- error,
3920
- sessionId,
3921
- server
3922
- }) {
3923
- const errorMessage = error instanceof Error ? error.message : String(error);
3924
- const logLine = `commitEntry failed for ${entryId}: ${errorMessage}${sessionId ? ` (session: ${sessionId})` : ""}`;
3925
- try {
3926
- await server.sendLoggingMessage({ level: "error", data: logLine, logger: "product-brain" });
3927
- } catch {
3928
- }
3929
- if (sessionId) {
3930
- try {
3931
- const tenName = `commitEntry failed for ${entryId} \u2014 ${errorMessage}`.slice(0, 250);
3932
- await kernelMutation("chain.createEntry", {
3933
- collectionSlug: "tensions",
3934
- name: tenName,
3935
- // Failure audit TENs intentionally stay draft — they need explicit human review,
3936
- // not auto-commit, even in Open mode.
3937
- status: "draft",
3938
- data: {},
3939
- createdBy: `agent:${sessionId}`,
3940
- sessionId
3941
- });
3942
- } catch {
3943
- }
3944
- }
3945
- }
3946
3670
  async function runContradictionCheck(name, description, excludeEntryId, excludeDocId) {
3947
3671
  const warnings = [];
3948
3672
  try {
@@ -3983,25 +3707,6 @@ async function runContradictionCheck(name, description, excludeEntryId, excludeD
3983
3707
  }
3984
3708
  return warnings;
3985
3709
  }
3986
- async function discoverSemanticConflicts(name, description, collectionHint) {
3987
- try {
3988
- const conflicts = await kernelQuery("chain.detectSemanticConflicts", {
3989
- name,
3990
- description,
3991
- ...collectionHint ? { collectionHint } : {}
3992
- });
3993
- return (conflicts ?? []).map((c) => ({
3994
- chainEntryId: c.chainEntryId,
3995
- chainEntryName: c.chainEntryName,
3996
- ...c.chainEntryDescription ? { chainEntryDescription: c.chainEntryDescription } : {},
3997
- type: c.type,
3998
- confidence: c.confidence,
3999
- explanation: c.explanation
4000
- }));
4001
- } catch {
4002
- return [];
4003
- }
4004
- }
4005
3710
 
4006
3711
  // src/tools/conflict-preflight.ts
4007
3712
  async function runConflictPreflight(name, description, collectionHint) {
@@ -4027,6 +3732,65 @@ async function runConflictPreflight(name, description, collectionHint) {
4027
3732
  }
4028
3733
  }
4029
3734
 
3735
+ // src/tools/coherency-refusal.ts
3736
+ function asDescription(value) {
3737
+ if (typeof value !== "string") return void 0;
3738
+ const trimmed = value.trim();
3739
+ return trimmed.length > 0 ? trimmed : void 0;
3740
+ }
3741
+ var GENERIC_RECOVERY_LINE = "Respond and retry: link the entry to the strategic spine, pass `coherencyAcknowledgement`, or supply a typed `steeringOverrideReason`.";
3742
+ function coherencyRefusedResult(toolName, entryId, refusal, options) {
3743
+ const headingLevel = options?.headingLevel ?? 1;
3744
+ const heading = "#".repeat(headingLevel);
3745
+ const lines = [
3746
+ `${heading} Write refused by the coherency gate`,
3747
+ "",
3748
+ refusal.reason ?? `The coherency gate refused this write on ${entryId}.`
3749
+ ];
3750
+ if (refusal.subject?.name) {
3751
+ lines.push(`On: ${refusal.subject.name}`);
3752
+ }
3753
+ if (refusal.mode) {
3754
+ lines.push("", `Mode: ${refusal.mode}`);
3755
+ }
3756
+ const routes = refusal.routes;
3757
+ const routeKeys = routes ? Object.keys(routes) : [];
3758
+ if (routeKeys.length > 0) {
3759
+ lines.push("", `${"#".repeat(headingLevel + 1)} Recovery routes`);
3760
+ const beforeRoutes = lines.length;
3761
+ if (routes && typeof routes.link === "object" && routes.link !== null) {
3762
+ const link = routes.link;
3763
+ lines.push(`- **link:** ${asDescription(link.description) ?? "Link the entry to the strategic spine."}`);
3764
+ }
3765
+ if (routes && typeof routes.acknowledge === "object" && routes.acknowledge !== null) {
3766
+ const ack = routes.acknowledge;
3767
+ const responses = ack.responses?.join(" | ") ?? "linked | accepted-fix | diverged";
3768
+ lines.push(
3769
+ `- **acknowledge** (\`${ack.param ?? "coherencyAcknowledgement"}\`): ${responses}${ack.minReasonChars ? ` (\u2265${ack.minReasonChars} chars for diverged)` : ""}. ${asDescription(ack.description) ?? ""}`.trim()
3770
+ );
3771
+ }
3772
+ if (routes && typeof routes.override === "object" && routes.override !== null) {
3773
+ const ov = routes.override;
3774
+ lines.push(
3775
+ `- **override** (\`${ov.param ?? "steeringOverrideReason"}\`): \u2265${ov.minChars ?? 12} chars. ${asDescription(ov.description) ?? ""}`.trim()
3776
+ );
3777
+ }
3778
+ if (lines.length === beforeRoutes) {
3779
+ lines.push(GENERIC_RECOVERY_LINE);
3780
+ }
3781
+ } else {
3782
+ lines.push("", GENERIC_RECOVERY_LINE);
3783
+ }
3784
+ return failureResult(
3785
+ lines.join("\n"),
3786
+ "COHERENCY_REFUSED",
3787
+ `Coherency gate refused ${toolName} on ${entryId}.`,
3788
+ "Use one of the refusal's routes (link / coherencyAcknowledgement / steeringOverrideReason), then retry.",
3789
+ void 0,
3790
+ { entryId, refusal }
3791
+ );
3792
+ }
3793
+
4030
3794
  // src/tools/knowledge/getHistory.ts
4031
3795
  import { z as z7 } from "zod/v3";
4032
3796
  var getHistorySchema = z7.object({
@@ -9496,7 +9260,7 @@ async function handleRecordActivation({
9496
9260
  // src/tools/orient.ts
9497
9261
  var PURPOSE_GAP_PREFIX = "purpose-gap-";
9498
9262
  var READINESS_GAPS_MAX = 50;
9499
- function formatRetrievalMissLines(verdict, domain) {
9263
+ function formatRetrievalMissLines(verdict) {
9500
9264
  const lines = [];
9501
9265
  if (verdict.served !== "ok") {
9502
9266
  if (verdict.served === "miss") {
@@ -9505,18 +9269,8 @@ function formatRetrievalMissLines(verdict, domain) {
9505
9269
  lines.push(`\xB7 weak serve (provisional, ${verdict.rubricVersion}): ${verdict.kind ?? "thin"}`);
9506
9270
  }
9507
9271
  }
9508
- if (domain?.reason) lines.push(` Reason: ${domain.reason}`);
9509
- if (domain?.nextAction) lines.push(` Next action: ${domain.nextAction}`);
9510
- if (domain?.evidenceGap) lines.push(` Evidence gap: ${domain.evidenceGap}`);
9511
9272
  return lines;
9512
9273
  }
9513
- function domainDetailFromRetrieval(retrieval) {
9514
- if (!retrieval) return null;
9515
- const reason = typeof retrieval.fallbackReason === "string" ? retrieval.fallbackReason : null;
9516
- const nextAction = typeof retrieval.fallbackAction === "string" ? retrieval.fallbackAction : null;
9517
- const evidenceGap = typeof retrieval.evidenceGap === "string" ? retrieval.evidenceGap : null;
9518
- return reason || nextAction || evidenceGap ? { reason, nextAction, evidenceGap } : null;
9519
- }
9520
9274
  async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot) {
9521
9275
  try {
9522
9276
  await kernelCall("agent.markOriented", {
@@ -9548,15 +9302,15 @@ var orientSchema = z22.object({
9548
9302
  task: z22.string().max(2e3).optional().describe(
9549
9303
  "For 'task': natural-language task description for task-scoped context. For 'start': what you're about to work on. When provided to 'task', orient returns scored, relevant entries for the task."
9550
9304
  ),
9551
- scope: z22.string().max(200).optional().describe("For 'task': optional domain scope to filter governance to entries relevant for this domain. Forwarded to Convex for workspace-specific validation."),
9552
- // WP-486 Slice 1 (FEAT-1371, TEN-2724): the startup-signal envelope resolveStartupDomain already
9553
- // consumes (startupResolver.ts:344-379) but this tool never sent — nested to match the server's StartupResolutionSignals shape, every field optional, sanitized server-side.
9305
+ // D1d (WP-754/TASK-204): nested to match the server's StartupResolutionSignals shape, every
9306
+ // field optional, sanitized server-side. Domain resolution (this envelope's original purpose)
9307
+ // is deleted; the sole surviving consumer is `context.served` activation telemetry.
9554
9308
  startupSignals: z22.object({
9555
9309
  changedPaths: z22.array(z22.string()).max(25).optional().describe("Paths changed in the current working tree, if known (e.g. from a prior git status/diff tool call)."),
9556
9310
  reviewedArtifactRefs: z22.array(z22.string()).max(25).optional().describe("Chain entry IDs the caller has already reviewed this session, if tracked."),
9557
9311
  branchName: z22.string().max(120).optional().describe("Current git branch name, if known."),
9558
9312
  worktreeName: z22.string().max(120).optional().describe("Current worktree/directory name, if known.")
9559
- }).optional().describe("For 'task': best-effort startup signals for domain resolution \u2014 changedPaths/reviewedArtifactRefs/branchName/worktreeName. All optional; omit fields you don't know."),
9313
+ }).optional().describe("For 'task': best-effort startup signals \u2014 changedPaths/reviewedArtifactRefs/branchName/worktreeName. All optional; omit fields you don't know."),
9560
9314
  invocationPath: z22.enum(["session-start", "session-close", "manual-orient", "handshake", "unknown"]).optional().describe("For 'task': how this orient was invoked. Defaults to 'manual-orient' (the direct `orient task=...` call shape) when omitted."),
9561
9315
  confirmedEntryCount: z22.number().int().min(0).optional().describe(
9562
9316
  "For 'record-activation': confirmed-entry count from the Phase 4 capture loop. The mutation enforces >=10."
@@ -9577,7 +9331,6 @@ var orientTaskVariant = z22.object({
9577
9331
  mode: z22.enum(["full", "brief"]).optional().default("full"),
9578
9332
  tier: z22.enum(["summary", "standard", "full"]).optional(),
9579
9333
  task: z22.string().max(2e3).optional(),
9580
- scope: z22.string().max(200).optional(),
9581
9334
  // WP-486 Slice 1 (FEAT-1371) — mirrors orientSchema's top-level declaration above; see its
9582
9335
  // doc comment for the shape rationale.
9583
9336
  startupSignals: z22.object({
@@ -9601,7 +9354,7 @@ var orientActionUnion = z22.discriminatedUnion("action", [
9601
9354
  ]);
9602
9355
  var ORIENT_ACTION_SPECS = {
9603
9356
  start: { params: ["task"], description: "Universal session opener; task is optional." },
9604
- task: { params: ["mode", "tier", "task", "scope"], description: "Task-grounded context loader; all params optional." },
9357
+ task: { params: ["mode", "tier", "task"], description: "Task-grounded context loader; all params optional." },
9605
9358
  "record-activation": {
9606
9359
  params: ["confirmedEntryCount", "entriesAcrossCollections", "retrievalDemoConfirmed"],
9607
9360
  description: "All three fields are required."
@@ -9633,7 +9386,6 @@ function registerOrientTool(server) {
9633
9386
  mode: data.mode,
9634
9387
  tier: data.tier,
9635
9388
  task: data.task,
9636
- scope: data.scope,
9637
9389
  startupSignals: data.startupSignals,
9638
9390
  invocationPath: data.invocationPath
9639
9391
  }),
@@ -9647,7 +9399,7 @@ function registerOrientTool(server) {
9647
9399
  "orient",
9648
9400
  {
9649
9401
  title: "Orient",
9650
- description: "Workspace orientation and session bootstrapping. Three actions:\n\n- **start**: Universal opener (absorbs `start_pb`) \u2014 say 'Start PB' to begin every session. Stage-aware: fresh workspaces (blank/seeded) get the SKILL-pb-setup body verbatim; active workspaces (grounded/connected) get a standup briefing. Orients the CURRENT session \u2014 it does not create one; for writes, call `session action=start` first.\n- **task**: Task-grounded context loader (the original `orient` behavior). Use after `action=start` to load governance and context for a specific task. Completing orientation unlocks write tools.\n- **record-activation**: Chat-only activation receipt writer (absorbs `record_activation`) \u2014 closes the install-to-activation arc for chat-only surfaces.\n\n**tier** (action=task): Controls payload depth.\n- `summary` (~10 KB) \u2014 compact, calibrated for task-scoped retrieval.\n- `standard` (~256 KB) \u2014 rich, suited to workspace standups.\n- `full` \u2014 complete payload, no cap. Use with deliberation.\n\nThe spine (vision, purpose, strategy highlights) is served in full and a grounding status flags when context was reduced.\n\nDefaults: `summary` when `task` is provided; `standard` when `task` is absent. Explicit `tier` always wins.\n\n**mode** (action=task): `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally.\n\n**scope** (action=task): Optional domain scope filtering governance to entries relevant for the specified domain.",
9402
+ description: "Workspace orientation and session bootstrapping. Three actions:\n\n- **start**: Universal opener (absorbs `start_pb`) \u2014 say 'Start PB' to begin every session. Stage-aware: fresh workspaces (blank/seeded) get the SKILL-pb-setup body verbatim; active workspaces (grounded/connected) get a standup briefing. Orients the CURRENT session \u2014 it does not create one; for writes, call `session action=start` first.\n- **task**: Task-grounded context loader (the original `orient` behavior). Use after `action=start` to load governance and context for a specific task. Completing orientation unlocks write tools.\n- **record-activation**: Chat-only activation receipt writer (absorbs `record_activation`) \u2014 closes the install-to-activation arc for chat-only surfaces.\n\n**tier** (action=task): Controls payload depth.\n- `summary` (~10 KB) \u2014 compact, calibrated for task-scoped retrieval.\n- `standard` (~256 KB) \u2014 rich, suited to workspace standups.\n- `full` \u2014 complete payload, no cap. Use with deliberation.\n\nThe spine (vision, purpose, strategy highlights) is served in full and a grounding status flags when context was reduced.\n\nDefaults: `summary` when `task` is provided; `standard` when `task` is absent. Explicit `tier` always wins.\n\n**mode** (action=task): `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally.",
9651
9403
  inputSchema: orientSchema,
9652
9404
  // Mixed read/write noun (§3 R3): 'start'/'record-activation' write session state.
9653
9405
  annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false }
@@ -9663,12 +9415,9 @@ function registerOrientTool(server) {
9663
9415
  })
9664
9416
  );
9665
9417
  }
9666
- async function _handleOrient({ mode = "full", tier, task, scope, startupSignals, invocationPath }) {
9418
+ async function _handleOrient({ mode = "full", tier, task, startupSignals, invocationPath }) {
9667
9419
  const errors = [];
9668
9420
  const callTier = tier ?? (mode === "brief" ? "summary" : void 0);
9669
- if (scope && !task) {
9670
- errors.push("--scope requires --task to filter governance. Scope was ignored.");
9671
- }
9672
9421
  const agentSessionId = getAgentSessionId();
9673
9422
  if (isSessionOriented() && mode === "brief" && !task) {
9674
9423
  return buildAlreadyOrientedResult(kernelQuery, agentSessionId, taskGroundingWarningLines());
@@ -9686,7 +9435,6 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9686
9435
  try {
9687
9436
  const orientArgs = {};
9688
9437
  if (task) orientArgs.task = task;
9689
- if (scope) orientArgs.scope = scope;
9690
9438
  if (startupSignals && Object.keys(startupSignals).length > 0) orientArgs.startupSignals = startupSignals;
9691
9439
  if (invocationPath) {
9692
9440
  orientArgs.invocationPath = invocationPath;
@@ -9787,10 +9535,7 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9787
9535
  }
9788
9536
  lines.push("");
9789
9537
  lines.push(...taskGroundingWarningLines(task, hasTaskGrounding));
9790
- const retrievalMissLines = orientView?.retrievalMiss ? formatRetrievalMissLines(
9791
- orientView.retrievalMiss,
9792
- domainDetailFromRetrieval(orientView.startup?.domainRetrieval)
9793
- ) : [];
9538
+ const retrievalMissLines = orientView?.retrievalMiss ? formatRetrievalMissLines(orientView.retrievalMiss) : [];
9794
9539
  if (retrievalMissLines.length > 0) {
9795
9540
  lines.push(...retrievalMissLines);
9796
9541
  lines.push("");
@@ -9822,15 +9567,6 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
9822
9567
  const degradedLineBrief = buildDegradedPreloadsLine(orientView?.degradedPreloads);
9823
9568
  if (degradedLineBrief) lines.push(degradedLineBrief);
9824
9569
  lines.push(...buildRitualsSurfaceLines(orientView, { fetchFailed: orientFetchFailed || orientView?.fetchFailed === true }));
9825
- if (orientView?.startup?.domainRetrieval) {
9826
- const retrieval = orientView.startup.domainRetrieval;
9827
- const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
9828
- lines.push(`Domain retrieval: ${retrieval.state}${scopedTo}`);
9829
- if (retrieval.activeSource) lines.push(`Active source: ${retrieval.activeSource}`);
9830
- if (retrieval.directRatifiedCount != null || retrieval.inheritedRatifiedCount != null || retrieval.orgFallbackCount != null) {
9831
- lines.push(`Domain relation evidence: ${retrieval.directRatifiedCount ?? 0} direct, ${retrieval.inheritedRatifiedCount ?? 0} inherited, ${retrieval.orgFallbackCount ?? 0} org fallback`);
9832
- }
9833
- }
9834
9570
  if (orientView?.writeBackHints && orientView.writeBackHints.length > 0) {
9835
9571
  lines.push("");
9836
9572
  lines.push("Write-back hints (what to capture this session):");
@@ -10086,13 +9822,6 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
10086
9822
  lines.push(`> \u26A0\uFE0F ${tc.groundingNote}`);
10087
9823
  lines.push("");
10088
9824
  }
10089
- if (orientView.startup?.domainRetrieval) {
10090
- const retrieval = orientView.startup.domainRetrieval;
10091
- const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
10092
- lines.push(`_Domain retrieval: ${retrieval.state}${scopedTo}_`);
10093
- if (retrieval.activeSource) lines.push(`_Active source: ${retrieval.activeSource}_`);
10094
- lines.push("");
10095
- }
10096
9825
  lines.push(`_Task-scoped entries (${tc.confidence} confidence, ${tc.totalFound} relevant)`);
10097
9826
  lines.push("");
10098
9827
  for (const e of tc.context) {
@@ -10390,7 +10119,6 @@ async function _handleOrient({ mode = "full", tier, task, scope, startupSignals,
10390
10119
  // PR #539 review fix
10391
10120
  // RCRT miss-alarm: machine-readable verdict, parity with the rendered prose alarm.
10392
10121
  ...orientView?.retrievalMiss ? { retrievalMiss: orientView.retrievalMiss } : {},
10393
- domainRetrieval: orientView?.startup?.domainRetrieval,
10394
10122
  orientationStatus,
10395
10123
  nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
10396
10124
  ...orientView?._budget ? { _budget: orientView._budget } : {},
@@ -16956,4 +16684,4 @@ export {
16956
16684
  createProductBrainServer,
16957
16685
  initFeatureFlags
16958
16686
  };
16959
- //# sourceMappingURL=chunk-MHKTOGAX.js.map
16687
+ //# sourceMappingURL=chunk-COH7GAUD.js.map