@productbrain/mcp 0.0.1-beta.951 → 0.0.1-beta.973

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.
@@ -4263,6 +4263,25 @@ function sanitizeEntryData(data) {
4263
4263
  );
4264
4264
  return Object.keys(filtered).length > 0 ? filtered : void 0;
4265
4265
  }
4266
+ function renderWhyLine(e) {
4267
+ const why = typeof e.why === "string" ? e.why : "";
4268
+ if (e.whyQuality === "missing") {
4269
+ return { line: `**Why:** \u2014 (no rationale captured)`, why, whySourceKey: null };
4270
+ }
4271
+ if (why.length > 0) {
4272
+ const suffix = e.whyQuality === "restated" ? " (restated)" : "";
4273
+ const d = e.data ?? {};
4274
+ let whySourceKey = null;
4275
+ const kf = e.whyField;
4276
+ if ((kf === "rationale" || kf === "description") && typeof d[kf] === "string" && d[kf].trim().length > 0) {
4277
+ whySourceKey = kf;
4278
+ } else if (typeof d.rationale === "string" && d.rationale.trim().length > 0) {
4279
+ whySourceKey = "rationale";
4280
+ }
4281
+ return { line: `**Why:** ${why}${suffix}`, why, whySourceKey };
4282
+ }
4283
+ return { line: null, why, whySourceKey: null };
4284
+ }
4266
4285
  var ENTRIES_ACTIONS = ["list", "get", "batch", "search"];
