@unbrained/pm-cli 2026.8.13 → 2026.8.15

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 (194) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +165 -113
  3. package/dist/cli/commander-usage.js +17 -4
  4. package/dist/cli/error-guidance.d.ts +2 -0
  5. package/dist/cli/error-guidance.js +52 -25
  6. package/dist/cli/main.js +40 -3
  7. package/dist/cli/register-mutation.js +4 -2
  8. package/dist/cli/register-operations.js +5 -5
  9. package/dist/cli-bundle/bundle-manifest.json +146 -178
  10. package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-24GAV7XL.js} +2 -2
  11. package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +13 -0
  12. package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
  13. package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-J42EGKDK.js} +2 -2
  14. package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
  15. package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-KLKYLSDX.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-LJHOAVGI.js} +59 -59
  17. package/dist/cli-bundle/chunks/chunk-MEM2ZS3O.js +5 -0
  18. package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
  19. package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-WLPDLNEZ.js} +2 -2
  20. package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-CT3LFDDN.js} +2 -2
  21. package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-NWEVA5YS.js} +3 -3
  22. package/dist/cli-bundle/chunks/register-operations-AHIAG5KM.js +2 -0
  23. package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-ZJZFVAKE.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +2 -0
  25. package/dist/cli-bundle/focused-chunks/chunk-6XKF3PGV.js +18 -0
  26. package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-EXZA4257.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
  29. package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-KLVUMNXJ.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-KT5XMYSX.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-KTKH4IMG.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-NSPYTG6G.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +2 -0
  36. package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +155 -0
  37. package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-SLKC6QLJ.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-WTSER4WJ.js +16 -0
  40. package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-ZMFXQ7VF.js} +2 -2
  41. package/dist/cli-bundle/main.js +13 -13
  42. package/dist/cli-bundle/sdk-authoring.js +1 -1
  43. package/dist/cli-bundle/sdk-contracts.js +1 -1
  44. package/dist/cli-bundle/sdk-core.js +41 -41
  45. package/dist/cli-bundle/sdk-governance.js +1 -1
  46. package/dist/cli-bundle/sdk-graph.js +1 -1
  47. package/dist/cli-bundle/sdk-merge.js +110 -1
  48. package/dist/cli-bundle/sdk-query.js +1 -1
  49. package/dist/cli-bundle/sdk-runtime.js +1 -1
  50. package/dist/cli-bundle/sdk-testing.js +1 -1
  51. package/dist/cli-bundle/sdk.js +2 -2
  52. package/dist/core/diagnostics/remediation.js +7 -2
  53. package/dist/core/extensions/reserved-host-flags.js +3 -2
  54. package/dist/core/history/drift-scan.d.ts +6 -0
  55. package/dist/core/history/drift-scan.js +74 -50
  56. package/dist/core/history/replay.d.ts +14 -1
  57. package/dist/core/history/replay.js +45 -8
  58. package/dist/core/history/workspace-history.d.ts +59 -0
  59. package/dist/core/history/workspace-history.js +197 -10
  60. package/dist/core/output/output.d.ts +2 -0
  61. package/dist/core/output/output.js +13 -4
  62. package/dist/core/shared/command-types.d.ts +2 -0
  63. package/dist/core/shared/command-types.js +2 -2
  64. package/dist/core/shared/errors.d.ts +12 -0
  65. package/dist/core/shared/errors.js +2 -2
  66. package/dist/mcp/tool-definitions.js +9 -5
  67. package/dist/sdk/agent/refusal-reachability.d.ts +61 -0
  68. package/dist/sdk/agent/refusal-reachability.js +91 -3
  69. package/dist/sdk/cli-bootstrap.d.ts +2 -0
  70. package/dist/sdk/cli-bootstrap.js +7 -2
  71. package/dist/sdk/cli-contracts/completeness.js +3 -2
  72. package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
  73. package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
  74. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +11 -1
  75. package/dist/sdk/cli-contracts/runtime-contracts.js +176 -65
  76. package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -5
  77. package/dist/sdk/cli-contracts/tool-schema.js +10 -3
  78. package/dist/sdk/cli-program.js +4 -3
  79. package/dist/sdk/context-relevance.js +12 -4
  80. package/dist/sdk/core.d.ts +2 -2
  81. package/dist/sdk/core.js +3 -3
  82. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -2
  83. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -26
  84. package/dist/sdk/governance/assurance-action.d.ts +7 -1
  85. package/dist/sdk/governance/assurance-action.js +7 -6
  86. package/dist/sdk/governance/assurance-mutation-error.d.ts +42 -1
  87. package/dist/sdk/governance/assurance-mutation-error.js +27 -3
  88. package/dist/sdk/governance/assurance-runtime.js +12 -11
  89. package/dist/sdk/governance/assurance.d.ts +9 -0
  90. package/dist/sdk/governance/assurance.js +82 -16
  91. package/dist/sdk/governance/extension-host-version.d.ts +25 -0
  92. package/dist/sdk/governance/extension-host-version.js +105 -0
  93. package/dist/sdk/governance/health.d.ts +32 -1
  94. package/dist/sdk/governance/health.js +132 -28
  95. package/dist/sdk/governance/provenance-health.d.ts +27 -0
  96. package/dist/sdk/governance/provenance-health.js +95 -3
  97. package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
  98. package/dist/sdk/governance/validate-history-drift.js +68 -0
  99. package/dist/sdk/governance/validate.js +9 -52
  100. package/dist/sdk/governance.d.ts +6 -0
  101. package/dist/sdk/governance.js +8 -2
  102. package/dist/sdk/graph/assembly.d.ts +23 -0
  103. package/dist/sdk/graph/assembly.js +54 -2
  104. package/dist/sdk/graph/durable-cache.js +50 -20
  105. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  106. package/dist/sdk/graph/governance-contracts.js +4 -2
  107. package/dist/sdk/graph/governance.d.ts +21 -1
  108. package/dist/sdk/graph/governance.js +94 -32
  109. package/dist/sdk/graph/index.d.ts +2 -2
  110. package/dist/sdk/graph/index.js +4 -4
  111. package/dist/sdk/graph/mutation-advisory.js +15 -7
  112. package/dist/sdk/graph/remediation.js +12 -2
  113. package/dist/sdk/history-read.d.ts +8 -0
  114. package/dist/sdk/history-read.js +2 -2
  115. package/dist/sdk/history-repair.d.ts +13 -1
  116. package/dist/sdk/history-repair.js +62 -18
  117. package/dist/sdk/index.d.ts +1 -1
  118. package/dist/sdk/index.js +3 -3
  119. package/dist/sdk/linked-artifacts.js +16 -5
  120. package/dist/sdk/pagination.d.ts +15 -0
  121. package/dist/sdk/pagination.js +9 -5
  122. package/dist/sdk/query/context.d.ts +5 -1
  123. package/dist/sdk/query/context.js +14 -5
  124. package/dist/sdk/query/history.js +20 -3
  125. package/dist/sdk/read-output/continuation.d.ts +11 -0
  126. package/dist/sdk/read-output/continuation.js +132 -0
  127. package/dist/sdk/read-output-budget.d.ts +3 -1
  128. package/dist/sdk/read-output-budget.js +24 -13
  129. package/dist/sdk/read-output-contracts.d.ts +127 -7
  130. package/dist/sdk/read-output-contracts.js +381 -35
  131. package/dist/sdk/read-output-rows.d.ts +13 -0
  132. package/dist/sdk/read-output-rows.js +60 -2
  133. package/dist/sdk/runtime-input.js +4 -2
  134. package/dist/sdk/runtime-primitives.d.ts +1 -1
  135. package/dist/sdk/runtime-primitives.js +3 -3
  136. package/dist/sdk/runtime.js +5 -3
  137. package/docs/ASSURANCE.md +68 -2
  138. package/docs/COMMANDS.md +39 -4
  139. package/docs/READ_OUTPUT_CONTRACTS.md +85 -8
  140. package/docs/RELATIONSHIP_GRAPH.md +20 -5
  141. package/docs/RELEASING.md +42 -5
  142. package/docs/SDK.md +12 -5
  143. package/docs/SDK_CONTEXT_INTEGRITY.md +94 -1
  144. package/docs/TESTING.md +23 -1
  145. package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
  146. package/marketplace.json +2 -2
  147. package/package.json +7 -7
  148. package/packages/pm-beads/extensions/beads/index.ts +1 -0
  149. package/packages/pm-beads/package.json +1 -1
  150. package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
  151. package/packages/pm-calendar/package.json +1 -1
  152. package/packages/pm-command-kit/package.json +1 -1
  153. package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
  154. package/packages/pm-digital-twin/package.json +1 -1
  155. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
  156. package/packages/pm-governance-audit/package.json +1 -1
  157. package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
  158. package/packages/pm-guide-shell/package.json +1 -1
  159. package/packages/pm-kanban/package.json +1 -1
  160. package/packages/pm-lifecycle-hooks/package.json +1 -1
  161. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +6 -0
  162. package/packages/pm-linked-test-adapters/package.json +1 -1
  163. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
  164. package/packages/pm-search-advanced/package.json +1 -1
  165. package/packages/pm-templates/extensions/templates/index.ts +4 -0
  166. package/packages/pm-templates/package.json +1 -1
  167. package/packages/pm-todos/extensions/todos/index.ts +2 -0
  168. package/packages/pm-todos/package.json +1 -1
  169. package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
  170. package/packages/pm-vcs/package.json +1 -1
  171. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  172. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  173. package/scripts/bundle-cli.mjs +17 -4
  174. package/sdk/public-surface.json +1283 -157
  175. package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +0 -196
  176. package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
  177. package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
  178. package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +0 -2
  179. package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +0 -34
  180. package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +0 -2
  181. package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
  182. package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
  183. package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
  184. package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
  185. package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
  186. package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
  187. package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
  188. package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +0 -2
  189. package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
  190. package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
  191. package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +0 -2
  192. package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
  193. package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
  194. package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +0 -18
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @module sdk/governance/extension-host-version
3
+ *
4
+ * Discovers the pm-cli copy that each loaded extension resolves at runtime so
5
+ * package-manager layout skew is visible before SDK singleton state diverges.
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]="b55cafdc-9a3b-5386-bd85-cbd2311a5933")}catch(e){}}();
9
+ import fs from "node:fs/promises";
10
+ import { createRequire } from "node:module";
11
+ import path from "node:path";
12
+ import { resolvePmPackageRootFromModule } from "../../core/packages/root.js";
13
+ function displayPackagePath(packageJsonPath, workspaceRoot) {
14
+ const relative = path.relative(workspaceRoot, packageJsonPath);
15
+ if (relative.length > 0 &&
16
+ relative !== ".." &&
17
+ !relative.startsWith(`..${path.sep}`) &&
18
+ !path.isAbsolute(relative)) {
19
+ return relative.split(path.sep).join("/");
20
+ }
21
+ const externalPath = path.resolve(packageJsonPath);
22
+ let fingerprint = 0xcbf29ce484222325n;
23
+ for (let index = 0; index < externalPath.length; index += 1) {
24
+ fingerprint ^= BigInt(externalPath.charCodeAt(index));
25
+ fingerprint = BigInt.asUintN(64, fingerprint * 0x100000001b3n);
26
+ }
27
+ const installationId = fingerprint.toString(16).padStart(16, "0");
28
+ return `<external>/${installationId}/${path.basename(path.dirname(packageJsonPath))}/package.json`;
29
+ }
30
+ function dependencyLayout(packageJsonPath) {
31
+ if (packageJsonPath.includes(`${path.sep}.pnpm${path.sep}`))
32
+ return "pnpm";
33
+ if (packageJsonPath.includes(`${path.sep}node_modules${path.sep}`)) {
34
+ return "npm";
35
+ }
36
+ return "other";
37
+ }
38
+ async function readPackageVersion(packageJsonPath) {
39
+ try {
40
+ const parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
41
+ return parsed.name === "@unbrained/pm-cli" &&
42
+ typeof parsed.version === "string" &&
43
+ parsed.version.trim().length > 0
44
+ ? parsed.version.trim()
45
+ : undefined;
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ }
51
+ /** Scan the host plus the nearest pm-cli package resolvable by every loaded extension. */
52
+ export async function scanExtensionHostVersions(loadedExtensions, workspaceRoot, hostPackageRoot = resolvePmPackageRootFromModule(import.meta.url, [
53
+ "../../..",
54
+ ])) {
55
+ const hostPackageJson = path.join(hostPackageRoot, "package.json");
56
+ const hostVersion = await readPackageVersion(hostPackageJson);
57
+ const copies = new Map();
58
+ if (hostVersion !== undefined) {
59
+ copies.set(path.resolve(hostPackageJson), {
60
+ version: hostVersion,
61
+ path: displayPackagePath(hostPackageJson, workspaceRoot),
62
+ layout: "host",
63
+ consumers: ["pm-cli-host"],
64
+ });
65
+ }
66
+ for (const extension of loadedExtensions) {
67
+ try {
68
+ const resolved = createRequire(extension.entry_path).resolve("@unbrained/pm-cli/package.json");
69
+ const version = await readPackageVersion(resolved);
70
+ if (version === undefined)
71
+ continue;
72
+ const key = path.resolve(resolved);
73
+ const existing = copies.get(key);
74
+ if (existing) {
75
+ if (!existing.consumers.includes(extension.name)) {
76
+ existing.consumers.push(extension.name);
77
+ existing.consumers.sort((left, right) => left.localeCompare(right));
78
+ }
79
+ continue;
80
+ }
81
+ copies.set(key, {
82
+ version,
83
+ path: displayPackagePath(resolved, workspaceRoot),
84
+ layout: dependencyLayout(resolved),
85
+ consumers: [extension.name],
86
+ });
87
+ }
88
+ catch {
89
+ // Extensions that do not resolve pm-cli use the host surface they were
90
+ // handed. Load/activation diagnostics own unrelated resolution failures.
91
+ }
92
+ }
93
+ const sortedCopies = [...copies.values()].sort((left, right) => left.path.localeCompare(right.path));
94
+ const mismatches = hostVersion === undefined
95
+ ? []
96
+ : sortedCopies.filter((copy) => copy.version !== hostVersion);
97
+ return {
98
+ host_version: hostVersion ?? null,
99
+ copies: sortedCopies,
100
+ mismatches,
101
+ warnings: mismatches.map((copy) => `extension_host_pm_cli_version_skew:${hostVersion}:${copy.version}:${copy.consumers.join("+")}`),
102
+ };
103
+ }
104
+ //# sourceMappingURL=extension-host-version.js.map
105
+ //# debugId=b55cafdc-9a3b-5386-bd85-cbd2311a5933
@@ -20,6 +20,21 @@ export interface HealthCheck {
20
20
  /** Value that configures or reports details for this contract. */
21
21
  details: Record<string, unknown>;
22
22
  }
23
+ /** One warning indexed to the check, severity, and safe next action that decide health. */
24
+ export interface HealthFinding {
25
+ /** Original stable warning token. */
26
+ warning: string;
27
+ /** Stable colon-delimited warning code. */
28
+ code: string;
29
+ /** Health check that owns the finding. */
30
+ check: HealthCheck["name"];
31
+ /** Whether the finding blocks the top-level health verdict. */
32
+ severity: "advisory" | "gate_failing";
33
+ /** Executable remediation when one is safe and fully specified. */
34
+ remediation?: string;
35
+ /** Explicit refusal when automatic remediation would require operator choices. */
36
+ disposition?: "no_safe_automatic_remediation";
37
+ }
23
38
  /** Documents the health result payload exchanged by command, SDK, and package integrations. */
24
39
  export interface HealthResult {
25
40
  /** Whether the operation completed without a blocking failure. */
@@ -28,8 +43,16 @@ export interface HealthResult {
28
43
  checks: HealthCheck[];
29
44
  /** Number of warning entries represented by this result. */
30
45
  warning_count?: number;
46
+ /** Maximum warning rows retained in every projection. */
47
+ warning_limit?: number;
48
+ /** Whether warning rows were omitted after the declared limit. */
49
+ warnings_truncated?: boolean;
31
50
  /** Value that configures or reports warnings for this contract. */
32
51
  warnings: string[];
52
+ /** Every retained warning indexed to its owning check and severity. */
53
+ findings: HealthFinding[];
54
+ /** Exact gate-failing warning tokens that make `ok` false. */
55
+ failed_because: string[];
33
56
  /** Value that configures or reports projection for this contract. */
34
57
  projection?: {
35
58
  mode: "brief" | "summary" | "full";
@@ -115,7 +138,7 @@ interface ExtensionHealthTriageSummary {
115
138
  top_warnings: string[];
116
139
  remediation: string[];
117
140
  }
118
- /** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance values remain immutable diagnostic evidence: write-time resolvers reject new invalid values, while health reports the bounded aggregate without requiring truthful history to be rewritten. */
141
+ /** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance remains advisory until an operator explicitly applies the privacy-safe history normalizer. */
119
142
  declare function isAdvisoryHealthWarning(warning: string, requireMergeDrivers?: boolean): boolean;
120
143
  declare function warningCode(value: string): string;
121
144
  declare function normalizeExtensionNameForMatch(value: string): string;
@@ -183,12 +206,20 @@ declare function buildStaleInProgressHealthSummary(scan: StaleInProgressScan): {
183
206
  scan: StaleInProgressScan;
184
207
  warnings: string[];
185
208
  };
209
+ /** Index every warning to exactly one health check, severity, and safe next action. */
210
+ declare function buildHealthFindings(params: {
211
+ warnings: string[];
212
+ checks: HealthCheck[];
213
+ remediationSources: Record<HealthCheck["name"], string[]>;
214
+ requireMergeDrivers: boolean;
215
+ }): HealthFinding[];
186
216
  declare function projectHealthResult(result: HealthResult, options: RunHealthOptions, summaryMode: boolean): HealthResult;
187
217
  /** Implements run health for the public runtime surface of this module. */
188
218
  export declare function runHealth(global: GlobalOptions, options?: RunHealthOptions): Promise<HealthResult>;
189
219
  /** Public contract for test only health command, shared by SDK and presentation-layer consumers. */
190
220
  export declare const _testOnlyHealthCommand: {
191
221
  buildExtensionHealthTriageSummary: typeof buildExtensionHealthTriageSummary;
222
+ buildHealthFindings: typeof buildHealthFindings;
192
223
  buildCapabilityContractMetadata: typeof buildCapabilityContractMetadata;
193
224
  buildStaleInProgressHealthSummary: typeof buildStaleInProgressHealthSummary;
194
225
  buildVectorizationProviderDetails: typeof buildVectorizationProviderDetails;
@@ -4,11 +4,11 @@
4
4
  * Implements the pm health command surface and its agent-facing runtime behavior.
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]="5cee1eaa-73f3-5709-867f-a8d73081da8b")}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]="e7be701e-085c-5903-96da-61149452c673")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
11
- import { isFileMissingError, pathExists, readFileIfExists } from "../../core/fs/fs-utils.js";
11
+ import { isFileMissingError, pathExists, readFileIfExists, } from "../../core/fs/fs-utils.js";
12
12
  import { activateExtensions, getActiveExtensionRegistrations, loadExtensions, runActiveOnReadHooks, } from "../../core/extensions/index.js";
