@unbrained/pm-cli 2026.8.11 → 2026.8.12
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +52 -21
- package/dist/cli/commander-usage.js +37 -11
- package/dist/cli/error-guidance.d.ts +2 -0
- package/dist/cli/error-guidance.js +80 -13
- package/dist/cli/main.js +34 -19
- package/dist/cli/register-annotations.js +56 -3
- package/dist/cli/register-list-query.js +10 -7
- package/dist/cli/register-operations.js +16 -6
- package/dist/cli-bundle/bundle-manifest.json +157 -157
- package/dist/cli-bundle/chunks/{chunk-2OOU2AFH.js → chunk-3PS7X6GS.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-7KL6KMWF.js +13 -0
- package/dist/cli-bundle/chunks/{chunk-WMEZHCFI.js → chunk-BM5YJ2UW.js} +51 -43
- package/dist/cli-bundle/chunks/chunk-D55A5AEN.js +33 -0
- package/dist/cli-bundle/chunks/chunk-KIKDWECH.js +196 -0
- package/dist/cli-bundle/chunks/{chunk-ZU34C3LH.js → chunk-KOQMGCTA.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-R76342NV.js +2 -0
- package/dist/cli-bundle/chunks/chunk-RBTK5EZV.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-IUNRVDAI.js → chunk-VLUQOIDT.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-A2SJGHSI.js → chunk-WLAHPSOX.js} +2 -2
- package/dist/cli-bundle/chunks/register-list-query-XPCJRUUD.js +10 -0
- package/dist/cli-bundle/chunks/register-mutation-4RJCBKRS.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-2OGISOVR.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-NOCOOWQY.js → register-setup-LLHAKP2V.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-2DALMVF7.js +5 -0
- package/dist/cli-bundle/focused-chunks/chunk-5OQIMELN.js +155 -0
- package/dist/cli-bundle/focused-chunks/chunk-5TAGTDRE.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-FPSYO5ZG.js → chunk-ECADZMVC.js} +11 -11
- package/dist/cli-bundle/focused-chunks/chunk-EJGXRA6B.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-FFGSZCPK.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-BKPIY34S.js → chunk-GQW4BPUT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ISKOBJCM.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-UDAZWT25.js → chunk-JAFRIWVF.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2DL3MRTD.js → chunk-KHM2CS2C.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-J5EKAIVD.js → chunk-KPSXVBDV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-23FTGO3W.js → chunk-KTLOKKCQ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-LGYK3NUF.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KDH5OX3D.js → chunk-NBLUKITQ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-55BIB6DV.js → chunk-NYLOUPOB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-DPO7TEFX.js → chunk-Q4T463SD.js} +28 -28
- package/dist/cli-bundle/focused-chunks/chunk-QVZVY53N.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TL5M2PAY.js → chunk-RWPAWUOT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-UTEWXDEQ.js +17 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4H5IA6AV.js → chunk-YIAXMC3T.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZMGWAYH7.js +2 -0
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +40 -40
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +1 -1
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +2 -2
- package/dist/core/extensions/reserved-host-flags.js +3 -2
- package/dist/core/history/drift-scan.js +13 -8
- package/dist/core/history/history.d.ts +8 -0
- package/dist/core/history/history.js +57 -7
- package/dist/core/history/replay.d.ts +9 -1
- package/dist/core/history/replay.js +48 -13
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +46 -14
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/command-types.js +2 -2
- package/dist/core/shared/errors.d.ts +5 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-metadata-cache.d.ts +1 -1
- package/dist/core/store/item-metadata-cache.js +14 -7
- package/dist/sdk/cli-bootstrap.d.ts +2 -0
- package/dist/sdk/cli-bootstrap.js +6 -2
- package/dist/sdk/cli-contracts/completeness.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +5 -2
- package/dist/sdk/cli-contracts/registration-helpers.d.ts +20 -3
- package/dist/sdk/cli-contracts/registration-helpers.js +18 -12
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +8 -6
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +4 -3
- package/dist/sdk/cli-contracts/tool-option-contracts.js +3 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +22 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +7 -4
- package/dist/sdk/cli-program.js +3 -2
- package/dist/sdk/completion.js +16 -7
- package/dist/sdk/context-intent-contracts.js +45 -4
- package/dist/sdk/core.d.ts +1 -0
- package/dist/sdk/core.js +3 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-1.d.ts +8 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1585 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-2.d.ts +8 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1608 -0
- package/dist/sdk/generated-error-code-catalog.js +6 -3140
- package/dist/sdk/governance/assurance-action.js +9 -7
- package/dist/sdk/governance/assurance-mutation-error.d.ts +7 -0
- package/dist/sdk/governance/assurance-mutation-error.js +35 -0
- package/dist/sdk/governance/assurance-runtime.js +11 -8
- package/dist/sdk/governance/assurance.d.ts +12 -6
- package/dist/sdk/governance/assurance.js +181 -66
- package/dist/sdk/governance/health.d.ts +3 -1
- package/dist/sdk/governance/health.js +21 -4
- package/dist/sdk/governance/validate-item-reader.js +3 -3
- package/dist/sdk/governance/validate.d.ts +2 -0
- package/dist/sdk/governance/validate.js +13 -3
- package/dist/sdk/graph/durable-cache.d.ts +1 -1
- package/dist/sdk/graph/durable-cache.js +98 -29
- package/dist/sdk/graph/governance.d.ts +14 -0
- package/dist/sdk/graph/governance.js +34 -9
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/lifecycle/claim.js +10 -3
- package/dist/sdk/merge/driver.d.ts +2 -2
- package/dist/sdk/merge/driver.js +3 -3
- package/dist/sdk/merge/receipts.d.ts +6 -4
- package/dist/sdk/merge/receipts.js +7 -5
- package/dist/sdk/merge/three-way.d.ts +2 -2
- package/dist/sdk/merge/three-way.js +3 -3
- package/dist/sdk/output-projection.d.ts +9 -1
- package/dist/sdk/output-projection.js +45 -9
- package/dist/sdk/query/activity.d.ts +49 -2
- package/dist/sdk/query/activity.js +183 -37
- package/dist/sdk/query/get.js +19 -2
- package/dist/sdk/read-output-contracts.d.ts +5 -1
- package/dist/sdk/read-output-contracts.js +17 -2
- package/dist/sdk/read-output-session.d.ts +2 -0
- package/dist/sdk/read-output-session.js +12 -5
- package/dist/sdk/runtime-primitives.d.ts +3 -3
- package/dist/sdk/runtime-primitives.js +5 -5
- package/dist/sdk/runtime-stats-options.js +3 -2
- package/dist/sdk/runtime.js +5 -9
- package/dist/sdk/stats.d.ts +36 -3
- package/dist/sdk/stats.js +55 -15
- package/dist/sdk/test/execution.d.ts +4 -0
- package/dist/sdk/test/execution.js +86 -21
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/ASSURANCE.md +17 -12
- package/docs/COMMANDS.md +29 -8
- package/docs/CONFIGURATION.md +7 -0
- package/docs/DEPENDENCY_KIND_CONTRACT.md +10 -8
- package/docs/MERGE_SAFETY.md +3 -1
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +26 -13
- package/docs/README.md +2 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +17 -2
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +12 -1
- package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +53 -0
- package/docs/SDK_CONTEXT_INTEGRITY.md +28 -1
- package/docs/TRUSTWORTHY_CONTEXT_EVIDENCE.md +106 -0
- package/docs/performance/sdk-entrypoint-import-costs.md +6 -2
- package/marketplace.json +2 -2
- package/package.json +5 -5
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +203 -52
- package/dist/cli-bundle/chunks/chunk-2RA2YTHJ.js +0 -33
- package/dist/cli-bundle/chunks/chunk-DSKYD4LG.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HC3GM6YY.js +0 -194
- package/dist/cli-bundle/chunks/chunk-W7CPZGSB.js +0 -2
- package/dist/cli-bundle/chunks/chunk-ZXOC6HG5.js +0 -5
- package/dist/cli-bundle/chunks/register-list-query-HAUXVUPY.js +0 -10
- package/dist/cli-bundle/chunks/register-mutation-7Y5U7ABT.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-EQX3DLAZ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3AYKXMYX.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4AHEC74N.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4SV3ZKG3.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-6JW6Z2P5.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-D4PIWE6D.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-E3KCL7AY.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-ERAAFLPS.js +0 -153
- package/dist/cli-bundle/focused-chunks/chunk-F6E4JZKG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-OJ3LVVIS.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-VABB4L5Y.js +0 -17
package/dist/sdk/stats.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ContentFieldUtilizationReport } from "../core/governance/content-fields.js";
|
|
2
|
-
import { type GroupedBreakdown, type MetadataCoverageReport } from "../core/governance/metadata-coverage.js";
|
|
2
|
+
import { type CoverageItem, type GroupedBreakdown, type LifecycleClassifier, type MetadataCoverageReport } from "../core/governance/metadata-coverage.js";
|
|
3
3
|
import { type HistoryStorageStats } from "../core/history/history-storage-stats.js";
|
|
4
4
|
import type { GlobalOptions } from "../core/shared/command-types.js";
|
|
5
5
|
import type { ItemStatus, ItemType } from "../types/index.js";
|
|
@@ -7,6 +7,8 @@ import { type ImprovementDirection, type ImprovementLedgerResult, type RecordImp
|
|
|
7
7
|
import { type FleetAttributionAnalytics, type ProvenanceCoverageAnalytics } from "./history-analytics.js";
|
|
8
8
|
/** Documents the stats command options payload exchanged by command, SDK, and package integrations. */
|
|
9
9
|
export interface StatsCommandOptions {
|
|
10
|
+
/** Restore zero-count item-type and status buckets for schema-governance dashboards. */
|
|
11
|
+
includeEmpty?: boolean;
|
|
10
12
|
/** Include aggregate per-stream history storage metrics (sizes, depth, oldest/newest). */
|
|
11
13
|
storage?: boolean;
|
|
12
14
|
/** Include metadata coverage percentages (AC, estimates, resolution, tags, parent) overall and by type. */
|
|
@@ -52,6 +54,29 @@ export interface StatsCommandOptions {
|
|
|
52
54
|
/** Minimum close or explicit-value denominator required for rates. */
|
|
53
55
|
minimumSample?: number;
|
|
54
56
|
}
|
|
57
|
+
/** Compact, tabular lifecycle row used by the default stats type distribution. */
|
|
58
|
+
export interface StatsTypeLifecycleRow {
|
|
59
|
+
/** Item type represented by this row. */
|
|
60
|
+
type: string;
|
|
61
|
+
/** Total items of this type across every lifecycle bucket. */
|
|
62
|
+
total: number;
|
|
63
|
+
/** Items in the default open lifecycle bucket. */
|
|
64
|
+
open: number;
|
|
65
|
+
/** Items in active non-default lifecycle states. */
|
|
66
|
+
in_progress: number;
|
|
67
|
+
/** Items in blocked lifecycle states. */
|
|
68
|
+
blocked: number;
|
|
69
|
+
/** Items in draft lifecycle states. */
|
|
70
|
+
draft: number;
|
|
71
|
+
/** Items in completed lifecycle states. */
|
|
72
|
+
closed: number;
|
|
73
|
+
/** Items in canceled lifecycle states. */
|
|
74
|
+
canceled: number;
|
|
75
|
+
/** Items whose custom status is outside the recognized lifecycle buckets. */
|
|
76
|
+
other: number;
|
|
77
|
+
}
|
|
78
|
+
/** Screen-sized type distribution rendered as one canonical TOON table. */
|
|
79
|
+
export type StatsTypeBreakdown = StatsTypeLifecycleRow[];
|
|
55
80
|
/** Documents the stats result payload exchanged by command, SDK, and package integrations. */
|
|
56
81
|
export interface StatsResult {
|
|
57
82
|
/** Value that configures or reports totals for this contract. */
|
|
@@ -61,9 +86,11 @@ export interface StatsResult {
|
|
|
61
86
|
history_entries: number;
|
|
62
87
|
};
|
|
63
88
|
/** Schema type that determines the shape and validation rules for this value. */
|
|
64
|
-
by_type:
|
|
89
|
+
by_type: StatsTypeBreakdown;
|
|
65
90
|
/** Item counts grouped by lifecycle status. */
|
|
66
|
-
by_status: Record<ItemStatus, number
|
|
91
|
+
by_status: Partial<Record<ItemStatus, number>>;
|
|
92
|
+
/** Total zero-count type and status buckets omitted from the default projection. */
|
|
93
|
+
omitted_zero_buckets: number;
|
|
67
94
|
/** Present only with --metadata-coverage: per-field coverage overall and by type. */
|
|
68
95
|
metadata_coverage?: MetadataCoverageReport;
|
|
69
96
|
/** Present only with --by-assignee/--by-tag/--by-priority: lifecycle-bucketed group breakdowns. */
|
|
@@ -89,6 +116,11 @@ export interface StatsResult {
|
|
|
89
116
|
}
|
|
90
117
|
declare function zeroByType(itemTypes: string[]): Record<ItemType, number>;
|
|
91
118
|
declare function zeroByStatus(statuses: string[]): Record<ItemStatus, number>;
|
|
119
|
+
declare function projectStatsDistributions(items: readonly CoverageItem[], itemTypes: readonly string[], statuses: readonly string[], classifier: LifecycleClassifier, includeEmpty: boolean): {
|
|
120
|
+
byType: StatsTypeBreakdown;
|
|
121
|
+
byStatus: Partial<Record<ItemStatus, number>>;
|
|
122
|
+
omitted: number;
|
|
123
|
+
};
|
|
92
124
|
declare function countNonEmptyLines(raw: string): number;
|
|
93
125
|
declare function readHistoryStreamContents(pmRoot: string): Promise<Array<{
|
|
94
126
|
id: string;
|
|
@@ -100,6 +132,7 @@ export declare const _testOnly: {
|
|
|
100
132
|
zeroByStatus: typeof zeroByStatus;
|
|
101
133
|
countNonEmptyLines: typeof countNonEmptyLines;
|
|
102
134
|
readHistoryStreamContents: typeof readHistoryStreamContents;
|
|
135
|
+
projectStatsDistributions: typeof projectStatsDistributions;
|
|
103
136
|
};
|
|
104
137
|
/** Implements run stats for the public runtime surface of this module. */
|
|
105
138
|
export declare function runStats(global: GlobalOptions, options?: StatsCommandOptions): Promise<StatsResult>;
|
package/dist/sdk/stats.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm stats 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]="
|
|
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]="d28c7ac7-9801-5b0c-84c9-51deede398be")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { getActiveExtensionRegistrations, runActiveOnReadHooks, } from "../core/extensions/index.js";
|
|
@@ -36,6 +36,53 @@ function zeroByStatus(statuses) {
|
|
|
36
36
|
return acc;
|
|
37
37
|
}, {});
|
|
38
38
|
}
|
|
39
|
+
function projectStatsDistributions(items, itemTypes, statuses, classifier, includeEmpty) {
|
|
40
|
+
const grouped = groupItemsByDimension(items, "type", classifier);
|
|
41
|
+
const presentTypes = new Set(grouped.rows.map((row) => row.key));
|
|
42
|
+
const missingTypes = itemTypes.filter((type) => !presentTypes.has(type));
|
|
43
|
+
const groupedRows = includeEmpty
|
|
44
|
+
? [
|
|
45
|
+
...grouped.rows,
|
|
46
|
+
...missingTypes.map((type) => ({
|
|
47
|
+
label: type,
|
|
48
|
+
key: type,
|
|
49
|
+
total: 0,
|
|
50
|
+
buckets: {
|
|
51
|
+
open: 0,
|
|
52
|
+
in_progress: 0,
|
|
53
|
+
blocked: 0,
|
|
54
|
+
draft: 0,
|
|
55
|
+
closed: 0,
|
|
56
|
+
canceled: 0,
|
|
57
|
+
other: 0,
|
|
58
|
+
},
|
|
59
|
+
})),
|
|
60
|
+
]
|
|
61
|
+
: grouped.rows;
|
|
62
|
+
const byType = groupedRows.map((row) => ({
|
|
63
|
+
type: row.key ?? row.label,
|
|
64
|
+
total: row.total,
|
|
65
|
+
open: row.buckets.open,
|
|
66
|
+
in_progress: row.buckets.in_progress,
|
|
67
|
+
blocked: row.buckets.blocked,
|
|
68
|
+
draft: row.buckets.draft,
|
|
69
|
+
closed: row.buckets.closed,
|
|
70
|
+
canceled: row.buckets.canceled,
|
|
71
|
+
other: row.buckets.other,
|
|
72
|
+
}));
|
|
73
|
+
const counts = zeroByStatus([...statuses]);
|
|
74
|
+
for (const item of items)
|
|
75
|
+
counts[item.status] += 1;
|
|
76
|
+
const byStatus = Object.fromEntries(Object.entries(counts).filter(([, count]) => includeEmpty || count > 0));
|
|
77
|
+
return {
|
|
78
|
+
byType,
|
|
79
|
+
byStatus,
|
|
80
|
+
omitted: includeEmpty
|
|
81
|
+
? 0
|
|
82
|
+
: missingTypes.length +
|
|
83
|
+
Object.values(counts).filter((count) => count === 0).length,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
39
86
|
function countNonEmptyLines(raw) {
|
|
40
87
|
if (raw.trim().length === 0) {
|
|
41
88
|
return 0;
|
|
@@ -75,6 +122,7 @@ export const _testOnly = {
|
|
|
75
122
|
zeroByStatus,
|
|
76
123
|
countNonEmptyLines,
|
|
77
124
|
readHistoryStreamContents,
|
|
125
|
+
projectStatsDistributions,
|
|
78
126
|
};
|
|
79
127
|
async function recordStatsObservations(global, options) {
|
|
80
128
|
const recorded = [];
|
|
@@ -129,12 +177,13 @@ async function requestedHistoryAnalytics(pmRoot, items, settings, terminalStatus
|
|
|
129
177
|
: undefined,
|
|
130
178
|
};
|
|
131
179
|
}
|
|
132
|
-
function assembleStatsResult(totals, byType, byStatus, optional) {
|
|
180
|
+
function assembleStatsResult(totals, byType, byStatus, omittedZeroBuckets, optional) {
|
|
133
181
|
const hasBreakdowns = Object.keys(optional.breakdowns).length > 0;
|
|
134
182
|
return {
|
|
135
183
|
totals,
|
|
136
184
|
by_type: byType,
|
|
137
185
|
by_status: byStatus,
|
|
186
|
+
omitted_zero_buckets: omittedZeroBuckets,
|
|
138
187
|
...(optional.metadataCoverage
|
|
139
188
|
? { metadata_coverage: optional.metadataCoverage }
|
|
140
189
|
: {}),
|
|
@@ -180,16 +229,8 @@ export async function runStats(global, options = {}) {
|
|
|
180
229
|
itemIds: items.map((item) => item.id),
|
|
181
230
|
commandLabel: "stats",
|
|
182
231
|
});
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
// zeroByType/zeroByStatus pre-seed a bucket for every registry type/status, and
|
|
186
|
-
// the light item-metadata reader drops any item whose type/status falls outside
|
|
187
|
-
// the active registry (parse rejects them) — so every item's bucket is already
|
|
188
|
-
// present here and no on-the-fly initialization is reachable.
|
|
189
|
-
for (const item of items) {
|
|
190
|
-
byType[item.type] += 1;
|
|
191
|
-
byStatus[item.status] += 1;
|
|
192
|
-
}
|
|
232
|
+
const classifier = lifecycleClassifierFromStatusRegistry(statusRegistry);
|
|
233
|
+
const distributions = projectStatsDistributions(items, typeRegistry.types, statusRegistry.definitions.map((definition) => definition.id), classifier, options.includeEmpty === true);
|
|
193
234
|
const streams = await readHistoryStreamContents(pmRoot);
|
|
194
235
|
let historyEntries = 0;
|
|
195
236
|
for (const stream of streams) {
|
|
@@ -198,7 +239,6 @@ export async function runStats(global, options = {}) {
|
|
|
198
239
|
const storage = options.storage
|
|
199
240
|
? computeHistoryStorageStats(streams)
|
|
200
241
|
: undefined;
|
|
201
|
-
const classifier = lifecycleClassifierFromStatusRegistry(statusRegistry);
|
|
202
242
|
const metadataCoverage = options.metadataCoverage
|
|
203
243
|
? computeMetadataCoverage(items, classifier)
|
|
204
244
|
: undefined;
|
|
@@ -219,7 +259,7 @@ export async function runStats(global, options = {}) {
|
|
|
219
259
|
items: items.length,
|
|
220
260
|
history_streams: streams.length,
|
|
221
261
|
history_entries: historyEntries,
|
|
222
|
-
}, byType, byStatus, {
|
|
262
|
+
}, distributions.byType, distributions.byStatus, distributions.omitted, {
|
|
223
263
|
metadataCoverage,
|
|
224
264
|
breakdowns,
|
|
225
265
|
storage,
|
|
@@ -231,4 +271,4 @@ export async function runStats(global, options = {}) {
|
|
|
231
271
|
});
|
|
232
272
|
}
|
|
233
273
|
//# sourceMappingURL=stats.js.map
|
|
234
|
-
//# debugId=
|
|
274
|
+
//# debugId=d28c7ac7-9801-5b0c-84c9-51deede398be
|
|
@@ -35,6 +35,8 @@ export interface TestCommandOptions {
|
|
|
35
35
|
addJson?: string[];
|
|
36
36
|
/** Value that configures or reports remove for this contract. */
|
|
37
37
|
remove?: string[];
|
|
38
|
+
/** Remove linked tests by their stable 1-based list position. */
|
|
39
|
+
removeIndex?: Array<string | number>;
|
|
38
40
|
/** Value that configures or reports list for this contract. */
|
|
39
41
|
list?: boolean;
|
|
40
42
|
/** Value that configures or reports run for this contract. */
|
|
@@ -146,6 +148,8 @@ export interface TestResult {
|
|
|
146
148
|
changed: boolean;
|
|
147
149
|
/** Value that configures or reports count for this contract. */
|
|
148
150
|
count: number;
|
|
151
|
+
/** Number of linked-test entries removed by this mutation. */
|
|
152
|
+
removed?: number;
|
|
149
153
|
/** Measurements supplied for the current producing run. */
|
|
150
154
|
measurements?: TestRunMeasurement[];
|
|
151
155
|
/** Existing and current measurements below the selected threshold. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm test 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]="
|
|
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]="b40f54be-2d3e-5b98-9d49-cb8608a782f5")}catch(e){}}();
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import { cp, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
@@ -507,7 +507,6 @@ function parseAddJsonEntries(raw) {
|
|
|
507
507
|
return parsed;
|
|
508
508
|
});
|
|
509
509
|
}
|
|
510
|
-
/* c8 ignore stop */
|
|
511
510
|
function parseRemoveEntries(raw) {
|
|
512
511
|
if (!raw)
|
|
513
512
|
return [];
|
|
@@ -516,19 +515,48 @@ function parseRemoveEntries(raw) {
|
|
|
516
515
|
if (!trimmed) {
|
|
517
516
|
throw new PmCliError("--remove requires command or path value", EXIT_CODE.USAGE);
|
|
518
517
|
}
|
|
519
|
-
|
|
520
|
-
|
|
518
|
+
const identityPrefix = /^(command|path)\s*=/i.exec(trimmed);
|
|
519
|
+
if (identityPrefix) {
|
|
520
|
+
const value = trimmed.slice(identityPrefix[0].length).trim();
|
|
521
|
+
if (!value) {
|
|
522
|
+
throw new PmCliError("--remove requires a non-empty command=<value> or path=<value>", EXIT_CODE.USAGE);
|
|
523
|
+
}
|
|
524
|
+
return {
|
|
525
|
+
kind: identityPrefix[1].toLowerCase(),
|
|
526
|
+
value,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (/^[A-Za-z_][\w-]*=\S+$/u.test(trimmed)) {
|
|
530
|
+
throw new PmCliError("--remove structured selectors require command=<value> or path=<value>", EXIT_CODE.USAGE);
|
|
531
|
+
}
|
|
532
|
+
if (/^(?:[-*+]\s+)?(?:path|command)\s*:/i.test(trimmed) ||
|
|
521
533
|
trimmed.startsWith("```")) {
|
|
522
534
|
const kv = parseCsvKv(trimmed, "--remove");
|
|
535
|
+
const kind = kv.path !== undefined ? "path" : "command";
|
|
523
536
|
const value = kv.path ?? kv.command;
|
|
524
537
|
if (!value?.trim()) {
|
|
525
538
|
throw new PmCliError("--remove requires command=<value> and/or path=<value>", EXIT_CODE.USAGE);
|
|
526
539
|
}
|
|
527
|
-
return value.trim();
|
|
540
|
+
return { kind, value: value.trim() };
|
|
528
541
|
}
|
|
529
|
-
return trimmed;
|
|
542
|
+
return { kind: "either", value: trimmed };
|
|
530
543
|
});
|
|
531
544
|
}
|
|
545
|
+
function parseRemoveIndexes(raw) {
|
|
546
|
+
if (!raw)
|
|
547
|
+
return [];
|
|
548
|
+
return [
|
|
549
|
+
...new Set(raw.map((value) => {
|
|
550
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(value, 10);
|
|
551
|
+
if (!Number.isInteger(parsed) ||
|
|
552
|
+
parsed < 1 ||
|
|
553
|
+
String(parsed) !== String(value).trim()) {
|
|
554
|
+
throw new PmCliError("--remove-index must be a positive integer", EXIT_CODE.USAGE);
|
|
555
|
+
}
|
|
556
|
+
return parsed;
|
|
557
|
+
})),
|
|
558
|
+
];
|
|
559
|
+
}
|
|
532
560
|
function closeLinkedTestStdin(child) {
|
|
533
561
|
// Force EOF on child stdin so non-interactive runs do not wait on input.
|
|
534
562
|
try {
|
|
@@ -1383,7 +1411,10 @@ function resolveLinkedTestPreflightResult(params) {
|
|
|
1383
1411
|
}
|
|
1384
1412
|
function buildLinkedTestExecutionEnv(params) {
|
|
1385
1413
|
const effectiveDirectives = resolveEffectiveLinkedTestDirectives(params.runtimeDirectives, params.linkedTest);
|
|
1386
|
-
const executionEnv = {
|
|
1414
|
+
const executionEnv = {
|
|
1415
|
+
...process.env,
|
|
1416
|
+
SENTRY_ENVIRONMENT: "test",
|
|
1417
|
+
};
|
|
1387
1418
|
applyEnvDirectiveStage(executionEnv, params.runtimeDirectives);
|
|
1388
1419
|
applyEnvDirectiveStage(executionEnv, {
|
|
1389
1420
|
env_set: params.linkedTest.env_set ?? {},
|
|
@@ -1538,6 +1569,7 @@ async function readLinkedTestItem(params) {
|
|
|
1538
1569
|
tests: loaded.document.metadata.tests ?? [],
|
|
1539
1570
|
testRuns: loaded.document.metadata.test_runs ?? [],
|
|
1540
1571
|
changed: false,
|
|
1572
|
+
removed: 0,
|
|
1541
1573
|
};
|
|
1542
1574
|
}
|
|
1543
1575
|
function linkedTestsHaveSameIdentity(left, right) {
|
|
@@ -1555,15 +1587,26 @@ function appendMissingLinkedTests(current, additions) {
|
|
|
1555
1587
|
}
|
|
1556
1588
|
return next;
|
|
1557
1589
|
}
|
|
1558
|
-
function removeLinkedTestsBySelector(current, removals) {
|
|
1559
|
-
if (removals.length === 0) {
|
|
1560
|
-
return current;
|
|
1590
|
+
function removeLinkedTestsBySelector(current, removals, removeIndexes) {
|
|
1591
|
+
if (removals.length === 0 && removeIndexes.length === 0) {
|
|
1592
|
+
return { tests: current, removed: 0 };
|
|
1561
1593
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1594
|
+
const indexSet = new Set(removeIndexes);
|
|
1595
|
+
const tests = current.filter((entry, index) => {
|
|
1596
|
+
if (indexSet.has(index + 1))
|
|
1597
|
+
return false;
|
|
1598
|
+
return !removals.some((selector) => {
|
|
1599
|
+
if (selector.kind === "command")
|
|
1600
|
+
return entry.command === selector.value;
|
|
1601
|
+
if (selector.kind === "path")
|
|
1602
|
+
return entry.path === selector.value;
|
|
1603
|
+
return entry.command === selector.value || entry.path === selector.value;
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1606
|
+
return { tests, removed: current.length - tests.length };
|
|
1564
1607
|
}
|
|
1565
|
-
function applyLinkedTestMutations(previous, adds, removes) {
|
|
1566
|
-
return removeLinkedTestsBySelector(appendMissingLinkedTests(previous, adds), removes);
|
|
1608
|
+
function applyLinkedTestMutations(previous, adds, removes, removeIndexes) {
|
|
1609
|
+
return removeLinkedTestsBySelector(appendMissingLinkedTests(previous, adds), removes, removeIndexes);
|
|
1567
1610
|
}
|
|
1568
1611
|
function hasTestRuntimeDirectiveFlags(options) {
|
|
1569
1612
|
return ((options.envSet?.length ?? 0) > 0 ||
|
|
@@ -1590,25 +1633,43 @@ function assertTestRunFlagUsage(options) {
|
|
|
1590
1633
|
}
|
|
1591
1634
|
}
|
|
1592
1635
|
async function resolveLinkedTestItem(params) {
|
|
1593
|
-
const { id, options, pmRoot, settings, typeToFolder, adds, removes } = params;
|
|
1594
|
-
if (adds.length === 0 && removes.length === 0) {
|
|
1636
|
+
const { id, options, pmRoot, settings, typeToFolder, adds, removes, removeIndexes, } = params;
|
|
1637
|
+
if (adds.length === 0 && removes.length === 0 && removeIndexes.length === 0) {
|
|
1595
1638
|
return readLinkedTestItem({ id, pmRoot, settings, typeToFolder });
|
|
1596
1639
|
}
|
|
1640
|
+
let removed = 0;
|
|
1597
1641
|
const result = await mutateItem({
|
|
1598
1642
|
pmRoot,
|
|
1599
1643
|
settings,
|
|
1600
1644
|
id,
|
|
1601
|
-
op: "tests_add",
|
|
1645
|
+
op: adds.length > 0 ? "tests_add" : "tests_remove",
|
|
1602
1646
|
author: resolveAuthor(options.author, settings.author_default),
|
|
1603
1647
|
message: options.message,
|
|
1604
1648
|
force: options.force,
|
|
1605
1649
|
skipNoop: true,
|
|
1606
1650
|
mutate(document) {
|
|
1607
1651
|
const previous = document.metadata.tests ?? [];
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1652
|
+
const mutation = applyLinkedTestMutations(previous, adds, removes, removeIndexes);
|
|
1653
|
+
removed = mutation.removed;
|
|
1654
|
+
if ((removes.length > 0 || removeIndexes.length > 0) && removed === 0) {
|
|
1655
|
+
throw new PmCliError("No linked tests matched the requested removal selector", EXIT_CODE.NOT_FOUND, {
|
|
1656
|
+
code: "linked_test_remove_no_match",
|
|
1657
|
+
unmatched: [
|
|
1658
|
+
...removes.map((entry) => `${entry.kind}=${entry.value}`),
|
|
1659
|
+
...removeIndexes.map((index) => `index=${index}`),
|
|
1660
|
+
],
|
|
1661
|
+
required: "List linked tests and retry with an exact command/path or a current 1-based --remove-index.",
|
|
1662
|
+
examples: [
|
|
1663
|
+
`pm test ${id} --list`,
|
|
1664
|
+
`pm test ${id} --remove-index 1`,
|
|
1665
|
+
],
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
document.metadata.tests = mutation.tests;
|
|
1610
1669
|
return {
|
|
1611
|
-
changedFields: stableValueEquals(previous,
|
|
1670
|
+
changedFields: stableValueEquals(previous, mutation.tests)
|
|
1671
|
+
? []
|
|
1672
|
+
: ["tests"],
|
|
1612
1673
|
};
|
|
1613
1674
|
},
|
|
1614
1675
|
});
|
|
@@ -1617,6 +1678,7 @@ async function resolveLinkedTestItem(params) {
|
|
|
1617
1678
|
tests: result.item.tests ?? [],
|
|
1618
1679
|
testRuns: result.item.test_runs ?? [],
|
|
1619
1680
|
changed: result.changedFields.length > 0,
|
|
1681
|
+
removed,
|
|
1620
1682
|
};
|
|
1621
1683
|
}
|
|
1622
1684
|
function resolveTestRunOptions(options, tests) {
|
|
@@ -1780,6 +1842,7 @@ export async function runTest(id, options, global) {
|
|
|
1780
1842
|
...parseAddJsonEntries(resolvedAddJsons),
|
|
1781
1843
|
];
|
|
1782
1844
|
const removes = parseRemoveEntries(resolvedRemoves);
|
|
1845
|
+
const removeIndexes = parseRemoveIndexes(options.removeIndex);
|
|
1783
1846
|
const item = await resolveLinkedTestItem({
|
|
1784
1847
|
id,
|
|
1785
1848
|
options,
|
|
@@ -1788,6 +1851,7 @@ export async function runTest(id, options, global) {
|
|
|
1788
1851
|
typeToFolder: typeRegistry.type_to_folder,
|
|
1789
1852
|
adds,
|
|
1790
1853
|
removes,
|
|
1854
|
+
removeIndexes,
|
|
1791
1855
|
});
|
|
1792
1856
|
const runOptions = resolveTestRunOptions(options, item.tests);
|
|
1793
1857
|
const runStartedAt = options.run === true ? nowIso() : undefined;
|
|
@@ -1835,6 +1899,7 @@ export async function runTest(id, options, global) {
|
|
|
1835
1899
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
1836
1900
|
changed: item.changed,
|
|
1837
1901
|
count: item.tests.length,
|
|
1902
|
+
...(item.removed > 0 ? { removed: item.removed } : {}),
|
|
1838
1903
|
...measurementProjection,
|
|
1839
1904
|
};
|
|
1840
1905
|
}
|
|
@@ -1874,4 +1939,4 @@ export const _testOnlyTestCommand = {
|
|
|
1874
1939
|
summarizeRunResultStatuses,
|
|
1875
1940
|
};
|
|
1876
1941
|
//# sourceMappingURL=execution.js.map
|
|
1877
|
-
//# debugId=
|
|
1942
|
+
//# debugId=b40f54be-2d3e-5b98-9d49-cb8608a782f5
|
package/dist/types.d.ts
CHANGED
|
@@ -776,6 +776,8 @@ export interface HistoryEntry {
|
|
|
776
776
|
before_hash: string;
|
|
777
777
|
/** Value that configures or reports after hash for this contract. */
|
|
778
778
|
after_hash: string;
|
|
779
|
+
/** Version of the item canonicalization used by before_hash and after_hash. Absent on legacy streams. */
|
|
780
|
+
item_hash_version?: number;
|
|
779
781
|
/** Human-readable explanation suitable for logs and agent-facing output. */
|
|
780
782
|
message?: string;
|
|
781
783
|
/** Structured audit metadata that does not alter replayed item state. */
|
package/dist/types.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Supported values accepted by the builtin item type contract. */
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
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]="8b39bc01-0325-5dc6-8492-585c98608076")}catch(e){}}();
|
|
9
9
|
export const BUILTIN_ITEM_TYPE_VALUES = [
|
|
10
10
|
"Epic",
|
|
11
11
|
"Feature",
|
|
@@ -241,4 +241,4 @@ export const CONTEXT_SECTION_VALUES = [
|
|
|
241
241
|
"tests",
|
|
242
242
|
];
|
|
243
243
|
//# sourceMappingURL=types.js.map
|
|
244
|
-
//# debugId=
|
|
244
|
+
//# debugId=8b39bc01-0325-5dc6-8492-585c98608076
|
package/docs/ASSURANCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Project Assurance Primitives
|
|
2
2
|
|
|
3
|
-
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon)
|
|
3
|
+
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon), [pm-py7qv2](../.agents/pm/issues/pm-py7qv2.toon), [pm-33mjrw](../.agents/pm/issues/pm-33mjrw.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon)
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
@@ -22,20 +22,22 @@ The assurance SDK keeps those semantics independent from presentation. Commander
|
|
|
22
22
|
|
|
23
23
|
Measurements support these built-in sources:
|
|
24
24
|
|
|
25
|
-
| Source
|
|
26
|
-
|
|
|
27
|
-
| `items`
|
|
28
|
-
| `dependency_kind` | Count typed relationship edges such as `blocked_by` or `verifies
|
|
29
|
-
| `graph`
|
|
30
|
-
| `validate`
|
|
31
|
-
| `health`
|
|
32
|
-
| `history`
|
|
33
|
-
| `links`
|
|
34
|
-
| `derived`
|
|
35
|
-
| `provider`
|
|
25
|
+
| Source | Purpose |
|
|
26
|
+
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `items` | Count authoritative full item records matching status, type, tags, an exact metadata field, or a field `state` of `present`/`missing`. |
|
|
28
|
+
| `dependency_kind` | Count typed relationship edges such as `blocked_by` or `verifies`; accepted aliases and canonical spellings measure the same population. |
|
|
29
|
+
| `graph` | Select a numeric or labelled-set field from a public graph SDK result. |
|
|
30
|
+
| `validate` | Select a validator check status or numeric detail. |
|
|
31
|
+
| `health` | Select a health check status, numeric detail, or labelled set. |
|
|
32
|
+
| `history` | Count immutable events by operation, author, harness, or model. |
|
|
33
|
+
| `links` | Count items with present or missing file, test, or documentation evidence. |
|
|
34
|
+
| `derived` | Combine numeric measurements with deterministic arithmetic and cycle detection. |
|
|
35
|
+
| `provider` | Delegate a measurement to an explicitly supplied host/package resolver. |
|
|
36
36
|
|
|
37
37
|
Each measurement may declare `max_cost`. Evaluation fails closed when the total abstract compute units exceed that ceiling. Every result reports units, scanned items, scanned history rows, provider calls, duration, population size, and contributors.
|
|
38
38
|
|
|
39
|
+
An `items` source with `field` must declare exactly one predicate: `equals` (including an explicit `null`) or `state`. `state: missing` treats an absent property, `null`, an empty string, or an empty array as missing; `state: present` selects the complement. Workspace evaluation loads full item metadata, so `files`, `tests`, and `docs` selectors measure stored evidence rather than a light projection that omitted those collections.
|
|
40
|
+
|
|
39
41
|
Assertions require exactly one polarity:
|
|
40
42
|
|
|
41
43
|
- `ceiling`, `floor`, `equals`, or `zero`
|
|
@@ -117,10 +119,13 @@ A gate emits one object containing:
|
|
|
117
119
|
- gate id, evaluated tree, trigger, timestamp, and dry-run status;
|
|
118
120
|
- overall `pass`, `warn`, or `block` plus stable exit code;
|
|
119
121
|
- every assertion's measurement, scope, population, observed value, structured bound, signed distance, enforcement, negative-control proof, cost, and contributors;
|
|
122
|
+
- every assertion's `measurement_definition_fingerprint`, a SHA-256 identity for the exact declaration that produced the observation;
|
|
120
123
|
- an aggregate compute receipt.
|
|
121
124
|
|
|
122
125
|
Dry runs never write history. Non-dry verdicts are immutable workspace audit events and remain queryable after ordinary registry changes. Verdict reads return newest entries first and default to a bounded result; use `--limit` to select up to 1,000 matching records. A blocking verdict exits non-zero; warnings and observations remain successful while preserving their failed assertion rows.
|
|
123
126
|
|
|
127
|
+
Verdicts persisted before definition fingerprints were introduced remain readable and are identifiable by the absence of `measurement_definition_fingerprint`. Registry mutations and verdict writes use the same explicit-author, configured-author, and detected-harness precedence as other SDK mutations; they do not manufacture an `unknown` author when a harness identity is available.
|
|
128
|
+
|
|
124
129
|
## Safety and Evolution
|
|
125
130
|
|
|
126
131
|
- Use stable lowercase ids; prose belongs in descriptions and mutation messages.
|
package/docs/COMMANDS.md
CHANGED
|
@@ -19,7 +19,9 @@ pm contracts --command <command> --flags-only --json
|
|
|
19
19
|
- Use `pm contracts --summary --json` for the cheapest command map, then narrow with command-scoped contracts.
|
|
20
20
|
- Every mutation writes history.
|
|
21
21
|
|
|
22
|
-
Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon)
|
|
22
|
+
Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon),
|
|
23
|
+
[pm-7nqo6b](../.agents/pm/issues/pm-7nqo6b.toon), and
|
|
24
|
+
[pm-j1r8gl](../.agents/pm/issues/pm-j1r8gl.toon).
|
|
23
25
|
|
|
24
26
|
## Command Families
|
|
25
27
|
|
|
@@ -941,17 +943,25 @@ pm history-repair <id> --dry-run
|
|
|
941
943
|
pm history-repair <id> --message "re-anchor legacy drift"
|
|
942
944
|
pm history-repair --all --dry-run
|
|
943
945
|
pm history-repair --all --message "bulk re-anchor drifted streams"
|
|
944
|
-
pm activity
|
|
946
|
+
pm activity # item digest for the last 24 hours
|
|
947
|
+
pm activity --raw --id <id> --limit 50
|
|
945
948
|
pm activity --full --id <id> --limit 50
|
|
946
949
|
pm activity --full --unbounded
|
|
947
950
|
pm restore <id> <timestamp-or-version>
|
|
948
951
|
```
|
|
949
952
|
|
|
950
953
|
History is append-only. Restore appends a new restore event instead of rewriting old history.
|
|
951
|
-
Bare `pm activity` is
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
954
|
+
Bare `pm activity` is an item-centric digest for the last 24 hours, bounded to
|
|
955
|
+
15 most-recently-touched items. Each row joins current `id`, `type`, `status`,
|
|
956
|
+
and title with the matching event count, first/last timestamps, and a bounded
|
|
957
|
+
operation histogram. `activity_summary` states the effective window plus event,
|
|
958
|
+
item, author, and operation counts, so an empty digest is distinguishable from
|
|
959
|
+
a bounded one. Use `--raw` for the legacy compact per-event stream, `--compact`
|
|
960
|
+
as its compatibility spelling, `--full` for events with patch payloads, or
|
|
961
|
+
`--provenance` for patch-free provenance rows. Every mode reports total and
|
|
962
|
+
omitted row counts plus the applied bound. Use `--limit` for a deliberate cap,
|
|
963
|
+
or `--unbounded` for an explicitly unlimited read; the two flags are mutually
|
|
964
|
+
exclusive.
|
|
955
965
|
Workspace-scoped mutations to settings, schema, profiles, init state, and
|
|
956
966
|
extension/package activation are recorded in
|
|
957
967
|
`.agents/pm/history/_workspace.jsonl` using the same patch/hash format.
|
|
@@ -962,10 +972,21 @@ workspace auditing and is created on the first audited singleton mutation.
|
|
|
962
972
|
|
|
963
973
|
`--diff` replays the history chain and emits, per entry, a `changes` array of `{ field, before, after }` field-level value transitions (alongside the `changed_fields` name list) — so you can see exactly what each field changed from and to without comparing snapshots. It is independent of the compact/full projection. `--field <name>` narrows the diff to a single field's transitions (implying `--diff`), answering "when did `<field>` change?" — e.g. `pm history <id> --diff --field status`.
|
|
964
974
|
|
|
965
|
-
`pm stats` reports item and history totals plus
|
|
975
|
+
`pm stats` reports item and history totals plus a screen-sized lifecycle table.
|
|
976
|
+
Every non-empty item type is one row with `total`, `open`, `in_progress`,
|
|
977
|
+
`blocked`, `draft`, `closed`, `canceled`, and `other` counts. Empty registered
|
|
978
|
+
types and statuses are suppressed and their combined count is retained in the
|
|
979
|
+
`omitted_zero_buckets` scalar. The default TOON projection is gated at no more
|
|
980
|
+
than 22 lines on the representative release fixture. Add `--include-empty` to
|
|
981
|
+
restore every zero-filled type and status for schema-governance dashboards.
|
|
982
|
+
Add `--storage` for aggregate history-stream metrics — `total_streams`,
|
|
983
|
+
`total_lines`, `total_bytes`, the top streams by size (`largest_by_bytes`) and
|
|
984
|
+
by depth (`deepest_by_lines`), and the global `oldest_entry`/`newest_entry` — to
|
|
985
|
+
decide when to compact or redact streams and to plan storage:
|
|
966
986
|
|
|
967
987
|
```bash
|
|
968
988
|
pm stats
|
|
989
|
+
pm stats --include-empty
|
|
969
990
|
pm stats --storage --json
|
|
970
991
|
pm stats --metadata-coverage --json
|
|
971
992
|
pm stats --field-utilization --json
|
|
@@ -973,7 +994,7 @@ pm stats --by-assignee --by-priority
|
|
|
973
994
|
pm stats --by-tag --tag-prefix domain: --json
|
|
974
995
|
```
|
|
975
996
|
|
|
976
|
-
For governance dashboards, `--metadata-coverage` adds a `metadata_coverage` block reporting per-field `present`/`applicable`/`percent` for `acceptance_criteria`, `estimated_minutes`, `resolution`, `tags`, and `parent` — overall and `by_type` (resolution coverage is scoped to terminal items, its only applicable population). `--field-utilization` adds a `field_utilization` block reporting `present`/`total`/`percent` for each content field (`notes`, `learnings`, `files`, `docs`, `tests`, `comments`, `deps`, `body`, `linked_command`) across all items, so under-documented content dimensions are visible at a glance and pair naturally with the `--has-*`/`--no-*` list filters for drill-down. `--by-assignee`, `--by-tag`, and `--by-priority` add a `breakdowns` block with lifecycle-bucketed rows (`open`/`in_progress`/`blocked`/`draft`/`closed`/`canceled`/`other` + `total`) per group; blank keys render an explicit `(unassigned)`/`(untagged)` label. `--by-tag` accepts `--tag-prefix` to restrict counting to a tag namespace (for example `domain:`). All of these sections are gated behind their flags so the default `pm stats`
|
|
997
|
+
For governance dashboards, `--metadata-coverage` adds a `metadata_coverage` block reporting per-field `present`/`applicable`/`percent` for `acceptance_criteria`, `estimated_minutes`, `resolution`, `tags`, and `parent` — overall and `by_type` (resolution coverage is scoped to terminal items, its only applicable population). `--field-utilization` adds a `field_utilization` block reporting `present`/`total`/`percent` for each content field (`notes`, `learnings`, `files`, `docs`, `tests`, `comments`, `deps`, `body`, `linked_command`) across all items, so under-documented content dimensions are visible at a glance and pair naturally with the `--has-*`/`--no-*` list filters for drill-down. `--by-assignee`, `--by-tag`, and `--by-priority` add a `breakdowns` block with lifecycle-bucketed rows (`open`/`in_progress`/`blocked`/`draft`/`closed`/`canceled`/`other` + `total`) per group; blank keys render an explicit `(unassigned)`/`(untagged)` label. `--by-tag` accepts `--tag-prefix` to restrict counting to a tag namespace (for example `domain:`). All of these sections are gated behind their flags so the default `pm stats` remains readable at first glance.
|
|
977
998
|
`history-redact` rewrites matching history payloads deterministically, recomputes hash chains, and appends an auditable `history_redact` marker entry when changes are applied. Its result reports only `literal_count`, `regex_count`, `total_count`, and whether the default replacement was selected; literal values, regex source text, and replacement text are never echoed in CLI, SDK, MCP, recovery, profile, or telemetry output. Treat regex text as sensitive input because it can contain the exact material being removed.
|
|
978
999
|
`history-compact` rewrites long streams into a synthetic checkpoint baseline plus a retained tail (`--before` accepts a 1-based version or ISO timestamp), re-anchors hashes, verifies integrity, and appends an auditable `history_compact` marker when applied.
|
|
979
1000
|
`history-compact` bulk mode (mutually exclusive with a positional `<id>`) compacts many streams in one audited pass. Select with `--ids <a,b,c>` (an explicit list — used on its own, not combined with the scan selectors below), or a scan: `--all-over <N>` (every stream with more than N entries) and/or a lifecycle filter `--closed` (terminal items only) or `--all-streams` (every stream). `--closed` and `--all-streams` are mutually exclusive. `--min-entries <N>` (default 3) skips already-compact streams; when `history.compact_policy` is enabled and `--all-over` is omitted, the policy's `max_entries` becomes the default threshold. `--before` is single-id only and is rejected in bulk mode. Each selected stream runs the same single-item compaction; one failing stream never aborts the rest — the result reports `totals` (`streams_considered`/`selected`/`items_compacted`/`items_skipped`/`items_errored`) plus one row per stream (`compacted`/`skipped` with a `skip_reason`/`errored`), and the command exits non-zero only if any stream errored.
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -183,6 +183,13 @@ Crash and error diagnostics are reported to Sentry only when telemetry is enable
|
|
|
183
183
|
|
|
184
184
|
> Sentry is hard-disabled under Vitest (`VITEST` / `VITEST_WORKER_ID`), so these knobs are no-ops inside the test suite.
|
|
185
185
|
|
|
186
|
+
Linked commands launched by `pm test --run` default
|
|
187
|
+
`SENTRY_ENVIRONMENT=test`, even when the parent process is classified as
|
|
188
|
+
production. This keeps sandbox failures out of production diagnostics. An
|
|
189
|
+
explicit run-level or per-test `env_set=SENTRY_ENVIRONMENT=<name>` directive
|
|
190
|
+
still overrides the default when a test intentionally targets another
|
|
191
|
+
environment.
|
|
192
|
+
|
|
186
193
|
## Item Storage Format
|
|
187
194
|
|
|
188
195
|
TOON is the default:
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Dependency-kind contract
|
|
2
2
|
|
|
3
|
-
Tracker: [pm-4020c5](../.agents/pm/issues/pm-4020c5.toon), [pm-jkbqt8](../.agents/pm/issues/pm-jkbqt8.toon)
|
|
3
|
+
Tracker: [pm-4020c5](../.agents/pm/issues/pm-4020c5.toon), [pm-jkbqt8](../.agents/pm/issues/pm-jkbqt8.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon)
|
|
4
4
|
|
|
5
5
|
Dependency rows have one canonical stored spelling per relationship meaning. Command inputs remain compatibility-friendly: hyphens normalize to underscores and the aliases below are accepted, but `pm create` and `pm update` persist the canonical kind. Existing historical rows are never rewritten implicitly.
|
|
6
6
|
|
|
7
|
-
| Canonical kind | Accepted legacy aliases
|
|
8
|
-
|
|
|
9
|
-
| `blocked_by`
|
|
10
|
-
| `related`
|
|
11
|
-
| `parent`
|
|
12
|
-
| `child`
|
|
7
|
+
| Canonical kind | Accepted legacy aliases |
|
|
8
|
+
| -------------- | -------------------------------------- |
|
|
9
|
+
| `blocked_by` | `depends_on`, `depends-on` |
|
|
10
|
+
| `related` | `related_to`, `related-to` |
|
|
11
|
+
| `parent` | `child_of`, `child-of`, `epic` |
|
|
12
|
+
| `child` | `parent_child`, `parent-child`, `task` |
|
|
13
13
|
|
|
14
14
|
`epic` and `task` are compatibility aliases, not item types embedded in the relationship ontology. New integrations should use `parent` or `child` and express the work classification through the item `type` field.
|
|
15
15
|
|
|
@@ -26,4 +26,6 @@ Readiness, `pm next`, context blocker summaries, `pm list-blocked`, downstream `
|
|
|
26
26
|
|
|
27
27
|
## Legacy observability
|
|
28
28
|
|
|
29
|
-
`pm deps` returns `legacy_alias_counts` for the workspace. `pm graph audit` returns the same field beside
|
|
29
|
+
`pm deps` returns `legacy_alias_counts` for the workspace. `pm graph audit` returns the same field beside canonical `profile.edges_by_kind` counts, `profile.edge_share_by_kind` composition ratios, and the `semantic_edges`/`semantic_edge_share` context-preservation census. The semantic census counts `discovered_from`, `incident_from`, `supersedes`, and `verifies` over all deduplicated directed edges. Empty objects and zero shares are explicit, not omitted. These diagnostics are read-only; terminal history remains untouched until an explicitly governed migration is requested.
|
|
30
|
+
|
|
31
|
+
Assurance `dependency_kind` measurements canonicalize both the declaration and stored row before comparing. A declaration using `related` and one using the accepted `related_to` alias therefore measure the same edge population; alias debt remains separately observable through `legacy_alias_counts`.
|