@productbrain/mcp 0.0.1-beta.6286 → 0.0.1-beta.6294
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.
- package/dist/{chunk-XJRVTFDC.js → chunk-73WYXKBT.js} +100 -336
- package/dist/chunk-73WYXKBT.js.map +1 -0
- package/dist/{chunk-OT4PU7IF.js → chunk-Q2BQSINV.js} +1 -9
- package/dist/{chunk-OT4PU7IF.js.map → chunk-Q2BQSINV.js.map} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{setup-KW27NKXI.js → setup-3C2GB2G6.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-XJRVTFDC.js.map +0 -1
- /package/dist/{setup-KW27NKXI.js.map → setup-3C2GB2G6.js.map} +0 -0
|
@@ -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-
|
|
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
|
-
//
|
|
1120
|
-
//
|
|
1121
|
-
//
|
|
1122
|
-
//
|
|
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-
|
|
1136
|
-
//
|
|
1137
|
-
|
|
1138
|
-
//
|
|
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-
|
|
2153
|
-
//
|
|
2154
|
-
//
|
|
2155
|
-
|
|
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", "
|
|
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", "
|
|
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,
|
|
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).
|
|
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,
|
|
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
|
-
|
|
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"
|
|
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}` :
|
|
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,
|
|
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
|
-
|
|
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
|
|
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 (
|
|
3530
|
+
if (spineFloored.length > 0) {
|
|
3742
3531
|
lines.push("");
|
|
3743
3532
|
lines.push("## Saved as draft");
|
|
3744
|
-
for (const r of
|
|
3745
|
-
|
|
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
|
|
3757
|
-
if (
|
|
3537
|
+
const entriesWithOverlaps = created.filter((r) => r.overlapCount && r.overlapCount > 0);
|
|
3538
|
+
if (entriesWithOverlaps.length > 0) {
|
|
3758
3539
|
lines.push("");
|
|
3759
|
-
lines.push("##
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
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
|
-
|
|
3852
|
-
//
|
|
3853
|
-
|
|
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({
|
|
@@ -15635,7 +15399,7 @@ async function handleQuestionCreate(text, domain, blocks) {
|
|
|
15635
15399
|
requireWriteAccess();
|
|
15636
15400
|
try {
|
|
15637
15401
|
const resolvedBlocks = blocks ? await Promise.all(blocks.map((b) => resolveEntryRef(b, "Blocked entry"))) : void 0;
|
|
15638
|
-
const result2 = await kernelMutation("question.create", { text, domainSlug: domain, blocks: resolvedBlocks });
|
|
15402
|
+
const result2 = await kernelMutation("question.create", { text, domainSlug: domain, blocks: resolvedBlocks, sessionId: getAgentSessionId() ?? void 0 });
|
|
15639
15403
|
const message = await renderCreateAdoptConfirmation(result2, false);
|
|
15640
15404
|
const next = result2.status === "unrouted" ? [{ tool: "question", description: "Confirm or reassign the suggestion", parameters: { action: "assign", entryId: result2.entryId } }] : void 0;
|
|
15641
15405
|
return successResult(message, message, result2, next);
|
|
@@ -15648,7 +15412,7 @@ async function handleQuestionAdopt(entryId, domain, blocks) {
|
|
|
15648
15412
|
try {
|
|
15649
15413
|
const resolvedEntryId = await resolveEntryRef(entryId, "Entry");
|
|
15650
15414
|
const resolvedBlocks = blocks ? await Promise.all(blocks.map((b) => resolveEntryRef(b, "Blocked entry"))) : void 0;
|
|
15651
|
-
const result2 = await kernelMutation("question.adopt", { entryId: resolvedEntryId, domainSlug: domain, blocks: resolvedBlocks });
|
|
15415
|
+
const result2 = await kernelMutation("question.adopt", { entryId: resolvedEntryId, domainSlug: domain, blocks: resolvedBlocks, sessionId: getAgentSessionId() ?? void 0 });
|
|
15652
15416
|
const message = await renderCreateAdoptConfirmation(result2, true);
|
|
15653
15417
|
return successResult(message, message, result2);
|
|
15654
15418
|
} catch (err) {
|
|
@@ -16956,4 +16720,4 @@ export {
|
|
|
16956
16720
|
createProductBrainServer,
|
|
16957
16721
|
initFeatureFlags
|
|
16958
16722
|
};
|
|
16959
|
-
//# sourceMappingURL=chunk-
|
|
16723
|
+
//# sourceMappingURL=chunk-73WYXKBT.js.map
|