pm-ops 2026.8.10 → 2026.8.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.8.17 - 2026-08-17
4
+
5
+ ### Fixed
6
+
7
+ - A truncated list-all answer corrupts fleet throughput and cycle-time metrics ([ops-x3wc](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-x3wc.toon))
8
+
9
+ ## 2026.8.16 - 2026-08-16
10
+
11
+ ### Added
12
+
13
+ - Measure the fleet's coverage and docstring quality as audited assurance bounds via a pm-ops quality measurement provider ([ops-a367](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/features/ops-a367.toon))
14
+
15
+ ### Fixed
16
+
17
+ - The pm CLI compatibility floor was declared only in peerDependencies, which only npm enforces, and not in manifest.json pm_min_version, which is the field the CLI enforces ([ops-zl7a](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-zl7a.toon))
18
+
3
19
  ## 2026.8.10 - 2026-08-10
4
20
 
5
21
  ### Fixed
package/README.md CHANGED
@@ -218,6 +218,8 @@ pm ops audit --format markdown
218
218
 
219
219
  Export pm workspace health as **Prometheus** text-format gauges so a Prometheus/Grafana stack can scrape fleet project-management signals — turning `project management = context management` into a dashboard. Reads each repo's items via the pm CLI (`pm list-all`, `pm list-blocked`) and derives counts, throughput, and cycle-time in-process (the same `closed_at` methodology `pm-brief` momentum uses).
220
220
 