13
13
  import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
14
14
  import { KNOWN_EXTENSION_CAPABILITIES, } from "../../core/extensions/loader.js";
@@ -30,9 +30,10 @@ import { parseItemDocument } from "../../core/item/item-format.js";
30
30
  import { effectiveItemFormatVersion, scanItemFormatVersions, } from "../../core/item/item-format-version.js";
31
31
  import { listAllItemMetadataLight, listAllItemMetadataWithBody, } from "../../core/store/item-store.js";
32
32
  import { PM_TELEMETRY_SOURCE_CONTEXT_VALUES, TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS, TELEMETRY_SCHEMA_VERSION, } from "../../core/telemetry/runtime.js";
33
- import { getItemFormatFromPath, getSettingsPath, ITEM_FILE_EXTENSIONS, resolveGlobalPmRoot, resolvePmRoot, } from "../../core/store/paths.js";
33
+ import { getItemFormatFromPath, getSettingsPath, ITEM_FILE_EXTENSIONS, resolveGlobalPmRoot, resolvePmRoot, resolveWorkspaceRoot, } from "../../core/store/paths.js";
34
34
  import { readSettingsWithMetadata } from "../../core/store/settings.js";
35
- import { buildRemediationMap } from "../../core/diagnostics/remediation.js";
35
+ import { buildRemediationMap, resolveRemediation, } from "../../core/diagnostics/remediation.js";
36
+ import { scanExtensionHostVersions } from "./extension-host-version.js";
36
37
  import { scanHistoryAuthorAttribution, } from "../author-attribution.js";
