@unbrained/pm-cli 2026.8.6 → 2026.8.7

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 (209) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +30 -0
  3. package/dist/cli/main.js +4 -2
  4. package/dist/cli/register-operations.js +11 -2
  5. package/dist/cli/stats-analytics-json.d.ts +9 -0
  6. package/dist/cli/stats-analytics-json.js +69 -0
  7. package/dist/cli-bundle/bundle-manifest.json +397 -397
  8. package/dist/cli-bundle/chunks/append-7BXBFDGD.js +2 -0
  9. package/dist/cli-bundle/chunks/{chunk-TPKDJ5WL.js → chunk-2AXF3VSK.js} +2 -2
  10. package/dist/cli-bundle/chunks/{chunk-R6RKEYYW.js → chunk-2XS43CCV.js} +2 -2
  11. package/dist/cli-bundle/chunks/{chunk-T45OHXDW.js → chunk-3A6KWB72.js} +2 -2
  12. package/dist/cli-bundle/chunks/chunk-3ISTDB42.js +8 -0
  13. package/dist/cli-bundle/chunks/{chunk-SXECIECW.js → chunk-4MTI7XOV.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-MCS73BKB.js → chunk-6BX5UDCN.js} +2 -2
  15. package/dist/cli-bundle/chunks/{chunk-A3XQ7VPU.js → chunk-6QPO7KLR.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-BP6EMEDP.js → chunk-7MXHZHSQ.js} +2 -2
  17. package/dist/cli-bundle/chunks/{chunk-GU3TSEHD.js → chunk-7ZPMJW4U.js} +2 -2
  18. package/dist/cli-bundle/chunks/{chunk-343QETLI.js → chunk-AGYNSNCI.js} +2 -2
  19. package/dist/cli-bundle/chunks/chunk-B4H7FEFH.js +5 -0
  20. package/dist/cli-bundle/chunks/{chunk-CA3BURYF.js → chunk-B4KLBBMN.js} +2 -2
  21. package/dist/cli-bundle/chunks/{chunk-3ZJRFYY2.js → chunk-CALJHNBL.js} +12 -12
  22. package/dist/cli-bundle/chunks/{chunk-M357ZCOR.js → chunk-CFIGP5LY.js} +2 -2
  23. package/dist/cli-bundle/chunks/{chunk-SVV3DQES.js → chunk-CS6MRHG7.js} +2 -2
  24. package/dist/cli-bundle/chunks/{chunk-DWOAOZHZ.js → chunk-CUGNQQKH.js} +2 -2
  25. package/dist/cli-bundle/chunks/chunk-D4FPS43D.js +164 -0
  26. package/dist/cli-bundle/chunks/{chunk-L6LGKJX3.js → chunk-H5Y5YE6A.js} +2 -2
  27. package/dist/cli-bundle/chunks/{chunk-5PBP2ZP3.js → chunk-H5Y6UV6E.js} +2 -2
  28. package/dist/cli-bundle/chunks/{chunk-QJ7C3JIW.js → chunk-H7KGWPDF.js} +2 -2
  29. package/dist/cli-bundle/chunks/{chunk-D7I3TUGV.js → chunk-HFSD77TQ.js} +2 -2
  30. package/dist/cli-bundle/chunks/{chunk-AOBDLU4T.js → chunk-HX2GTA6L.js} +2 -2
  31. package/dist/cli-bundle/chunks/{chunk-4AVFKHHC.js → chunk-J2IEKAVR.js} +2 -2
  32. package/dist/cli-bundle/chunks/{chunk-OXY3SJ3N.js → chunk-K44PYFXH.js} +2 -2
  33. package/dist/cli-bundle/chunks/{chunk-M4VEE3FK.js → chunk-K4KGEEBT.js} +2 -2
  34. package/dist/cli-bundle/chunks/chunk-KFLK5TRH.js +21 -0
  35. package/dist/cli-bundle/chunks/{chunk-FDBRXV25.js → chunk-KL6IEBV2.js} +2 -2
  36. package/dist/cli-bundle/chunks/{chunk-JQ4NZ5EB.js → chunk-KWQZDZSS.js} +2 -2
  37. package/dist/cli-bundle/chunks/{chunk-UVVXHGYS.js → chunk-KZ4X3DGU.js} +2 -2
  38. package/dist/cli-bundle/chunks/chunk-LD77HJMQ.js +13 -0
  39. package/dist/cli-bundle/chunks/{chunk-AYRUGRNS.js → chunk-ME2JJ4LA.js} +2 -2
  40. package/dist/cli-bundle/chunks/chunk-NFLJ3FHD.js +2 -0
  41. package/dist/cli-bundle/chunks/{chunk-MDTH7SAE.js → chunk-NG6OXIBR.js} +8 -8
  42. package/dist/cli-bundle/chunks/{chunk-R6LSRGPS.js → chunk-NYIGHWQY.js} +2 -2
  43. package/dist/cli-bundle/chunks/{chunk-3KFVGGRE.js → chunk-NZ75GNSA.js} +2 -2
  44. package/dist/cli-bundle/chunks/{chunk-Q3VOP62W.js → chunk-PCJWJNC2.js} +2 -2
  45. package/dist/cli-bundle/chunks/{chunk-C3YABSJK.js → chunk-PD3225AM.js} +2 -2
  46. package/dist/cli-bundle/chunks/{chunk-JFZIS6JF.js → chunk-PDEGKG7P.js} +2 -2
  47. package/dist/cli-bundle/chunks/chunk-PIE5HBNA.js +2 -0
  48. package/dist/cli-bundle/chunks/{chunk-SD3YXU2U.js → chunk-PW2H7YJR.js} +20 -20
  49. package/dist/cli-bundle/chunks/{chunk-PECV7L5T.js → chunk-TPKN3S7S.js} +2 -2
  50. package/dist/cli-bundle/chunks/{chunk-F4NREH3G.js → chunk-TPXAXTCO.js} +2 -2
  51. package/dist/cli-bundle/chunks/chunk-UFWUJO4V.js +2 -0
  52. package/dist/cli-bundle/chunks/{chunk-WSI5KZQJ.js → chunk-UQLZQVFW.js} +2 -2
  53. package/dist/cli-bundle/chunks/{chunk-4OVGQW22.js → chunk-VT3Z5G7D.js} +2 -2
  54. package/dist/cli-bundle/chunks/{chunk-RUAU5OSH.js → chunk-WOD3WWUN.js} +2 -2
  55. package/dist/cli-bundle/chunks/{chunk-DQGJ2RWT.js → chunk-WSJEIGJF.js} +2 -2
  56. package/dist/cli-bundle/chunks/{chunk-RAFUN7IX.js → chunk-WYNUU7ZW.js} +49 -46
  57. package/dist/cli-bundle/chunks/{chunk-5ZKQPA44.js → chunk-YGPNCCXZ.js} +2 -2
  58. package/dist/cli-bundle/chunks/close-CMY3BAUG.js +2 -0
  59. package/dist/cli-bundle/chunks/close-many-SA4XZCTK.js +2 -0
  60. package/dist/cli-bundle/chunks/comments-EZ556ZD3.js +2 -0
  61. package/dist/cli-bundle/chunks/copy-ZSGPA52X.js +2 -0
  62. package/dist/cli-bundle/chunks/{create-TG67IVFI.js → create-I5DVV4YG.js} +2 -2
  63. package/dist/cli-bundle/chunks/delete-RL3JACSW.js +2 -0
  64. package/dist/cli-bundle/chunks/{deps-AJUGP2OH.js → deps-S7UBCECS.js} +2 -2
  65. package/dist/cli-bundle/chunks/{docs-QOCLDRKJ.js → docs-ZZNVBBYO.js} +2 -2
  66. package/dist/cli-bundle/chunks/{files-3ST5TY64.js → files-27C337VT.js} +2 -2
  67. package/dist/cli-bundle/chunks/focus-5Z2SG7LU.js +2 -0
  68. package/dist/cli-bundle/chunks/{history-compact-7BJFML4S.js → history-compact-HJQK67CZ.js} +2 -2
  69. package/dist/cli-bundle/chunks/{history-redact-WJN3HYXR.js → history-redact-PWC6PDWA.js} +2 -2
  70. package/dist/cli-bundle/chunks/{history-repair-XDNZUB7F.js → history-repair-N3CY4WBF.js} +2 -2
  71. package/dist/cli-bundle/chunks/{learnings-SZMUPVNA.js → learnings-4FH23XDT.js} +2 -2
  72. package/dist/cli-bundle/chunks/{profile-KL53JIAC.js → profile-5Y5XXH5N.js} +2 -2
  73. package/dist/cli-bundle/chunks/{register-list-query-QH7ONPKU.js → register-list-query-FJZCJ67O.js} +2 -2
  74. package/dist/cli-bundle/chunks/{register-mutation-OCRQNZK4.js → register-mutation-YGYPW3BL.js} +3 -3
  75. package/dist/cli-bundle/chunks/register-operations-WMDSUMQF.js +2 -0
  76. package/dist/cli-bundle/chunks/{register-setup-QWBQ6HBS.js → register-setup-DL7FFABC.js} +2 -2
  77. package/dist/cli-bundle/chunks/restore-6KYBV5BY.js +2 -0
  78. package/dist/cli-bundle/chunks/{schema-QJ27OTRV.js → schema-EQGKBYXJ.js} +2 -2
  79. package/dist/cli-bundle/chunks/update-QVTYOD6I.js +2 -0
  80. package/dist/cli-bundle/chunks/update-many-DJSBU525.js +2 -0
  81. package/dist/cli-bundle/focused-chunks/{chunk-MBBMTDD3.js → chunk-2ECLECMK.js} +3 -3
  82. package/dist/cli-bundle/focused-chunks/{chunk-CL3NB7VW.js → chunk-3K4XV2BF.js} +2 -2
  83. package/dist/cli-bundle/focused-chunks/{chunk-ME4XVOBJ.js → chunk-4EX25PXM.js} +2 -2
  84. package/dist/cli-bundle/focused-chunks/chunk-4VJQTS3P.js +2 -0
  85. package/dist/cli-bundle/focused-chunks/chunk-73JUDYXT.js +2 -0
  86. package/dist/cli-bundle/focused-chunks/{chunk-GSW2Y7VZ.js → chunk-CIXVQPB7.js} +2 -2
  87. package/dist/cli-bundle/focused-chunks/{chunk-7YTZ7A4E.js → chunk-DLTS3IHM.js} +2 -2
  88. package/dist/cli-bundle/focused-chunks/{chunk-YHDCGUIW.js → chunk-DQ6FKGL3.js} +10 -10
  89. package/dist/cli-bundle/focused-chunks/{chunk-YLPZHWX7.js → chunk-HNL6IFGS.js} +2 -2
  90. package/dist/cli-bundle/focused-chunks/chunk-JLG2C4EQ.js +2 -0
  91. package/dist/cli-bundle/focused-chunks/{chunk-6KDHXURF.js → chunk-MHMTKV5V.js} +2 -2
  92. package/dist/cli-bundle/focused-chunks/{chunk-GEYU23YS.js → chunk-MOTJFQ3F.js} +22 -22
  93. package/dist/cli-bundle/focused-chunks/{chunk-EYO4F74Z.js → chunk-NBJKQP4S.js} +2 -2
  94. package/dist/cli-bundle/focused-chunks/{chunk-XNVXIQ4B.js → chunk-QHRTT7WT.js} +2 -2
  95. package/dist/cli-bundle/focused-chunks/{chunk-27DK4A5O.js → chunk-R2LEMEV5.js} +2 -2
  96. package/dist/cli-bundle/focused-chunks/{chunk-4JC3AOGS.js → chunk-RPNYG5MO.js} +2 -2
  97. package/dist/cli-bundle/focused-chunks/{chunk-EAXXF2HW.js → chunk-RW5IYD4J.js} +2 -2
  98. package/dist/cli-bundle/focused-chunks/{chunk-TQMFQYXR.js → chunk-TIKDBG4D.js} +16 -16
  99. package/dist/cli-bundle/focused-chunks/{chunk-N7QN3NE6.js → chunk-VZFU2R4M.js} +2 -2
  100. package/dist/cli-bundle/focused-chunks/{chunk-GIERI4YU.js → chunk-YZEZAPJK.js} +2 -2
  101. package/dist/cli-bundle/focused-chunks/chunk-ZJIMJHDB.js +2 -0
  102. package/dist/cli-bundle/main.js +2 -2
  103. package/dist/cli-bundle/sdk-authoring.js +1 -1
  104. package/dist/cli-bundle/sdk-contracts.js +1 -1
  105. package/dist/cli-bundle/sdk-core.js +29 -28
  106. package/dist/cli-bundle/sdk-governance.js +1 -1
  107. package/dist/cli-bundle/sdk-graph.js +1 -1
  108. package/dist/cli-bundle/sdk-merge.js +1 -1
  109. package/dist/cli-bundle/sdk-query.js +1 -1
  110. package/dist/cli-bundle/sdk-runtime.js +1 -1
  111. package/dist/cli-bundle/sdk-testing.js +1 -1
  112. package/dist/cli-bundle/sdk.js +1 -1
  113. package/dist/core/extensions/reserved-host-flags.js +3 -2
  114. package/dist/core/history/workspace-history.d.ts +22 -2
  115. package/dist/core/history/workspace-history.js +60 -36
  116. package/dist/core/output/output.d.ts +2 -0
  117. package/dist/core/output/output.js +3 -2
  118. package/dist/core/shared/command-types.d.ts +2 -0
  119. package/dist/core/shared/command-types.js +2 -2
  120. package/dist/mcp/tool-definitions.js +6 -2
  121. package/dist/sdk/author-attribution.js +23 -7
  122. package/dist/sdk/cli-bootstrap.d.ts +2 -0
  123. package/dist/sdk/cli-bootstrap.js +7 -2
  124. package/dist/sdk/cli-contracts/completeness.js +51 -4
  125. package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
  126. package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
  127. package/dist/sdk/cli-contracts/runtime-contracts.js +14 -8
  128. package/dist/sdk/cli-contracts/tool-parameter-tables.js +116 -10
  129. package/dist/sdk/cli-contracts/tool-schema.js +18 -2
  130. package/dist/sdk/cli-program.js +3 -2
  131. package/dist/sdk/completion.js +5 -2
  132. package/dist/sdk/contracts.d.ts +1 -0
  133. package/dist/sdk/contracts.js +2 -2
  134. package/dist/sdk/core.d.ts +3 -1
  135. package/dist/sdk/core.js +4 -3
  136. package/dist/sdk/extension.js +9 -11
  137. package/dist/sdk/generated-error-code-catalog.js +112 -2
  138. package/dist/sdk/history-analytics.d.ts +141 -0
  139. package/dist/sdk/history-analytics.js +283 -0
  140. package/dist/sdk/improvement-ledger-validation.d.ts +3 -0
  141. package/dist/sdk/improvement-ledger-validation.js +63 -0
  142. package/dist/sdk/improvement-ledger.d.ts +139 -0
  143. package/dist/sdk/improvement-ledger.js +261 -0
  144. package/dist/sdk/index.d.ts +6 -2
  145. package/dist/sdk/index.js +8 -4
  146. package/dist/sdk/lifecycle/plan.js +6 -3
  147. package/dist/sdk/merge/install.js +10 -2
  148. package/dist/sdk/read-output-budget.js +24 -22
  149. package/dist/sdk/read-output-contracts.d.ts +10 -2
  150. package/dist/sdk/read-output-contracts.js +124 -65
  151. package/dist/sdk/read-output-rows.d.ts +29 -0
  152. package/dist/sdk/read-output-rows.js +100 -0
  153. package/dist/sdk/read-output-session.d.ts +69 -0
  154. package/dist/sdk/read-output-session.js +200 -0
  155. package/dist/sdk/runtime-input.d.ts +2 -0
  156. package/dist/sdk/runtime-input.js +14 -2
  157. package/dist/sdk/runtime-primitives.d.ts +1 -1
  158. package/dist/sdk/runtime-primitives.js +3 -3
  159. package/dist/sdk/runtime-stats-options.d.ts +9 -0
  160. package/dist/sdk/runtime-stats-options.js +38 -0
  161. package/dist/sdk/runtime.d.ts +1 -0
  162. package/dist/sdk/runtime.js +6 -27
  163. package/dist/sdk/stats.d.ts +40 -0
  164. package/dist/sdk/stats.js +112 -29
  165. package/docs/IMPROVEMENT_ANALYTICS.md +103 -0
  166. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +5 -5
  167. package/docs/README.md +1 -0
  168. package/docs/READ_OUTPUT_CONTRACTS.md +60 -1
  169. package/marketplace.json +2 -2
  170. package/package.json +3 -3
  171. package/packages/pm-beads/package.json +1 -1
  172. package/packages/pm-calendar/package.json +1 -1
  173. package/packages/pm-command-kit/package.json +1 -1
  174. package/packages/pm-digital-twin/package.json +1 -1
  175. package/packages/pm-governance-audit/package.json +1 -1
  176. package/packages/pm-guide-shell/package.json +1 -1
  177. package/packages/pm-kanban/package.json +1 -1
  178. package/packages/pm-lifecycle-hooks/package.json +1 -1
  179. package/packages/pm-linked-test-adapters/package.json +1 -1
  180. package/packages/pm-search-advanced/package.json +1 -1
  181. package/packages/pm-templates/package.json +1 -1
  182. package/packages/pm-todos/package.json +1 -1
  183. package/packages/pm-vcs/package.json +1 -1
  184. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  185. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  186. package/sdk/public-surface.json +374 -821
  187. package/dist/cli-bundle/chunks/append-XAJ5Z4XS.js +0 -2
  188. package/dist/cli-bundle/chunks/chunk-AJE3AHPD.js +0 -8
  189. package/dist/cli-bundle/chunks/chunk-E7BFPLUZ.js +0 -5
  190. package/dist/cli-bundle/chunks/chunk-HS7OVAUN.js +0 -164
  191. package/dist/cli-bundle/chunks/chunk-SV3YQ4RY.js +0 -2
  192. package/dist/cli-bundle/chunks/chunk-V663653R.js +0 -20
  193. package/dist/cli-bundle/chunks/chunk-XPOQQJTX.js +0 -13
  194. package/dist/cli-bundle/chunks/chunk-YCCDXBNU.js +0 -2
  195. package/dist/cli-bundle/chunks/chunk-ZFBWCKYF.js +0 -2
  196. package/dist/cli-bundle/chunks/close-DI66JMSB.js +0 -2
  197. package/dist/cli-bundle/chunks/close-many-VFKT6U3O.js +0 -2
  198. package/dist/cli-bundle/chunks/comments-E73HIEZJ.js +0 -2
  199. package/dist/cli-bundle/chunks/copy-WBYVLCPC.js +0 -2
  200. package/dist/cli-bundle/chunks/delete-6XKUVVQN.js +0 -2
  201. package/dist/cli-bundle/chunks/focus-R2AWS63Y.js +0 -2
  202. package/dist/cli-bundle/chunks/register-operations-HIBJXRGB.js +0 -2
  203. package/dist/cli-bundle/chunks/restore-FXA5QPM7.js +0 -2
  204. package/dist/cli-bundle/chunks/update-7GBO4SXG.js +0 -2
  205. package/dist/cli-bundle/chunks/update-many-VF6ZKQUO.js +0 -2
  206. package/dist/cli-bundle/focused-chunks/chunk-74CWP3A4.js +0 -2
  207. package/dist/cli-bundle/focused-chunks/chunk-7AZDTGPA.js +0 -2
  208. package/dist/cli-bundle/focused-chunks/chunk-LKQXXO62.js +0 -2
  209. package/dist/cli-bundle/focused-chunks/chunk-QL5H3AQH.js +0 -2
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @module sdk/history-analytics
3
+ *
4
+ * Derives bounded provenance coverage and fleet outcome analytics from the
5
+ * immutable history event index without introducing telemetry-owned state.
6
+ */
7
+ import { type HarnessSignalDescriptor } from "../core/shared/author.js";
8
+ import type { HistoryEntry, ItemMetadata } from "../types/index.js";
9
+ import { type AgentProvenanceDescriptorCoverage, type AgentProvenanceDimensionCoverage } from "./provenance.js";
10
+ /** Bounded immutable-history window controls shared by analytics surfaces. */
11
+ export interface HistoryAnalyticsWindowOptions {
12
+ /** Inclusive ISO timestamp or negative day/hour duration such as -30d. */
13
+ since?: string;
14
+ /** Maximum indexed events consumed across all pages. */
15
+ eventLimit?: number;
16
+ /** Minimum denominator required before a rate is reported. */
17
+ minimumSample?: number;
18
+ }
19
+ /** Read receipt proving how much immutable history contributed. */
20
+ export interface HistoryAnalyticsWindowReceipt {
21
+ /** Inclusive lower bound used for the scan. */
22
+ since: string;
23
+ /** Number of indexed immutable events inspected. */
24
+ events: number;
25
+ /** Whether the configured event ceiling omitted matching rows. */
26
+ truncated: boolean;
27
+ /** Cursor that resumes after the last inspected event when truncated. */
28
+ next_cursor?: string;
29
+ /** Derived read source. */
30
+ source: "history_event_index";
31
+ }
32
+ /** Live declared-versus-observed provenance report. */
33
+ export interface ProvenanceCoverageAnalytics {
34
+ /** Descriptor coverage for every declared dimension. */
35
+ descriptors: AgentProvenanceDescriptorCoverage[];
36
+ /** Per-harness availability over the bounded event window. */
37
+ observations: AgentProvenanceDimensionCoverage[];
38
+ /** Declared dimensions with enough explicit samples but no observations. */
39
+ inert: Array<{
40
+ harness: string;
41
+ dimension: string;
42
+ explicit_samples: number;
43
+ }>;
44
+ /** Dimensions no configured harness declares. */
45
+ undeclared: string[];
46
+ /** Stable warning codes suitable for health/gate adapters. */
47
+ warnings: string[];
48
+ /** Bounded source receipt. */
49
+ window: HistoryAnalyticsWindowReceipt;
50
+ }
51
+ /** One bounded attribution bucket with honest denominator states. */
52
+ export interface FleetAttributionRow {
53
+ /** Recorded grouping value. */
54
+ value: string;
55
+ /** Immutable events attributed to the bucket. */
56
+ events: number;
57
+ /** State-changing events attributed to the bucket. */
58
+ state_events: number;
59
+ /** Annotation/evidence events attributed to the bucket. */
60
+ annotation_events: number;
61
+ /** Terminal transitions attributed to the bucket. */
62
+ closes: number;
63
+ /** Active transitions after a terminal transition in the observed window. */
64
+ reopens: number;
65
+ /** Issue items linked discovered_from to work closed by this bucket. */
66
+ defect_escapes: number;
67
+ /** Terminal transitions per observed day, or null for insufficient samples. */
68
+ throughput_per_day: number | null;
69
+ /** Reopens divided by closes, or null for insufficient samples. */
70
+ rework_rate: number | null;
71
+ /** Defect escapes divided by closes, or null for insufficient samples. */
72
+ defect_escape_rate: number | null;
73
+ /** Denominator state preventing tiny samples from masquerading as rates. */
74
+ sample_status: "available" | "insufficient";
75
+ }
76
+ /** One supported fleet grouping dimension. */
77
+ export interface FleetAttributionDimension {
78
+ /** Stable dimension name. */
79
+ dimension: "harness" | "model" | "author_source";
80
+ /** Whether at least one event supplied this dimension. */
81
+ status: "available" | "unavailable";
82
+ /** Deterministically sorted bounded aggregate rows. */
83
+ rows: FleetAttributionRow[];
84
+ }
85
+ /** Observational fleet analytics derived only from immutable history. */
86
+ export interface FleetAttributionAnalytics {
87
+ /** Grouped analytics for every supported provenance dimension. */
88
+ dimensions: FleetAttributionDimension[];
89
+ /** Minimum close denominator required for rates. */
90
+ minimum_sample: number;
91
+ /** Safety statement retained in every transport. */
92
+ policy: "observational_only_not_for_authorization_or_routing";
93
+ /** Bounded source receipt. */
94
+ window: HistoryAnalyticsWindowReceipt;
95
+ }
96
+ /** One immutable history entry paired with its owning tracked item. */
97
+ export interface HistoryAnalyticsEvent {
98
+ /** Tracked item owning the immutable event. */
99
+ item_id: string;
100
+ /** Immutable history entry consumed by analytics. */
101
+ entry: HistoryEntry;
102
+ }
103
+ /** Reusable bounded history read shared across multiple analytics projections. */
104
+ export interface HistoryAnalyticsWindow {
105
+ /** Immutable events retained by the configured bound. */
106
+ events: HistoryAnalyticsEvent[];
107
+ /** Receipt describing the bounded source read. */
108
+ receipt: HistoryAnalyticsWindowReceipt;
109
+ }
110
+ declare function parseHistoryAnalyticsLimit(value: number | undefined): number;
111
+ declare function parseMinimumSample(value: number | undefined): number;
112
+ declare function resolveHistoryAnalyticsSince(value: string | undefined): string;
113
+ /** Read one reusable bounded immutable-history window. */
114
+ export declare function readHistoryAnalyticsWindow(pmRoot: string, options: HistoryAnalyticsWindowOptions): Promise<HistoryAnalyticsWindow>;
115
+ declare function provenanceValue(entry: HistoryEntry, dimension: FleetAttributionDimension["dimension"]): string | undefined;
116
+ declare function statusFromEntry(entry: HistoryEntry): string | undefined;
117
+ declare function annotationOperation(op: string): boolean;
118
+ declare function buildFleetDimension(dimension: FleetAttributionDimension["dimension"], events: readonly HistoryAnalyticsEvent[], items: readonly Pick<ItemMetadata, "id" | "type" | "dependencies">[], terminalStatuses: ReadonlySet<string>, minimumSample: number, windowDays: number): FleetAttributionDimension;
119
+ declare function resolveHistoryWindowDays(events: readonly HistoryAnalyticsEvent[], since: string): number;
120
+ /** Evaluate a negative-control-friendly declared-versus-observed coverage gate. */
121
+ export declare function evaluateProvenanceCoverage(entries: readonly HistoryEntry[], descriptors: readonly HarnessSignalDescriptor[], minimumSample: number): Omit<ProvenanceCoverageAnalytics, "window">;
122
+ /** Read live, bounded provenance coverage from authoritative history. */
123
+ export declare function runProvenanceCoverageAnalytics(pmRoot: string, descriptors?: readonly HarnessSignalDescriptor[], options?: HistoryAnalyticsWindowOptions): Promise<ProvenanceCoverageAnalytics>;
124
+ /** Project provenance coverage from an already-read immutable-history window. */
125
+ export declare function projectProvenanceCoverageAnalytics(window: HistoryAnalyticsWindow, descriptors?: readonly HarnessSignalDescriptor[], options?: Pick<HistoryAnalyticsWindowOptions, "minimumSample">): ProvenanceCoverageAnalytics;
126
+ /** Derive bounded fleet rates grouped by harness, model, and author source. */
127
+ export declare function runFleetAttributionAnalytics(pmRoot: string, items: readonly Pick<ItemMetadata, "id" | "type" | "dependencies">[], terminalStatuses: ReadonlySet<string>, options?: HistoryAnalyticsWindowOptions): Promise<FleetAttributionAnalytics>;
128
+ /** Project fleet attribution from an already-read immutable-history window. */
129
+ export declare function projectFleetAttributionAnalytics(window: HistoryAnalyticsWindow, items: readonly Pick<ItemMetadata, "id" | "type" | "dependencies">[], terminalStatuses: ReadonlySet<string>, options?: Pick<HistoryAnalyticsWindowOptions, "minimumSample">): FleetAttributionAnalytics;
130
+ /** Pure seams for deterministic analytics and negative-control tests. */
131
+ export declare const _testOnlyHistoryAnalytics: {
132
+ annotationOperation: typeof annotationOperation;
133
+ buildFleetDimension: typeof buildFleetDimension;
134
+ parseHistoryAnalyticsLimit: typeof parseHistoryAnalyticsLimit;
135
+ parseMinimumSample: typeof parseMinimumSample;
136
+ provenanceValue: typeof provenanceValue;
137
+ resolveHistoryAnalyticsSince: typeof resolveHistoryAnalyticsSince;
138
+ resolveHistoryWindowDays: typeof resolveHistoryWindowDays;
139
+ statusFromEntry: typeof statusFromEntry;
140
+ };
141
+ export {};
@@ -0,0 +1,283 @@
1
+ /**
2
+ * @module sdk/history-analytics
3
+ *
4
+ * Derives bounded provenance coverage and fleet outcome analytics from the
5
+ * immutable history event index without introducing telemetry-owned state.
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]="f0e89b0b-ccd1-5dbb-afad-119d5a98590a")}catch(e){}}();
9
+ import { AGENT_PROVENANCE_DIMENSIONS, BUILTIN_HARNESS_SIGNAL_DESCRIPTORS, } from "../core/shared/author.js";
10
+ import { EXIT_CODE } from "../core/shared/constants.js";
11
+ import { PmCliError } from "../core/shared/errors.js";
12
+ import { listMutationEvents } from "./mutation-events.js";
13
+ import { analyzeAgentProvenanceDescriptorCoverage, summarizeAgentProvenance, } from "./provenance.js";
14
+ const DEFAULT_HISTORY_ANALYTICS_LIMIT = 10_000;
15
+ const MAX_HISTORY_ANALYTICS_LIMIT = 100_000;
16
+ const HISTORY_EVENT_PAGE_LIMIT = 1_000;
17
+ const DEFAULT_HISTORY_WINDOW_DAYS = 30;
18
+ const ANNOTATION_OPERATION_PREFIXES = [
19
+ "append",
20
+ "comment",
21
+ "docs",
22
+ "file",
23
+ "learning",
24
+ "note",
25
+ "test_run",
26
+ ];
27
+ function parseHistoryAnalyticsLimit(value) {
28
+ const limit = value ?? DEFAULT_HISTORY_ANALYTICS_LIMIT;
29
+ if (!Number.isSafeInteger(limit) ||
30
+ limit < 1 ||
31
+ limit > MAX_HISTORY_ANALYTICS_LIMIT) {
32
+ throw new PmCliError(`History analytics event limit must be an integer from 1 to ${MAX_HISTORY_ANALYTICS_LIMIT}.`, EXIT_CODE.USAGE, { code: "invalid_history_analytics_limit" });
33
+ }
34
+ return limit;
35
+ }
36
+ function parseMinimumSample(value) {
37
+ const minimum = value ?? 5;
38
+ if (!Number.isSafeInteger(minimum) || minimum < 1 || minimum > 10_000) {
39
+ throw new PmCliError("History analytics minimum sample must be an integer from 1 to 10000.", EXIT_CODE.USAGE, { code: "invalid_history_analytics_minimum_sample" });
40
+ }
41
+ return minimum;
42
+ }
43
+ function resolveHistoryAnalyticsSince(value) {
44
+ const raw = value?.trim();
45
+ if (!raw) {
46
+ return new Date(Date.now() - DEFAULT_HISTORY_WINDOW_DAYS * 86_400_000).toISOString();
47
+ }
48
+ const relative = /^-(\d+)([dh])$/u.exec(raw);
49
+ if (relative) {
50
+ const amount = Number(relative[1]);
51
+ const multiplier = relative[2] === "d" ? 86_400_000 : 3_600_000;
52
+ if (!Number.isSafeInteger(amount) || amount < 1) {
53
+ throw new PmCliError("History analytics --since duration must be positive.", EXIT_CODE.USAGE, {
54
+ code: "invalid_history_analytics_since",
55
+ });
56
+ }
57
+ return new Date(Date.now() - amount * multiplier).toISOString();
58
+ }
59
+ const milliseconds = Date.parse(raw);
60
+ if (!Number.isFinite(milliseconds)) {
61
+ throw new PmCliError("History analytics --since must be an ISO timestamp or negative duration such as -30d.", EXIT_CODE.USAGE, { code: "invalid_history_analytics_since" });
62
+ }
63
+ return new Date(milliseconds).toISOString();
64
+ }
65
+ /** Read one reusable bounded immutable-history window. */
66
+ export async function readHistoryAnalyticsWindow(pmRoot, options) {
67
+ const eventLimit = parseHistoryAnalyticsLimit(options.eventLimit);
68
+ const since = resolveHistoryAnalyticsSince(options.since);
69
+ const events = [];
70
+ let cursor = since;
71
+ let hasMore = false;
72
+ while (events.length < eventLimit) {
73
+ const page = await listMutationEvents({
74
+ pmRoot,
75
+ since: cursor,
76
+ limit: Math.min(HISTORY_EVENT_PAGE_LIMIT, eventLimit - events.length),
77
+ full: true,
78
+ });
79
+ const pageEvents = page.events.map((event) => ({
80
+ item_id: event.item_id,
81
+ entry: event.entry,
82
+ }));
83
+ events.push(...pageEvents);
84
+ hasMore = page.has_more;
85
+ cursor = page.next_cursor;
86
+ if (!page.has_more)
87
+ break;
88
+ }
89
+ return {
90
+ events,
91
+ receipt: {
92
+ since,
93
+ events: events.length,
94
+ truncated: hasMore,
95
+ ...(hasMore ? { next_cursor: cursor } : {}),
96
+ source: "history_event_index",
97
+ },
98
+ };
99
+ }
100
+ function provenanceValue(entry, dimension) {
101
+ if (dimension === "harness")
102
+ return entry.agent_harness;
103
+ if (dimension === "author_source")
104
+ return entry.author_source;
105
+ return entry.agent_model ?? entry.agent_provenance?.model?.value;
106
+ }
107
+ function statusFromEntry(entry) {
108
+ for (let index = entry.patch.length - 1; index >= 0; index -= 1) {
109
+ const operation = entry.patch[index];
110
+ if (operation.path === "/metadata/status" &&
111
+ "value" in operation &&
112
+ typeof operation.value === "string") {
113
+ return operation.value;
114
+ }
115
+ }
116
+ return undefined;
117
+ }
118
+ function annotationOperation(op) {
119
+ return ANNOTATION_OPERATION_PREFIXES.some((prefix) => op.startsWith(prefix));
120
+ }
121
+ function bucketFor(buckets, value) {
122
+ const existing = buckets.get(value);
123
+ if (existing)
124
+ return existing;
125
+ const created = {
126
+ events: 0,
127
+ stateEvents: 0,
128
+ annotationEvents: 0,
129
+ closes: 0,
130
+ reopens: 0,
131
+ defectEscapes: 0,
132
+ };
133
+ buckets.set(value, created);
134
+ return created;
135
+ }
136
+ function accumulateFleetEvents(dimension, events, terminalStatuses) {
137
+ const buckets = new Map();
138
+ const streamTerminal = new Map();
139
+ const lastCloseValue = new Map();
140
+ for (const event of events) {
141
+ const value = provenanceValue(event.entry, dimension);
142
+ const status = statusFromEntry(event.entry);
143
+ const wasTerminal = streamTerminal.get(event.item_id) === true;
144
+ const isTerminal = status === undefined ? wasTerminal : terminalStatuses.has(status);
145
+ if (status !== undefined)
146
+ streamTerminal.set(event.item_id, isTerminal);
147
+ if (!value)
148
+ continue;
149
+ const bucket = bucketFor(buckets, value);
150
+ bucket.events += 1;
151
+ if (annotationOperation(event.entry.op))
152
+ bucket.annotationEvents += 1;
153
+ else
154
+ bucket.stateEvents += 1;
155
+ if (status !== undefined && !wasTerminal && isTerminal) {
156
+ bucket.closes += 1;
157
+ lastCloseValue.set(event.item_id, value);
158
+ }
159
+ else if (status !== undefined && wasTerminal && !isTerminal) {
160
+ bucket.reopens += 1;
161
+ }
162
+ }
163
+ return { buckets, lastCloseValue };
164
+ }
165
+ function attributeDefectEscapes(buckets, lastCloseValue, items) {
166
+ for (const item of items) {
167
+ if (item.type !== "Issue")
168
+ continue;
169
+ const sources = new Set((item.dependencies ?? [])
170
+ .filter((dependency) => dependency.kind === "discovered_from")
171
+ .map((dependency) => dependency.id));
172
+ for (const source of sources) {
173
+ const value = lastCloseValue.get(source);
174
+ if (value)
175
+ bucketFor(buckets, value).defectEscapes += 1;
176
+ }
177
+ }
178
+ }
179
+ function fleetRow(value, bucket, minimumSample, windowDays) {
180
+ const sampleStatus = bucket.closes >= minimumSample ? "available" : "insufficient";
181
+ return {
182
+ value,
183
+ events: bucket.events,
184
+ state_events: bucket.stateEvents,
185
+ annotation_events: bucket.annotationEvents,
186
+ closes: bucket.closes,
187
+ reopens: bucket.reopens,
188
+ defect_escapes: bucket.defectEscapes,
189
+ throughput_per_day: sampleStatus === "available" ? bucket.closes / windowDays : null,
190
+ rework_rate: sampleStatus === "available" ? bucket.reopens / bucket.closes : null,
191
+ defect_escape_rate: sampleStatus === "available"
192
+ ? bucket.defectEscapes / bucket.closes
193
+ : null,
194
+ sample_status: sampleStatus,
195
+ };
196
+ }
197
+ function buildFleetDimension(dimension, events, items, terminalStatuses, minimumSample, windowDays) {
198
+ const { buckets, lastCloseValue } = accumulateFleetEvents(dimension, events, terminalStatuses);
199
+ attributeDefectEscapes(buckets, lastCloseValue, items);
200
+ return {
201
+ dimension,
202
+ status: buckets.size === 0 ? "unavailable" : "available",
203
+ rows: [...buckets]
204
+ .map(([value, bucket]) => fleetRow(value, bucket, minimumSample, windowDays))
205
+ .sort((left, right) => right.events - left.events || left.value.localeCompare(right.value)),
206
+ };
207
+ }
208
+ function resolveHistoryWindowDays(events, since) {
209
+ const firstTimestamp = events[0]?.entry.ts ?? since;
210
+ const lastTimestamp = events[events.length - 1]?.entry.ts ?? firstTimestamp;
211
+ const firstMilliseconds = Date.parse(firstTimestamp);
212
+ const lastMilliseconds = Date.parse(lastTimestamp);
213
+ if (!Number.isFinite(firstMilliseconds) ||
214
+ !Number.isFinite(lastMilliseconds)) {
215
+ return 1;
216
+ }
217
+ return Math.max(1, (lastMilliseconds - firstMilliseconds) / 86_400_000);
218
+ }
219
+ /** Evaluate a negative-control-friendly declared-versus-observed coverage gate. */
220
+ export function evaluateProvenanceCoverage(entries, descriptors, minimumSample) {
221
+ const descriptorCoverage = analyzeAgentProvenanceDescriptorCoverage(descriptors);
222
+ const observations = summarizeAgentProvenance(entries, AGENT_PROVENANCE_DIMENSIONS, minimumSample);
223
+ const inert = observations
224
+ .filter((row) => row.inert)
225
+ .map((row) => ({
226
+ harness: row.harness,
227
+ dimension: row.dimension,
228
+ explicit_samples: row.observed + row.unavailable,
229
+ }));
230
+ const undeclared = descriptorCoverage
231
+ .filter((row) => !row.covered)
232
+ .map((row) => row.dimension);
233
+ return {
234
+ descriptors: descriptorCoverage,
235
+ observations,
236
+ inert,
237
+ undeclared,
238
+ warnings: [
239
+ ...inert.map((row) => `provenance_dimension_inert:${row.harness}:${row.dimension}:${String(row.explicit_samples)}`),
240
+ ...undeclared.map((dimension) => `provenance_dimension_undeclared:${dimension}`),
241
+ ],
242
+ };
243
+ }
244
+ /** Read live, bounded provenance coverage from authoritative history. */
245
+ export async function runProvenanceCoverageAnalytics(pmRoot, descriptors = BUILTIN_HARNESS_SIGNAL_DESCRIPTORS, options = {}) {
246
+ return projectProvenanceCoverageAnalytics(await readHistoryAnalyticsWindow(pmRoot, options), descriptors, options);
247
+ }
248
+ /** Project provenance coverage from an already-read immutable-history window. */
249
+ export function projectProvenanceCoverageAnalytics(window, descriptors = BUILTIN_HARNESS_SIGNAL_DESCRIPTORS, options = {}) {
250
+ const minimumSample = parseMinimumSample(options.minimumSample);
251
+ return {
252
+ ...evaluateProvenanceCoverage(window.events.map((event) => event.entry), descriptors, minimumSample),
253
+ window: window.receipt,
254
+ };
255
+ }
256
+ /** Derive bounded fleet rates grouped by harness, model, and author source. */
257
+ export async function runFleetAttributionAnalytics(pmRoot, items, terminalStatuses, options = {}) {
258
+ return projectFleetAttributionAnalytics(await readHistoryAnalyticsWindow(pmRoot, options), items, terminalStatuses, options);
259
+ }
260
+ /** Project fleet attribution from an already-read immutable-history window. */
261
+ export function projectFleetAttributionAnalytics(window, items, terminalStatuses, options = {}) {
262
+ const minimumSample = parseMinimumSample(options.minimumSample);
263
+ const windowDays = resolveHistoryWindowDays(window.events, window.receipt.since);
264
+ return {
265
+ dimensions: ["harness", "model", "author_source"].map((dimension) => buildFleetDimension(dimension, window.events, items, terminalStatuses, minimumSample, windowDays)),
266
+ minimum_sample: minimumSample,
267
+ policy: "observational_only_not_for_authorization_or_routing",
268
+ window: window.receipt,
269
+ };
270
+ }
271
+ /** Pure seams for deterministic analytics and negative-control tests. */
272
+ export const _testOnlyHistoryAnalytics = {
273
+ annotationOperation,
274
+ buildFleetDimension,
275
+ parseHistoryAnalyticsLimit,
276
+ parseMinimumSample,
277
+ provenanceValue,
278
+ resolveHistoryAnalyticsSince,
279
+ resolveHistoryWindowDays,
280
+ statusFromEntry,
281
+ };
282
+ //# sourceMappingURL=history-analytics.js.map
283
+ //# debugId=f0e89b0b-ccd1-5dbb-afad-119d5a98590a
@@ -0,0 +1,3 @@
1
+ import type { ImprovementLedgerDocument } from "./improvement-ledger.js";
2
+ /** Parse and validate a serialized improvement-ledger singleton. */
3
+ export declare function parseImprovementLedgerDocument(raw: string | null): ImprovementLedgerDocument;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @module sdk/improvement-ledger-validation
3
+ *
4
+ * Validates the persisted improvement-ledger envelope and observations at the
5
+ * storage boundary so malformed workspace state never reaches analytics.
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]="939d5f93-d287-5c1c-bc78-d013f76735f2")}catch(e){}}();
9
+ import { EXIT_CODE } from "../core/shared/constants.js";
10
+ import { PmCliError } from "../core/shared/errors.js";
11
+ const IMPROVEMENT_LEDGER_FORMAT_VERSION = 1;
12
+ function isValidLedgerObservation(observation) {
13
+ if (typeof observation !== "object" || observation === null)
14
+ return false;
15
+ const candidate = observation;
16
+ const hasRequiredFields = typeof candidate.id === "string" &&
17
+ typeof candidate.metric === "string" &&
18
+ typeof candidate.value === "number" &&
19
+ Number.isFinite(candidate.value) &&
20
+ ["higher", "lower", "target"].includes(String(candidate.direction)) &&
21
+ typeof candidate.observed_at === "string" &&
22
+ typeof candidate.revision === "string" &&
23
+ ["caller", "git", "unversioned"].includes(String(candidate.revision_source)) &&
24
+ typeof candidate.author === "string";
25
+ if (!hasRequiredFields)
26
+ return false;
27
+ return (candidate.direction !== "target" ||
28
+ (typeof candidate.threshold === "number" &&
29
+ Number.isFinite(candidate.threshold)));
30
+ }
31
+ /** Parse and validate a serialized improvement-ledger singleton. */
32
+ export function parseImprovementLedgerDocument(raw) {
33
+ if (raw === null) {
34
+ return {
35
+ format_version: IMPROVEMENT_LEDGER_FORMAT_VERSION,
36
+ observations: [],
37
+ };
38
+ }
39
+ let parsed;
40
+ try {
41
+ parsed = JSON.parse(raw);
42
+ }
43
+ catch {
44
+ throw new PmCliError("Improvement ledger contains invalid JSON.", EXIT_CODE.GENERIC_FAILURE, { code: "invalid_improvement_ledger" });
45
+ }
46
+ if (typeof parsed !== "object" ||
47
+ parsed === null ||
48
+ Array.isArray(parsed) ||
49
+ parsed.format_version !==
50
+ IMPROVEMENT_LEDGER_FORMAT_VERSION ||
51
+ !Array.isArray(parsed.observations)) {
52
+ throw new PmCliError("Improvement ledger has an unsupported shape or format version.", EXIT_CODE.GENERIC_FAILURE, { code: "invalid_improvement_ledger" });
53
+ }
54
+ const observations = parsed.observations;
55
+ for (const observation of observations) {
56
+ if (!isValidLedgerObservation(observation)) {
57
+ throw new PmCliError("Improvement ledger contains an invalid observation.", EXIT_CODE.GENERIC_FAILURE, { code: "invalid_improvement_ledger" });
58
+ }
59
+ }
60
+ return parsed;
61
+ }
62
+ //# sourceMappingURL=improvement-ledger-validation.js.map
63
+ //# debugId=939d5f93-d287-5c1c-bc78-d013f76735f2
@@ -0,0 +1,139 @@
1
+ import { parseImprovementLedgerDocument as parseLedger } from "./improvement-ledger-validation.js";
2
+ /** Direction in which a metric represents improvement. */
3
+ export type ImprovementDirection = "higher" | "lower" | "target";
4
+ /** One immutable quantitative observation retained by the workspace ledger. */
5
+ export interface ImprovementObservation {
6
+ /** Content-derived observation identity. */
7
+ id: string;
8
+ /** Stable, agent-readable metric name. */
9
+ metric: string;
10
+ /** Finite observed numeric value. */
11
+ value: number;
12
+ /** Direction in which later values improve. */
13
+ direction: ImprovementDirection;
14
+ /** Optional domain unit such as count, ms, bytes, or percent. */
15
+ unit?: string;
16
+ /** Required target when direction is target; optional gate threshold otherwise. */
17
+ threshold?: number;
18
+ /** ISO timestamp at which the value was observed. */
19
+ observed_at: string;
20
+ /** Git commit, caller revision, or explicit unversioned marker. */
21
+ revision: string;
22
+ /** How the revision value was obtained. */
23
+ revision_source: "caller" | "git" | "unversioned";
24
+ /** Attributed actor that recorded the observation. */
25
+ author: string;
26
+ /** Optional tracked item owning the measurement. */
27
+ item_id?: string;
28
+ /** Optional producing instrument or gate name. */
29
+ source?: string;
30
+ /** Stable retry key when supplied or derivable from a revision. */
31
+ idempotency_key?: string;
32
+ }
33
+ /** Versioned workspace singleton containing every retained observation. */
34
+ export interface ImprovementLedgerDocument {
35
+ /** Storage contract revision. */
36
+ format_version: 1;
37
+ /** Append-only observations in deterministic chronological order. */
38
+ observations: ImprovementObservation[];
39
+ }
40
+ /** Mutation controls accepted by {@link recordImprovementObservation}. */
41
+ export interface RecordImprovementObservationOptions {
42
+ /** Stable metric name. */
43
+ metric: string;
44
+ /** Finite observed numeric value. */
45
+ value: number;
46
+ /** Direction in which later values improve. */
47
+ direction?: ImprovementDirection;
48
+ /** Optional domain unit. */
49
+ unit?: string;
50
+ /** Target or gate threshold associated with this observation. */
51
+ threshold?: number;
52
+ /** Optional producing instrument or gate name. */
53
+ source?: string;
54
+ /** Optional tracked item owning the observation. */
55
+ itemId?: string;
56
+ /** Explicit source revision; otherwise git HEAD is resolved when available. */
57
+ revision?: string;
58
+ /** Explicit observation time, primarily for reproducible importers. */
59
+ observedAt?: string;
60
+ /** Explicit retry identity. */
61
+ idempotencyKey?: string;
62
+ /** Intentional author override. */
63
+ author?: string;
64
+ /** Human-readable audit rationale. */
65
+ message?: string;
66
+ }
67
+ /** Receipt returned after recording or replaying one observation. */
68
+ export interface RecordImprovementObservationResult {
69
+ /** Whether a new observation was appended. */
70
+ changed: boolean;
71
+ /** Recorded or idempotently replayed observation. */
72
+ observation: ImprovementObservation;
73
+ /** Workspace-relative singleton path. */
74
+ ledger_path: "improvement-ledger.json";
75
+ }
76
+ /** Bounded read controls for {@link readImprovementLedger}. */
77
+ export interface ReadImprovementLedgerOptions {
78
+ /** Explicit tracker root, equivalent to global --pm-path. */
79
+ pmRoot?: string;
80
+ /** Working directory used for implicit tracker discovery. */
81
+ cwd?: string;
82
+ /** Optional exact metric filter. */
83
+ metric?: string;
84
+ /** Optional tracked owner filter. */
85
+ itemId?: string;
86
+ /** Inclusive ISO timestamp lower bound. */
87
+ since?: string;
88
+ /** Maximum newest observations returned. */
89
+ limit?: number;
90
+ }
91
+ /** One baseline-to-latest trend computed without rewriting observations. */
92
+ export interface ImprovementTrend {
93
+ /** Stable metric name. */
94
+ metric: string;
95
+ /** Direction used to interpret the delta. */
96
+ direction: ImprovementDirection;
97
+ /** Oldest matching observation. */
98
+ baseline: ImprovementObservation;
99
+ /** Newest matching observation. */
100
+ latest: ImprovementObservation;
101
+ /** Latest value minus baseline value. */
102
+ delta: number;
103
+ /** Whether the latest value improved over the baseline. */
104
+ improved: boolean;
105
+ /** Number of observations contributing to the trend. */
106
+ sample_count: number;
107
+ }
108
+ /** Bounded ledger page plus complete aggregate trend metadata. */
109
+ export interface ImprovementLedgerResult {
110
+ /** Newest-first observation page. */
111
+ observations: ImprovementObservation[];
112
+ /** Matching observation count before the page limit. */
113
+ total: number;
114
+ /** Whether older matching rows were omitted. */
115
+ truncated: boolean;
116
+ /** Trends for every matching metric, sorted by metric name. */
117
+ trends: ImprovementTrend[];
118
+ /** Read provenance for deterministic consumers. */
119
+ source: "audited_workspace_singleton";
120
+ }
121
+ declare function normalizeMetricName(value: string): string;
122
+ declare function normalizeDirection(value: ImprovementDirection | undefined): ImprovementDirection;
123
+ declare function parseObservationLimit(value: number | undefined): number;
124
+ declare function trendForMetric(observations: ImprovementObservation[]): ImprovementTrend;
125
+ /** Record one audited observation, returning an idempotent receipt on retry. */
126
+ export declare function recordImprovementObservation(options: RecordImprovementObservationOptions, global?: {
127
+ path?: string;
128
+ }): Promise<RecordImprovementObservationResult>;
129
+ /** Read a bounded newest-first observation page and derive complete trends. */
130
+ export declare function readImprovementLedger(options?: ReadImprovementLedgerOptions): Promise<ImprovementLedgerResult>;
131
+ /** Pure helpers exposed for storage and trend contract tests. */
132
+ export declare const _testOnlyImprovementLedger: {
133
+ normalizeMetricName: typeof normalizeMetricName;
134
+ normalizeDirection: typeof normalizeDirection;
135
+ parseLedger: typeof parseLedger;
136
+ parseObservationLimit: typeof parseObservationLimit;
137
+ trendForMetric: typeof trendForMetric;
138
+ };
139
+ export {};