221
+ Every pm item-list read explicitly uses `--full --output-budget unbounded` and is accepted only when the CLI's pagination, completeness, omission, and row-count receipts all prove that every item was returned. If any signal disagrees, pm-ops marks that repository as unavailable (`pm_workspace_available 0`) instead of publishing plausible but incomplete throughput, cycle-time, status-count, or blocked-item data.
222
+
221
223
  ```bash
222
224
  pm ops metrics # Prometheus exposition for the current repo
223
225
  pm ops metrics --repos ~/container/pm-* # fleet-wide, one series set per repo
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Assurance measurement provider that turns the fleet's pinned code-quality
3
+ * thresholds into audited bounds.
4
+ *
5
+ * Every fleet package historically hand-rolled a `scripts/coverage-gate.ts`
6
+ * with thresholds pinned under `coverageGate` in `package.json`. Lowering one
7
+ * was an ordinary diff: nothing in the workflow recorded *why* a number moved,
8
+ * and nothing proved the bound still meant anything. Under pm-cli's assurance
9
+ * surface, weakening a bound requires an `authorization_decision` naming a
10
+ * terminal Decision item the host verifies, and every non-dry gate verdict is
11
+ * appended to the immutable workspace history stream. That only bites if the
12
+ * quality numbers can be *measured* by an assurance provider, which is what
13
+ * this module exports.
14
+ *
15
+ * The provider reads a local lcov coverage report and the canonical docstring
16
+ * analyzer and reduces them to four measurement keys. It owns no quality
17
+ * thresholds itself — those live in assertions and gates the consuming
18
+ * workspace declares — but it refuses to be satisfied by a *stale* coverage
19
+ * report, because a gate that runs against yesterday's `lcov.info` after today's
20
+ * source edit is a gate that measures nothing.
21
+ *
22
+ * @see {@link https://github.com/unbraind/pm-cli/blob/main/docs/ASSURANCE.md ASSURANCE.md}
23
+ * for the measurement / assertion / gate vocabulary this provider plugs into.
24
+ */
25
+ import type { ExtensionApi } from "@unbrained/pm-cli/sdk/authoring";
26
+ /**
27
+ * Exact contract the host's `api.registerAssuranceMeasurementProvider`
28
+ * expects for one provider registration.
29
+ *
30
+ * `@unbrained/pm-cli` keeps this type on its internal
31
+ * `core/extensions/extension-types` module and does not yet re-export it
32
+ * through any public `sdk/*` barrel (the SDK only exposes it as the parameter
33
+ * of the registration method). Deriving it from that public method gives the
34
+ * identical, exact shape without reaching into `dist/` internals or
35
+ * hand-copying field names — if the SDK ever widens the method signature, this
36
+ * alias widens with it.
37
+ */
38
+ export type AssuranceMeasurementProviderDefinition = Parameters<ExtensionApi["registerAssuranceMeasurementProvider"]>[0];
39
+ /** Stable provider id used by measurement declarations and gate allow-lists. */
40
+ export declare const QUALITY_PROVIDER_ID = "pm-ops-quality";
41
+ /**
42
+ * The pm-ops quality assurance measurement provider.
43
+ *
44
+ * Registered through the `services` capability, it exposes four keys over a
45
+ * local lcov report and the canonical docstring analyzer. It declares no
46
+ * network use and a `medium` cost class so a trigger policy that caps work at
47
+ * `low` can decline it before invocation. Key ids use the hyphen form the pm-cli
48
+ * host requires for every stable lowercase id (`^[a-z0-9][a-z0-9-]*$`); the
49
+ * hyphen and underscore spellings name the same measurements.
50
+ */
51
+ export declare const qualityMeasurementProvider: AssuranceMeasurementProviderDefinition;
52
+ //# sourceMappingURL=assurance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assurance.d.ts","sourceRoot":"","sources":["../assurance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAKpE;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,sCAAsC,GAChD,UAAU,CAAC,YAAY,CAAC,sCAAsC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtE,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AA+epD;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,EAAE,sCAgFtC,CAAC"}
@@ -0,0 +1,493 @@
1
+ /**
2
+ * Assurance measurement provider that turns the fleet's pinned code-quality
3
+ * thresholds into audited bounds.
4
+ *
5
+ * Every fleet package historically hand-rolled a `scripts/coverage-gate.ts`
6
+ * with thresholds pinned under `coverageGate` in `package.json`. Lowering one
7
+ * was an ordinary diff: nothing in the workflow recorded *why* a number moved,
8
+ * and nothing proved the bound still meant anything. Under pm-cli's assurance
9
+ * surface, weakening a bound requires an `authorization_decision` naming a
10
+ * terminal Decision item the host verifies, and every non-dry gate verdict is
11
+ * appended to the immutable workspace history stream. That only bites if the
12
+ * quality numbers can be *measured* by an assurance provider, which is what
13
+ * this module exports.
14
+ *
15
+ * The provider reads a local lcov coverage report and the canonical docstring
16
+ * analyzer and reduces them to four measurement keys. It owns no quality
17
+ * thresholds itself — those live in assertions and gates the consuming
18
+ * workspace declares — but it refuses to be satisfied by a *stale* coverage
19
+ * report, because a gate that runs against yesterday's `lcov.info` after today's
20
+ * source edit is a gate that measures nothing.
21
+ *
22
+ * @see {@link https://github.com/unbraind/pm-cli/blob/main/docs/ASSURANCE.md ASSURANCE.md}
23
+ * for the measurement / assertion / gate vocabulary this provider plugs into.
24
+ */
25
+ import { readFileSync, statSync } from "node:fs";
26
+ import { isAbsolute, join, relative, sep } from "node:path";
27
+ import { analyzeDocstringCoverage } from "./docstrings.js";
28
+ /** Stable provider id used by measurement declarations and gate allow-lists. */
29
+ export const QUALITY_PROVIDER_ID = "pm-ops-quality";
30
+ /**
31
+ * The four lcov dimensions this provider can reduce to a single percentage.
32
+ *
33
+ * lcov has native `LF`/`LH`, `BRF`/`BRH`, and `FNF`/`FNH` counters for lines,
34
+ * branches, and functions, but no native statement counter: statements are
35
+ * reconstructed from the per-line `DA:` records the reporter already emits.
36
+ */
37
+ const COVERAGE_DIMENSIONS = [
38
+ "lines",
39
+ "branches",
40
+ "functions",
41
+ "statements",
42
+ ];
43
+ /** Default lcov report path when a measurement omits the `report` parameter. */
44
+ const DEFAULT_REPORT = "coverage/lcov.info";
45
+ /** Default source root when a docstring measurement omits the `root` parameter. */
46
+ const DEFAULT_ROOT = ".";
47
+ /**
48
+ * Parse lcov text into one record per covered file.
49
+ *
50
+ * lcov delimits file sections with `SF:` and `end_of_record`. A well-formed
51
+ * report always pairs them, but real reporters occasionally omit the trailing
52
+ * `end_of_record` on the last section, so the parser flushes a pending record
53
+ * on the next `SF:` and once more at end-of-input rather than dropping it.
54
+ * `SF:` paths may be absolute or repo-relative; both are normalised to a
55
+ * repo-relative POSIX label resolved against `base`, matching how the package's
56
+ * own `coverage-gate.ts` reads them back.
57
+ */
58
+ function parseLcov(text, base) {
59
+ const records = [];
60
+ let file = "";
61
+ let sourcePath = "";
62
+ let linesFound = 0;
63
+ let linesHit = 0;
64
+ let branchesFound = 0;
65
+ let branchesHit = 0;
66
+ let functionsFound = 0;
67
+ let functionsHit = 0;
68
+ let statementsFound = 0;
69
+ let statementsHit = 0;
70
+ let started = false;
71
+ const flush = () => {
72
+ if (!started) {
73
+ return;
74
+ }
75
+ records.push({
76
+ file,
77
+ sourcePath,
78
+ linesFound,
79
+ linesHit,
80
+ branchesFound,
81
+ branchesHit,
82
+ functionsFound,
83
+ functionsHit,
84
+ statementsFound,
85
+ statementsHit,
86
+ });
87
+ started = false;
88
+ file = "";
89
+ sourcePath = "";
90
+ linesFound = 0;
91
+ linesHit = 0;
92
+ branchesFound = 0;
93
+ branchesHit = 0;
94
+ functionsFound = 0;
95
+ functionsHit = 0;
96
+ statementsFound = 0;
97
+ statementsHit = 0;
98
+ };
99
+ for (const rawLine of text.split("\n")) {
100
+ const line = rawLine.trimEnd();
101
+ if (line === "end_of_record") {
102
+ flush();
103
+ continue;
104
+ }
105
+ if (line.startsWith("SF:")) {
106
+ flush();
107
+ const raw = line.slice(3).trim();
108
+ const absolute = isAbsolute(raw) ? raw : join(base, raw);
109
+ file = relative(base, absolute).split(sep).join("/");
110
+ sourcePath = absolute;
111
+ started = true;
112
+ continue;
113
+ }
114
+ if (!started) {
115
+ continue;
116
+ }
117
+ if (line.startsWith("DA:")) {
118
+ // Each `DA:<line>,<count>[,<checksum>]` record is one instrumented
119
+ // statement: count it as found unconditionally and as hit when its
120
+ // execution count (the second field, never the line number) is > 0.
121
+ statementsFound++;
122
+ const firstComma = line.indexOf(",", 3);
123
+ const secondComma = firstComma === -1 ? -1 : line.indexOf(",", firstComma + 1);
124
+ const countEnd = secondComma === -1 ? line.length : secondComma;
125
+ const count = firstComma === -1
126
+ ? Number.NaN
127
+ : Number(line.slice(firstComma + 1, countEnd));
128
+ if (Number.isFinite(count) && count > 0) {
129
+ statementsHit++;
130
+ }
131
+ continue;
132
+ }
133
+ if (line.startsWith("LF:")) {
134
+ linesFound = countAfter(line, 3);
135
+ }
136
+ else if (line.startsWith("LH:")) {
137
+ linesHit = countAfter(line, 3);
138
+ }
139
+ else if (line.startsWith("BRF:")) {
140
+ branchesFound = countAfter(line, 4);
141
+ }
142
+ else if (line.startsWith("BRH:")) {
143
+ branchesHit = countAfter(line, 4);
144
+ }
145
+ else if (line.startsWith("FNF:")) {
146
+ functionsFound = countAfter(line, 4);
147
+ }
148
+ else if (line.startsWith("FNH:")) {
149
+ functionsHit = countAfter(line, 4);
150
+ }
151
+ }
152
+ flush();
153
+ return records;
154
+ }
155
+ /**
156
+ * Read the integer payload following an lcov count tag (`LF:42`).
157
+ *
158
+ * `tagLength` is the length of the tag including its colon. A malformed payload
159
+ * coerces to `0` rather than `NaN` so one corrupt line cannot poison an
160
+ * otherwise valid report into a non-finite percentage.
161
+ */
162
+ function countAfter(line, tagLength) {
163
+ return Number(line.slice(tagLength)) || 0;
164
+ }
165
+ /**
166
+ * Resolve a path-shaped provider parameter against the workspace base.
167
+ *
168
+ * Absolute paths are honoured as-is; relative paths resolve against the base so
169
+ * a measurement declared with the default `coverage/lcov.info` finds the report
170
+ * regardless of the process working directory the host happened to launch from.
171
+ * A non-string value falls back to the default rather than throwing, because the
172
+ * host has already validated the parameter against its declared `string` type.
173
+ */
174
+ function resolveParameterPath(value, fallback, base) {
175
+ const raw = typeof value === "string" ? value : fallback;
176
+ return isAbsolute(raw) ? raw : join(base, raw);
177
+ }
178
+ /**
179
+ * Best on-disk root for resolving relative report and source paths.
180
+ *
181
+ * The host populates `repo_root` and `source_workspace_root` from the Git root
182
+ * and the launch directory; `process.cwd()` is the last resort for direct unit
183
+ * tests that construct a context by hand.
184
+ */
185
+ function workspaceBase(context) {
186
+ return context.repo_root ?? context.source_workspace_root ?? process.cwd();
187
+ }
188
+ /**
189
+ * Reduce one record to the found/hit pair for the requested dimension.
190
+ *
191
+ * Statements are the only dimension reconstructed from `DA:` records rather than
192
+ * read from a native lcov counter, so they branch on the parsed field.
193
+ */
194
+ function dimensionCount(record, dimension) {
195
+ switch (dimension) {
196
+ case "lines":
197
+ return { found: record.linesFound, hit: record.linesHit };
198
+ case "branches":
199
+ return { found: record.branchesFound, hit: record.branchesHit };
200
+ case "functions":
201
+ return { found: record.functionsFound, hit: record.functionsHit };
202
+ case "statements":
203
+ return { found: record.statementsFound, hit: record.statementsHit };
204
+ }
205
+ }
206
+ /** Round a percentage to two decimals so verdicts carry stable, readable values. */
207
+ function roundPercent(value) {
208
+ return Math.round(value * 100) / 100;
209
+ }
210
+ /**
211
+ * Read and parse the lcov report, then refuse it if it is stale.
212
+ *
213
+ * A missing report fails with an actionable message rather than an opaque
214
+ * filesystem error, because the gate author needs to know the `report`
215
+ * parameter resolved to a path nothing wrote to. After parsing, the staleness
216
+ * refusal compares the report's mtime against every covered source; see
217
+ * {@link assertReportNotStale} for why that comparison is the provider's core
218
+ * security property.
219
+ */
220
+ function readCoverageReport(reportPath, base) {
221
+ let text;
222
+ try {
223
+ text = readFileSync(reportPath, "utf8");
224
+ }
225
+ catch {
226
+ throw new Error(`pm-ops-quality: coverage report not found at ${reportPath}. ` +
227
+ 'Provide the "report" parameter or generate the report by running the ' +
228
+ "test suite with an lcov reporter before evaluating the gate.");
229
+ }
230
+ const records = parseLcov(text, base);
231
+ assertReportNotStale(reportPath, records.map((record) => record.sourcePath));
232
+ return records;
233
+ }
234
+ /**
235
+ * Refuse a coverage report older than any source file it covers.
236
+ *
237
+ * This is the security property that makes the provider worth registering: a
238
+ * gate that reads a report file can be satisfied by a *stale* report — run the
239
+ * suite once at full coverage, edit the source, and the gate still passes
240
+ * against yesterday's numbers. Comparing the report's mtime against the mtime of
241
+ * every covered source (and only those, never wall-clock age) makes the verdict
242
+ * depend on *what changed* rather than on *when the gate ran*. If any covered
243
+ * source is newer than the report, resolution throws naming the offending file
244
+ * and both timestamps, so the verdict can never be computed from a stale report
245
+ * and can never silently downgrade to a pass.
246
+ *
247
+ * A source the report names but that no longer exists is skipped here: a missing
248
+ * file cannot be "newer", and the absence is already visible in the verdict's
249
+ * population and contributors. This check answers exactly one question — is the
250
+ * report behind the source tree? — and refuses only when it is.
251
+ */
252
+ function assertReportNotStale(reportPath, sourcePaths) {
253
+ const reportMtime = statSync(reportPath).mtimeMs;
254
+ const stale = [];
255
+ for (const source of sourcePaths) {
256
+ let info;
257
+ try {
258
+ info = statSync(source);
259
+ }
260
+ catch {
261
+ continue;
262
+ }
263
+ if (info.mtimeMs > reportMtime) {
264
+ stale.push({ source, mtime: info.mtimeMs });
265
+ }
266
+ }
267
+ if (stale.length === 0) {
268
+ return;
269
+ }
270
+ const reportIso = new Date(reportMtime).toISOString();
271
+ const offenders = stale
272
+ .map((entry) => ` ${entry.source} (modified ${new Date(entry.mtime).toISOString()})`)
273
+ .join("\n");
274
+ throw new Error(`pm-ops-quality: refusing a stale coverage report.\n` +
275
+ `The report ${reportPath} (modified ${reportIso}) is older than source ` +
276
+ "file(s) it covers, so its numbers no longer describe the current tree. " +
277
+ "Re-run the test suite to regenerate the report before evaluating the gate.\n" +
278
+ `Source files newer than the report:\n${offenders}`);
279
+ }
280
+ /**
281
+ * Resolve the `coverage_percent` measurement for one dimension.
282
+ *
283
+ * The percentage is the dimension's total hit over its total found across the
284
+ * whole report; the population denominator is that same total found, so a gate
285
+ * reading the receipt can tell a 100% over two hundred lines from a vacuous
286
+ * 100% over zero. Contributors are the repo-relative files still below full
287
+ * coverage on the requested dimension, sorted for deterministic verdicts.
288
+ */
289
+ function resolveCoveragePercent(context) {
290
+ const dimension = requireCoverageDimension(context.parameters.dimension);
291
+ const base = workspaceBase(context);
292
+ const reportPath = resolveParameterPath(context.parameters.report, DEFAULT_REPORT, base);
293
+ const records = readCoverageReport(reportPath, base);
294
+ let found = 0;
295
+ let hit = 0;
296
+ const contributors = [];
297
+ for (const record of records) {
298
+ const counts = dimensionCount(record, dimension);
299
+ found += counts.found;
300
+ hit += counts.hit;
301
+ if (counts.hit < counts.found) {
302
+ contributors.push(record.file);
303
+ }
304
+ }
305
+ contributors.sort();
306
+ const value = found === 0 ? 100 : roundPercent((hit / found) * 100);
307
+ return {
308
+ value,
309
+ population_size: found,
310
+ cost: records.length,
311
+ contributors,
312
+ };
313
+ }
314
+ /**
315
+ * Resolve the `uncovered_files` measurement.
316
+ *
317
+ * The value is the repo-relative set of files that are below full coverage on
318
+ * *any* dimension, so a gate can bound how many files still carry coverage debt
319
+ * without caring which dimension slipped. The population is every file in the
320
+ * report, so the receipt reads "3 of 41 files are not fully covered".
321
+ */
322
+ function resolveUncoveredFiles(context) {
323
+ const base = workspaceBase(context);
324
+ const reportPath = resolveParameterPath(context.parameters.report, DEFAULT_REPORT, base);
325
+ const records = readCoverageReport(reportPath, base);
326
+ // A file is "uncovered" when it falls short of full coverage on any one
327
+ // dimension; a dimension lcov reports as empty (`found` 0) is vacuously
328
+ // satisfied, so a branchless file can still be fully covered.
329
+ const uncovered = records
330
+ .filter((record) => record.linesHit < record.linesFound ||
331
+ record.branchesHit < record.branchesFound ||
332
+ record.functionsHit < record.functionsFound ||
333
+ record.statementsHit < record.statementsFound)
334
+ .map((record) => record.file)
335
+ .sort();
336
+ return {
337
+ value: uncovered,
338
+ population_size: records.length,
339
+ cost: records.length,
340
+ contributors: uncovered,
341
+ };
342
+ }
343
+ /**
344
+ * Resolve the `docstring_percent` measurement.
345
+ *
346
+ * Delegates to the canonical analyzer at {@link analyzeDocstringCoverage} rather
347
+ * than reimplementing it, so the fleet has exactly one docstring definition.
348
+ * The population is the count of documentable symbols and contributors are the
349
+ * `path:symbol` labels still missing a docstring, matching the analyzer's own
350
+ * violation output.
351
+ */
352
+ function resolveDocstringPercent(context) {
353
+ const base = workspaceBase(context);
354
+ const root = resolveParameterPath(context.parameters.root, DEFAULT_ROOT, base);
355
+ const report = analyzeDocstringCoverage({ root });
356
+ const total = report.declarations_checked;
357
+ const missing = report.violations.length;
358
+ const value = total === 0 ? 100 : roundPercent(((total - missing) / total) * 100);
359
+ const contributors = docstringContributors(report.violations);
360
+ return { value, population_size: total, cost: total, contributors };
361
+ }
362
+ /**
363
+ * Resolve the `undocumented_symbols` measurement.
364
+ *
365
+ * The value is the stable `path:symbol` label set for every symbol the analyzer
366
+ * flagged, so a gate can name exactly which declarations carry the debt. The
367
+ * population is the full documentable-symbol count, not just the violators, so
368
+ * the receipt distinguishes "5 of 5 undocumented" from "5 of 200 undocumented".
369
+ */
370
+ function resolveUndocumentedSymbols(context) {
371
+ const base = workspaceBase(context);
372
+ const root = resolveParameterPath(context.parameters.root, DEFAULT_ROOT, base);
373
+ const report = analyzeDocstringCoverage({ root });
374
+ const labels = docstringContributors(report.violations);
375
+ return {
376
+ value: labels,
377
+ population_size: report.declarations_checked,
378
+ cost: report.declarations_checked,
379
+ contributors: labels,
380
+ };
381
+ }
382
+ /**
383
+ * Build sorted `path:symbol` contributor labels from analyzer violations.
384
+ *
385
+ * Centralised so both docstring keys derive identical labels from the same
386
+ * violation stream; a future change to the label format changes both at once.
387
+ */
388
+ function docstringContributors(violations) {
389
+ return violations
390
+ .map((violation) => `${violation.file}:${violation.symbol}`)
391
+ .sort();
392
+ }
393
+ /**
394
+ * Validate and accept the required `dimension` parameter for `coverage_percent`.
395
+ *
396
+ * The host validates that a required parameter is *present* and *string-typed*,
397
+ * but it cannot validate the value domain, so an unknown dimension like
398
+ * `"loc"` would otherwise flow through to a percentage of nothing. This guard
399
+ * fails fast with the accepted vocabulary instead of returning a misleading 0%.
400
+ */
401
+ function requireCoverageDimension(value) {
402
+ if (typeof value !== "string") {
403
+ throw new Error('pm-ops-quality: key "coverage_percent" requires a string "dimension" ' +
404
+ `parameter; received ${value === null ? "null" : typeof value}.`);
405
+ }
406
+ if (!COVERAGE_DIMENSIONS.includes(value)) {
407
+ throw new Error(`pm-ops-quality: unknown coverage dimension "${value}". Expected one of: ` +
408
+ `${COVERAGE_DIMENSIONS.join(", ")}.`);
409
+ }
410
+ return value;
411
+ }
412
+ /**
413
+ * The pm-ops quality assurance measurement provider.
414
+ *
415
+ * Registered through the `services` capability, it exposes four keys over a
416
+ * local lcov report and the canonical docstring analyzer. It declares no
417
+ * network use and a `medium` cost class so a trigger policy that caps work at
418
+ * `low` can decline it before invocation. Key ids use the hyphen form the pm-cli
419
+ * host requires for every stable lowercase id (`^[a-z0-9][a-z0-9-]*$`); the
420
+ * hyphen and underscore spellings name the same measurements.
421
+ */
422
+ export const qualityMeasurementProvider = {
423
+ id: QUALITY_PROVIDER_ID,
424
+ cost_class: "medium",
425
+ network: false,
426
+ timeout_ms: 30_000,
427
+ keys: {
428
+ "coverage-percent": {
429
+ value_type: "number",
430
+ description: "Percentage covered for one lcov dimension across the whole report.",
431
+ parameters: {
432
+ dimension: {
433
+ type: "string",
434
+ required: true,
435
+ description: "One of lines, branches, functions, or statements.",
436
+ },
437
+ report: {
438
+ type: "string",
439
+ required: false,
440
+ description: "Path to an lcov report; defaults to coverage/lcov.info.",
441
+ },
442
+ },
443
+ },
444
+ "uncovered-files": {
445
+ value_type: "string_set",
446
+ description: "Repo-relative files that are not at 100% on every dimension.",
447
+ parameters: {
448
+ report: {
449
+ type: "string",
450
+ required: false,
451
+ description: "Path to an lcov report; defaults to coverage/lcov.info.",
452
+ },
453
+ },
454
+ },
455
+ "docstring-percent": {
456
+ value_type: "number",
457
+ description: "Percentage of documentable symbols carrying a docstring.",
458
+ parameters: {
459
+ root: {
460
+ type: "string",
461
+ required: false,
462
+ description: "Source root to scan; defaults to the workspace root.",
463
+ },
464
+ },
465
+ },
466
+ "undocumented-symbols": {
467
+ value_type: "string_set",
468
+ description: "Stable path:symbol labels for symbols missing a docstring.",
469
+ parameters: {
470
+ root: {
471
+ type: "string",
472
+ required: false,
473
+ description: "Source root to scan; defaults to the workspace root.",
474
+ },
475
+ },
476
+ },
477
+ },
478
+ resolve(context) {
479
+ switch (context.key) {
480
+ case "coverage-percent":
481
+ return resolveCoveragePercent(context);
482
+ case "uncovered-files":
483
+ return resolveUncoveredFiles(context);
484
+ case "docstring-percent":
485
+ return resolveDocstringPercent(context);
486
+ case "undocumented-symbols":
487
+ return resolveUndocumentedSymbols(context);
488
+ default:
489
+ throw new Error(`pm-ops-quality: provider does not declare key "${context.key}".`);
490
+ }
491
+ },
492
+ };
493
+ //# sourceMappingURL=assurance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assurance.js","sourceRoot":"","sources":["../assurance.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,16 @@
1
1
  import type { ExtensionApi } from "@unbrained/pm-cli/sdk/authoring";