37
38
  import { readManagedExtensionState } from "../extension.js";
38
39
  import { scanProvenanceResolverHealth } from "./provenance-health.js";
@@ -45,6 +46,7 @@ import { listMergeReceipts, partitionMergeReceipts, } from "../merge/receipts.js
45
46
  const PM_TELEMETRY_SOURCE_CONTEXT_SET = new Set(PM_TELEMETRY_SOURCE_CONTEXT_VALUES);
46
47
  const STALE_VECTORIZATION_SUMMARY_LIMIT = 25;
47
48
  const BRIEF_HEALTH_DETAIL_LIMIT = 8;
49
+ const HEALTH_WARNING_LIMIT = 100;
48
50
  const TELEMETRY_QUEUE_RELATIVE_PATH = path.join("runtime", "telemetry", "events.jsonl");
49
51
  const TELEMETRY_STATE_RELATIVE_PATH = path.join("runtime", "telemetry", "state.json");
50
52
  const TELEMETRY_ENDPOINT_PROBE_TIMEOUT_MS = 2_500;
@@ -54,7 +56,7 @@ const TELEMETRY_SERVER_MAX_SCHEMA_VERSION_HEADERS = [
54
56
  "x-pm-telemetry-max-schema-version",
55
57
  "x-pm-telemetry-max-version",
56
58
  ];
