@productbrain/mcp 0.0.1-beta.1463 → 0.0.1-beta.1470

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.
@@ -37,7 +37,7 @@ import {
37
37
  trackSessionCaptureRate,
38
38
  trackWriteBackHintServed,
39
39
  trackZeroCaptureAuditFired
40
- } from "./chunk-Q5IQ5I37.js";
40
+ } from "./chunk-AMJILQKI.js";
41
41
 
42
42
  // src/server.ts
43
43
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -616,11 +616,6 @@ async function isGoverned(slug) {
616
616
  const col = await getCollectionBySlug(slug);
617
617
  return !!col?.governed;
618
618
  }
619
- async function isWorkPlanningCollection(slug) {
620
- const col = await getCollectionBySlug(slug);
621
- const layer = col?.thinkingLayer;
622
- return layer === "delivery-container" || layer === "delivery-grouping" || layer === "delivery-work";
623
- }
624
619
 
625
620
  // src/tools/smart-capture.ts
626
621
  var COMMON_CHECKS = {
@@ -1852,15 +1847,21 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
1852
1847
  author: agentId ? `agent:${agentId}` : void 0,
1853
1848
  sessionId: agentId ?? void 0
1854
1849
  });
1855
- finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
1856
- if (finalStatus === "committed") {
1857
- await recordSessionActivity({ entryModified: internalId });
1858
- trackChainEntryCommitted(wsCtx.workspaceId, {
1859
- entry_id: finalEntryId,
1860
- collection: resolvedCollection,
1861
- commit_method: "auto",
1862
- surface: "mcp_capture"
1863
- });
1850
+ const refusalReason = coherencyRefusalReason(commitResult);
1851
+ if (refusalReason) {
1852
+ commitError = `coherency gate refused this accept \u2014 ${refusalReason}`;
1853
+ finalStatus = "draft_on_failure";
1854
+ } else {
1855
+ finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
1856
+ if (finalStatus === "committed") {
1857
+ await recordSessionActivity({ entryModified: internalId });
1858
+ trackChainEntryCommitted(wsCtx.workspaceId, {
1859
+ entry_id: finalEntryId,
1860
+ collection: resolvedCollection,
1861
+ commit_method: "auto",
1862
+ surface: "mcp_capture"
1863
+ });
1864
+ }
1864
1865
  }
1865
1866
  }
1866
1867
  } catch (e) {
@@ -2423,15 +2424,21 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
2423
2424
  author: agentId ? `agent:${agentId}` : void 0,
2424
2425
  sessionId: agentId ?? void 0
2425
2426
  });
2426
- finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
2427
- if (finalStatus === "committed") {
2428
- await recordSessionActivity({ entryModified: internalId });
2429
- trackChainEntryCommitted(wsCtx.workspaceId, {
2430
- entry_id: finalEntryId,
2431
- collection: resolvedSlug ?? void 0,
2432
- commit_method: "auto",
2433
- surface: "mcp_capture"
2434
- });
2427
+ const refusalReason = coherencyRefusalReason(commitResult);
2428
+ if (refusalReason) {
2429
+ commitError = `coherency gate refused this accept \u2014 ${refusalReason}`;
2430
+ finalStatus = "draft_on_failure";
2431
+ } else {
2432
+ finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
2433
+ if (finalStatus === "committed") {
2434
+ await recordSessionActivity({ entryModified: internalId });
2435
+ trackChainEntryCommitted(wsCtx.workspaceId, {
2436
+ entry_id: finalEntryId,
2437
+ collection: resolvedSlug ?? void 0,
2438
+ commit_method: "auto",
2439
+ surface: "mcp_capture"
2440
+ });
2441
+ }
2435
2442
  }
2436
2443
  }
2437
2444
  } catch (error) {
@@ -2677,6 +2684,10 @@ _Use \`move-entry\` to correct any misclassified entries._`);
2677
2684
  );
2678
2685
  trackWriteTool(batchCaptureTool);
2679
2686
  }