2
+ import { type MergeDecisionReceipt } from "@unbrained/pm-cli/sdk/merge";
3
+ /**
4
+ * Project a receipt's requested preference side for the fleet view.
5
+ *
6
+ * The SDK's receipt reader normalizes every receipt it returns to carry
7
+ * `requested_preference`, folding the legacy schema-v1 `preferred` key and
8
+ * defaulting to `"ours"` when a receipt records neither — the exact chain
9
+ * `summarizeMergeReceipt` applies for committed-history summaries. Centralizing
10
+ * it here keeps the fleet view's field consistent with those summaries and
11
+ * gives the legacy/default arms a directly testable home.
12
+ */
13
+ export declare function receiptPreferredSide(receipt: Readonly<Pick<MergeDecisionReceipt, "requested_preference" | "preferred">>): "ours" | "theirs";
2
14
  interface RepoMetrics {
3
15
  path: string;
4
16
  repo: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA0C,MAAM,iCAAiC,CAAC;AAg7D5G,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,wEAAwE;IACxE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,CAAC;IAClC,4EAA4E;IAC5E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wFAAwF;IACxF,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AA6KD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,IAAI,CA0BvE;;;;kBAqNe,YAAY"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA0C,MAAM,iCAAiC,CAAC;AAY5G,OAAO,EAKL,KAAK,oBAAoB,EAG1B,MAAM,6BAA6B,CAAC;AAqpDrC;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,oBAAoB,EAAE,sBAAsB,GAAG,WAAW,CAAC,CAAC,GAClF,MAAM,GAAG,QAAQ,CAEnB;AAkTD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,wEAAwE;IACxE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,CAAC;IAClC,4EAA4E;IAC5E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wFAAwF;IACxF,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AA6KD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,IAAI,CA0BvE;;;;kBAqNe,YAAY"}