57
- /** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance values remain immutable diagnostic evidence: write-time resolvers reject new invalid values, while health reports the bounded aggregate without requiring truthful history to be rewritten. */
59
+ /** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance remains advisory until an operator explicitly applies the privacy-safe history normalizer. */
58
60
  function isAdvisoryHealthWarning(warning, requireMergeDrivers = false) {
59
61
  return (warning.startsWith("telemetry_") ||
60
62
  warning.startsWith("history_stream_over_compact_threshold:") ||
@@ -612,6 +614,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
612
614
  noExtensions: noExtensionsFlag,
613
615
  });
614
616
  const loadedSummaries = loadResult.loaded.map((extension) => summarizeLoadedExtension(extension));
617
+ const hostVersionCensus = await scanExtensionHostVersions(loadResult.loaded, resolveWorkspaceRoot(pmRoot));
615
618
  const activationResult = await activateExtensions({
616
619
  ...loadResult,
617
620
  loaded: loadResult.loaded,
@@ -696,6 +699,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
696
699
  ...projectManagedState.warnings,
697
700
  ...globalManagedState.warnings,
698
701
  ...updateCoverageWarnings,
702
+ ...hostVersionCensus.warnings,
699
703
  ];
700
704
  const capabilityGuidance = collectUnknownCapabilityGuidance(extensionWarnings);
701
705
  const capabilityContract = buildCapabilityContractMetadata();
@@ -721,6 +725,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
721
725
  : {}),
