@productbrain/mcp 0.0.1-beta.11155 → 0.0.1-beta.11161

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.
@@ -2363,6 +2363,8 @@ var updateEntrySchema = z6.object({
2363
2363
  sourceExcerpt: z6.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Write-once: can only be set if currently empty."),
2364
2364
  // WP-465 slice ⑤ — relay-only (TEN-2233): validation/min-length/recording live in Convex.
2365
2365
  steeringOverrideReason: z6.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block on a misaligned governance write \u2014 always recorded with author attribution."),
2366
+ qualityOverrideReason: z6.string().optional().describe("Why (\u226512 chars) to keep an accepted spine text its quality checklist failed \u2014 recorded as an override with who wrote it."),
2367
+ // TASK-954
2366
2368
  coherencyAcknowledgement: z6.object({
2367
2369
  response: z6.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
2368
2370
  entryId: z6.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
@@ -2375,24 +2377,22 @@ var commitEntrySchema = z6.object({
2375
2377
  preview: z6.boolean().optional().describe("If true, validates the accept without writing. Returns what would happen. Default false."),
2376
2378
  // WP-465 slice ⑤ — relay-only (TEN-2233): validation/recording live in Convex.
2377
2379
  steeringOverrideReason: z6.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block at the publish chokepoint \u2014 always recorded with author attribution."),
2380
+ qualityOverrideReason: z6.string().optional().describe("Why (\u226512 chars) to accept over a failing quality checklist \u2014 recorded as an override with who wrote it."),
2381
+ // TASK-954
2378
2382
  coherencyAcknowledgement: z6.object({
2379
2383
  response: z6.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
2380
2384
  entryId: z6.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
2381
2385
  reason: z6.string().optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
2382
2386
  }).optional().describe("Explicit response to a coherency challenge (standard/strict workspace modes).")
2383
2387
  });
2384
- async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, changeReason, sourceRef, sourceExcerpt, steeringOverrideReason, coherencyAcknowledgement }, toolName = "entries") {
2388
+ async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, changeReason, sourceRef, sourceExcerpt, steeringOverrideReason, qualityOverrideReason, coherencyAcknowledgement }, toolName = "entries") {
2385
2389
  requireWriteAccess();
2386
2390
  const fieldsProvided = [];
2387
- if (name !== void 0) fieldsProvided.push("name");
2388
- if (rawStatus !== void 0) fieldsProvided.push("status");
2389
- if (rawWorkflowStatus !== void 0) fieldsProvided.push("workflowStatus");
2390
- if (data !== void 0) fieldsProvided.push("data");
2391
- if (order !== void 0) fieldsProvided.push("order");
2391
+ for (const [k, v] of [["name", name], ["status", rawStatus], ["workflowStatus", rawWorkflowStatus], ["data", data], ["order", order]]) if (v !== void 0) fieldsProvided.push(k);
2392
2392
  for (const [k, v] of [["canonicalKey", canonicalKey], ["sourceRef", sourceRef], ["sourceExcerpt", sourceExcerpt]]) if (v !== void 0) fieldsProvided.push(k);
2393
2393
  const status2 = rawStatus;
2394
2394
  const workflowStatus = rawWorkflowStatus;
2395
- const updateResult = await kernelMutation("chain.updateEntry", {
2395
+ const send = () => kernelMutation("chain.updateEntry", {
2396
2396
  entryId,
2397
2397
  name,
2398
2398
  status: status2,
@@ -2407,16 +2407,31 @@ async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowSta
2407
2407
  ...sourceRef !== void 0 ? { sourceRef } : {},
2408
2408
  ...sourceExcerpt !== void 0 ? { sourceExcerpt } : {},
2409
2409
  ...steeringOverrideReason ? { steeringOverrideReason } : {},
2410
+ ...qualityOverrideReason ? { qualityOverrideReason } : {},
2410
2411
  ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {}
2411
2412
  });
2413
+ let updateResult = await send();
2414
+ const held = updateResult.refusal;
2415
+ if (held?.code === "QUALITY_HELD" && held.state === "judging") {
2416
+ await settleVerdictBeforeAccept(async () => ({ judgeInFlight: true }), async () => {
2417
+ const read = await kernelQuery("quality.getLatestVerdictForEntry", { entryId, textHash: held.textHash });
2418
+ return read?.verdict && !read.stale ? read : { verdict: { llmStatus: "pending" } };
2419
+ });
2420
+ updateResult = await send();
2421
+ }
2412
2422
  const maybeRefused = updateResult;
2413
2423
  if (maybeRefused.outcome === "refused" && maybeRefused.refusal) {
2424
+ const mcp = maybeRefused.refusal.mcp;
2425
+ if (mcp) return failureResult(`# ${entryId} not saved
2426
+
2427
+ ${mcp}`, "QUALITY_HELD", mcp.split("\n")[0] ?? mcp, mcp.split("\n")[1] ?? mcp, void 0, { entryId, refusal: maybeRefused.refusal });
2414
2428
  return updateRefusedResult(toolName, entryId, maybeRefused.refusal);
2415
2429
  }
2416
- const id = updateResult.id;
2430
+ const applied = updateResult;
2431
+ const id = applied.id;
2417
2432
  const fieldArgs = { name, status: rawStatus, workflowStatus: rawWorkflowStatus, order, canonicalKey, sourceRef, sourceExcerpt };
2418
- const revertedByServer = updateResult.revertedFields ?? [];
2419
- const { appliedFields, rejectedDataFields, revertedFields } = computeUpdateEntryAppliedFields(fieldArgs, updateResult.normalization, updateResult.provenanceApplied, revertedByServer);
2433
+ const revertedByServer = applied.revertedFields ?? [];
2434
+ const { appliedFields, rejectedDataFields, revertedFields } = computeUpdateEntryAppliedFields(fieldArgs, applied.normalization, applied.provenanceApplied, revertedByServer);
2420
2435
  const totalFailure = buildFieldsRejectedFailure(entryId, fieldsProvided, appliedFields, rejectedDataFields, revertedFields);
2421
2436
  if (totalFailure) return totalFailure;
2422
2437
  await recordSessionActivity({ entryModified: id });
@@ -2427,29 +2442,28 @@ async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowSta
2427
2442
  const responseLines = [
2428
2443
  `# Entry Updated`,
2429
2444
  ``,
2430
- updateResult.receipt ?? `**${entryId}** \u2014 ${versionMode}.`,
2445
+ applied.receipt ?? `**${entryId}** \u2014 ${versionMode}.`,
2431
2446
  // TASK-773: a draft team's discard names the drafts it took
2432
- ...updateResult.restsOnCount !== void 0 ? [restsOnCountLine(updateResult.restsOnCount, updateResult.restsOnBounded === true)] : [],
2447
+ ...applied.qualityOverride ? [applied.qualityOverride] : [],
2448
+ // TASK-954: the recorded line, never a silent clear
2449
+ ...applied.restsOnCount !== void 0 ? [restsOnCountLine(applied.restsOnCount, applied.restsOnBounded === true)] : [],
2433
2450
  ``,
2434
2451
  // TASK-935
2435
2452
  `Internal ID: ${id}`,
2436
2453
  `**Workspace:** ${wsCtx.workspaceSlug} (${wsCtx.workspaceId})`
2437
2454
  ];
2438
2455
  pushAppliedFieldsLines(responseLines, fieldsProvided, appliedFields, rejectedDataFields, revertedFields);
2439
- const warnings = updateResult.normalizationWarnings ?? [];
2456
+ const warnings = applied.normalizationWarnings ?? [];
2440
2457
  if (warnings.length > 0) {
2441
2458
  responseLines.push("");
2442
2459
  responseLines.push("\u26A0\uFE0F **Normalization warnings:**");
2443
2460
  for (const warning of warnings) responseLines.push(` - ${warning}`);
2444
2461
  }
2445
- if ((updateResult.validationWarnings ?? []).length > 0) {
2446
- responseLines.push("");
2447
- responseLines.push("\u26A0\uFE0F **Validation warnings:**");
2448
- for (const warning of updateResult.validationWarnings ?? []) {
2449
- responseLines.push(` - ${warning}`);
2450
- }
2462
+ if ((applied.validationWarnings ?? []).length > 0) {
2463
+ responseLines.push("", "\u26A0\uFE0F **Validation warnings:**");
2464
+ for (const warning of applied.validationWarnings ?? []) responseLines.push(` - ${warning}`);
2451
2465
  }
2452
- const summary = updateResult.receipt ?? `Updated ${entryId} \u2014 ${versionMode}. Fields: ${appliedFields.join(", ") || "none"}.`;
2466
+ const summary = [applied.receipt ?? `Updated ${entryId} \u2014 ${versionMode}. Fields: ${appliedFields.join(", ") || "none"}.`, applied.qualityOverride].filter(Boolean).join(" ");
2453
2467
  const next = [
2454
2468
  { tool: "context", description: "View updated entry", parameters: { action: "get", entryId } },
2455
2469
  // DEC-1894: reads live on context
@@ -2463,26 +2477,26 @@ async function handleUpdateEntry({ entryId, name, status: rawStatus, workflowSta
2463
2477
  fieldsApplied: appliedFields,
2464
2478
  // PR B: renamed from fieldsProvided (caller intent) — this is the server's verdict, matching the text above
2465
2479
  // BET-192: normalization breakdown in structuredContent — symmetric with capture tool
2466
- ...updateResult.normalization && (Object.keys(updateResult.normalization.remapped).length > 0 || updateResult.normalization.rejected.length > 0) && {
2480
+ ...applied.normalization && (Object.keys(applied.normalization.remapped).length > 0 || applied.normalization.rejected.length > 0) && {
2467
2481
  normalization: {
2468
- remapped: updateResult.normalization.remapped,
2469
- rejected: updateResult.normalization.rejected
2482
+ remapped: applied.normalization.remapped,
2483
+ rejected: applied.normalization.rejected
2470
2484
  }
2471
2485
  },
2472
- ...(updateResult.normalizationWarnings ?? []).length > 0 && {
2473
- normalizationWarnings: updateResult.normalizationWarnings
2486
+ ...(applied.normalizationWarnings ?? []).length > 0 && {
2487
+ normalizationWarnings: applied.normalizationWarnings
2474
2488
  },
2475
- ...(updateResult.validationWarnings ?? []).length > 0 && {
2476
- validationWarnings: updateResult.validationWarnings
2489
+ ...(applied.validationWarnings ?? []).length > 0 && {
2490
+ validationWarnings: applied.validationWarnings
2477
2491
  },
2478
2492
  ...revertedFields.length > 0 && { revertedFields },
2479
2493
  // #1026 R2: symmetric with the text above
2480
- ...updateResult.restsOnCount !== void 0 ? { restsOnCount: updateResult.restsOnCount, restsOnBounded: updateResult.restsOnBounded } : {}
2494
+ ...applied.restsOnCount !== void 0 ? { restsOnCount: applied.restsOnCount, restsOnBounded: applied.restsOnBounded } : {}
2481
2495
  // TASK-935
2482
2496
  }, next)
2483
2497
  };
2484
2498
  }
2485
- async function handleCommitEntry({ entryId, preview, steeringOverrideReason, coherencyAcknowledgement }, toolName = "entries") {
2499
+ async function handleCommitEntry({ entryId, preview, steeringOverrideReason, qualityOverrideReason, coherencyAcknowledgement }, toolName = "entries") {
2486
2500
  requireWriteAccess();
2487
2501
  const entry = await kernelQuery("chain.getEntry", { entryId });
2488
2502
  if (!entry) {
@@ -2524,6 +2538,8 @@ async function handleCommitEntry({ entryId, preview, steeringOverrideReason, coh
2524
2538
  sessionId: getAgentSessionId() ?? void 0,
2525
2539
  ...preview ? { preview: true } : {},
2526
2540
  ...steeringOverrideReason ? { steeringOverrideReason } : {},
2541
+ ...qualityOverrideReason ? { qualityOverrideReason } : {},
2542
+ // TASK-954
2527
2543
  ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {},
2528
2544
  ...conflictEvidence.length > 0 ? { conflicts: conflictEvidence } : {}
2529
2545
  });
@@ -3268,6 +3284,9 @@ var entriesSchema = z10.object({
3268
3284
  steeringOverrideReason: z10.string().max(2e3).optional().describe(
3269
3285
  "For 'update'/'commit': typed override (\u226512 chars) that clears a steering coherency block."
3270
3286
  ),
3287
+ qualityOverrideReason: z10.string().max(2e3).optional().describe(
3288
+ "For 'update'/'commit': why (\u226512 chars) to keep a spine text its quality checklist failed; recorded as an override with who wrote it."
3289
+ ),
3271
3290
  coherencyAcknowledgement: coherencyAcknowledgementFlatSchema.optional().describe(
3272
3291
  "For 'update'/'commit': explicit response to a coherency challenge (standard/strict workspace modes)."
3273
3292
  ),
@@ -3297,8 +3316,8 @@ var entriesActionUnion = z10.discriminatedUnion("action", [
3297
3316
  ]);
3298
3317
  var ENTRIES_ACTION_SPECS = {
3299
3318
  preflight: { params: ["collection", "canonicalKey", "links"], description: "Inspect structure before composition; no writes or permission grant." },
3300
- update: { params: ["entryId", "name", "status", "workflowStatus", "data", "order", "canonicalKey", "autoPublish", "changeNote", "changeReason", "sourceRef", "sourceExcerpt", "steeringOverrideReason", "coherencyAcknowledgement"], description: "entryId is required; every other field is optional." },
3301
- commit: { params: ["entryId", "preview", "steeringOverrideReason", "coherencyAcknowledgement"], description: "entryId is required." },
3319
+ update: { params: ["entryId", "name", "status", "workflowStatus", "data", "order", "canonicalKey", "autoPublish", "changeNote", "changeReason", "sourceRef", "sourceExcerpt", "steeringOverrideReason", "qualityOverrideReason", "coherencyAcknowledgement"], description: "entryId is required; every other field is optional." },
3320
+ commit: { params: ["entryId", "preview", "steeringOverrideReason", "qualityOverrideReason", "coherencyAcknowledgement"], description: "entryId is required." },
3302
3321
  move: { params: ["entryId", "toCollection", "canonicalKey"], description: "entryId and toCollection are required; canonicalKey is optional (atomic move+retype)." },
3303
3322
  verify: { params: ["entryId"], description: "entryId is required." },
3304
3323
  "still-true": { params: ["entryId"], description: "entryId is required. Allowed for the holder of the owning role; if that role is empty, the nearest seated Team Lead up the team tree." }
@@ -3505,7 +3524,7 @@ async function handleGet(entryId) {
3505
3524
  if (e.sourceExcerpt) lines.push(`**Source excerpt:** ${e.sourceExcerpt}`);
3506
3525
  const parsedOwner = parseOwnerOutput(e.owner);
3507
3526
  if (parsedOwner) lines.push(formatOwnerLine2(parsedOwner));
3508
- if (typeof e.pendingMove === "string") lines.push(sanitizeSingleLineField(e.pendingMove));
3527
+ for (const line of [e.pendingMove, e.qualityOverride]) if (typeof line === "string") lines.push(sanitizeSingleLineField(line));
3509
3528
  const restsOnChanged = Array.isArray(e.restsOnChanged) ? e.restsOnChanged : [];
3510
3529
  for (const item of restsOnChanged) lines.push(sanitizeSingleLineField(restsOnLine(item)));
3511
3530
  if (epistemic) lines.push(formatEpistemicLine(epistemic));
@@ -3553,7 +3572,8 @@ async function handleGet(entryId) {
3553
3572
  ...e.sourceRef ? { sourceRef: String(e.sourceRef) } : {},
3554
3573
  ...e.sourceExcerpt ? { sourceExcerpt: String(e.sourceExcerpt) } : {},
3555
3574
  ...parsedOwner ? { owner: parsedOwner } : {},
3556
- ...typeof e.pendingMove === "string" ? { pendingMove: e.pendingMove } : {},
3575
+ ...Object.fromEntries(["pendingMove", "qualityOverride"].filter((k) => typeof e[k] === "string").map((k) => [k, e[k]])),
3576
+ // TASK-954
3557
3577
  ...restsOnChanged.length > 0 ? { restsOnChanged } : {},
3558
3578
  // TEN-2191: surface the WHY and its quality in the structured payload too.
3559
3579
  ...why.length > 0 ? { why } : {},
@@ -12890,4 +12910,4 @@ export {
12890
12910
  createProductBrainServer,
12891
12911
  initFeatureFlags
12892
12912
  };
12893
- //# sourceMappingURL=chunk-A56KNDI2.js.map
12913
+ //# sourceMappingURL=chunk-HOGSWOSY.js.map