4267
4286
  var entriesSchema = z4.object({
4268
4287
  action: z4.enum(ENTRIES_ACTIONS).describe(
@@ -4291,6 +4310,9 @@ var entriesGetOutputSchema = z4.object({
4291
4310
  verificationStatus: z4.string().optional(),
4292
4311
  sourceRef: z4.string().optional(),
4293
4312
  sourceExcerpt: z4.string().optional(),
4313
+ why: z4.string().optional(),
4314
+ // TEN-2191: quality of the captured WHY — 'rationale' | 'missing' | 'restated'.
4315
+ whyQuality: z4.enum(["rationale", "missing", "restated"]).optional(),
4294
4316
  data: z4.record(z4.unknown()).optional(),
4295
4317
  relations: z4.array(z4.object({
4296
4318
  entryId: z4.string().optional(),
@@ -4299,7 +4321,7 @@ var entriesGetOutputSchema = z4.object({
4299
4321
  direction: z4.string()
4300
4322
  })).optional(),
4301
4323
  labels: z4.array(z4.string()).optional()
4302
- });
4324
+ }).passthrough();
4303
4325
  var entriesListOutputSchema = z4.object({
4304
4326
  entries: z4.array(z4.object({
4305
4327
  entryId: z4.string(),
@@ -4332,8 +4354,11 @@ var entriesBatchOutputSchema = z4.object({
4332
4354
  verificationStatus: z4.string().optional(),
4333
4355
  sourceRef: z4.string().optional(),
4334
4356
  sourceExcerpt: z4.string().optional(),
4357
+ // TEN-2191: mirror entriesGetOutputSchema — batch entries now carry why/whyQuality.
4358
+ why: z4.string().optional(),
4359
+ whyQuality: z4.enum(["rationale", "missing", "restated"]).optional(),
4335
4360
  data: z4.record(z4.unknown()).optional()
4336
- })),
4361
+ }).passthrough()),
4337
4362
  total: z4.number()
4338
4363
  });
4339
4364
  function registerEntriesTools(server) {
@@ -4419,10 +4444,13 @@ async function handleGet(entryId) {
4419
4444
  if (epistemic) {
4420
4445
  lines.push(formatEpistemicLine(epistemic));
4421
4446
  }
4447
+ const { line: whyLine, why, whySourceKey } = renderWhyLine(e);
4448
+ if (whyLine !== null) lines.push(whyLine);
4422
4449
  const visibleData = sanitizeEntryData(e.data);
4423
- if (visibleData) {
4450
+ const filteredData = visibleData && whySourceKey ? Object.keys(visibleData).filter((k) => k !== whySourceKey).length > 0 ? Object.fromEntries(Object.entries(visibleData).filter(([k]) => k !== whySourceKey)) : void 0 : visibleData;
4451
+ if (filteredData) {
4424
4452
  lines.push("");
4425
- for (const [key, val] of Object.entries(visibleData)) {
4453
+ for (const [key, val] of Object.entries(filteredData)) {
4426
4454
  const display = typeof val === "string" ? val : JSON.stringify(val);
4427
4455
  lines.push(`**${key}:** ${display}`);
4428
4456
  }
@@ -4463,8 +4491,17 @@ async function handleGet(entryId) {
4463
4491
  ...e.verificationStatus ? { verificationStatus: String(e.verificationStatus) } : {},
4464
4492
  ...e.sourceRef ? { sourceRef: String(e.sourceRef) } : {},
4465
4493
  ...e.sourceExcerpt ? { sourceExcerpt: String(e.sourceExcerpt) } : {},
4494
+ // TEN-2191: surface the WHY and its quality in the structured payload too.
4495
+ ...why.length > 0 ? { why } : {},
4496
+ ...e.whyQuality ? { whyQuality: String(e.whyQuality) } : {},
4466
4497
  entries: [{ entryId: e.entryId, name: e.name, status: e.status, ...e.workflowStatus ? { workflowStatus: e.workflowStatus } : {}, collectionName: String(e.collectionName ?? e.canonicalKey ?? "\u2014") }],
4467
- ...visibleData ? { data: visibleData } : {},
4498
+ // Structured payload uses the same filteredData as the text render — the
4499
+ // WHY-source field (rationale or description) is intentionally omitted from
4500
+ // `data` because its full value is carried in the top-level `why` field
4501
+ // (no information loss; `why` is the complete untruncated extractWhy result).
4502
+ // This restores true STD-218 text/structured parity and removes the duplication
4503
+ // that commit 8f3b1664 left in the structured payload. (Codex finding, TEN-2191.)
4504
+ ...filteredData ? { data: filteredData } : {},
4468
4505
  ...Array.isArray(e.relations) && e.relations.length > 0 ? {
4469
4506
  relations: e.relations.map((r) => ({
4470
4507
  ...r.otherEntryId ? { entryId: r.otherEntryId } : {},
@@ -4521,10 +4558,13 @@ async function handleBatch(entryIds) {
4521
4558
  if (entry.sourceExcerpt) {
4522
4559
  lines.push(`**Source excerpt:** ${entry.sourceExcerpt}`);
4523
4560
  }
4561
+ const { line: whyLine, whySourceKey } = renderWhyLine(entry);
4562
+ if (whyLine !== null) lines.push(whyLine);
4524
4563
  const visibleData = sanitizeEntryData(entry.data);
4525
- if (visibleData) {
4564
+ const filteredData = visibleData && whySourceKey ? Object.keys(visibleData).filter((k) => k !== whySourceKey).length > 0 ? Object.fromEntries(Object.entries(visibleData).filter(([k]) => k !== whySourceKey)) : void 0 : visibleData;
4565
+ if (filteredData) {
4526
4566
  lines.push("");
4527
- for (const [key, val] of Object.entries(visibleData)) {
4567
+ for (const [key, val] of Object.entries(filteredData)) {
4528
4568
  const display = typeof val === "string" ? val : JSON.stringify(val);
4529
4569
  lines.push(`**${key}:** ${display}`);
4530
4570
  }
@@ -4555,6 +4595,9 @@ async function handleBatch(entryIds) {
4555
4595
  }
4556
4596
  const structuredEntries = results.filter((r) => !r.error && r.entry).map((r) => {
4557
4597
  const entry = r.entry;
4598
+ const { why: entryWhy, whySourceKey: entryWhySourceKey } = renderWhyLine(entry);
4599
+ const entryVisibleData = sanitizeEntryData(entry.data);
4600
+ const entryFilteredData = entryVisibleData && entryWhySourceKey ? Object.keys(entryVisibleData).filter((k) => k !== entryWhySourceKey).length > 0 ? Object.fromEntries(Object.entries(entryVisibleData).filter(([k]) => k !== entryWhySourceKey)) : void 0 : entryVisibleData;
4558
4601
  return {
4559
4602
  entryId: String(entry.entryId ?? ""),
4560
4603
  name: String(entry.name ?? ""),
@@ -4567,7 +4610,10 @@ async function handleBatch(entryIds) {
4567
4610
  ...entry.sourceRef ? { sourceRef: String(entry.sourceRef) } : {},
4568
4611
  ...entry.sourceExcerpt ? { sourceExcerpt: String(entry.sourceExcerpt) } : {},
4569
4612
  ...entry.workflowStatus ? { workflowStatus: String(entry.workflowStatus) } : {},
4570
- ...sanitizeEntryData(entry.data) ? { data: sanitizeEntryData(entry.data) } : {}
4613
+ // TEN-2191: surface why/whyQuality in structured payload — mirrors handleGet.
4614
+ ...entryWhy.length > 0 ? { why: entryWhy } : {},
4615
+ ...entry.whyQuality ? { whyQuality: String(entry.whyQuality) } : {},
4616
+ ...entryFilteredData ? { data: entryFilteredData } : {}
4571
4617
  };
4572
4618
  });
4573
4619
  const total = structuredEntries.length;
@@ -12527,11 +12573,16 @@ function replaceVocabTokens(body, workspaceCtx, collectionCtxMap) {
12527
12573
 
12528
12574
  // src/tools/orient.ts
12529
12575
  var PURPOSE_GAP_PREFIX = "purpose-gap-";
12530
- function reportOrientWrapperBytes(toolResult, truncated) {
12576
+ var NON_MEANINGFUL_TASK_RE = /^[\s​‌‍⁠]*$/u;
12577
+ function taskIsMeaningful(task) {
12578
+ if (typeof task !== "string") return false;
12579
+ return !NON_MEANINGFUL_TASK_RE.test(task);
12580
+ }
12581
+ function reportOrientWrapperBytes(toolResult, truncated, tier, taskProvided) {
12531
12582
  try {
12532
12583
  const fullToolOutput = JSON.stringify({ content: toolResult.content ?? [] });
12533
12584
  const bytes = Buffer.byteLength(fullToolOutput, "utf8");
12534
- void kernelMutation("agent.reportOrientMetric", { bytes, truncated }).catch(() => {
12585
+ void kernelMutation("agent.reportOrientMetric", { bytes, truncated, tier, taskProvided }).catch(() => {
12535
12586
  });
12536
12587
  } catch {
12537
12588
  }
@@ -12584,7 +12635,7 @@ var VALID_TASK_DOMAINS = [
12584
12635
  var orientSchema = z21.object({
12585
12636
  mode: z21.enum(["full", "brief"]).optional().default("full").describe("full = full context (default). brief = compact summary for mid-session re-orientation. Prefer using the `tier` param for depth control."),
12586
12637
  tier: z21.enum(["summary", "standard", "full"]).optional().describe(
12587
- "Payload depth. summary = ~10 KB compact. standard = ~256 KB default. full = complete payload (large). Defaults to standard."
12638
+ "Payload depth. Defaults to summary (~10 KB) when task is provided; standard (~256 KB) when task is absent. Pass summary, standard, or full to override."
12588
12639
  ),
12589
12640
  task: z21.string().optional().describe("Natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task."),
12590
12641
  scope: z21.enum(VALID_TASK_DOMAINS).optional().describe(`Optional domain scope to filter governance to entries relevant for this domain. Valid values: ${VALID_TASK_DOMAINS.join(", ")}.`)
@@ -12613,712 +12664,725 @@ function registerOrientTool(server) {
12613
12664
  "orient",
12614
12665
  {
12615
12666
  title: "Orient \u2014 Task Grounding",
12616
- description: "Task-grounded context loader. Use AFTER `start_pb` (the canonical session opener) to load governance and context for a specific task. Returns workspace context with a single recommended next action for low-readiness workspaces, or a standup-style briefing for established workspaces.\n\n**Not the session opener.** For 'how do I begin a session' or 'Start PB', call `start_pb` instead. `orient` is for refreshing or scoping context once a session is already underway.\n\nCompleting orientation unlocks write tools for the active session.\n\n**tier:** Controls payload depth. `standard` (default, ~256 KB) is the recommended default. `summary` (~10 KB) for quick mid-session re-orientation. `full` for complete payload when deep context is needed.\n\n**mode:** `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally. Prefer `tier` for explicit depth control.\n\n**task:** Optional natural-language task description. When provided, returns task-scoped context (scored, relevant entries) in addition to standard orient sections.\n\n**scope:** Optional domain scope. Filters governance entries to those relevant for the specified domain. Authority roots include strategy, product, product-design, engineering, architecture, data, governance, and go-to-market. Child scopes such as product-design/ux, engineering/frontend, data/analytics, and governance/principles are accepted. Legacy internal scopes remain accepted.",
12667
+ description: "Task-grounded context loader. Use AFTER `start_pb` (the canonical session opener) to load governance and context for a specific task. Returns workspace context with a single recommended next action for low-readiness workspaces, or a standup-style briefing for established workspaces.\n\n**Not the session opener.** For 'how do I begin a session' or 'Start PB', call `start_pb` instead. `orient` is for refreshing or scoping context once a session is already underway.\n\nCompleting orientation unlocks write tools for the active session.\n\n**tier:** 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\nDefaults: `summary` when `task` is provided; `standard` when `task` is absent. Explicit `tier` always wins. Pair with `mode='brief'` for compact formatting (orthogonal to depth).\n\n**mode:** `full` (default) returns full context. `brief` returns compact summary \u2014 mapped to tier=summary internally. Prefer `tier` for explicit depth control.\n\n**task:** Optional natural-language task description. When provided, returns task-scoped context (scored, relevant entries) in addition to standard orient sections.\n\n**scope:** Optional domain scope. Filters governance entries to those relevant for the specified domain. Authority roots include strategy, product, product-design, engineering, architecture, data, governance, and go-to-market. Child scopes such as product-design/ux, engineering/frontend, data/analytics, and governance/principles are accepted. Legacy internal scopes remain accepted.",
12617
12668
  inputSchema: orientSchema,
12618
12669
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
12619
12670
  },
12620
- thinWrapper(async ({ mode = "full", tier, task, scope }) => {
12621
- const errors = [];
12622
- const effectiveTier = tier ?? (mode === "brief" ? "summary" : "standard");
12623
- if (scope && !task) {
12624
- errors.push("--scope requires --task to filter governance. Scope was ignored.");
12625
- }
12626
- const agentSessionId = getAgentSessionId();
12627
- if (isSessionOriented() && mode === "brief" && !task) {
12628
- return {
12629
- content: [{
12630
- type: "text",
12631
- text: "Already oriented. Session active, writes unlocked.\n\n" + taskGroundingWarningLines().join("\n") + "Use `orient mode='full'` for workspace context or `orient task='...'` before substantive work."
12632
- }],
12633
- structuredContent: success(
12634
- "Already oriented. Session active, writes unlocked.",
12635
- {
12636
- alreadyOriented: true,
12637
- sessionId: agentSessionId,
12638
- taskGroundingStatus: "workspace_only",
12639
- taskGroundingRequired: true,
12640
- nextStep: 'Run `orient task="describe the work"` before substantive work.'
12641
- }
12642
- )
12643
- };
12644
- }
12645
- let wsCtx = null;
12646
- try {
12647
- wsCtx = await getWorkspaceContext();
12648
- } catch (e) {
12649
- errors.push(`Workspace: ${e instanceof Error ? e.message : String(e)}`);
12650
- }
12651
- let priorSessions = [];
12652
- let recoveryBlock = null;
12653
- let orientView = null;
12671
+ thinWrapper(_handleOrient)
12672
+ );
12673
+ }
12674
+ async function _handleOrient({ mode = "full", tier, task, scope }) {
12675
+ const errors = [];
12676
+ const callTier = tier ?? (mode === "brief" ? "summary" : void 0);
12677
+ const resolvedTier = callTier ?? (taskIsMeaningful(task) ? "summary" : "standard");
12678
+ if (scope && !task) {
12679
+ errors.push("--scope requires --task to filter governance. Scope was ignored.");
12680
+ }
12681
+ const agentSessionId = getAgentSessionId();
12682
+ if (isSessionOriented() && mode === "brief" && !task) {
12683
+ return {
12684
+ content: [{
12685
+ type: "text",
12686
+ text: "Already oriented. Session active, writes unlocked.\n\n" + taskGroundingWarningLines().join("\n") + "Use `orient mode='full'` for workspace context or `orient task='...'` before substantive work."
12687
+ }],
12688
+ structuredContent: success(
12689
+ "Already oriented. Session active, writes unlocked.",
12690
+ {
12691
+ alreadyOriented: true,
12692
+ sessionId: agentSessionId,
12693
+ taskGroundingStatus: "workspace_only",
12694
+ taskGroundingRequired: true,
12695
+ nextStep: 'Run `orient task="describe the work"` before substantive work.'
12696
+ }
12697
+ )
12698
+ };
12699
+ }
12700
+ let wsCtx = null;
12701
+ try {
12702
+ wsCtx = await getWorkspaceContext();
12703
+ } catch (e) {
12704
+ errors.push(`Workspace: ${e instanceof Error ? e.message : String(e)}`);
12705
+ }
12706
+ let priorSessions = [];
12707
+ let recoveryBlock = null;
12708
+ let orientView = null;
12709
+ try {
12710
+ const orientArgs = {};
12711
+ if (task) orientArgs.task = task;
12712
+ if (scope) orientArgs.scope = scope;
12713
+ if (callTier) orientArgs.tier = callTier;
12714
+ orientView = await kernelQuery("chain.getOrientView", orientArgs);
12715
+ } catch {
12716
+ }
12717
+ let vocabCtx;
12718
+ try {
12719
+ const vocab = await kernelQuery("chain.getVocabulary", {});
12720
+ if (vocab?.collectionLabels || vocab?.collectionDefaults) {
12721
+ vocabCtx = {
12722
+ ...vocab.collectionLabels ? { collectionLabels: vocab.collectionLabels } : {},
12723
+ ...vocab.collectionDefaults ? { collectionDefaults: vocab.collectionDefaults } : {}
12724
+ };
12725
+ }
12726
+ } catch {
12727
+ }
12728
+ if (orientView) {
12729
+ priorSessions = orientView.priorSessions ?? [];
12730
+ recoveryBlock = orientView.recoveryBlock ?? null;
12731
+ }
12732
+ const hasTaskGrounding = Boolean(task && orientView?.taskContext?.context?.length > 0);
12733
+ if (wsCtx && hasTaskGrounding && orientView?.writeBackHints) {
12734
+ const hints = Array.isArray(orientView.writeBackHints) ? orientView.writeBackHints : [];
12735
+ if (hints.length > 0) {
12736
+ trackWriteBackHintServed(wsCtx.workspaceId, {
12737
+ hint_count: hints.length,
12738
+ has_task: !!task
12739
+ });
12740
+ }
12741
+ }
12742
+ let openTensions = [];
12743
+ try {
12744
+ const tensions = await kernelQuery("chain.listEntries", { collectionSlug: "tensions" });
12745
+ openTensions = (tensions ?? []).filter((e) => e.workflowStatus === "open");
12746
+ } catch {
12747
+ }
12748
+ let allCollections = [];
12749
+ try {
12750
+ allCollections = await kernelQuery("chain.listCollections") ?? [];
12751
+ } catch {
12752
+ }
12753
+ let readiness = null;
12754
+ try {
12755
+ readiness = await kernelQuery("chain.workspaceReadiness");
12756
+ } catch (e) {
12757
+ errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
12758
+ }
12759
+ if (readiness?.stage === "blank") {
12760
+ const scanLines = [
12761
+ `# Welcome to ${wsCtx?.workspaceName ?? "your workspace"}`,
12762
+ "",
12763
+ "Your workspace is fresh \u2014 let's set it up.",
12764
+ "",
12765
+ "**Recommended:** call the `start` tool instead of `orient` for the best first-run experience.",
12766
+ "It will guide you through setting up your workspace \u2014 you can tell me about your product, scan your codebase, or use a preset.",
12767
+ "",
12768
+ "Or tell me about your product and I'll start capturing knowledge directly."
12769
+ ];
12770
+ let oriented = false;
12771
+ let orientationStatus2 = "no_session";
12772
+ if (agentSessionId) {
12654
12773
  try {
12655
- const orientArgs = {};
12656
- if (task) orientArgs.task = task;
12657
- if (scope) orientArgs.scope = scope;
12658
- orientArgs.tier = effectiveTier;
12659
- orientView = await kernelQuery("chain.getOrientView", orientArgs);
12774
+ await kernelCall("agent.markOriented", { sessionId: agentSessionId });
12775
+ setSessionOriented(true);
12776
+ oriented = true;
12777
+ orientationStatus2 = "complete";
12660
12778
  } catch {
12779
+ orientationStatus2 = "failed";
12661
12780
  }
12662
- let vocabCtx;
12663
- try {
12664
- const vocab = await kernelQuery("chain.getVocabulary", {});
12665
- if (vocab?.collectionLabels || vocab?.collectionDefaults) {
12666
- vocabCtx = {
12667
- ...vocab.collectionLabels ? { collectionLabels: vocab.collectionLabels } : {},
12668
- ...vocab.collectionDefaults ? { collectionDefaults: vocab.collectionDefaults } : {}
12669
- };
12670
- }
12671
- } catch {
12781
+ }
12782
+ const blankResult = {
12783
+ content: [{ type: "text", text: scanLines.join("\n") }],
12784
+ structuredContent: success(
12785
+ "Workspace is blank. Use the start_pb tool for guided setup.",
12786
+ { stage: "blank", readinessScore: readiness?.score ?? 0, oriented, orientationStatus: orientationStatus2, redirectHint: "Use the `start_pb` tool for the full guided setup experience." },
12787
+ [{ tool: "start_pb", description: "Guided workspace setup", parameters: {} }]
12788
+ )
12789
+ };
12790
+ reportOrientWrapperBytes(blankResult, false, resolvedTier, taskIsMeaningful(task));
12791
+ return blankResult;
12792
+ }
12793
+ const lines = [];
12794
+ const isLowReadiness = readiness && readiness.score < 50;
12795
+ if (wsCtx) {
12796
+ lines.push(`# ${wsCtx.workspaceName}`);
12797
+ lines.push(`_Workspace \`${wsCtx.workspaceSlug}\` \u2014 Product Brain is healthy._`);
12798
+ } else {
12799
+ lines.push("# Workspace");
12800
+ lines.push("_Could not resolve workspace._");
12801
+ }
12802
+ lines.push("");
12803
+ lines.push(...taskGroundingWarningLines(task, hasTaskGrounding));
12804
+ if (mode === "brief") {
12805
+ const briefStage = readiness?.stage ?? (readiness?.score != null ? readiness.score < 50 ? "seeded" : "grounded" : "unknown");
12806
+ lines.push(`Brain stage: ${briefStage}`);
12807
+ if (orientView?.strategicContext) {
12808
+ const sc = orientView.strategicContext;
12809
+ if (sc.vision) lines.push(`Vision: ${sc.vision}`);
12810
+ if (sc.purpose) lines.push(`Purpose: ${sc.purpose}`);
12811
+ if (sc.productAreaCount != null && sc.productAreaCount > 0) {
12812
+ lines.push(`Product areas (${sc.productAreaCount}): ${(sc.productAreas ?? []).join(", ")}`);
12813
+ }
12814
+ if (sc.playingFieldCount != null && sc.playingFieldCount > 0) {
12815
+ lines.push(`Playing field (${sc.playingFieldCount}): ${(sc.playingField ?? []).join(", ")}`);
12816
+ }
12817
+ const wpPlural = getCollectionLabel("work_package", "plural", vocabCtx);
12818
+ lines.push(`${sc.activeBetCount} active ${wpPlural}, ${sc.activeTensionCount} tension(s).`);
12819
+ }
12820
+ if (orientView?.taskContext && orientView.taskContext.context.length > 0) {
12821
+ lines.push(`Task context: ${orientView.taskContext.totalFound} relevant entries (${orientView.taskContext.confidence} confidence).`);
12822
+ if (orientView.taskContext.isGroundingStub && orientView.taskContext.groundingNote) {
12823
+ lines.push(`\u26A0\uFE0F ${orientView.taskContext.groundingNote}`);
12824
+ }
12825
+ }
12826
+ if (orientView?.startup?.domainRetrieval) {
12827
+ const retrieval = orientView.startup.domainRetrieval;
12828
+ const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
12829
+ lines.push(`Domain retrieval: ${retrieval.state}${scopedTo}`);
12830
+ if (retrieval.activeSource) lines.push(`Active source: ${retrieval.activeSource}`);
12831
+ if (retrieval.fallbackReason) lines.push(`Fallback: ${retrieval.fallbackReason}`);
12832
+ if (retrieval.fallbackAction) lines.push(`Action: ${retrieval.fallbackAction}`);
12833
+ if (retrieval.evidenceGap) lines.push(`Evidence gap: ${retrieval.evidenceGap}`);
12834
+ if (retrieval.directRatifiedCount != null || retrieval.inheritedRatifiedCount != null || retrieval.orgFallbackCount != null) {
12835
+ lines.push(`Domain relation evidence: ${retrieval.directRatifiedCount ?? 0} direct, ${retrieval.inheritedRatifiedCount ?? 0} inherited, ${retrieval.orgFallbackCount ?? 0} org fallback`);
12836
+ }
12837
+ }
12838
+ if (orientView?.writeBackHints && orientView.writeBackHints.length > 0) {
12839
+ lines.push("");
12840
+ lines.push("Write-back hints (what to capture this session):");
12841
+ for (const h of orientView.writeBackHints) {
12842
+ lines.push(` ${h.collectionSlug}: ${h.hint}`);
12672
12843
  }
12673
- if (orientView) {
12674
- priorSessions = orientView.priorSessions ?? [];
12675
- recoveryBlock = orientView.recoveryBlock ?? null;
12676
- }
12677
- const hasTaskGrounding = Boolean(task && orientView?.taskContext?.context?.length > 0);
12678
- if (wsCtx && hasTaskGrounding && orientView?.writeBackHints) {
12679
- const hints = Array.isArray(orientView.writeBackHints) ? orientView.writeBackHints : [];
12680
- if (hints.length > 0) {
12681
- trackWriteBackHintServed(wsCtx.workspaceId, {
12682
- hint_count: hints.length,
12683
- has_task: !!task
12684
- });
12685
- }
12844
+ }
12845
+ if (orientView?.activeWorkPackages?.length > 0) {
12846
+ for (const e of orientView.activeWorkPackages) {
12847
+ const tensions = e.linkedTensions;
12848
+ const tensionPart = tensions?.length ? ` \u2014 ${tensions.map((t) => `${t.entryId ?? t.name} (${t.severity ?? "\u2014"})`).join(", ")}` : "";
12849
+ const originPart = e.origin ? ` (origin: ${e.origin})` : "";
12850
+ lines.push(`- \`${e.entryId ?? e._id}\` ${e.name}${originPart}${tensionPart}`);
12686
12851
  }
12687
- let openTensions = [];
12688
- try {
12689
- const tensions = await kernelQuery("chain.listEntries", { collectionSlug: "tensions" });
12690
- openTensions = (tensions ?? []).filter((e) => e.workflowStatus === "open");
12691
- } catch {
12852
+ }
12853
+ if (orientView?.trustMetrics) {
12854
+ const tm = orientView.trustMetrics;
12855
+ if (tm.unverified > 0 || tm.verified > 0) {
12856
+ const capNote = tm.scannedCap ? "+" : "";
12857
+ lines.push(`Trust: ${tm.verified} verified, ${tm.unverified} unverified, ${tm.noStatus} no-status (${tm.total}${capNote} scanned).`);
12692
12858
  }
12693
- let allCollections = [];
12694
- try {
12695
- allCollections = await kernelQuery("chain.listCollections") ?? [];
12696
- } catch {
12859
+ }
12860
+ const briefWna = formatWhatNeedsAttentionBrief(orientView?.whatNeedsAttention);
12861
+ if (briefWna.length > 0) {
12862
+ lines.push("");
12863
+ lines.push(...briefWna);
12864
+ }
12865
+ const briefGaps = readiness?.gaps ?? [];
12866
+ if (briefGaps.length > 0) {
12867
+ const oneLiner = formatGapOneLiner(briefGaps[0]);
12868
+ if (oneLiner) lines.push(oneLiner);
12869
+ }
12870
+ const briefClassificationGaps = briefGaps.filter((g) => g.id?.startsWith?.(PURPOSE_GAP_PREFIX));
12871
+ if (briefClassificationGaps.length > 0) {
12872
+ lines.push(`${briefClassificationGaps.length} collection(s) with weak purpose \u2014 classification may be inaccurate.`);
12873
+ }
12874
+ if (recoveryBlock) {
12875
+ lines.push("");
12876
+ lines.push(...formatRecoveryBlock(recoveryBlock));
12877
+ } else if (priorSessions.length > 0) {
12878
+ const last = priorSessions[0];
12879
+ const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
12880
+ const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
12881
+ const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
12882
+ lines.push(`Last session (${date}): ${created} created, ${modified} modified`);
12883
+ }
12884
+ let coherenceSnapshot;
12885
+ const coherence = buildCoherenceSection();
12886
+ if (coherence) {
12887
+ lines.push("");
12888
+ lines.push(...coherence.lines);
12889
+ coherenceSnapshot = coherence.snapshot;
12890
+ }
12891
+ if (allCollections.length > 0) {
12892
+ const docCompleteness = buildDocCompletenessSection(allCollections);
12893
+ if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
12894
+ lines.push(...docCompleteness.lines);
12697
12895
  }
12698
- let readiness = null;
12699
- try {
12700
- readiness = await kernelQuery("chain.workspaceReadiness");
12701
- } catch (e) {
12702
- errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
12896
+ }
12897
+ if (orientView) {
12898
+ lines.push("");
12899
+ if (task) {
12900
+ const mapGovernanceEntry = (e) => ({
12901
+ entryId: e.entryId,
12902
+ name: e.name,
12903
+ description: typeof e.preview === "string" ? e.preview : void 0,
12904
+ tier: typeof e.tier === "number" ? e.tier : void 0,
12905
+ // Phase 4 (DEC-1141): thread provenance fields to buildOperatingProtocol.
12906
+ provenance: e.provenance,
12907
+ anchoredBy: typeof e.anchoredBy === "string" ? e.anchoredBy : void 0
12908
+ });
12909
+ const gov = orientView.governance ?? { principles: [], standards: [], businessRules: [] };
12910
+ lines.push(...buildOperatingProtocol({
12911
+ principles: (gov.principles ?? []).map(mapGovernanceEntry),
12912
+ standards: (gov.standards ?? []).map(mapGovernanceEntry),
12913
+ businessRules: (gov.businessRules ?? []).map(mapGovernanceEntry)
12914
+ }, task));
12915
+ } else {
12916
+ lines.push(...buildOperatingProtocol());
12703
12917
  }
12704
- if (readiness?.stage === "blank") {
12705
- const scanLines = [
12706
- `# Welcome to ${wsCtx?.workspaceName ?? "your workspace"}`,
12707
- "",
12708
- "Your workspace is fresh \u2014 let's set it up.",
12709
- "",
12710
- "**Recommended:** call the `start` tool instead of `orient` for the best first-run experience.",
12711
- "It will guide you through setting up your workspace \u2014 you can tell me about your product, scan your codebase, or use a preset.",
12712
- "",
12713
- "Or tell me about your product and I'll start capturing knowledge directly."
12714
- ];
12715
- let oriented = false;
12716
- let orientationStatus2 = "no_session";
12717
- if (agentSessionId) {
12718
- try {
12719
- await kernelCall("agent.markOriented", { sessionId: agentSessionId });
12720
- setSessionOriented(true);
12721
- oriented = true;
12722
- orientationStatus2 = "complete";
12723
- } catch {
12724
- orientationStatus2 = "failed";
12725
- }
12726
- }
12727
- const blankResult = {
12728
- content: [{ type: "text", text: scanLines.join("\n") }],
12729
- structuredContent: success(
12730
- "Workspace is blank. Use the start_pb tool for guided setup.",
12731
- { stage: "blank", readinessScore: readiness?.score ?? 0, oriented, orientationStatus: orientationStatus2, redirectHint: "Use the `start_pb` tool for the full guided setup experience." },
12732
- [{ tool: "start_pb", description: "Guided workspace setup", parameters: {} }]
12733
- )
12734
- };
12735
- reportOrientWrapperBytes(blankResult, false);
12736
- return blankResult;
12918
+ }
12919
+ let orientationStatus2 = "no_session";
12920
+ if (agentSessionId && hasTaskGrounding) {
12921
+ const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot);
12922
+ if (orientedOk) {
12923
+ orientationStatus2 = "complete";
12924
+ lines.push("---");
12925
+ lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
12926
+ } else {
12927
+ orientationStatus2 = "failed";
12928
+ lines.push("---");
12929
+ lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
12737
12930
  }
12738
- const lines = [];
12739
- const isLowReadiness = readiness && readiness.score < 50;
12740
- if (wsCtx) {
12741
- lines.push(`# ${wsCtx.workspaceName}`);
12742
- lines.push(`_Workspace \`${wsCtx.workspaceSlug}\` \u2014 Product Brain is healthy._`);
12931
+ } else if (agentSessionId) {
12932
+ orientationStatus2 = "task_required";
12933
+ lines.push("---");
12934
+ lines.push('Workspace orientation loaded. Write tools stay locked until you run `orient task="describe the work"`.');
12935
+ } else {
12936
+ lines.push("---");
12937
+ lines.push("_No active agent session. Call `session action=start` to begin._");
12938
+ }
12939
+ const briefTruncated = orientView?._budget?.truncated ?? orientView?._truncated ?? false;
12940
+ if (briefTruncated) {
12941
+ const reasons = orientView?._budget?.truncationReasons;
12942
+ lines.push("");
12943
+ if (reasons && reasons.length > 0) {
12944
+ lines.push(`_Context truncated to fit tier budget: ${reasons.join(", ")}. Use tier=full for complete payload._`);
12743
12945
  } else {
12744
- lines.push("# Workspace");
12745
- lines.push("_Could not resolve workspace._");
12946
+ lines.push("_Context truncated to fit tier budget. Use tier=full for complete payload._");
12746
12947
  }
12948
+ }
12949
+ if (errors.length > 0) {
12950
+ lines.push("");
12951
+ for (const err of errors) lines.push(`- ${err}`);
12952
+ }
12953
+ const briefResult = {
12954
+ content: [{ type: "text", text: lines.join("\n") }],
12955
+ structuredContent: success(
12956
+ `Oriented (brief). Stage: ${readiness?.stage ?? "unknown"}.`,
12957
+ {
12958
+ mode: "brief",
12959
+ stage: readiness?.stage ?? "unknown",
12960
+ oriented: hasTaskGrounding ? isSessionOriented() : false,
12961
+ sessionId: agentSessionId,
12962
+ taskGroundingStatus: hasTaskGrounding ? "task_scoped" : task ? "missing_task_context" : "workspace_only",
12963
+ taskGroundingRequired: !hasTaskGrounding,
12964
+ // STD-219 §4 (DEC-1147): machine-readable stub flag for agent consumers.
12965
+ ...orientView?.taskContext?.isGroundingStub ? { groundingStub: true } : {},
12966
+ orientationStatus: orientationStatus2,
12967
+ nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
12968
+ ...orientView?._budget ? { _budget: orientView._budget } : {}
12969
+ }
12970
+ )
12971
+ };
12972
+ reportOrientWrapperBytes(briefResult, briefTruncated, resolvedTier, taskIsMeaningful(task));
12973
+ return briefResult;
12974
+ }
12975
+ const orientStage = readiness?.stage ?? "seeded";
12976
+ if (isLowReadiness && wsCtx?.createdAt) {
12977
+ const ageDays = Math.floor((Date.now() - wsCtx.createdAt) / (1e3 * 60 * 60 * 24));
12978
+ if (ageDays >= 30) {
12979
+ lines.push(`Your workspace has been around for ${ageDays} days and is still at the **${orientStage}** stage.`);
12980
+ lines.push("Let's close the gaps \u2014 or if the current structure doesn't fit, we can reshape it.");
12747
12981
  lines.push("");
12748
- lines.push(...taskGroundingWarningLines(task, hasTaskGrounding));
12749
- if (mode === "brief") {
12750
- const briefStage = readiness?.stage ?? (readiness?.score != null ? readiness.score < 50 ? "seeded" : "grounded" : "unknown");
12751
- lines.push(`Brain stage: ${briefStage}`);
12752
- if (orientView?.strategicContext) {
12753
- const sc = orientView.strategicContext;
12754
- if (sc.vision) lines.push(`Vision: ${sc.vision}`);
12755
- if (sc.purpose) lines.push(`Purpose: ${sc.purpose}`);
12756
- if (sc.productAreaCount != null && sc.productAreaCount > 0) {
12757
- lines.push(`Product areas (${sc.productAreaCount}): ${(sc.productAreas ?? []).join(", ")}`);
12982
+ }
12983
+ }
12984
+ let fullCoherenceSnapshot;
12985
+ if (isLowReadiness) {
12986
+ const captureBehaviorNote = (readiness?.governanceMode ?? wsCtx?.governanceMode ?? "open") === "open" ? "_In Open mode, captures commit automatically unless you ask me to keep them as drafts._" : "_Everything stays as a draft until you confirm._";
12987
+ const gaps = readiness.gaps ?? [];
12988
+ if (gaps.length > 0) {
12989
+ const gapCtx = {
12990
+ stage: orientStage,
12991
+ passedChecks: readiness.passedChecks ?? 0,
12992
+ totalChecks: readiness.totalChecks ?? 0,
12993
+ score: readiness.score ?? 0
12994
+ };
12995
+ lines.push(formatTopGapPrompt(gaps[0], gaps.length - 1, gapCtx));
12996
+ lines.push("");
12997
+ lines.push(captureBehaviorNote);
12998
+ lines.push("");
12999
+ const remainingGaps = gaps.length - 1;
13000
+ if (remainingGaps > 0 || openTensions.length > 0) {
13001
+ const parts = [];
13002
+ if (remainingGaps > 0) parts.push(`${remainingGaps} more area${remainingGaps === 1 ? "" : "s"} to cover`);
13003
+ if (openTensions.length > 0) parts.push(`${openTensions.length} open tension${openTensions.length === 1 ? "" : "s"}`);
13004
+ lines.push(`_${parts.join(" and ")} \u2014 ask for full status to see everything._`);
13005
+ lines.push("");
13006
+ }
13007
+ }
13008
+ lines.push("_Need a collection that doesn't exist yet? Just ask \u2014 I'll set it up._");
13009
+ lines.push("");
13010
+ } else if (readiness) {
13011
+ const fmt = (e) => {
13012
+ const type = e.canonicalKey ?? "generic";
13013
+ const stratum = e.stratum ?? "?";
13014
+ const confidencePart = e.confidence ? ` [confidence: ${e.confidence}]` : "";
13015
+ const reviewOverdue = e.reviewAt && new Date(e.reviewAt).getTime() < Date.now();
13016
+ const overduePart = reviewOverdue ? " [review overdue]" : "";
13017
+ const originPart = e.origin ? ` (origin: ${e.origin})` : "";
13018
+ const mark = provenanceMark(e.provenance);
13019
+ const anchorSuffix = e.anchoredBy ? ` (${e.anchoredBy})` : "";
13020
+ return `- ${mark}\`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}${anchorSuffix}${originPart}${confidencePart}${overduePart}`;
13021
+ };
13022
+ const fullCoherence = buildCoherenceSection();
13023
+ if (fullCoherence) {
13024
+ fullCoherenceSnapshot = fullCoherence.snapshot;
13025
+ }
13026
+ if (task) {
13027
+ lines.push(`**Brain stage: ${orientStage}.** Working on: **${task}**`);
13028
+ lines.push("");
13029
+ if (orientView?.strategicContext) {
13030
+ const sc = orientView.strategicContext;
13031
+ lines.push("## Strategic Context");
13032
+ if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
13033
+ if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
13034
+ if (sc.productAreaCount != null && sc.productAreaCount > 0) {
13035
+ lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
13036
+ }
13037
+ if (sc.playingFieldCount != null && sc.playingFieldCount > 0) {
13038
+ lines.push(`**Playing field (${sc.playingFieldCount}):** ${(sc.playingField ?? []).join(", ")}`);
13039
+ }
13040
+ const currentWP = sc.currentWorkPackage;
13041
+ const wpSingularFull = getCollectionLabel("work_package", "singular", vocabCtx);
13042
+ const wpPluralFull = getCollectionLabel("work_package", "plural", vocabCtx);
13043
+ const betLine = currentWP ? `**Current ${wpSingularFull}:** ${currentWP}. ${sc.activeBetCount} active ${wpPluralFull}.` : `No active ${wpPluralFull}.`;
13044
+ lines.push(`${betLine} ${sc.activeTensionCount} open tension(s).`);
13045
+ lines.push("");
13046
+ }
13047
+ if (orientView?.continuingFrom && orientView.continuingFrom.length > 0) {
13048
+ lines.push("## Continuing from");
13049
+ lines.push("_Prior-session entries most relevant to your task._");
13050
+ lines.push("");
13051
+ for (const e of orientView.continuingFrom) {
13052
+ const id = e.entryId ?? e.name;
13053
+ const type = e.canonicalKey ?? "generic";
13054
+ const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
13055
+ lines.push(`- \`${id}\` (score ${e.score}) [${type}]${coll} \u2014 ${e.name}`);
13056
+ if (e.reasoning) lines.push(` _${e.reasoning}_`);
13057
+ if ("primer" in e && typeof e.primer === "string" && e.primer.length > 0) {
13058
+ const PRIMER_MAX = 1200;
13059
+ const primerText = e.primer.length > PRIMER_MAX ? e.primer.slice(0, PRIMER_MAX) + "\n\u2026 (truncated \u2014 use entries action=get for full primer)" : e.primer;
13060
+ lines.push("");
13061
+ lines.push(" **Primer (paste when starting implementation):**");
13062
+ lines.push(" ```");
13063
+ for (const line of primerText.split("\n")) lines.push(" " + line);
13064
+ lines.push(" ```");
13065
+ lines.push("");
12758
13066
  }
12759
- if (sc.playingFieldCount != null && sc.playingFieldCount > 0) {
12760
- lines.push(`Playing field (${sc.playingFieldCount}): ${(sc.playingField ?? []).join(", ")}`);
13067
+ }
13068
+ lines.push("");
13069
+ }
13070
+ if (orientView?.lastSessionTouched && orientView.lastSessionTouched.length > 0) {
13071
+ lines.push("## Last session touched");
13072
+ lines.push("_Entries created or modified in your most recent session._");
13073
+ lines.push("");
13074
+ for (const e of orientView.lastSessionTouched) {
13075
+ const id = e.entryId ?? e.name;
13076
+ const type = e.canonicalKey ?? "generic";
13077
+ const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
13078
+ lines.push(`- \`${id}\` [${type}]${coll} \u2014 ${e.name}`);
13079
+ if ("primer" in e && typeof e.primer === "string" && e.primer.length > 0) {
13080
+ const PRIMER_MAX = 1200;
13081
+ const primerText = e.primer.length > PRIMER_MAX ? e.primer.slice(0, PRIMER_MAX) + "\n\u2026 (truncated \u2014 use entries action=get for full primer)" : e.primer;
13082
+ lines.push("");
13083
+ lines.push(" **Primer:**");
13084
+ lines.push(" ```");
13085
+ for (const line of primerText.split("\n")) lines.push(" " + line);
13086
+ lines.push(" ```");
13087
+ lines.push("");
12761
13088
  }
12762
- const wpPlural = getCollectionLabel("work_package", "plural", vocabCtx);
12763
- lines.push(`${sc.activeBetCount} active ${wpPlural}, ${sc.activeTensionCount} tension(s).`);
12764
13089
  }
12765
- if (orientView?.taskContext && orientView.taskContext.context.length > 0) {
12766
- lines.push(`Task context: ${orientView.taskContext.totalFound} relevant entries (${orientView.taskContext.confidence} confidence).`);
13090
+ lines.push("");
13091
+ }
13092
+ if (orientView?.taskContext && orientView.taskContext.context.length > 0) {
13093
+ const tc = orientView.taskContext;
13094
+ lines.push("## Task Context");
13095
+ if (tc.isGroundingStub && tc.groundingNote) {
13096
+ lines.push(`> \u26A0\uFE0F ${tc.groundingNote}`);
13097
+ lines.push("");
12767
13098
  }
12768
- if (orientView?.startup?.domainRetrieval) {
13099
+ if (orientView.startup?.domainRetrieval) {
12769
13100
  const retrieval = orientView.startup.domainRetrieval;
12770
13101
  const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
12771
- lines.push(`Domain retrieval: ${retrieval.state}${scopedTo}`);
12772
- if (retrieval.activeSource) lines.push(`Active source: ${retrieval.activeSource}`);
12773
- if (retrieval.fallbackReason) lines.push(`Fallback: ${retrieval.fallbackReason}`);
12774
- if (retrieval.fallbackAction) lines.push(`Action: ${retrieval.fallbackAction}`);
12775
- if (retrieval.evidenceGap) lines.push(`Evidence gap: ${retrieval.evidenceGap}`);
12776
- if (retrieval.directRatifiedCount != null || retrieval.inheritedRatifiedCount != null || retrieval.orgFallbackCount != null) {
12777
- lines.push(`Domain relation evidence: ${retrieval.directRatifiedCount ?? 0} direct, ${retrieval.inheritedRatifiedCount ?? 0} inherited, ${retrieval.orgFallbackCount ?? 0} org fallback`);
12778
- }
12779
- }
12780
- if (orientView?.writeBackHints && orientView.writeBackHints.length > 0) {
13102
+ lines.push(`_Domain retrieval: ${retrieval.state}${scopedTo}_`);
13103
+ if (retrieval.activeSource) lines.push(`_Active source: ${retrieval.activeSource}_`);
13104
+ if (retrieval.fallbackReason) lines.push(`_${retrieval.fallbackReason}_`);
13105
+ if (retrieval.fallbackAction) lines.push(`_${retrieval.fallbackAction}_`);
13106
+ if (retrieval.evidenceGap) lines.push(`_Evidence gap: ${retrieval.evidenceGap}_`);
12781
13107
  lines.push("");
12782
- lines.push("Write-back hints (what to capture this session):");
12783
- for (const h of orientView.writeBackHints) {
12784
- lines.push(` ${h.collectionSlug}: ${h.hint}`);
12785
- }
12786
13108
  }
12787
- if (orientView?.activeWorkPackages?.length > 0) {
12788
- for (const e of orientView.activeWorkPackages) {
12789
- const tensions = e.linkedTensions;
12790
- const tensionPart = tensions?.length ? ` \u2014 ${tensions.map((t) => `${t.entryId ?? t.name} (${t.severity ?? "\u2014"})`).join(", ")}` : "";
12791
- const originPart = e.origin ? ` (origin: ${e.origin})` : "";
12792
- lines.push(`- \`${e.entryId ?? e._id}\` ${e.name}${originPart}${tensionPart}`);
12793
- }
13109
+ lines.push(`_Task-scoped entries (${tc.confidence} confidence, ${tc.totalFound} relevant)`);
13110
+ lines.push("");
13111
+ for (const e of tc.context) {
13112
+ const id = e.entryId ?? e.name;
13113
+ const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
13114
+ const originTag = e.origin ? ` (origin: ${e.origin})` : "";
13115
+ lines.push(`- \`${id}\` (score ${e.score})${coll}${originTag}${e.name !== id ? ` \u2014 ${e.name}` : ""}`);
13116
+ if (e.preview) lines.push(` _${e.preview}_`);
13117
+ }
13118
+ lines.push("");
13119
+ }
13120
+ if (orientView?.taskContext?.constellationEntries && orientView.taskContext.constellationEntries.length > 0) {
13121
+ lines.push(...formatBetConstellationLines(
13122
+ orientView.taskContext.constellationEntries,
13123
+ orientView.taskContext.constellationBetName
13124
+ ));
13125
+ }
13126
+ if (orientView?.writeBackHints && orientView.writeBackHints.length > 0) {
13127
+ lines.push("");
13128
+ lines.push("## Write-Back Hints");
13129
+ lines.push("_What to capture this session (derived from task context):_");
13130
+ lines.push("");
13131
+ for (const h of orientView.writeBackHints) {
13132
+ lines.push(`- **${h.collectionSlug}**: ${h.hint}`);
12794
13133
  }
12795
- if (orientView?.trustMetrics) {
13134
+ lines.push("");
13135
+ }
13136
+ if (orientView) {
13137
+ const result = await runAlignmentCheck(
13138
+ task,
13139
+ orientView.activeWorkPackages ?? [],
13140
+ orientView.taskContext?.context
13141
+ );
13142
+ lines.push(...buildAlignmentCheckLines(result));
13143
+ lines.push(...formatInitiativeStatusLines(orientView.initiativeStatus));
13144
+ lines.push(...formatWorkstreamHealthLines(orientView.workstreamHealth));
13145
+ lines.push(...formatWhatNeedsAttentionLines(orientView.whatNeedsAttention));
13146
+ if (orientView.trustMetrics) {
12796
13147
  const tm = orientView.trustMetrics;
12797
- if (tm.unverified > 0 || tm.verified > 0) {
12798
- const capNote = tm.scannedCap ? "+" : "";
12799
- lines.push(`Trust: ${tm.verified} verified, ${tm.unverified} unverified, ${tm.noStatus} no-status (${tm.total}${capNote} scanned).`);
13148
+ if (tm.verified > 0 || tm.unverified > 0) {
13149
+ const capNote = tm.scannedCap ? " (capped at 500)" : "";
13150
+ lines.push("## Trust metrics");
13151
+ lines.push(`_Entry verification status across workspace${capNote}._`);
13152
+ lines.push("");
13153
+ lines.push(`- **Verified:** ${tm.verified}`);
13154
+ lines.push(`- **Unverified:** ${tm.unverified}`);
13155
+ lines.push(`- **No status (pre-BET-240):** ${tm.noStatus}`);
13156
+ lines.push(`- **Total scanned:** ${tm.total}`);
13157
+ lines.push("");
12800
13158
  }
12801
13159
  }
12802
- const briefWna = formatWhatNeedsAttentionBrief(orientView?.whatNeedsAttention);
12803
- if (briefWna.length > 0) {
12804
- lines.push("");
12805
- lines.push(...briefWna);
12806
- }
12807
- const briefGaps = readiness?.gaps ?? [];
12808
- if (briefGaps.length > 0) {
12809
- const oneLiner = formatGapOneLiner(briefGaps[0]);
12810
- if (oneLiner) lines.push(oneLiner);
12811
- }
12812
- const briefClassificationGaps = briefGaps.filter((g) => g.id?.startsWith?.(PURPOSE_GAP_PREFIX));
12813
- if (briefClassificationGaps.length > 0) {
12814
- lines.push(`${briefClassificationGaps.length} collection(s) with weak purpose \u2014 classification may be inaccurate.`);
13160
+ }
13161
+ if (fullCoherence) {
13162
+ lines.push(...fullCoherence.lines);
13163
+ }
13164
+ if (allCollections.length > 0) {
13165
+ const docCompleteness = buildDocCompletenessSection(allCollections);
13166
+ if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
13167
+ lines.push(...docCompleteness.lines);
12815
13168
  }
12816
- if (recoveryBlock) {
12817
- lines.push("");
12818
- lines.push(...formatRecoveryBlock(recoveryBlock));
12819
- } else if (priorSessions.length > 0) {
12820
- const last = priorSessions[0];
12821
- const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
12822
- const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
12823
- const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
12824
- lines.push(`Last session (${date}): ${created} created, ${modified} modified`);
12825
- }
12826
- let coherenceSnapshot;
12827
- const coherence = buildCoherenceSection();
12828
- if (coherence) {
13169
+ }
13170
+ if (orientView) {
13171
+ if (orientView.activeWorkPackages?.length > 0) {
13172
+ lines.push("## Active work packages \u2014 current scope");
13173
+ lines.push("_Work outside these work packages requires explicit user confirmation._");
12829
13174
  lines.push("");
12830
- lines.push(...coherence.lines);
12831
- coherenceSnapshot = coherence.snapshot;
12832
- }
12833
- if (allCollections.length > 0) {
12834
- const docCompleteness = buildDocCompletenessSection(allCollections);
12835
- if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
12836
- lines.push(...docCompleteness.lines);
13175
+ for (const e of orientView.activeWorkPackages) {
13176
+ lines.push(fmt(e));
13177
+ const tensions = e.linkedTensions;
13178
+ if (tensions?.length) {
13179
+ const tensionLines = tensions.map((t) => {
13180
+ const meta = [t.severity, t.priority].filter(Boolean).join(", ");
13181
+ return `\`${t.entryId ?? t.name}\` (${t.name}${meta ? `, ${meta}` : ""})`;
13182
+ });
13183
+ lines.push(` Tensions: ${tensionLines.join("; ")}`);
13184
+ }
12837
13185
  }
12838
- }
12839
- if (orientView) {
12840
13186
  lines.push("");
12841
- if (task) {
12842
- const mapGovernanceEntry = (e) => ({
12843
- entryId: e.entryId,
12844
- name: e.name,
12845
- description: typeof e.preview === "string" ? e.preview : void 0,
12846
- tier: typeof e.tier === "number" ? e.tier : void 0,
12847
- // Phase 4 (DEC-1141): thread provenance fields to buildOperatingProtocol.
12848
- provenance: e.provenance,
12849
- anchoredBy: typeof e.anchoredBy === "string" ? e.anchoredBy : void 0
12850
- });
12851
- const gov = orientView.governance ?? { principles: [], standards: [], businessRules: [] };
12852
- lines.push(...buildOperatingProtocol({
12853
- principles: (gov.principles ?? []).map(mapGovernanceEntry),
12854
- standards: (gov.standards ?? []).map(mapGovernanceEntry),
12855
- businessRules: (gov.businessRules ?? []).map(mapGovernanceEntry)
12856
- }, task));
12857
- } else {
12858
- lines.push(...buildOperatingProtocol());
12859
- }
12860
- }
12861
- let orientationStatus2 = "no_session";
12862
- if (agentSessionId && hasTaskGrounding) {
12863
- const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot);
12864
- if (orientedOk) {
12865
- orientationStatus2 = "complete";
12866
- lines.push("---");
12867
- lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
12868
- } else {
12869
- orientationStatus2 = "failed";
12870
- lines.push("---");
12871
- lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
12872
- }
12873
- } else if (agentSessionId) {
12874
- orientationStatus2 = "task_required";
12875
- lines.push("---");
12876
- lines.push('Workspace orientation loaded. Write tools stay locked until you run `orient task="describe the work"`.');
12877
- } else {
12878
- lines.push("---");
12879
- lines.push("_No active agent session. Call `session action=start` to begin._");
12880
13187
  }
12881
- const briefTruncated = orientView?._budget?.truncated ?? orientView?._truncated ?? false;
12882
- if (briefTruncated) {
12883
- const reasons = orientView?._budget?.truncationReasons;
13188
+ if (orientView.activeGoals?.length > 0) {
13189
+ lines.push("## Active goals");
13190
+ orientView.activeGoals.forEach((e) => lines.push(fmt(e)));
12884
13191
  lines.push("");
12885
- if (reasons && reasons.length > 0) {
12886
- lines.push(`_Context truncated to fit tier budget: ${reasons.join(", ")}. Use tier=full for complete payload._`);
12887
- } else {
12888
- lines.push("_Context truncated to fit tier budget. Use tier=full for complete payload._");
12889
- }
12890
13192
  }
12891
- if (errors.length > 0) {
13193
+ if (orientView.strategyHighlights?.length > 0) {
13194
+ lines.push("## Strategy highlights");
13195
+ lines.push("_One-sentence strategy, positioning, moat, business model, GTM \u2014 high-level strategic context._");
12892
13196
  lines.push("");
12893
- for (const err of errors) lines.push(`- ${err}`);
12894
- }
12895
- const briefResult = {
12896
- content: [{ type: "text", text: lines.join("\n") }],
12897
- structuredContent: success(
12898
- `Oriented (brief). Stage: ${readiness?.stage ?? "unknown"}.`,
12899
- {
12900
- mode: "brief",
12901
- stage: readiness?.stage ?? "unknown",
12902
- oriented: hasTaskGrounding ? isSessionOriented() : false,
12903
- sessionId: agentSessionId,
12904
- taskGroundingStatus: hasTaskGrounding ? "task_scoped" : task ? "missing_task_context" : "workspace_only",
12905
- taskGroundingRequired: !hasTaskGrounding,
12906
- orientationStatus: orientationStatus2,
12907
- nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
12908
- ...orientView?._budget ? { _budget: orientView._budget } : {}
12909
- }
12910
- )
12911
- };
12912
- reportOrientWrapperBytes(briefResult, briefTruncated);
12913
- return briefResult;
12914
- }
12915
- const orientStage = readiness?.stage ?? "seeded";
12916
- if (isLowReadiness && wsCtx?.createdAt) {
12917
- const ageDays = Math.floor((Date.now() - wsCtx.createdAt) / (1e3 * 60 * 60 * 24));
12918
- if (ageDays >= 30) {
12919
- lines.push(`Your workspace has been around for ${ageDays} days and is still at the **${orientStage}** stage.`);
12920
- lines.push("Let's close the gaps \u2014 or if the current structure doesn't fit, we can reshape it.");
13197
+ orientView.strategyHighlights.forEach((e) => lines.push(fmt(e)));
12921
13198
  lines.push("");
12922
13199
  }
12923
- }
12924
- let fullCoherenceSnapshot;
12925
- if (isLowReadiness) {
12926
- const captureBehaviorNote = (readiness?.governanceMode ?? wsCtx?.governanceMode ?? "open") === "open" ? "_In Open mode, captures commit automatically unless you ask me to keep them as drafts._" : "_Everything stays as a draft until you confirm._";
12927
- const gaps = readiness.gaps ?? [];
12928
- if (gaps.length > 0) {
12929
- const gapCtx = {
12930
- stage: orientStage,
12931
- passedChecks: readiness.passedChecks ?? 0,
12932
- totalChecks: readiness.totalChecks ?? 0,
12933
- score: readiness.score ?? 0
12934
- };
12935
- lines.push(formatTopGapPrompt(gaps[0], gaps.length - 1, gapCtx));
13200
+ if (orientView.playingField?.length > 0) {
13201
+ lines.push("## Playing field");
13202
+ lines.push("_Products and opportunities in the strategic landscape._");
12936
13203
  lines.push("");
12937
- lines.push(captureBehaviorNote);
13204
+ orientView.playingField.forEach((e) => lines.push(fmt(e)));
12938
13205
  lines.push("");
12939
- const remainingGaps = gaps.length - 1;
12940
- if (remainingGaps > 0 || openTensions.length > 0) {
12941
- const parts = [];
12942
- if (remainingGaps > 0) parts.push(`${remainingGaps} more area${remainingGaps === 1 ? "" : "s"} to cover`);
12943
- if (openTensions.length > 0) parts.push(`${openTensions.length} open tension${openTensions.length === 1 ? "" : "s"}`);
12944
- lines.push(`_${parts.join(" and ")} \u2014 ask for full status to see everything._`);
12945
- lines.push("");
12946
- }
12947
13206
  }
12948
- lines.push("_Need a collection that doesn't exist yet? Just ask \u2014 I'll set it up._");
12949
- lines.push("");
12950
- } else if (readiness) {
12951
- const fmt = (e) => {
12952
- const type = e.canonicalKey ?? "generic";
12953
- const stratum = e.stratum ?? "?";
12954
- const confidencePart = e.confidence ? ` [confidence: ${e.confidence}]` : "";
12955
- const reviewOverdue = e.reviewAt && new Date(e.reviewAt).getTime() < Date.now();
12956
- const overduePart = reviewOverdue ? " [review overdue]" : "";
12957
- const originPart = e.origin ? ` (origin: ${e.origin})` : "";
12958
- const mark = provenanceMark(e.provenance);
12959
- const anchorSuffix = e.anchoredBy ? ` (${e.anchoredBy})` : "";
12960
- return `- ${mark}\`${e.entryId ?? e._id}\` [${type} \xB7 ${stratum}] ${e.name}${anchorSuffix}${originPart}${confidencePart}${overduePart}`;
12961
- };
12962
- const fullCoherence = buildCoherenceSection();
12963
- if (fullCoherence) {
12964
- fullCoherenceSnapshot = fullCoherence.snapshot;
13207
+ if (orientView.recentDecisions?.length > 0) {
13208
+ lines.push("## Recent decisions");
13209
+ orientView.recentDecisions.forEach((e) => lines.push(fmt(e)));
13210
+ lines.push("");
12965
13211
  }
12966
- if (task) {
12967
- lines.push(`**Brain stage: ${orientStage}.** Working on: **${task}**`);
13212
+ if (orientView.recentlySuperseded?.length > 0) {
13213
+ lines.push("## Recently superseded");
13214
+ orientView.recentlySuperseded.forEach((e) => lines.push(fmt(e)));
12968
13215
  lines.push("");
12969
- if (orientView?.strategicContext) {
12970
- const sc = orientView.strategicContext;
12971
- lines.push("## Strategic Context");
12972
- if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
12973
- if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
12974
- if (sc.productAreaCount != null && sc.productAreaCount > 0) {
12975
- lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
12976
- }
12977
- if (sc.playingFieldCount != null && sc.playingFieldCount > 0) {
12978
- lines.push(`**Playing field (${sc.playingFieldCount}):** ${(sc.playingField ?? []).join(", ")}`);
12979
- }
12980
- const currentWP = sc.currentWorkPackage;
12981
- const wpSingularFull = getCollectionLabel("work_package", "singular", vocabCtx);
12982
- const wpPluralFull = getCollectionLabel("work_package", "plural", vocabCtx);
12983
- const betLine = currentWP ? `**Current ${wpSingularFull}:** ${currentWP}. ${sc.activeBetCount} active ${wpPluralFull}.` : `No active ${wpPluralFull}.`;
12984
- lines.push(`${betLine} ${sc.activeTensionCount} open tension(s).`);
12985
- lines.push("");
12986
- }
12987
- if (orientView?.continuingFrom && orientView.continuingFrom.length > 0) {
12988
- lines.push("## Continuing from");
12989
- lines.push("_Prior-session entries most relevant to your task._");
12990
- lines.push("");
12991
- for (const e of orientView.continuingFrom) {
12992
- const id = e.entryId ?? e.name;
12993
- const type = e.canonicalKey ?? "generic";
12994
- const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
12995
- lines.push(`- \`${id}\` (score ${e.score}) [${type}]${coll} \u2014 ${e.name}`);
12996
- if (e.reasoning) lines.push(` _${e.reasoning}_`);
12997
- if ("primer" in e && typeof e.primer === "string" && e.primer.length > 0) {
12998
- const PRIMER_MAX = 1200;
12999
- const primerText = e.primer.length > PRIMER_MAX ? e.primer.slice(0, PRIMER_MAX) + "\n\u2026 (truncated \u2014 use entries action=get for full primer)" : e.primer;
13000
- lines.push("");
13001
- lines.push(" **Primer (paste when starting implementation):**");
13002
- lines.push(" ```");
13003
- for (const line of primerText.split("\n")) lines.push(" " + line);
13004
- lines.push(" ```");
13005
- lines.push("");
13006
- }
13007
- }
13008
- lines.push("");
13009
- }
13010
- if (orientView?.lastSessionTouched && orientView.lastSessionTouched.length > 0) {
13011
- lines.push("## Last session touched");
13012
- lines.push("_Entries created or modified in your most recent session._");
13013
- lines.push("");
13014
- for (const e of orientView.lastSessionTouched) {
13015
- const id = e.entryId ?? e.name;
13016
- const type = e.canonicalKey ?? "generic";
13017
- const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
13018
- lines.push(`- \`${id}\` [${type}]${coll} \u2014 ${e.name}`);
13019
- if ("primer" in e && typeof e.primer === "string" && e.primer.length > 0) {
13020
- const PRIMER_MAX = 1200;
13021
- const primerText = e.primer.length > PRIMER_MAX ? e.primer.slice(0, PRIMER_MAX) + "\n\u2026 (truncated \u2014 use entries action=get for full primer)" : e.primer;
13022
- lines.push("");
13023
- lines.push(" **Primer:**");
13024
- lines.push(" ```");
13025
- for (const line of primerText.split("\n")) lines.push(" " + line);
13026
- lines.push(" ```");
13027
- lines.push("");
13028
- }
13029
- }
13030
- lines.push("");
13031
- }
13032
- if (orientView?.taskContext && orientView.taskContext.context.length > 0) {
13033
- const tc = orientView.taskContext;
13034
- lines.push("## Task Context");
13035
- if (orientView.startup?.domainRetrieval) {
13036
- const retrieval = orientView.startup.domainRetrieval;
13037
- const scopedTo = retrieval.resolvedDomainSlug ? ` (${retrieval.resolvedDomainSlug})` : "";
13038
- lines.push(`_Domain retrieval: ${retrieval.state}${scopedTo}_`);
13039
- if (retrieval.activeSource) lines.push(`_Active source: ${retrieval.activeSource}_`);
13040
- if (retrieval.fallbackReason) lines.push(`_${retrieval.fallbackReason}_`);
13041
- if (retrieval.fallbackAction) lines.push(`_${retrieval.fallbackAction}_`);
13042
- if (retrieval.evidenceGap) lines.push(`_Evidence gap: ${retrieval.evidenceGap}_`);
13043
- lines.push("");
13044
- }
13045
- lines.push(`_Task-scoped entries (${tc.confidence} confidence, ${tc.totalFound} relevant)`);
13046
- lines.push("");
13047
- for (const e of tc.context) {
13048
- const id = e.entryId ?? e.name;
13049
- const coll = e.collectionSlug ? ` [${e.collectionSlug}]` : "";
13050
- const originTag = e.origin ? ` (origin: ${e.origin})` : "";
13051
- lines.push(`- \`${id}\` (score ${e.score})${coll}${originTag}${e.name !== id ? ` \u2014 ${e.name}` : ""}`);
13052
- if (e.preview) lines.push(` _${e.preview}_`);
13053
- }
13054
- lines.push("");
13055
- }
13056
- if (orientView?.taskContext?.constellationEntries && orientView.taskContext.constellationEntries.length > 0) {
13057
- lines.push(...formatBetConstellationLines(
13058
- orientView.taskContext.constellationEntries,
13059
- orientView.taskContext.constellationBetName
13060
- ));
13061
- }
13062
- if (orientView?.writeBackHints && orientView.writeBackHints.length > 0) {
13063
- lines.push("");
13064
- lines.push("## Write-Back Hints");
13065
- lines.push("_What to capture this session (derived from task context):_");
13066
- lines.push("");
13067
- for (const h of orientView.writeBackHints) {
13068
- lines.push(`- **${h.collectionSlug}**: ${h.hint}`);
13069
- }
13070
- lines.push("");
13071
- }
13072
- if (orientView) {
13073
- const result = await runAlignmentCheck(
13074
- task,
13075
- orientView.activeWorkPackages ?? [],
13076
- orientView.taskContext?.context
13077
- );
13078
- lines.push(...buildAlignmentCheckLines(result));
13079
- lines.push(...formatInitiativeStatusLines(orientView.initiativeStatus));
13080
- lines.push(...formatWorkstreamHealthLines(orientView.workstreamHealth));
13081
- lines.push(...formatWhatNeedsAttentionLines(orientView.whatNeedsAttention));
13082
- if (orientView.trustMetrics) {
13083
- const tm = orientView.trustMetrics;
13084
- if (tm.verified > 0 || tm.unverified > 0) {
13085
- const capNote = tm.scannedCap ? " (capped at 500)" : "";
13086
- lines.push("## Trust metrics");
13087
- lines.push(`_Entry verification status across workspace${capNote}._`);
13088
- lines.push("");
13089
- lines.push(`- **Verified:** ${tm.verified}`);
13090
- lines.push(`- **Unverified:** ${tm.unverified}`);
13091
- lines.push(`- **No status (pre-BET-240):** ${tm.noStatus}`);
13092
- lines.push(`- **Total scanned:** ${tm.total}`);
13093
- lines.push("");
13094
- }
13095
- }
13096
- }
13097
- if (fullCoherence) {
13098
- lines.push(...fullCoherence.lines);
13099
- }
13100
- if (allCollections.length > 0) {
13101
- const docCompleteness = buildDocCompletenessSection(allCollections);
13102
- if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
13103
- lines.push(...docCompleteness.lines);
13104
- }
13105
- }
13106
- if (orientView) {
13107
- if (orientView.activeWorkPackages?.length > 0) {
13108
- lines.push("## Active work packages \u2014 current scope");
13109
- lines.push("_Work outside these work packages requires explicit user confirmation._");
13110
- lines.push("");
13111
- for (const e of orientView.activeWorkPackages) {
13112
- lines.push(fmt(e));
13113
- const tensions = e.linkedTensions;
13114
- if (tensions?.length) {
13115
- const tensionLines = tensions.map((t) => {
13116
- const meta = [t.severity, t.priority].filter(Boolean).join(", ");
13117
- return `\`${t.entryId ?? t.name}\` (${t.name}${meta ? `, ${meta}` : ""})`;
13118
- });
13119
- lines.push(` Tensions: ${tensionLines.join("; ")}`);
13120
- }
13121
- }
13122
- lines.push("");
13123
- }
13124
- if (orientView.activeGoals?.length > 0) {
13125
- lines.push("## Active goals");
13126
- orientView.activeGoals.forEach((e) => lines.push(fmt(e)));
13127
- lines.push("");
13128
- }
13129
- if (orientView.strategyHighlights?.length > 0) {
13130
- lines.push("## Strategy highlights");
13131
- lines.push("_One-sentence strategy, positioning, moat, business model, GTM \u2014 high-level strategic context._");
13132
- lines.push("");
13133
- orientView.strategyHighlights.forEach((e) => lines.push(fmt(e)));
13134
- lines.push("");
13135
- }
13136
- if (orientView.playingField?.length > 0) {
13137
- lines.push("## Playing field");
13138
- lines.push("_Products and opportunities in the strategic landscape._");
13139
- lines.push("");
13140
- orientView.playingField.forEach((e) => lines.push(fmt(e)));
13141
- lines.push("");
13142
- }
13143
- if (orientView.recentDecisions?.length > 0) {
13144
- lines.push("## Recent decisions");
13145
- orientView.recentDecisions.forEach((e) => lines.push(fmt(e)));
13146
- lines.push("");
13147
- }
13148
- if (orientView.recentlySuperseded?.length > 0) {
13149
- lines.push("## Recently superseded");
13150
- orientView.recentlySuperseded.forEach((e) => lines.push(fmt(e)));
13151
- lines.push("");
13152
- }
13153
- if (orientView.staleEntries?.length > 0) {
13154
- lines.push("## Needs confirmation");
13155
- lines.push(`_Domain stratum entries not confirmed in ${orientView.stalenessThresholdDays} days._`);
13156
- orientView.staleEntries.forEach((e) => lines.push(fmt(e)));
13157
- lines.push("");
13158
- }
13159
- if (orientView.architectureNotes?.length > 0) {
13160
- lines.push("## Architecture notes");
13161
- orientView.architectureNotes.forEach((e) => lines.push(fmt(e)));
13162
- lines.push("");
13163
- }
13164
- const mapGovernanceEntry = (e) => ({
13165
- entryId: e.entryId,
13166
- name: e.name,
13167
- description: typeof e.preview === "string" ? e.preview : void 0,
13168
- tier: typeof e.tier === "number" ? e.tier : void 0,
13169
- // Phase 4 (DEC-1141): thread provenance fields to buildOperatingProtocol.
13170
- provenance: e.provenance,
13171
- anchoredBy: typeof e.anchoredBy === "string" ? e.anchoredBy : void 0
13172
- });
13173
- const gov = orientView.governance ?? { principles: [], standards: [], businessRules: [] };
13174
- lines.push(...buildOperatingProtocol({
13175
- principles: (gov.principles ?? []).map(mapGovernanceEntry),
13176
- standards: (gov.standards ?? []).map(mapGovernanceEntry),
13177
- businessRules: (gov.businessRules ?? []).map(mapGovernanceEntry)
13178
- }, task));
13179
- }
13180
- let allEntries = [];
13181
- try {
13182
- allEntries = await kernelQuery("chain.listEntries", {}) ?? [];
13183
- } catch {
13184
- }
13185
- const plannedWork = buildPlannedWork(allEntries);
13186
- if (hasPlannedWork(plannedWork)) {
13187
- lines.push(...buildPlannedWorkSection(plannedWork, priorSessions, recoveryBlock));
13188
- } else if (recoveryBlock) {
13189
- lines.push(...formatRecoveryBlock(recoveryBlock));
13190
- }
13191
- } else {
13192
- lines.push(`**Brain stage: ${orientStage}.**`);
13216
+ }
13217
+ if (orientView.staleEntries?.length > 0) {
13218
+ lines.push("## Needs confirmation");
13219
+ lines.push(`_Domain stratum entries not confirmed in ${orientView.stalenessThresholdDays} days._`);
13220
+ orientView.staleEntries.forEach((e) => lines.push(fmt(e)));
13193
13221
  lines.push("");
13194
- if (orientView?.activeWorkPackages?.length) {
13195
- lines.push("## Active work packages \u2014 current scope");
13196
- lines.push("_Work outside these work packages requires explicit user confirmation._");
13197
- lines.push("");
13198
- for (const e of orientView.activeWorkPackages) {
13199
- lines.push(fmt(e));
13200
- }
13201
- lines.push("");
13202
- }
13203
- lines.push(...formatInitiativeStatusLines(orientView?.initiativeStatus));
13204
- lines.push(...formatWorkstreamHealthLines(orientView?.workstreamHealth));
13205
- lines.push(...formatWhatNeedsAttentionLines(orientView?.whatNeedsAttention));
13206
- if (orientView?.trustMetrics) {
13207
- const tm = orientView.trustMetrics;
13208
- if (tm.verified > 0 || tm.unverified > 0) {
13209
- const capNote = tm.scannedCap ? " (capped at 500)" : "";
13210
- lines.push("## Trust metrics");
13211
- lines.push(`_Entry verification status across workspace${capNote}._`);
13212
- lines.push("");
13213
- lines.push(`- **Verified:** ${tm.verified}`);
13214
- lines.push(`- **Unverified:** ${tm.unverified}`);
13215
- lines.push(`- **No status (pre-BET-240):** ${tm.noStatus}`);
13216
- lines.push(`- **Total scanned:** ${tm.total}`);
13217
- lines.push("");
13218
- }
13219
- }
13220
- lines.push(...buildOperatingProtocol());
13221
- if (fullCoherence) {
13222
- lines.push(...fullCoherence.lines);
13223
- }
13224
- if (allCollections.length > 0) {
13225
- const docCompleteness = buildDocCompletenessSection(allCollections);
13226
- if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
13227
- lines.push(...docCompleteness.lines);
13228
- }
13229
- }
13230
- if (priorSessions.length > 0 && !recoveryBlock) {
13231
- const last = priorSessions[0];
13232
- const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
13233
- const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
13234
- const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
13235
- lines.push(`_Last session (${date}): ${created} created, ${modified} modified._`);
13236
- lines.push("");
13237
- }
13238
- if (recoveryBlock) {
13239
- lines.push(...formatRecoveryBlock(recoveryBlock));
13240
- }
13241
- lines.push("**What are you working on?** Tell me and I'll load relevant governance and context.");
13222
+ }
13223
+ if (orientView.architectureNotes?.length > 0) {
13224
+ lines.push("## Architecture notes");
13225
+ orientView.architectureNotes.forEach((e) => lines.push(fmt(e)));
13242
13226
  lines.push("");
13243
13227
  }
13228
+ const mapGovernanceEntry = (e) => ({
13229
+ entryId: e.entryId,
13230
+ name: e.name,
13231
+ description: typeof e.preview === "string" ? e.preview : void 0,
13232
+ tier: typeof e.tier === "number" ? e.tier : void 0,
13233
+ // Phase 4 (DEC-1141): thread provenance fields to buildOperatingProtocol.
13234
+ provenance: e.provenance,
13235
+ anchoredBy: typeof e.anchoredBy === "string" ? e.anchoredBy : void 0
13236
+ });
13237
+ const gov = orientView.governance ?? { principles: [], standards: [], businessRules: [] };
13238
+ lines.push(...buildOperatingProtocol({
13239
+ principles: (gov.principles ?? []).map(mapGovernanceEntry),
13240
+ standards: (gov.standards ?? []).map(mapGovernanceEntry),
13241
+ businessRules: (gov.businessRules ?? []).map(mapGovernanceEntry)
13242
+ }, task));
13243
+ }
13244
+ let allEntries = [];
13245
+ try {
13246
+ allEntries = await kernelQuery("chain.listEntries", {}) ?? [];
13247
+ } catch {
13248
+ }
13249
+ const plannedWork = buildPlannedWork(allEntries);
13250
+ if (hasPlannedWork(plannedWork)) {
13251
+ lines.push(...buildPlannedWorkSection(plannedWork, priorSessions, recoveryBlock));
13252
+ } else if (recoveryBlock) {
13253
+ lines.push(...formatRecoveryBlock(recoveryBlock));
13244
13254
  }
13245
- const classificationGaps = readiness?.gaps?.filter((g) => g.id?.startsWith?.(PURPOSE_GAP_PREFIX)) ?? [];
13246
- if (classificationGaps.length > 0) {
13247
- lines.push("## Classification gaps");
13248
- lines.push("_Collections with weak purpose \u2014 entry classification may be inaccurate._");
13255
+ } else {
13256
+ lines.push(`**Brain stage: ${orientStage}.**`);
13257
+ lines.push("");
13258
+ if (orientView?.activeWorkPackages?.length) {
13259
+ lines.push("## Active work packages \u2014 current scope");
13260
+ lines.push("_Work outside these work packages requires explicit user confirmation._");
13249
13261
  lines.push("");
13250
- for (const g of classificationGaps) {
13251
- lines.push(`- ${g.label ?? g.id?.replace?.("purpose-gap-", "") ?? "unknown"}`);
13262
+ for (const e of orientView.activeWorkPackages) {
13263
+ lines.push(fmt(e));
13252
13264
  }
13253
13265
  lines.push("");
13254
13266
  }
13255
- if (errors.length > 0) {
13256
- lines.push("## Errors");
13257
- for (const err of errors) lines.push(`- ${err}`);
13258
- lines.push("");
13259
- }
13260
- let orientationStatus = "no_session";
13261
- if (agentSessionId && hasTaskGrounding) {
13262
- const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, fullCoherenceSnapshot);
13263
- if (orientedOk) {
13264
- orientationStatus = "complete";
13265
- lines.push("---");
13266
- lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
13267
- } else {
13268
- orientationStatus = "failed";
13269
- lines.push("---");
13270
- lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
13267
+ lines.push(...formatInitiativeStatusLines(orientView?.initiativeStatus));
13268
+ lines.push(...formatWorkstreamHealthLines(orientView?.workstreamHealth));
13269
+ lines.push(...formatWhatNeedsAttentionLines(orientView?.whatNeedsAttention));
13270
+ if (orientView?.trustMetrics) {
13271
+ const tm = orientView.trustMetrics;
13272
+ if (tm.verified > 0 || tm.unverified > 0) {
13273
+ const capNote = tm.scannedCap ? " (capped at 500)" : "";
13274
+ lines.push("## Trust metrics");
13275
+ lines.push(`_Entry verification status across workspace${capNote}._`);
13276
+ lines.push("");
13277
+ lines.push(`- **Verified:** ${tm.verified}`);
13278
+ lines.push(`- **Unverified:** ${tm.unverified}`);
13279
+ lines.push(`- **No status (pre-BET-240):** ${tm.noStatus}`);
13280
+ lines.push(`- **Total scanned:** ${tm.total}`);
13281
+ lines.push("");
13271
13282
  }
13272
- try {
13273
- await kernelMutation("chain.recordSessionSignal", {
13274
- sessionId: agentSessionId,
13275
- signalType: "immediate_context_load",
13276
- metadata: { source: "orient" }
13277
- });
13278
- } catch (err) {
13279
- process.stderr.write(`[MCP] recordSessionSignal failed: ${err.message}
13280
- `);
13283
+ }
13284
+ lines.push(...buildOperatingProtocol());
13285
+ if (fullCoherence) {
13286
+ lines.push(...fullCoherence.lines);
13287
+ }
13288
+ if (allCollections.length > 0) {
13289
+ const docCompleteness = buildDocCompletenessSection(allCollections);
13290
+ if (docCompleteness.errorCount > 0 || docCompleteness.warningCount > 0) {
13291
+ lines.push(...docCompleteness.lines);
13281
13292
  }
13282
- } else if (agentSessionId) {
13283
- orientationStatus = "task_required";
13284
- lines.push("---");
13285
- lines.push('Workspace orientation loaded. Write tools stay locked until you run `orient task="describe the work"`.');
13286
- } else {
13287
- lines.push("---");
13288
- lines.push("_No active agent session. Call `session action=start` to begin a tracked session._");
13289
13293
  }
13290
- const fullTruncated = orientView?._budget?.truncated ?? orientView?._truncated ?? false;
13291
- if (fullTruncated) {
13292
- const reasons = orientView?._budget?.truncationReasons;
13294
+ if (priorSessions.length > 0 && !recoveryBlock) {
13295
+ const last = priorSessions[0];
13296
+ const date = last.startedAt ? new Date(last.startedAt).toISOString().split("T")[0] : "unknown";
13297
+ const created = Array.isArray(last.entriesCreated) ? last.entriesCreated.length : last.entriesCreated ?? 0;
13298
+ const modified = Array.isArray(last.entriesModified) ? last.entriesModified.length : last.entriesModified ?? 0;
13299
+ lines.push(`_Last session (${date}): ${created} created, ${modified} modified._`);
13293
13300
  lines.push("");
13294
- if (reasons && reasons.length > 0) {
13295
- lines.push(`_Context truncated to fit tier budget: ${reasons.join(", ")}. Use tier=full for complete payload._`);
13296
- } else {
13297
- lines.push("_Context truncated to fit tier budget. Use tier=full for complete payload._");
13298
- }
13299
13301
  }
13300
- const fullResult = {
13301
- content: [{ type: "text", text: lines.join("\n") }],
13302
- structuredContent: success(
13303
- `Oriented (full). Stage: ${orientStage}. ${isLowReadiness ? "Low readiness \u2014 gaps remain." : "Ready."}`,
13304
- {
13305
- mode: "full",
13306
- stage: orientStage,
13307
- oriented: hasTaskGrounding ? isSessionOriented() : false,
13308
- sessionId: agentSessionId,
13309
- taskGroundingStatus: hasTaskGrounding ? "task_scoped" : task ? "missing_task_context" : "workspace_only",
13310
- taskGroundingRequired: !hasTaskGrounding,
13311
- domainRetrieval: orientView?.startup?.domainRetrieval,
13312
- orientationStatus,
13313
- nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
13314
- ...orientView?._budget ? { _budget: orientView._budget } : {}
13315
- }
13316
- )
13317
- };
13318
- reportOrientWrapperBytes(fullResult, fullTruncated);
13319
- return fullResult;
13320
- })
13321
- );
13302
+ if (recoveryBlock) {
13303
+ lines.push(...formatRecoveryBlock(recoveryBlock));
13304
+ }
13305
+ lines.push("**What are you working on?** Tell me and I'll load relevant governance and context.");
13306
+ lines.push("");
13307
+ }
13308
+ }
13309
+ const classificationGaps = readiness?.gaps?.filter((g) => g.id?.startsWith?.(PURPOSE_GAP_PREFIX)) ?? [];
13310
+ if (classificationGaps.length > 0) {
13311
+ lines.push("## Classification gaps");
13312
+ lines.push("_Collections with weak purpose \u2014 entry classification may be inaccurate._");
13313
+ lines.push("");
13314
+ for (const g of classificationGaps) {
13315
+ lines.push(`- ${g.label ?? g.id?.replace?.("purpose-gap-", "") ?? "unknown"}`);
13316
+ }
13317
+ lines.push("");
13318
+ }
13319
+ if (errors.length > 0) {
13320
+ lines.push("## Errors");
13321
+ for (const err of errors) lines.push(`- ${err}`);
13322
+ lines.push("");
13323
+ }
13324
+ let orientationStatus = "no_session";
13325
+ if (agentSessionId && hasTaskGrounding) {
13326
+ const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, fullCoherenceSnapshot);
13327
+ if (orientedOk) {
13328
+ orientationStatus = "complete";
13329
+ lines.push("---");
13330
+ lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
13331
+ } else {
13332
+ orientationStatus = "failed";
13333
+ lines.push("---");
13334
+ lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
13335
+ }
13336
+ try {
13337
+ await kernelMutation("chain.recordSessionSignal", {
13338
+ sessionId: agentSessionId,
13339
+ signalType: "immediate_context_load",
13340
+ metadata: { source: "orient" }
13341
+ });
13342
+ } catch (err) {
13343
+ process.stderr.write(`[MCP] recordSessionSignal failed: ${err.message}
13344
+ `);
13345
+ }
13346
+ } else if (agentSessionId) {
13347
+ orientationStatus = "task_required";
13348
+ lines.push("---");
13349
+ lines.push('Workspace orientation loaded. Write tools stay locked until you run `orient task="describe the work"`.');
13350
+ } else {
13351
+ lines.push("---");
13352
+ lines.push("_No active agent session. Call `session action=start` to begin a tracked session._");
13353
+ }
13354
+ const fullTruncated = orientView?._budget?.truncated ?? orientView?._truncated ?? false;
13355
+ if (fullTruncated) {
13356
+ const reasons = orientView?._budget?.truncationReasons;
13357
+ lines.push("");
13358
+ if (reasons && reasons.length > 0) {
13359
+ lines.push(`_Context truncated to fit tier budget: ${reasons.join(", ")}. Use tier=full for complete payload._`);
13360
+ } else {
13361
+ lines.push("_Context truncated to fit tier budget. Use tier=full for complete payload._");
13362
+ }
13363
+ }
13364
+ const fullResult = {
13365
+ content: [{ type: "text", text: lines.join("\n") }],
13366
+ structuredContent: success(
13367
+ `Oriented (full). Stage: ${orientStage}. ${isLowReadiness ? "Low readiness \u2014 gaps remain." : "Ready."}`,
13368
+ {
13369
+ mode: "full",
13370
+ stage: orientStage,
13371
+ oriented: hasTaskGrounding ? isSessionOriented() : false,
13372
+ sessionId: agentSessionId,
13373
+ taskGroundingStatus: hasTaskGrounding ? "task_scoped" : task ? "missing_task_context" : "workspace_only",
13374
+ taskGroundingRequired: !hasTaskGrounding,
13375
+ // STD-219 §4 (DEC-1147): machine-readable stub flag for agent consumers.
13376
+ ...orientView?.taskContext?.isGroundingStub ? { groundingStub: true } : {},
13377
+ domainRetrieval: orientView?.startup?.domainRetrieval,
13378
+ orientationStatus,
13379
+ nextStep: hasTaskGrounding ? void 0 : 'Run `orient task="describe the work"` before substantive work.',
13380
+ ...orientView?._budget ? { _budget: orientView._budget } : {}
13381
+ }
13382
+ )
13383
+ };
13384
+ reportOrientWrapperBytes(fullResult, fullTruncated, resolvedTier, taskIsMeaningful(task));
13385
+ return fullResult;
13322
13386
  }
13323
13387
 
13324
13388
  // src/tools/health.ts
@@ -15204,4 +15268,4 @@ export {
15204
15268
  createProductBrainServer,
15205
15269
  initFeatureFlags
15206
15270
  };
15207
- //# sourceMappingURL=chunk-ZPK5CSCQ.js.map
15271
+ //# sourceMappingURL=chunk-JJJO3SDX.js.map