722
726
  capability_contract: capabilityContract,
723
727
  capability_guidance: capabilityGuidance,
728
+ host_version_census: hostVersionCensus,
724
729
  },
725
730
  },
726
731
  warnings: extensionWarnings,
@@ -858,6 +863,7 @@ const HEALTH_DETAIL_SUMMARIZERS = {
858
863
  triage: details.triage,
859
864
  capability_contract: details.capability_contract,
860
865
  capability_guidance: summarizeRecordList(details.capability_guidance, limit),
866
+ host_version_census: details.host_version_census,
861
867
  };
862
868
  },
863
869
  storage: (details, limit) => {
@@ -917,6 +923,9 @@ const HEALTH_DETAIL_SUMMARIZERS = {
917
923
  unreadable_streams: summarizeStringList(details.unreadable_streams, limit),
918
924
  hash_mismatches: summarizeStringList(details.hash_mismatches, limit),
919
925
  chain_mismatches: summarizeStringList(details.chain_mismatches, limit),
926
+ workspace_state_mismatches: summarizeStringList(details.workspace_state_mismatches, limit),
927
+ workspace_state_missing: summarizeStringList(details.workspace_state_missing, limit),
928
+ workspace_state_unreadable: summarizeStringList(details.workspace_state_unreadable, limit),
920
929
  skipped: details.skipped,
921
930
  }),
922
931
  vectorization: (details, limit) => ({
@@ -958,6 +967,9 @@ function applyBriefHealthProjection(result) {
958
967
  details: summarizeHealthCheckDetails(check, BRIEF_HEALTH_DETAIL_LIMIT),
959
968
  })),
960
969
  warnings: warningsSummary.sample,
970
+ findings: result.findings.filter((finding) => warningsSummary.sample.includes(finding.warning) ||
971
+ result.failed_because.includes(finding.warning)),
972
+ failed_because: result.failed_because,
961
973
  projection: {
962
974
  mode: "brief",
963
975
  warning_count: warningsSummary.count,
@@ -987,6 +999,9 @@ function applySummaryHealthProjection(result) {
987
999
  })),
988
1000
  warning_count: warningsSummary.count,
989
1001
  warnings: warningsSummary.sample,