2687
+ function coherencyRefusalReason(commitResult) {
2688
+ if (commitResult?.status !== "coherency_refused") return null;
2689
+ return commitResult.refusal?.reason ?? "refused by the coherency gate";
2690
+ }
2680
2691
  async function recordCommitFailure({
2681
2692
  entryId,
2682
2693
  error,
@@ -2989,15 +3000,45 @@ var updateEntrySchema = z3.object({
2989
3000
  autoPublish: z3.boolean().optional().default(false).describe("Only true when user explicitly asks to publish. Default false = draft. Never auto-publish without user confirmation."),
2990
3001
  changeNote: z3.string().optional().describe("Strongly recommended: short human-readable rationale for WHY this change was made (e.g. 'Aligned description with F1-themed copy'). Surfaces in activity feed and pb get. If omitted, falls back to session purpose or auto-generated field summary."),
2991
3002
  sourceRef: z3.string().optional().describe("URI or path of the source document backing this entry. Write-once: can only be set if currently empty."),
2992
- sourceExcerpt: z3.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Write-once: can only be set if currently empty.")
3003
+ sourceExcerpt: z3.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Write-once: can only be set if currently empty."),
3004
+ // WP-465 slice ⑤ — relay-only (TEN-2233): validation/min-length/recording live in Convex.
3005
+ steeringOverrideReason: z3.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block on a misaligned governance write \u2014 always recorded with author attribution."),
3006
+ coherencyAcknowledgement: z3.object({
3007
+ response: z3.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
3008
+ entryId: z3.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
3009
+ reason: z3.string().optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
3010
+ }).optional().describe("Explicit response to a coherency challenge (standard/strict workspace modes). One acknowledgement per challenge per entry per session.")
2993
3011
  });
3012
+ function coherencyRefusedResult(toolName, entryId, refusal) {
3013
+ return failureResult(
3014
+ [
3015
+ `# Write refused by the coherency gate`,
3016
+ "",
3017
+ refusal.reason ?? `The coherency gate refused this write on ${entryId}.`,
3018
+ "",
3019
+ `Respond and retry: link the entry to the strategic spine, pass \`coherencyAcknowledgement\`, or supply a typed \`steeringOverrideReason\`.`
3020
+ ].join("\n"),
3021
+ "COHERENCY_REFUSED",
3022
+ `Coherency gate refused ${toolName} on ${entryId}.`,
3023
+ "Use one of the refusal's routes (link / coherencyAcknowledgement / steeringOverrideReason), then retry.",
3024
+ void 0,
3025
+ { entryId, refusal }
3026
+ );
3027
+ }
2994
3028
  var getHistorySchema = z3.object({
2995
3029
  entryId: z3.string().describe("Entry ID, e.g. 'T-SUPPLIER', '<PREFIX>-<n>'")
2996
3030
  });
2997
3031
  var commitEntrySchema = z3.object({
2998
3032
  entryId: z3.string().describe("Entry ID to accept, e.g. 'TEN-abc123', '<PREFIX>-<n>'"),
2999
3033
  // WP-316 S3: Preview gate — dry-run mode. Returns would-succeed result, no DB writes.
3000
- preview: z3.boolean().optional().describe("If true, validates the accept without writing. Returns what would happen. Default false.")
3034
+ preview: z3.boolean().optional().describe("If true, validates the accept without writing. Returns what would happen. Default false."),
3035
+ // WP-465 slice ⑤ — relay-only (TEN-2233): validation/recording live in Convex.
3036
+ steeringOverrideReason: z3.string().optional().describe("Typed override (\u226512 chars) that clears a steering coherency block at the publish chokepoint \u2014 always recorded with author attribution."),
3037
+ coherencyAcknowledgement: z3.object({
3038
+ response: z3.enum(["linked", "accepted-fix", "diverged"]).describe("Explicit response to an acknowledge-required coherency challenge."),
3039
+ entryId: z3.string().optional().describe("Authorizing entry being linked/accepted (required for 'linked' and 'accepted-fix')."),
3040
+ reason: z3.string().optional().describe("Divergence rationale (required for 'diverged', \u226512 chars).")
3041
+ }).optional().describe("Explicit response to a coherency challenge (standard/strict workspace modes).")
3001
3042
  });
3002
3043
  function registerKnowledgeTools(server) {
3003
3044
  const updateTool = server.registerTool(
@@ -3008,7 +3049,7 @@ function registerKnowledgeTools(server) {
3008
3049
  inputSchema: updateEntrySchema,
3009
3050
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
3010
3051
  },
3011
- thinWrapper(async ({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, sourceRef, sourceExcerpt }) => {
3052
+ thinWrapper(async ({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, sourceRef, sourceExcerpt, steeringOverrideReason, coherencyAcknowledgement }) => {
3012
3053
  requireWriteAccess();
3013
3054
  const fieldsProvided = [];
3014
3055
  if (name !== void 0) fieldsProvided.push("name");
@@ -3039,8 +3080,14 @@ function registerKnowledgeTools(server) {
3039
3080
  changeNote,
3040
3081
  changedBy: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
3041
3082
  ...sourceRef ? { sourceRef } : {},
3042
- ...sourceExcerpt ? { sourceExcerpt } : {}
3083
+ ...sourceExcerpt ? { sourceExcerpt } : {},
3084
+ ...steeringOverrideReason ? { steeringOverrideReason } : {},
3085
+ ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {}
3043
3086
  });
3087
+ const maybeRefused = updateResult;
3088
+ if (maybeRefused.outcome === "refused" && maybeRefused.refusal) {
3089
+ return coherencyRefusedResult("update-entry", entryId, maybeRefused.refusal);
3090
+ }
3044
3091
  const id = updateResult.id;
3045
3092
  await recordSessionActivity({ entryModified: id });
3046
3093
  const wsCtx = await getWorkspaceContext();
@@ -3149,7 +3196,7 @@ ${formatted}` }],
3149
3196
  inputSchema: commitEntrySchema,
3150
3197
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
3151
3198
  },
3152
- thinWrapper(async ({ entryId, preview }) => {
3199
+ thinWrapper(async ({ entryId, preview, steeringOverrideReason, coherencyAcknowledgement }) => {
3153
3200
  requireWriteAccess();
3154
3201
  const entry = await kernelQuery("chain.getEntry", { entryId });
3155
3202
  if (!entry) {
@@ -3213,7 +3260,9 @@ ${formatted}` }],
3213
3260
  entryId,
3214
3261
  author: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
3215
3262
  sessionId: getAgentSessionId() ?? void 0,
3216
- ...preview ? { preview: true } : {}
3263
+ ...preview ? { preview: true } : {},
3264
+ ...steeringOverrideReason ? { steeringOverrideReason } : {},
3265
+ ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {}
3217
3266
  });
3218
3267
  } catch (commitErr) {
3219
3268
  const errCode = commitErr?.code;
@@ -3232,6 +3281,9 @@ ${formatted}` }],
3232
3281
  }
3233
3282
  throw commitErr;
3234
3283
  }
3284
+ if (result?.status === "coherency_refused" && result?.refusal) {
3285
+ return coherencyRefusedResult("commit-entry", entryId, result.refusal);
3286
+ }
3235
3287
  if (result?.preview) {
3236
3288
  const previewEnvelope = success(
3237
3289
  `Preview: would accept ${entryId} \u2014 no DB writes`,
@@ -3336,6 +3388,11 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
3336
3388
  warning_types: uniqueTypes
3337
3389
  });
3338
3390
  }
3391
+ const steeringAdvisory = typeof result?.steeringAdvisory === "string" && result.steeringAdvisory.trim() ? result.steeringAdvisory : void 0;
3392
+ if (steeringAdvisory) {
3393
+ lines.push("");
3394
+ lines.push(`\u26A0 Coherency advisory (entry accepted): ${steeringAdvisory}`);
3395
+ }
3339
3396
  const epistemic = deriveEpistemicStatus(toEpistemicInput(entry));
3340
3397
  if (epistemic && (epistemic.level === "hypothesis" || epistemic.level === "untested")) {
3341
3398
  lines.push("");
@@ -3371,7 +3428,8 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
3371
3428
  qualityVerdict: coachingResult?.verdict ?? void 0,
3372
3429
  source: coachingResult?.source ?? void 0,
3373
3430
  contradictions: advisoryWarnings.length,
3374
- ...epistemic ? { epistemicStatus: epistemic } : {}
3431
+ ...epistemic ? { epistemicStatus: epistemic } : {},
3432
+ ...steeringAdvisory ? { steeringAdvisory } : {}
3375
3433
  },
3376
3434
  next
3377
3435
  );
@@ -6948,6 +7006,14 @@ async function runWrapupCommitAll(data, cachedSuggestions) {
6948
7006
  author: `agent:${sessionId}`,
6949
7007
  sessionId
6950
7008
  });
7009
+ if (result?.status === "coherency_refused") {
7010
+ results.push({
7011
+ entryId: draft.entryId,
7012
+ ok: false,
7013
+ error: `coherency gate refused this accept \u2014 ${result.refusal?.reason ?? "refused by the coherency gate"}`
7014
+ });
7015
+ continue;
7016
+ }
6951
7017
  const proposed = result?.status === "proposal_created";
6952
7018
  if (!proposed) {
6953
7019
  await recordSessionActivity({ entryModified: draft.docId });
@@ -9186,12 +9252,26 @@ function parseListOutput(output) {
9186
9252
  // src/tools/facilitate.ts
9187
9253
  import { z as z14 } from "zod";
9188
9254
  var FACILITATE_ACTIONS = ["resume", "commit-constellation"];
9255
+ var coherencyAcknowledgementSchema = z14.object({
9256
+ response: z14.string().describe("Acknowledgement response per offender: 'linked' | 'accepted-fix' | 'diverged'."),
9257
+ entryId: z14.string().optional().describe("Entry the acknowledgement links to (e.g. the strategic spine entry)."),
9258
+ reason: z14.string().optional().describe("Free-text justification, required for a 'diverged' response."),
9259
+ subjectEntryId: z14.string().optional().describe("The refused entry this acknowledgement answers.")
9260
+ });
9189
9261
  var facilitateSchema = z14.object({
9190
9262
  action: z14.enum(FACILITATE_ACTIONS).describe(
9191
9263
  "'resume': load session state from an existing bet entry. 'commit-constellation': atomically accept a bet and all its linked draft entries in one call. Requires betEntryId."
9192
9264
  ),
9193
9265
  betEntryId: z14.string().optional().describe("Bet entry ID. Required for both actions."),
9194
- operationId: z14.string().optional().describe("Optional idempotency key for commit-constellation retries.")
9266
+ operationId: z14.string().optional().describe("Optional idempotency key for commit-constellation retries."),
9267
+ // WP-465 slice ⑤: coherency retry controls for a COHERENCY_REFUSED constellation hold.
9268
+ // Forwarded verbatim to agentKnowledge.facilitateEnvelope (validation lives at the gate).
9269
+ coherencyAcknowledgements: z14.array(coherencyAcknowledgementSchema).optional().describe(
9270
+ "Per-offender acknowledgements to retry a constellation held under standard/strict coherency mode. Each: {subjectEntryId, response: 'linked' | 'accepted-fix' | 'diverged', entryId?, reason?}."
9271
+ ),
9272
+ steeringOverrideReason: z14.string().optional().describe(
9273
+ "Typed override reason (>= 12 chars) to push a constellation past a coherency hold instead of acknowledging."
9274
+ )
9195
9275
  });
9196
9276
  function buildCortexUrl(workspaceSlug, entryId) {
9197
9277
  const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://work.productbrain.io";
@@ -9340,11 +9420,39 @@ async function handleCommitConstellation(args) {
9340
9420
  betEntryId: betId,
9341
9421
  operationId,
9342
9422
  sessionId: sessionId ?? void 0,
9343
- author: sessionId ? `agent:${sessionId}` : "kernel:facilitate"
9423
+ author: sessionId ? `agent:${sessionId}` : "kernel:facilitate",
9424
+ // WP-465 slice ⑤ (TEN-2439, §3.7): relay the coherency retry controls so a
9425
+ // COHERENCY_REFUSED constellation hold is actually retryable through MCP.
9426
+ ...args.coherencyAcknowledgements ? { coherencyAcknowledgements: args.coherencyAcknowledgements } : {},
9427
+ ...args.steeringOverrideReason ? { steeringOverrideReason: args.steeringOverrideReason } : {}
9344
9428
  });
9345
9429
  } catch (err) {
9346
9430
  const msg = err instanceof Error ? err.message : String(err);
9431
+ const code = err?.code;
9347
9432
  const diagnostics = err?.diagnostics;
9433
+ if (code === "COHERENCY_REFUSED") {
9434
+ const coherencyRefusals = Array.isArray(diagnostics?.coherencyRefusals) ? diagnostics.coherencyRefusals : [];
9435
+ const offenderLines = coherencyRefusals.map((r) => `- \`${r.entryId}\` ${r.name}: ${String(r.refusal?.reason ?? "coherency challenge unsatisfied")}`).join("\n");
9436
+ const count = coherencyRefusals.length;
9437
+ return {
9438
+ content: [{
9439
+ type: "text",
9440
+ text: [
9441
+ `# Constellation held by the coherency gate`,
9442
+ "",
9443
+ `\`${betId}\` was not accepted \u2014 ${count} entr${count === 1 ? "y" : "ies"} refused. Nothing was committed; drafts persist.`,
9444
+ ...offenderLines ? ["", offenderLines] : []
9445
+ ].join("\n")
9446
+ }],
9447
+ structuredContent: failure(
9448
+ "COHERENCY_REFUSED",
9449
+ `Constellation held: ${count} entr${count === 1 ? "y" : "ies"} refused by the coherency gate \u2014 nothing was committed, drafts persist.`,
9450
+ "Respond per offender and retry commit-constellation: link the entry to the strategic spine, pass coherencyAcknowledgements [{subjectEntryId, response: 'linked' | 'accepted-fix' | 'diverged', entryId?, reason?}], or supply a typed steeringOverrideReason (at least 12 characters).",
9451
+ [{ tool: "facilitate", description: "Retry with coherency acknowledgements", parameters: { action: "commit-constellation", betEntryId: betId } }],
9452
+ { coherencyRefusals }
9453
+ )
9454
+ };
9455
+ }
9348
9456
  return {
9349
9457
  content: [{
9350
9458
  type: "text",
@@ -9688,6 +9796,7 @@ function registerVerifyTools(server) {
9688
9796
  });
9689
9797
  const fixes = [];
9690
9798
  const fixUpdateWarnings = [];
9799
+ const fixRefusals = [];
9691
9800
  if (mode === "fix") {
9692
9801
  const driftedByEntry = /* @__PURE__ */ new Map();
9693
9802
  for (const mc of mappingChecks) {
@@ -9706,6 +9815,13 @@ function registerVerifyTools(server) {
9706
9815
  entryId: entry.entryId,
9707
9816
  data: { codeMapping: updated }
9708
9817
  });
9818
+ if (updateResult.outcome === "refused") {
9819
+ fixRefusals.push({
9820
+ entryId: entry.entryId,
9821
+ reason: updateResult.refusal?.reason ?? "coherency gate refused this update"
9822
+ });
9823
+ continue;
9824
+ }
9709
9825
  if (updateResult.normalizationWarnings.length > 0 || updateResult.validationWarnings.length > 0) {
9710
9826
  fixUpdateWarnings.push({
9711
9827
  entryId: entry.entryId,
@@ -9735,6 +9851,13 @@ function registerVerifyTools(server) {
9735
9851
  projectRoot
9736
9852
  );
9737
9853
  let reportText = report;
9854
+ if (fixRefusals.length > 0) {
9855
+ reportText += "\n\n---\n\n\u{1F6D1} **Coherency refusals (fix NOT applied \u2014 entry unchanged):**";
9856
+ for (const r of fixRefusals) {
9857
+ reportText += `
9858
+ - **${r.entryId}**: ${r.reason}`;
9859
+ }
9860
+ }
9738
9861
  if (fixUpdateWarnings.length > 0) {
9739
9862
  reportText += "\n\n---\n\n\u26A0\uFE0F **Fix update warnings:**";
9740
9863
  for (const w of fixUpdateWarnings) {
@@ -9764,6 +9887,7 @@ function registerVerifyTools(server) {
9764
9887
  refsValid,
9765
9888
  refsBroken,
9766
9889
  fixesApplied: fixes.length,
9890
+ ...fixRefusals.length > 0 ? { fixesRefused: fixRefusals.length, coherencyRefusals: fixRefusals } : {},
9767
9891
  mode
9768
9892
  }
9769
9893
  )
@@ -10040,48 +10164,27 @@ function buildDocCompletenessSection(collections) {
10040
10164
  const lines = renderDocCompletenessLines(report);
10041
10165
  return { lines, errorCount: report.summary.errors, warningCount: report.summary.warnings };
10042
10166
  }
10043
- async function runAlignmentCheck(task, activeBets, taskContextHits) {
10044
- const betNames = activeBets.map((b) => b.name);
10045
- const taskWords = extractKeywords(task);
10046
- const matchingBet = activeBets.find((b) => {
10047
- const words = (b.name ?? "").toLowerCase().split(/\s+/);
10048
- return taskWords.some((tw) => words.some((w) => w === tw || w.startsWith(tw + "-")));
10049
- });
10050
- if (matchingBet) {
10051
- return { aligned: true, matchedBet: matchingBet.name, matchSource: "active_bet", betNames };
10052
- }
10053
- const betHits = [];
10054
- for (const e of taskContextHits ?? []) {
10055
- if (e.collectionSlug && await isWorkPlanningCollection(e.collectionSlug)) {
10056
- betHits.push(e);
10167
+ function buildTaskAlignmentLines(ta) {
10168
+ if (!ta) return [];
10169
+ const lines = ["## Alignment Check"];
10170
+ lines.push(ta.wording);
10171
+ if (ta.candidates.length > 0) {
10172
+ lines.push("");
10173
+ lines.push("**Candidate authorizing entries:**");
10174
+ for (const c of ta.candidates) {
10175
+ lines.push(`- \`${c.entryId}\` [${c.collectionSlug}] ${c.name} (${Math.round(c.overlapRatio * 100)}% overlap)`);
10057
10176
  }
10058
10177
  }
10059
- if (betHits.length > 0) {
10060
- return { aligned: true, matchedBet: betHits[0]?.name ?? null, matchSource: "task_context", betNames };
10178
+ if (ta.escapeRoutes.length > 0) {
10179
+ lines.push("");
10180
+ lines.push("**Your routes:**");
10181
+ for (let i = 0; i < ta.escapeRoutes.length; i++) {
10182
+ lines.push(`${i + 1}. **${ta.escapeRoutes[i].kind}** \u2014 ${ta.escapeRoutes[i].instruction}`);
10183
+ }
10061
10184
  }
10062
- return { aligned: false, matchedBet: null, matchSource: null, betNames };
10063
- }
10064
- function buildAlignmentCheckLines(result) {
10065
- const lines = ["## Alignment Check"];
10066
- if (result.aligned && result.matchSource === "active_bet" && result.matchedBet) {
10067
- lines.push(
10068
- `Task aligns with active bet: **${result.matchedBet}**. Proceed.`
10069
- );
10070
- } else if (result.aligned && result.matchSource === "task_context" && result.matchedBet) {
10071
- const noActiveBets = result.betNames.length === 0;
10072
- lines.push(
10073
- `Task related to **${result.matchedBet}** via task context${noActiveBets ? " (no active bets in horizon=now)" : ""}. Proceed with caution \u2014 confirm scope with the user if uncertain.`
10074
- );
10075
- } else if (result.betNames.length === 0) {
10076
- lines.push(
10077
- "No active bets in workspace. Consider shaping a bet before building."
10078
- );
10079
- } else {
10080
- lines.push("**This task does not match any active bet.**");
10081
- lines.push(`Active bets: ${result.betNames.join(", ")}`);
10082
- lines.push(
10083
- "Stop and confirm with the user before designing. This may be out of scope."
10084
- );
10185
+ if (ta.verdict === "misaligned" && ta.citedRule) {
10186
+ lines.push("");
10187
+ lines.push(`_Workspace rule: \`${ta.citedRule.entryId ?? ""}\` ${ta.citedRule.name}._`);
10085
10188
  }
10086
10189
  lines.push("");
10087
10190
  return lines;
@@ -10102,17 +10205,6 @@ function provenanceMark(p) {
10102
10205
  }
10103
10206
  var MAX_ENTRIES_NO_TASK = 3;
10104
10207
  var MAX_ENTRIES_WITH_TASK = 5;
10105
- function extractKeywords(text) {
10106
- const normalized = text.toLowerCase().replace(/[^\w\s-]/g, " ");
10107
- const tokens = [];
10108
- for (const raw of normalized.split(/\s+/)) {
10109
- if (!raw) continue;
10110
- const parts = raw.split(/[-_]/);
10111
- if (parts.length > 1) tokens.push(raw.replace(/[-_]/g, ""));
10112
- for (const p of parts) if (p) tokens.push(p);
10113
- }
10114
- return [...new Set(tokens.filter((w) => w.length > 2))];
10115
- }
10116
10208
  function formatGovernanceEntry(entry) {
10117
10209
  const id = entry.entryId ?? entry.name;
10118
10210
  const desc = entry.description ? ` \u2014 ${entry.description.slice(0, 120)}${entry.description.length > 120 ? "..." : ""}` : "";
@@ -12026,6 +12118,9 @@ async function _handleOrient({ mode = "full", tier, task, scope }) {
12026
12118
  lines.push(`\u26A0\uFE0F ${orientView.taskContext.groundingNote}`);
12027
12119
  }
12028
12120
  }
12121
+ if (orientView?.taskAlignment) {
12122
+ lines.push(`Task alignment: ${orientView.taskAlignment.verdict} \u2014 ${orientView.taskAlignment.wording.replace(/\*\*/g, "")}`);
12123
+ }
12029
12124
  if (orientView?.startup?.domainRetrieval) {
12030
12125
  const retrieval = orientView.startup.domainRetrieval;
12031
12126
  const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
@@ -12166,6 +12261,8 @@ async function _handleOrient({ mode = "full", tier, task, scope }) {
12166
12261
  taskGroundingRequired: !hasTaskGrounding,
12167
12262
  // STD-219 §4 (DEC-1147): machine-readable stub flag for agent consumers.
12168
12263
  ...orientView?.taskContext?.isGroundingStub ? { groundingStub: true } : {},
12264
+ // WP-465 slice ③ (§4.1): served verbatim — identical on CLI and MCP.
12265
+ ...orientView?.taskAlignment ? { taskAlignment: orientView.taskAlignment } : {},
12169
12266
  orientationStatus: orientationStatus2,
12170
12267
  nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
12171
12268
  ...orientView?._budget ? { _budget: orientView._budget } : {}
@@ -12337,12 +12434,7 @@ async function _handleOrient({ mode = "full", tier, task, scope }) {
12337
12434
  lines.push("");
12338
12435
  }
12339
12436
  if (orientView) {
12340
- const result = await runAlignmentCheck(
12341
- task,
12342
- orientView.activeWorkPackages ?? [],
12343
- orientView.taskContext?.context
12344
- );
12345
- lines.push(...buildAlignmentCheckLines(result));
12437
+ lines.push(...buildTaskAlignmentLines(orientView.taskAlignment));
12346
12438
  lines.push(...formatInitiativeStatusLines(orientView.initiativeStatus));
12347
12439
  lines.push(...formatWorkstreamHealthLines(orientView.workstreamHealth));
12348
12440
  lines.push(...formatWhatNeedsAttentionLines(orientView.whatNeedsAttention));
@@ -12579,6 +12671,8 @@ async function _handleOrient({ mode = "full", tier, task, scope }) {
12579
12671
  taskGroundingRequired: !hasTaskGrounding,
12580
12672
  // STD-219 §4 (DEC-1147): machine-readable stub flag for agent consumers.
12581
12673
  ...orientView?.taskContext?.isGroundingStub ? { groundingStub: true } : {},
12674
+ // WP-465 slice ③ (§4.1): served verbatim — identical on CLI and MCP.
12675
+ ...orientView?.taskAlignment ? { taskAlignment: orientView.taskAlignment } : {},
12582
12676
  domainRetrieval: orientView?.startup?.domainRetrieval,
12583
12677
  orientationStatus,
12584
12678
  nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
@@ -14472,4 +14566,4 @@ export {
14472
14566
  createProductBrainServer,
14473
14567
  initFeatureFlags
14474
14568
  };
14475
- //# sourceMappingURL=chunk-T566VC4F.js.map
14569
+ //# sourceMappingURL=chunk-GL6INEHP.js.map