@unbrained/pm-cli 2026.9.2 → 2026.9.3

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.
Files changed (123) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +17 -0
  3. package/dist/cli/after-command-context-usage.js +16 -3
  4. package/dist/cli-bundle/bundle-manifest.json +154 -154
  5. package/dist/cli-bundle/chunks/{chunk-T6H5BZCP.js → chunk-34HASX3S.js} +2 -2
  6. package/dist/cli-bundle/chunks/chunk-AY324UJ5.js +9 -0
  7. package/dist/cli-bundle/chunks/{chunk-TAG4VC22.js → chunk-DKGP3QLE.js} +27 -27
  8. package/dist/cli-bundle/chunks/chunk-E5RBBCXO.js +230 -0
  9. package/dist/cli-bundle/chunks/{chunk-DTGWEL23.js → chunk-EDPIS7EB.js} +2 -2
  10. package/dist/cli-bundle/chunks/{chunk-X4RCGLTX.js → chunk-IEHHE6GA.js} +5 -5
  11. package/dist/cli-bundle/chunks/{chunk-UDW64J2W.js → chunk-L7B7343B.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-FZ4Z2J4F.js → chunk-LENC656S.js} +41 -41
  13. package/dist/cli-bundle/chunks/{chunk-ZLJIFSOE.js → chunk-LISESA7W.js} +33 -33
  14. package/dist/cli-bundle/chunks/{chunk-3WICXLVT.js → chunk-UPPM2FOZ.js} +2 -2
  15. package/dist/cli-bundle/chunks/{chunk-Y7VOMSZT.js → chunk-Y4PJ6HPK.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-list-query-XYNX4ASQ.js → register-list-query-W2ZTOMKP.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-mutation-WFQ7MJTX.js → register-mutation-RVND5NCG.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-operations-JVTI7JPP.js → register-operations-TTROIVC4.js} +2 -2
  19. package/dist/cli-bundle/chunks/{register-setup-KVNC5KPL.js → register-setup-D3ZFHY3L.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/chunk-3ZBI35HU.js +176 -0
  21. package/dist/cli-bundle/focused-chunks/{chunk-SVXJYD6G.js → chunk-4HJFY4MB.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/chunk-4RRHC3S4.js +6 -0
  23. package/dist/cli-bundle/focused-chunks/chunk-4WR46RMG.js +9 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-5RFXUPN5.js +3 -0
  25. package/dist/cli-bundle/focused-chunks/chunk-BWKHEIVF.js +2 -0
  26. package/dist/cli-bundle/focused-chunks/{chunk-4O4CJAR6.js → chunk-D7KXFBXV.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/{chunk-MKHG3T76.js → chunk-GHCZ3YFR.js} +3 -3
  28. package/dist/cli-bundle/focused-chunks/{chunk-KB5OFSFD.js → chunk-GT7MXDLW.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/chunk-KBLZRU62.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/chunk-KZ2NB3ET.js +2 -0
  31. package/dist/cli-bundle/focused-chunks/chunk-M5M6SVHS.js +3 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-BEVHCEWG.js → chunk-OL5EH6I3.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/{chunk-MEASX544.js → chunk-Q45NHPF2.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/{chunk-O67VDLOT.js → chunk-QKHCSUGJ.js} +42 -42
  35. package/dist/cli-bundle/focused-chunks/chunk-S27XMBIN.js +8 -0
  36. package/dist/cli-bundle/focused-chunks/chunk-TXE4TSHM.js +12 -0
  37. package/dist/cli-bundle/focused-chunks/chunk-UCLO3XDU.js +2 -0
  38. package/dist/cli-bundle/main.js +15 -15
  39. package/dist/cli-bundle/sdk-authoring.js +1 -1
  40. package/dist/cli-bundle/sdk-contracts.js +1 -1
  41. package/dist/cli-bundle/sdk-core.js +28 -28
  42. package/dist/cli-bundle/sdk-governance.js +1 -1
  43. package/dist/cli-bundle/sdk-graph.js +1 -1
  44. package/dist/cli-bundle/sdk-merge.js +35 -33
  45. package/dist/cli-bundle/sdk-query.js +1 -1
  46. package/dist/cli-bundle/sdk-runtime.js +1 -1
  47. package/dist/cli-bundle/sdk-testing.js +1 -1
  48. package/dist/cli-bundle/sdk.js +9 -9
  49. package/dist/core/history/event-classification.d.ts +21 -0
  50. package/dist/core/history/event-classification.js +109 -0
  51. package/dist/core/history/event-index.d.ts +14 -3
  52. package/dist/core/history/event-index.js +543 -88
  53. package/dist/core/history/history.js +47 -18
  54. package/dist/core/history/workspace-history.js +7 -6
  55. package/dist/core/lock/lock.d.ts +22 -2
  56. package/dist/core/lock/lock.js +121 -19
  57. package/dist/core/output/output.js +31 -7
  58. package/dist/core/shared/time.d.ts +2 -0
  59. package/dist/core/shared/time.js +8 -2
  60. package/dist/core/store/item-metadata-query-index.js +5 -5
  61. package/dist/sdk/context/recency.d.ts +9 -0
  62. package/dist/sdk/context/recency.js +34 -0
  63. package/dist/sdk/context/usage-egress.d.ts +9 -0
  64. package/dist/sdk/context/usage-egress.js +30 -0
  65. package/dist/sdk/context-intent-contracts.js +7 -3
  66. package/dist/sdk/context-relevance.d.ts +23 -0
  67. package/dist/sdk/context-relevance.js +94 -23
  68. package/dist/sdk/context-signal-store.d.ts +7 -3
  69. package/dist/sdk/context-signal-store.js +155 -42
  70. package/dist/sdk/context-usage.d.ts +54 -0
  71. package/dist/sdk/context-usage.js +245 -16
  72. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -14
  73. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
  74. package/dist/sdk/index.d.ts +2 -0
  75. package/dist/sdk/index.js +4 -2
  76. package/dist/sdk/init.d.ts +2 -0
  77. package/dist/sdk/init.js +18 -9
  78. package/dist/sdk/query/context.d.ts +3 -1
  79. package/dist/sdk/query/context.js +21 -9
  80. package/dist/sdk/query/next.js +18 -9
  81. package/dist/sdk/runtime-input.d.ts +2 -0
  82. package/dist/sdk/runtime-input.js +25 -2
  83. package/dist/sdk/runtime.d.ts +1 -0
  84. package/dist/sdk/runtime.js +17 -26
  85. package/dist/types.d.ts +2 -0
  86. package/dist/types.js +2 -2
  87. package/docs/CONTEXT_RELEVANCE.md +44 -1
  88. package/docs/PERFORMANCE.md +6 -3
  89. package/docs/READ_OUTPUT_CONTRACTS.md +9 -1
  90. package/docs/SDK.md +11 -8
  91. package/docs/SDK_CONTEXT.md +7 -0
  92. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
  93. package/marketplace.json +2 -2
  94. package/package.json +4 -4
  95. package/packages/pm-beads/package.json +1 -1
  96. package/packages/pm-calendar/package.json +1 -1
  97. package/packages/pm-command-kit/package.json +1 -1
  98. package/packages/pm-digital-twin/package.json +1 -1
  99. package/packages/pm-governance-audit/package.json +1 -1
  100. package/packages/pm-guide-shell/package.json +1 -1
  101. package/packages/pm-kanban/package.json +1 -1
  102. package/packages/pm-lifecycle-hooks/package.json +1 -1
  103. package/packages/pm-linked-test-adapters/package.json +1 -1
  104. package/packages/pm-search-advanced/package.json +1 -1
  105. package/packages/pm-templates/package.json +1 -1
  106. package/packages/pm-todos/package.json +1 -1
  107. package/packages/pm-vcs/package.json +1 -1
  108. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  109. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  110. package/sdk/public-surface.json +241 -24
  111. package/dist/cli-bundle/chunks/chunk-GOACULJW.js +0 -13
  112. package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +0 -205
  113. package/dist/cli-bundle/focused-chunks/chunk-242AXYB2.js +0 -2
  114. package/dist/cli-bundle/focused-chunks/chunk-2FEZ5SKM.js +0 -3
  115. package/dist/cli-bundle/focused-chunks/chunk-6GCRSLPG.js +0 -2
  116. package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +0 -16
  117. package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +0 -2
  118. package/dist/cli-bundle/focused-chunks/chunk-PF3E6Q36.js +0 -8
  119. package/dist/cli-bundle/focused-chunks/chunk-QDFJIRKN.js +0 -4
  120. package/dist/cli-bundle/focused-chunks/chunk-RMRCQPWU.js +0 -2
  121. package/dist/cli-bundle/focused-chunks/chunk-S4U5CN5Q.js +0 -2
  122. package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +0 -158
  123. package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +0 -5
@@ -4,7 +4,7 @@
4
4
  * Maintains a rebuildable SQLite projection for bounded metadata queries.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e94075b0-810d-506c-b6a2-ae322526c078")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="97cfeab2-8e3f-5b70-9f64-10494158d141")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { randomUUID } from "node:crypto";
@@ -185,13 +185,13 @@ function readIndexMetadata(database) {
185
185
  * callers can remove and lazily rebuild this optional projection.
186
186
  */
187
187
  export async function updateItemMetadataQueryIndex(options) {
188
+ const Database = resolveDatabaseSync();
189
+ if (!Database)
190
+ return false;
188
191
  const indexPath = queryIndexPath(options.pmRoot);
189
192
  let database;
190
193
  try {
191
194
  await fs.access(indexPath);
192
- const Database = resolveDatabaseSync();
193
- if (!Database)
194
- return false;
195
195
  database = new Database(indexPath);
196
196
  database.exec("PRAGMA foreign_keys = ON");
197
197
  const metadata = readIndexMetadata(database);
@@ -470,4 +470,4 @@ export const _testOnly = {
470
470
  },
471
471
  };
472
472
  //# sourceMappingURL=item-metadata-query-index.js.map
473
- //# debugId=e94075b0-810d-506c-b6a2-ae322526c078
473
+ //# debugId=97cfeab2-8e3f-5b70-9f64-10494158d141
@@ -0,0 +1,9 @@
1
+ /** Deterministic oldest coordinate used when legacy creation metadata is invalid. */
2
+ export declare const CONTEXT_RECENCY_EPOCH = "1970-01-01T00:00:00.000Z";
3
+ /**
4
+ * Canonicalize a calendar-valid RFC 3339 instant or dashed legacy date-only
5
+ * value. Compact dates, sub-millisecond instants, and host-local date-times are
6
+ * rejected because they cannot round-trip through the strict timestamp contract
7
+ * losslessly and deterministically.
8
+ */
9
+ export declare function canonicalizeContextRecencyCoordinate(value: unknown): string | null;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @module sdk/context/recency
3
+ *
4
+ * Canonicalizes the absolute timestamps used as durable context-recency
5
+ * coordinates without accepting relative or host-local date-time values.
6
+ */
7
+
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="377499d7-13b3-55f0-9d44-425bfcaf7964")}catch(e){}}();
9
+ import { isMillisecondPrecisionRfc3339DateTime, resolveIsoOrRelative, } from "../../core/shared/time.js";
10
+ /** Deterministic oldest coordinate used when legacy creation metadata is invalid. */
11
+ export const CONTEXT_RECENCY_EPOCH = "1970-01-01T00:00:00.000Z";
12
+ /**
13
+ * Canonicalize a calendar-valid RFC 3339 instant or dashed legacy date-only
14
+ * value. Compact dates, sub-millisecond instants, and host-local date-times are
15
+ * rejected because they cannot round-trip through the strict timestamp contract
16
+ * losslessly and deterministically.
17
+ */
18
+ export function canonicalizeContextRecencyCoordinate(value) {
19
+ if (typeof value !== "string")
20
+ return null;
21
+ const trimmed = value.trim();
22
+ if (!isMillisecondPrecisionRfc3339DateTime(trimmed) &&
23
+ !/^\d{4}-\d{2}-\d{2}$/u.test(trimmed)) {
24
+ return null;
25
+ }
26
+ try {
27
+ return resolveIsoOrRelative(trimmed, new Date(Number.NaN), "context signal recency coordinate");
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ //# sourceMappingURL=recency.js.map
34
+ //# debugId=377499d7-13b3-55f0-9d44-425bfcaf7964
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @module sdk/context/usage-egress
3
+ *
4
+ * Keeps post-projection context feedback best-effort without weakening the
5
+ * response contract returned by embedded SDK and MCP hosts.
6
+ */
7
+ import { finalizeContextUsageDelivery } from "../context-usage.js";
8
+ /** Finalize derived usage feedback and attach a stable warning on failure. */
9
+ export declare function finalizeContextUsageEgress(pmRoot: string, projected: unknown, finalize?: typeof finalizeContextUsageDelivery): Promise<void>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module sdk/context/usage-egress
3
+ *
4
+ * Keeps post-projection context feedback best-effort without weakening the
5
+ * response contract returned by embedded SDK and MCP hosts.
6
+ */
7
+
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c5a14f99-ce5b-5da7-8b17-6b6a56f0644a")}catch(e){}}();
9
+ import { finalizeContextUsageDelivery } from "../context-usage.js";
10
+ /** Finalize derived usage feedback and attach a stable warning on failure. */
11
+ export async function finalizeContextUsageEgress(pmRoot, projected, finalize = finalizeContextUsageDelivery) {
12
+ try {
13
+ await finalize({ pmRoot, result: projected });
14
+ }
15
+ catch {
16
+ if (typeof projected === "object" &&
17
+ projected !== null &&
18
+ !Array.isArray(projected)) {
19
+ const record = projected;
20
+ const warnings = Array.isArray(record.warnings)
21
+ ? record.warnings.filter((warning) => typeof warning === "string")
22
+ : [];
23
+ record.warnings = [
24
+ ...new Set([...warnings, "context_usage_feedback_write_failed"]),
25
+ ].sort();
26
+ }
27
+ }
28
+ }
29
+ //# sourceMappingURL=usage-egress.js.map
30
+ //# debugId=c5a14f99-ce5b-5da7-8b17-6b6a56f0644a
@@ -5,12 +5,13 @@
5
5
  * workspace configuration, and packages.
6
6
  */
7
7
 
8
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="da15ca02-02cc-5886-8c82-610939b8581c")}catch(e){}}();
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5dc9c6e4-6db8-560f-a87f-368132e2ffb3")}catch(e){}}();
9
9
  import { AsyncLocalStorage } from "node:async_hooks";
10
10
  import { renderPmCommand } from "./command-line.js";
11
11
  import { attachOutputOmissionReceipt } from "./output-projection.js";
12
12
  import { encodeQueryCursor } from "./pagination.js";
13
13
  import { applyReadOutputDimensions, stabilizeReadOutputReceiptEstimates, } from "./read-output-contracts.js";
14
+ import { propagateContextUsageServingReceipt } from "./context-usage.js";
14
15
  import { EXIT_CODE } from "../core/shared/constants.js";
15
16
  import { PmCliError } from "../core/shared/errors.js";
16
17
  /** Built-in intent projections shared by CLI, SDK, MCP, and package authors. */
@@ -692,6 +693,7 @@ export function attachReadOutputContracts(command, options, result) {
692
693
  !Array.isArray(disclosedResult)
693
694
  ? applyReadOutputDimensions(command ?? "", options, collapseContinuationMetadata(options, attachContextIntentReceipt(command ?? "", options, disclosedResult)))
694
695
  : disclosedResult;
696
+ propagateContextUsageServingReceipt(result, projected);
695
697
  if (options.outputRowContract === true ||
696
698
  options.output_row_contract === true ||
697
699
  typeof projected !== "object" ||
@@ -700,7 +702,9 @@ export function attachReadOutputContracts(command, options, result) {
700
702
  !Object.hasOwn(projected, "row_contract")) {
701
703
  return projected;
702
704
  }
703
- return stabilizeSuppressedRowContractReceipts(Object.fromEntries(Object.entries(projected).filter(([key]) => key !== "row_contract")), options);
705
+ const suppressed = stabilizeSuppressedRowContractReceipts(Object.fromEntries(Object.entries(projected).filter(([key]) => key !== "row_contract")), options);
706
+ propagateContextUsageServingReceipt(projected, suppressed);
707
+ return suppressed;
704
708
  }
705
709
  //# sourceMappingURL=context-intent-contracts.js.map
706
- //# debugId=da15ca02-02cc-5886-8c82-610939b8581c
710
+ //# debugId=5dc9c6e4-6db8-560f-a87f-368132e2ffb3
@@ -1,11 +1,28 @@
1
1
  import type { RuntimeStatusRegistry } from "../core/schema/runtime-schema.js";
2
2
  import type { ItemMetadata } from "../types/index.js";
3
+ import type { HistoryEventClass } from "../core/history/event-classification.js";
3
4
  /** Canonical signal keys understood by the built-in relevance model. */
4
5
  export declare const CONTEXT_RELEVANCE_SIGNAL_NAMES: readonly ["structural", "recency", "activity_density", "graph_proximity", "claim_focus", "priority_pressure", "risk_pressure", "deadline_pressure", "knowledge_density", "author_affinity", "usage_affinity", "semantic_similarity"];
5
6
  /** A normalized signal consumed by the built-in context relevance scorer. */
6
7
  export type ContextRelevanceSignalName = (typeof CONTEXT_RELEVANCE_SIGNAL_NAMES)[number];
7
8
  /** Normalized candidate features; omitted signals are excluded from weighting. */
8
9
  export type ContextRelevanceSignals = Partial<Record<Exclude<ContextRelevanceSignalName, "structural">, number>>;
10
+ /** Authoritative coordinate and fallback that produced an item's recency. */
11
+ export interface ContextRecencyEvidence {
12
+ /** Source selected by the canonical fallback ladder. */
13
+ source: "substantive_history" | "release_cohort" | "created_at";
14
+ /** ISO coordinate used for deterministic recency ordering. */
15
+ coordinate: string;
16
+ /** Immutable operation selected from history when source is substantive_history. */
17
+ history_op?: string;
18
+ /** Declared class selected from history when source is substantive_history. */
19
+ event_class?: HistoryEventClass;
20
+ }
21
+ /** Per-signal provenance exposed by explained relevance results. */
22
+ export interface ContextSignalProvenance {
23
+ /** Evidence for the canonical temporal component. */
24
+ recency: ContextRecencyEvidence;
25
+ }
9
26
  /** A project-management object and its derived relevance signals. */
10
27
  export interface ContextRelevanceCandidate<TItem> {
11
28
  /** Stable identifier used to reference this record across commands and storage. */
@@ -14,11 +31,15 @@ export interface ContextRelevanceCandidate<TItem> {
14
31
  item: TItem;
15
32
  /** Value that configures or reports signals for this contract. */
16
33
  signals?: ContextRelevanceSignals;
34
+ /** Authoritative source details for explainable derived signals. */
35
+ signal_provenance?: ContextSignalProvenance;
17
36
  }
18
37
  /** Item candidate whose built-in metadata derivation always supplies signals. */
19
38
  export interface ItemContextRelevanceCandidate extends ContextRelevanceCandidate<ItemMetadata> {
20
39
  /** Complete built-in derivation result, with unavailable signals omitted by value. */
21
40
  signals: ContextRelevanceSignals;
41
+ /** Built-in recency derivation always discloses its source. */
42
+ signal_provenance: ContextSignalProvenance;
22
43
  }
23
44
  /** Inputs that make item-signal derivation deterministic and host-configurable. */
24
45
  export interface BuildItemContextRelevanceCandidatesOptions {
@@ -42,6 +63,8 @@ export interface BuildItemContextRelevanceCandidatesOptions {
42
63
  knowledgeDensity?: Readonly<Record<string, number>>;
43
64
  /** Optional history-derived author affinity by item id. */
44
65
  authorAffinity?: Readonly<Record<string, number>>;
66
+ /** Latest substantive history evidence keyed by item id. */
67
+ recencyEvidence?: Readonly<Record<string, ContextRecencyEvidence>>;
45
68
  }
46
69
  /**
47
70
  * Derive the canonical metadata signals consumed by `pm context` and `pm next`.
@@ -6,10 +6,11 @@
6
6
  * with core, extension, or project-specific feature stores.
7
7
  */
8
8
 
9
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7eefe5f0-364d-559a-b365-0e7d539ee19e")}catch(e){}}();
9
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="80a03884-711e-5170-a3c1-f05ccb065702")}catch(e){}}();
10
10
  import { runActiveServiceOverride } from "../core/extensions/index.js";
11
11
  import { normalizeStatusForRegistry, normalizeStatusInput, } from "../core/item/status.js";
12
- import { compareTimestampStrings, resolveIsoOrRelative } from "../core/shared/time.js";
12
+ import { compareTimestampStrings } from "../core/shared/time.js";
13
+ import { canonicalizeContextRecencyCoordinate, CONTEXT_RECENCY_EPOCH, } from "./context/recency.js";
13
14
  /** Canonical signal keys understood by the built-in relevance model. */
14
15
  export const CONTEXT_RELEVANCE_SIGNAL_NAMES = [
15
16
  "structural",
@@ -33,12 +34,67 @@ function normalizeContextActor(value, missingValue) {
33
34
  const normalized = value.trim().toLowerCase();
34
35
  return normalized.length > 0 ? normalized : missingValue;
35
36
  }
37
+ function releaseCohortCoordinate(value) {
38
+ if (typeof value !== "string")
39
+ return undefined;
40
+ const match = /^v?(\d{4})\.(\d{1,2})\.(\d{1,2})(?:$|[-+])/u.exec(value.trim());
41
+ if (!match)
42
+ return undefined;
43
+ const year = Number(match[1]);
44
+ const month = Number(match[2]);
45
+ const day = Number(match[3]);
46
+ const date = new Date(Date.UTC(year, month - 1, day));
47
+ return date.getUTCFullYear() === year &&
48
+ date.getUTCMonth() === month - 1 &&
49
+ date.getUTCDate() === day
50
+ ? date.toISOString()
51
+ : undefined;
52
+ }
53
+ function fallbackRecencyEvidence(item) {
54
+ const releaseCoordinate = releaseCohortCoordinate(item.release);
55
+ if (releaseCoordinate !== undefined) {
56
+ return { source: "release_cohort", coordinate: releaseCoordinate };
57
+ }
58
+ return {
59
+ source: "created_at",
60
+ coordinate: canonicalizeContextRecencyCoordinate(item.created_at) ??
61
+ CONTEXT_RECENCY_EPOCH,
62
+ };
63
+ }
64
+ function canonicalizeRecencyEvidence(evidence) {
65
+ if (!["substantive_history", "release_cohort", "created_at"].includes(evidence.source) ||
66
+ (evidence.source === "substantive_history"
67
+ ? (evidence.history_op !== undefined &&
68
+ typeof evidence.history_op !== "string") ||
69
+ (evidence.event_class !== undefined &&
70
+ evidence.event_class !== "substantive")
71
+ : evidence.history_op !== undefined || evidence.event_class !== undefined)) {
72
+ throw new TypeError("Context signal recency provenance must match its source");
73
+ }
74
+ const coordinate = canonicalizeContextRecencyCoordinate(evidence.coordinate);
75
+ if (coordinate === null) {
76
+ throw new TypeError("Context signal recency coordinate must be a valid absolute timestamp with millisecond precision");
77
+ }
78
+ return { ...evidence, coordinate };
79
+ }
36
80
  function normalizedPressure(value, maximum) {
37
- const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseFloat(value) : Number.NaN;
38
- return Number.isFinite(parsed) ? 1 - Math.min(Math.max(parsed, 0), maximum) / maximum : 0;
81
+ const parsed = typeof value === "number"
82
+ ? value
83
+ : typeof value === "string"
84
+ ? Number.parseFloat(value)
85
+ : Number.NaN;
86
+ return Number.isFinite(parsed)
87
+ ? 1 - Math.min(Math.max(parsed, 0), maximum) / maximum
88
+ : 0;
39
89
  }
40
90
  function deadlinePressure(deadline, nowMs) {
41
- const deadlineMs = typeof deadline === "string" ? Date.parse(deadline) : deadline instanceof Date ? deadline.getTime() : typeof deadline === "number" ? deadline : Number.NaN;
91
+ const deadlineMs = typeof deadline === "string"
92
+ ? Date.parse(deadline)
93
+ : deadline instanceof Date
94
+ ? deadline.getTime()
95
+ : typeof deadline === "number"
96
+ ? deadline
97
+ : Number.NaN;
42
98
  if (!Number.isFinite(deadlineMs) || !Number.isFinite(nowMs))
43
99
  return 0;
44
100
  const days = (deadlineMs - nowMs) / 86_400_000;
@@ -61,20 +117,22 @@ function derivedSignalOrFallback(values, id, fallback) {
61
117
  * to reproduce built-in ranking without private imports or subprocesses.
62
118
  */
63
119
  export function buildItemContextRelevanceCandidates(items, options) {
64
- const sortableTimestamp = (value) => {
65
- if (typeof value !== "string")
66
- return "";
67
- try {
68
- return resolveIsoOrRelative(value, new Date(Number.NaN), "updated_at");
69
- }
70
- catch {
71
- return "";
72
- }
73
- };
120
+ const recencyEvidence = new Map(items.map((item) => {
121
+ const suppliedEvidence = options.recencyEvidence?.[item.id];
122
+ return [
123
+ item.id,
124
+ suppliedEvidence === undefined
125
+ ? fallbackRecencyEvidence(item)
126
+ : canonicalizeRecencyEvidence(suppliedEvidence),
127
+ ];
128
+ }));
74
129
  const recencyOrder = [...items].sort((left, right) => {
75
- const leftTime = sortableTimestamp(left.updated_at);
76
- const rightTime = sortableTimestamp(right.updated_at);
77
- return compareTimestampStrings(rightTime, leftTime) || left.id.localeCompare(right.id);
130
+ const leftTime = recencyEvidence.get(left.id)
131
+ .coordinate;
132
+ const rightTime = recencyEvidence.get(right.id)
133
+ .coordinate;
134
+ return (compareTimestampStrings(rightTime, leftTime) ||
135
+ left.id.localeCompare(right.id));
78
136
  });
79
137
  const recencyRank = new Map(recencyOrder.map((item, index) => [item.id, index]));
80
138
  const denominator = Math.max(items.length - 1, 1);
@@ -82,16 +140,29 @@ export function buildItemContextRelevanceCandidates(items, options) {
82
140
  const inProgressStatus = normalizeStatusInput("in_progress", options.statusRegistry);
83
141
  const nowMs = Date.parse(options.now);
84
142
  return items.map((item) => {
85
- const assigned = normalizeContextActor(item.assignee, NO_ITEM_ASSIGNEE) === normalizedAuthor;
86
- const knowledgeEntries = (item.comments?.length ?? 0) + (item.notes?.length ?? 0) + (item.learnings?.length ?? 0);
143
+ const assigned = normalizeContextActor(item.assignee, NO_ITEM_ASSIGNEE) ===
144
+ normalizedAuthor;
145
+ const knowledgeEntries = (item.comments?.length ?? 0) +
146
+ (item.notes?.length ?? 0) +
147
+ (item.learnings?.length ?? 0);
87
148
  return {
88
149
  id: item.id,
89
150
  item,
151
+ signal_provenance: {
152
+ recency: recencyEvidence.get(item.id),
153
+ },
90
154
  signals: {
91
- recency: items.length === 1 ? 1 : 1 - recencyRank.get(item.id) / denominator,
155
+ recency: items.length === 1
156
+ ? 1
157
+ : 1 - recencyRank.get(item.id) / denominator,
92
158
  activity_density: options.activityDensity?.[item.id],
93
159
  graph_proximity: derivedSignalOrFallback(options.graphProximity, item.id, item.parent ? 0.3 : 0),
94
- claim_focus: derivedSignalOrFallback(options.claimFocus, item.id, normalizeStatusForRegistry(item.status, options.statusRegistry) === inProgressStatus ? 1 : assigned ? 0.75 : 0),
160
+ claim_focus: derivedSignalOrFallback(options.claimFocus, item.id, normalizeStatusForRegistry(item.status, options.statusRegistry) ===
161
+ inProgressStatus
162
+ ? 1
163
+ : assigned
164
+ ? 0.75
165
+ : 0),
95
166
  priority_pressure: normalizedPressure(item.priority, 4),
96
167
  risk_pressure: riskPressure(item.risk),
97
168
  deadline_pressure: deadlinePressure(item.deadline, nowMs),
@@ -430,4 +501,4 @@ export async function runContextEvaluationCorpus(scenarios, reader, thresholds)
430
501
  return summarizeContextEvaluationReports(reports, thresholds);
431
502
  }
432
503
  //# sourceMappingURL=context-relevance.js.map
433
- //# debugId=7eefe5f0-364d-559a-b365-0e7d539ee19e
504
+ //# debugId=80a03884-711e-5170-a3c1-f05ccb065702
@@ -1,9 +1,9 @@
1
- import { type BuildItemContextRelevanceCandidatesOptions, type ContextRelevanceCandidate, type ContextRelevanceSignals } from "./context-relevance.js";
1
+ import { type BuildItemContextRelevanceCandidatesOptions, type ContextRelevanceCandidate, type ContextRelevanceSignals, type ContextSignalProvenance } from "./context-relevance.js";
2
2
  import type { ItemMetadata } from "../types/index.js";
3
3
  /** Current serialized feature-store envelope version. */
4
- export declare const CONTEXT_SIGNAL_STORE_FORMAT_VERSION = 1;
4
+ export declare const CONTEXT_SIGNAL_STORE_FORMAT_VERSION = 3;
5
5
  /** Current canonical signal-vector version. */
6
- export declare const CONTEXT_SIGNAL_SET_VERSION = 1;
6
+ export declare const CONTEXT_SIGNAL_SET_VERSION = 2;
7
7
  /** Authoritative substrate used to derive one snapshot. */
8
8
  export type ContextSignalSnapshotSource = "derived_index" | "scan_fallback";
9
9
  /** One immutable item signal row. */
@@ -12,6 +12,8 @@ export interface ContextSignalSnapshotItem {
12
12
  id: string;
13
13
  /** Canonical normalized signal vector. */
14
14
  signals: ContextRelevanceSignals;
15
+ /** Authoritative temporal source retained for explained ranking. */
16
+ signal_provenance: ContextSignalProvenance;
15
17
  }
16
18
  /** Rebuildable, deterministic context-signal snapshot. */
17
19
  export interface ContextSignalSnapshot {
@@ -21,6 +23,8 @@ export interface ContextSignalSnapshot {
21
23
  signal_set_version: number;
22
24
  /** Authoritative history or derived-index cursor folded into this snapshot. */
23
25
  source_cursor: string;
26
+ /** Deterministic digest of substantive recency provenance used by the fold. */
27
+ recency_evidence_fingerprint: string;
24
28
  /** Stable clock supplied by the caller. */
25
29
  generated_at: string;
26
30
  /** Read substrate used for the fold. */