1002
+ findings: result.findings.filter((finding) => warningsSummary.sample.includes(finding.warning) ||
1003
+ result.failed_because.includes(finding.warning)),
1004
+ failed_because: result.failed_because,
990
1005
  projection: {
991
1006
  mode: "summary",
992
1007
  warning_count: warningsSummary.count,
@@ -1351,12 +1366,15 @@ async function buildLocksCheck(pmRoot) {
1351
1366
  }
1352
1367
  async function buildHistoryDriftCheck(pmRoot, items) {
1353
1368
  const cacheHitVerification = "metadata";
1354
- const { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems, } = await scanHistoryDrift(pmRoot, items, { cacheHitVerification });
1369
+ const { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems, workspaceStateMismatches, workspaceStateMissing, workspaceStateUnreadable, } = await scanHistoryDrift(pmRoot, items, { cacheHitVerification });
1355
1370
  const warnings = [
1356
1371
  ...missingStreams.map((id) => `history_drift_missing_stream:${id}`),
1357
1372
  ...unreadableStreams.map((id) => `history_drift_unreadable_stream:${id}`),
1358
1373
  ...hashMismatches.map((id) => `history_drift_hash_mismatch:${id}`),
1359
1374
  ...chainMismatches.map((id) => `history_drift_chain_mismatch:${id}`),
1375
+ ...workspaceStateMismatches.map((documentPath) => `history_drift_workspace_state_mismatch:${documentPath}`),
1376
+ ...workspaceStateMissing.map((documentPath) => `history_drift_workspace_state_missing:${documentPath}`),
1377
+ ...workspaceStateUnreadable.map((documentPath) => `history_drift_workspace_state_unreadable:${documentPath}`),
1360
1378
  ];
1361
1379
  return {
1362
1380
  check: {
@@ -1373,11 +1391,17 @@ async function buildHistoryDriftCheck(pmRoot, items) {
1373
1391
  unreadable_streams: unreadableStreams.length,
1374
1392
  hash_mismatches: hashMismatches.length,
1375
1393
  chain_mismatches: chainMismatches.length,
1394
+ workspace_state_mismatches: workspaceStateMismatches.length,
1395
+ workspace_state_missing: workspaceStateMissing.length,
1396
+ workspace_state_unreadable: workspaceStateUnreadable.length,
1376
1397
  },
1377
1398
  missing_streams: missingStreams,
1378
1399
  unreadable_streams: unreadableStreams,
1379
1400
  hash_mismatches: hashMismatches,
1380
1401
  chain_mismatches: chainMismatches,
1402
+ workspace_state_mismatches: workspaceStateMismatches,
1403
+ workspace_state_missing: workspaceStateMissing,
1404
+ workspace_state_unreadable: workspaceStateUnreadable,
1381
1405
  },
1382
1406
  },
1383
1407
  warnings,
@@ -1807,22 +1831,62 @@ function extractHistoryDriftedCount(historyDriftCheck) {
1807
1831
  function buildHealthRemediationSources(params) {
1808
1832
  return {
1809
1833
  settings: params.normalizedSettingsReadWarnings,
1810
- directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`),
1834
+ directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`).concat(params.directoryState.hookWarnings),
1811
1835
  settings_values: params.settingWarnings,
1812
1836
  telemetry: params.telemetryCheck.warnings,
1813
1837
  extensions: params.extensionCheck.warnings,
1814
1838
  storage: [
1839
+ ...params.historyPolicyWarnings,
1815
1840
  ...params.historySummary.over_threshold.map((id) => `history_stream_over_compact_threshold:${id}`),
1816
1841
  ...params.authorAttributionWarnings,
1817
1842
  ...params.staleInProgressWarnings,
1818
1843
  ...params.provenanceWarnings,
1819
1844
  ],
1820
1845
  locks: params.locksCheck.warnings,
1821
- integrity: params.integrityCheck.warnings,
1846
+ integrity: [
1847
+ ...params.normalizedItemReadWarnings,
1848
+ ...params.integrityCheck.warnings,
1849
+ ],
1822
1850
  history_drift: params.historyDriftCheck.warnings,
1823
1851
  vectorization: params.vectorizationCheck.warnings,
1824
1852
  };
1825
1853
  }
1854
+ /** Index every warning to exactly one health check, severity, and safe next action. */
1855
+ function buildHealthFindings(params) {
1856
+ const owners = new Map();
1857
+ for (const [check, warnings] of Object.entries(params.remediationSources)) {
1858
+ for (const warning of warnings) {
1859
+ if (!owners.has(warning))
1860
+ owners.set(warning, check);
1861
+ }
1862
+ }
1863
+ const checksByName = new Map(params.checks.map((check) => [check.name, check]));
1864
+ const findings = params.warnings.map((warning) => {
1865
+ const check = owners.get(warning) ?? "integrity";
1866
+ const code = resolveRemediation(warning)?.code ?? warningCode(warning);
1867
+ const details = checksByName.get(check)?.details;
1868
+ const remediationMap = typeof details?.remediation_map === "object" &&
1869
+ details.remediation_map !== null
1870
+ ? details.remediation_map
1871
+ : {};
1872
+ const remediation = remediationMap[code];
1873
+ const severity = isAdvisoryHealthWarning(warning, params.requireMergeDrivers)
1874
+ ? "advisory"
1875
+ : "gate_failing";
1876
+ return {
1877
+ warning,
1878
+ code,
1879
+ check,
1880
+ severity,
1881
+ ...(typeof remediation === "string"
1882
+ ? { remediation }
1883
+ : severity === "gate_failing"
1884
+ ? { disposition: "no_safe_automatic_remediation" }
1885
+ : {}),
1886
+ };
1887
+ });
1888
+ return findings;
1889
+ }
1826
1890
  function rewriteBulkHealthRemediation(params) {
1827
1891
  if (params.check.name === "history_drift" && params.historyDriftedCount > 1) {
1828
1892
  for (const code of Object.keys(params.remediationMap)) {
@@ -1850,10 +1914,38 @@ function attachHealthRemediationMaps(params) {
1850
1914
  }
1851
1915
  }
1852
1916
  function projectHealthResult(result, options, summaryMode) {
1853
- if (summaryMode) {
1854
- return applySummaryHealthProjection(result);
1855
- }
1856
- return options.brief === true ? applyBriefHealthProjection(result) : result;
1917
+ const warningCount = result.warning_count ?? result.warnings.length;
1918
+ const boundedResult = {
1919
+ ...result,
1920
+ warning_count: warningCount,
1921
+ warning_limit: HEALTH_WARNING_LIMIT,
1922
+ warnings_truncated: warningCount > HEALTH_WARNING_LIMIT,
1923
+ warnings: result.warnings.slice(0, HEALTH_WARNING_LIMIT),
1924
+ findings: (result.findings ?? []).filter((finding) => result.warnings
1925
+ .slice(0, HEALTH_WARNING_LIMIT)
1926
+ .includes(finding.warning) ||
1927
+ result.failed_because.includes(finding.warning)),
1928
+ };
1929
+ const projected = summaryMode
1930
+ ? applySummaryHealthProjection(boundedResult)
1931
+ : options.brief === true
1932
+ ? applyBriefHealthProjection(boundedResult)
1933
+ : boundedResult;
1934
+ return {
1935
+ ...projected,
1936
+ warning_count: warningCount,
1937
+ warning_limit: HEALTH_WARNING_LIMIT,
1938
+ warnings_truncated: warningCount > projected.warnings.length,
1939
+ ...(projected.projection
1940
+ ? {
1941
+ projection: {
1942
+ ...projected.projection,
1943
+ warning_count: warningCount,
1944
+ warnings_truncated: warningCount > projected.warnings.length,
1945
+ },
1946
+ }
1947
+ : {}),
1948
+ };
1857
1949
  }
1858
1950
  /** Implements run health for the public runtime surface of this module. */
1859
1951
  export async function runHealth(global, options = {}) {
@@ -1945,23 +2037,26 @@ export async function runHealth(global, options = {}) {
1945
2037
  historyDriftCheck,
1946
2038
  vectorizationCheck,
1947
2039
  });
2040
+ const remediationSources = buildHealthRemediationSources({
2041
+ directoryState,
2042
+ normalizedSettingsReadWarnings,
2043
+ settingWarnings,
2044
+ normalizedItemReadWarnings,
2045
+ telemetryCheck,
2046
+ extensionCheck,
2047
+ historyPolicyWarnings: historyPolicy.warnings,
2048
+ historySummary,
2049
+ authorAttributionWarnings,
2050
+ staleInProgressWarnings: staleInProgress.warnings,
2051
+ provenanceWarnings,
2052
+ locksCheck,
2053
+ integrityCheck,
2054
+ historyDriftCheck,
2055
+ vectorizationCheck,
2056
+ });
1948
2057
  attachHealthRemediationMaps({
1949
2058
  checks,
1950
- remediationSources: buildHealthRemediationSources({
1951
- directoryState,
1952
- normalizedSettingsReadWarnings,
1953
- settingWarnings,
1954
- telemetryCheck,
1955
- extensionCheck,
1956
- historySummary,
1957
- authorAttributionWarnings,
1958
- staleInProgressWarnings: staleInProgress.warnings,
1959
- provenanceWarnings,
1960
- locksCheck,
1961
- integrityCheck,
1962
- historyDriftCheck,
1963
- vectorizationCheck,
1964
- }),
2059
+ remediationSources,
1965
2060
  historyDriftedCount: extractHistoryDriftedCount(historyDriftCheck),
1966
2061
  overThresholdCount: historySummary.over_threshold.length,
1967
2062
  });
@@ -1970,10 +2065,18 @@ export async function runHealth(global, options = {}) {
1970
2065
  // it must never flip overall project health to not-ok. Such warnings are still
1971
2066
  // surfaced in `warnings` and the telemetry check's own `warn` status.
1972
2067
  const blockingWarnings = normalizedWarnings.filter((warning) => !isAdvisoryHealthWarning(warning, options.requireMergeDrivers === true));
2068
+ const findings = buildHealthFindings({
2069
+ warnings: normalizedWarnings,
2070
+ checks,
2071
+ remediationSources,
2072
+ requireMergeDrivers: options.requireMergeDrivers === true,
2073
+ });
1973
2074
  const result = {
1974
2075
  ok: blockingWarnings.length === 0,
1975
2076
  checks,
1976
2077
  warnings: normalizedWarnings,
2078
+ findings,
2079
+ failed_because: blockingWarnings,
1977
2080
  generated_at: nowIso(),
1978
2081
  };
1979
2082
  return projectHealthResult(result, options, skipPolicy.summaryMode);
@@ -1981,6 +2084,7 @@ export async function runHealth(global, options = {}) {
1981
2084
  /** Public contract for test only health command, shared by SDK and presentation-layer consumers. */
1982
2085
  export const _testOnlyHealthCommand = {
1983
2086
  buildExtensionHealthTriageSummary,
2087
+ buildHealthFindings,
1984
2088
  buildCapabilityContractMetadata,
1985
2089
  buildStaleInProgressHealthSummary,
1986
2090
  buildVectorizationProviderDetails,
@@ -2007,4 +2111,4 @@ export const _testOnlyHealthCommand = {
2007
2111
  warningCode,
2008
2112
  };
2009
2113
  //# sourceMappingURL=health.js.map
2010
- //# debugId=5cee1eaa-73f3-5709-867f-a8d73081da8b
2114
+ //# debugId=e7be701e-085c-5903-96da-61149452c673
@@ -1,3 +1,4 @@
1
+ import type { HistoryEntry } from "../../types/index.js";
1
2
  /** Aggregated resolver attempts for one harness provenance dimension. */
2
3
  export interface ProvenanceResolverHealthOutcome {
3
4
  /** Detected harness namespace. */
@@ -35,5 +36,31 @@ export interface ProvenanceResolverHealthScan {
35
36
  /** Whether an event or byte ceiling omitted history input. */
36
37
  truncated: boolean;
37
38
  }
39
+ /** Privacy-safe receipt for an explicit provenance normalization pass. */
40
+ export interface ProvenanceNormalizationReceipt {
41
+ /** Whether at least one immutable event required normalization. */
42
+ changed: boolean;
43
+ /** Immutable events whose invalid provenance observations were removed. */
44
+ events_changed: number;
45
+ /** Total invalid observations removed without retaining their values. */
46
+ observations_removed: number;
47
+ /** Aggregate invalid-value classes removed by the pass. */
48
+ invalid_values: ProvenanceValueHealthFinding[];
49
+ }
50
+ /** Normalized entries plus the privacy-safe mutation receipt. */
51
+ export interface ProvenanceNormalizationResult {
52
+ /** History entries with invalid bounded observations removed. */
53
+ entries: HistoryEntry[];
54
+ /** Aggregate mutation receipt; never includes an observed value. */
55
+ receipt: ProvenanceNormalizationReceipt;
56
+ }
57
+ /**
58
+ * Remove only provenance observations whose values violate the bounded domain.
59
+ * History operations, patches, timestamps, authors, and hashes are retained;
60
+ * the receipt exposes aggregate classes and counts but never the removed value.
61
+ */
62
+ export declare function normalizeInvalidHistoryProvenance(entries: HistoryEntry[]): ProvenanceNormalizationResult;
63
+ /** Find every history stream requiring provenance normalization without returning raw values. */
64
+ export declare function listInvalidProvenanceHistoryStreamIds(pmRoot: string): Promise<string[]>;
38
65
  /** Scan immutable history without failing over malformed streams owned by integrity checks. */
39
66
  export declare function scanProvenanceResolverHealth(pmRoot: string, eventLimit?: number): Promise<ProvenanceResolverHealthScan>;
@@ -4,7 +4,7 @@
4
4
  * Reads bounded, privacy-safe provenance resolver outcomes for health checks.
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]="60154e1b-8348-5b6b-badf-e76bba43bef8")}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]="6efed404-acd2-5c3a-a008-856df67c8b77")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  const DEFAULT_PROVENANCE_HISTORY_BYTE_LIMIT = 8_388_608;
@@ -27,6 +27,98 @@ const INVALID_PROVENANCE_VALUE_CLASSIFIERS = [
27
27
  function isRecord(value) {
28
28
  return typeof value === "object" && value !== null && !Array.isArray(value);
29
29
  }
30
+ function invalidProvenanceValueKind(value) {
31
+ return INVALID_PROVENANCE_VALUE_CLASSIFIERS.find((classifier) => classifier.matches(value))?.kind;
32
+ }
33
+ /**
34
+ * Remove only provenance observations whose values violate the bounded domain.
35
+ * History operations, patches, timestamps, authors, and hashes are retained;
36
+ * the receipt exposes aggregate classes and counts but never the removed value.
37
+ */
38
+ export function normalizeInvalidHistoryProvenance(entries) {
39
+ const invalidValues = new Map();
40
+ let eventsChanged = 0;
41
+ let observationsRemoved = 0;
42
+ const normalized = entries.map((entry) => {
43
+ const provenance = isRecord(entry.agent_provenance)
44
+ ? entry.agent_provenance
45
+ : undefined;
46
+ if (provenance === undefined)
47
+ return entry;
48
+ const retained = {};
49
+ let eventChanged = false;
50
+ for (const [dimension, observation] of Object.entries(provenance)) {
51
+ const kind = isRecord(observation)
52
+ ? invalidProvenanceValueKind(observation.value)
53
+ : undefined;
54
+ if (kind === undefined) {
55
+ retained[dimension] = observation;
56
+ continue;
57
+ }
58
+ eventChanged = true;
59
+ observationsRemoved += 1;
60
+ const harness = entry.agent_harness ?? "unknown";
61
+ const key = `${harness}\0${dimension}\0${kind}`;
62
+ const aggregate = invalidValues.get(key) ?? {
63
+ harness,
64
+ dimension,
65
+ kind,
66
+ count: 0,
67
+ };
68
+ aggregate.count += 1;
69
+ invalidValues.set(key, aggregate);
70
+ }
71
+ if (!eventChanged)
72
+ return entry;
73
+ eventsChanged += 1;
74
+ const next = { ...entry };
75
+ if (Object.keys(retained).length === 0) {
76
+ delete next.agent_provenance;
77
+ }
78
+ else {
79
+ next.agent_provenance = retained;
80
+ }
81
+ return next;
82
+ });
83
+ return {
84
+ entries: normalized,
85
+ receipt: {
86
+ changed: eventsChanged > 0,
87
+ events_changed: eventsChanged,
88
+ observations_removed: observationsRemoved,
89
+ invalid_values: [...invalidValues.values()].sort((left, right) => left.harness.localeCompare(right.harness) ||
90
+ left.dimension.localeCompare(right.dimension) ||
91
+ left.kind.localeCompare(right.kind)),
92
+ },
93
+ };
94
+ }
95
+ /** Find every history stream requiring provenance normalization without returning raw values. */
96
+ export async function listInvalidProvenanceHistoryStreamIds(pmRoot) {
97
+ const ids = [];
98
+ for (const file of await listHistoryFiles(pmRoot)) {
99
+ try {
100
+ const content = await fs.readFile(path.join(pmRoot, "history", file), "utf8");
101
+ for (const line of content.split("\n")) {
102
+ if (line.trim().length === 0)
103
+ continue;
104
+ const entry = parseHistoryEntry(line);
105
+ if (entry === null || !isRecord(entry.agent_provenance))
106
+ continue;
107
+ const invalid = Object.values(entry.agent_provenance).some((observation) => isRecord(observation) &&
108
+ invalidProvenanceValueKind(observation.value) !== undefined);
109
+ if (invalid) {
110
+ ids.push(file.slice(0, -".jsonl".length));
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ catch {
116
+ // Integrity diagnostics own unreadable or malformed streams. This census
117
+ // only selects safely parseable streams for the explicit normalizer.
118
+ }
119
+ }
120
+ return ids;
121
+ }
30
122
  async function listHistoryFiles(pmRoot) {
31
123
  try {
32
124
  return (await fs.readdir(path.join(pmRoot, "history")))
@@ -84,7 +176,7 @@ function collectResolverOutcomes(entry, aggregates, invalidValues) {
84
176
  Object.entries(provenance).forEach(([dimension, observation]) => {
85
177
  if (!isRecord(observation))
86
178
  return;
87
- const kind = INVALID_PROVENANCE_VALUE_CLASSIFIERS.find((classifier) => classifier.matches(observation.value))?.kind;
179
+ const kind = invalidProvenanceValueKind(observation.value);
88
180
  if (!kind)
89
181
  return;
90
182
  const key = `${harness}\0${dimension}\0${kind}`;
@@ -182,4 +274,4 @@ export async function scanProvenanceResolverHealth(pmRoot, eventLimit = 10_000)
182
274
  };
183
275
  }
184
276
  //# sourceMappingURL=provenance-health.js.map
185
- //# debugId=60154e1b-8348-5b6b-badf-e76bba43bef8
277
+ //# debugId=6efed404-acd2-5c3a-a008-856df67c8b77
@@ -0,0 +1,7 @@
1
+ import type { ValidateCheck } from "./validate.js";
2
+ import type { ValidateItem } from "./validate-item-reader.js";
3
+ /** Build the validation warning and bounded evidence projection for history drift. */
4
+ export declare function buildValidateHistoryDriftCheck(pmRoot: string, items: ValidateItem[], verboseDiagnostics: boolean): Promise<{
5
+ check: ValidateCheck;
6
+ warnings: string[];
7
+ }>;