@unbrained/pm-cli 2026.9.1 → 2026.9.2
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 +10 -0
- package/dist/cli-bundle/bundle-manifest.json +59 -59
- package/dist/cli-bundle/chunks/{chunk-2MC2LCXZ.js → chunk-FZ4Z2J4F.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-6XIIGE7U.js → chunk-T6H5BZCP.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-U45JXJCC.js → chunk-UDW64J2W.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-ZLJIFSOE.js +35 -0
- package/dist/cli-bundle/chunks/{register-mutation-2MVLRS3J.js → register-mutation-WFQ7MJTX.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-WCIDXBU3.js → register-operations-JVTI7JPP.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FWPLDEXF.js → chunk-242AXYB2.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-Y6JJIX6I.js → chunk-O67VDLOT.js} +48 -48
- package/dist/cli-bundle/main.js +2 -2
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +1 -1
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +32 -32
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +1 -1
- package/dist/core/diagnostics/remediation.js +9 -4
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
- package/dist/sdk/governance/health.js +77 -11
- package/dist/sdk/governance/validate.js +4 -2
- package/dist/sdk/merge/index.d.ts +1 -1
- package/dist/sdk/merge/index.js +2 -2
- package/dist/sdk/merge/receipts.d.ts +24 -0
- package/dist/sdk/merge/receipts.js +122 -30
- package/docs/CONTEXT_RECOVERY_PRIMITIVES.md +11 -2
- package/docs/MERGE_SAFETY.md +16 -2
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
- package/marketplace.json +2 -2
- package/package.json +1 -1
- 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 +29 -6
- package/dist/cli-bundle/chunks/chunk-ALKKAUFN.js +0 -35
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* value for the coordinator that performed the merge.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!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]="
|
|
10
|
+
!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]="df7d5bd9-8381-5961-bda1-9e8ed335afc9")}catch(e){}}();
|
|
11
11
|
import { execFile } from "node:child_process";
|
|
12
12
|
import { randomUUID } from "node:crypto";
|
|
13
|
-
import { readdir } from "node:fs/promises";
|
|
13
|
+
import { readdir, stat } from "node:fs/promises";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { promisify } from "node:util";
|
|
16
16
|
import { ensureDir, isFileAbsentError, isFileMissingError, pathExists, writeFileAtomic, } from "../../core/fs/fs-utils.js";
|
|
@@ -24,6 +24,7 @@ const RECEIPT_FIELD_MAX = 2_048;
|
|
|
24
24
|
const RECEIPT_FILE_MAX_BYTES = 16 * 1024 * 1024;
|
|
25
25
|
const RECEIPT_VALUE_MAX_DEPTH = 64;
|
|
26
26
|
const RECEIPT_VALUE_MAX_NODES = 100_000;
|
|
27
|
+
const RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT = 100;
|
|
27
28
|
const RECEIPT_KEYS = new Set([
|
|
28
29
|
"version",
|
|
29
30
|
"id",
|
|
@@ -42,6 +43,10 @@ const RECEIPT_KEYS = new Set([
|
|
|
42
43
|
"value_availability",
|
|
43
44
|
"evidence_source",
|
|
44
45
|
]);
|
|
46
|
+
/** Return whether a receipt id is safe to expose in cleartext diagnostics. */
|
|
47
|
+
export function isSafeReceiptId(value) {
|
|
48
|
+
return RECEIPT_ID_PATTERN.test(value);
|
|
49
|
+
}
|
|
45
50
|
const RECEIPT_DECISION_KEYS = new Set([
|
|
46
51
|
"field",
|
|
47
52
|
"base",
|
|
@@ -163,7 +168,7 @@ function hasValidReceiptIdentity(value) {
|
|
|
163
168
|
return !hasOnlyKeys(value, RECEIPT_KEYS) || value.version !== 1
|
|
164
169
|
? false
|
|
165
170
|
: typeof value.id === "string" &&
|
|
166
|
-
|
|
171
|
+
isSafeReceiptId(value.id) &&
|
|
167
172
|
typeof value.item_id === "string" &&
|
|
168
173
|
RECEIPT_ITEM_ID_PATTERN.test(value.item_id) &&
|
|
169
174
|
isSafeReceiptItemPath(value.item_path, value.item_id);
|
|
@@ -372,54 +377,115 @@ async function readReceiptsFromDirectory(directory, evidenceSource) {
|
|
|
372
377
|
names = await readdir(directory);
|
|
373
378
|
}
|
|
374
379
|
catch (error) {
|
|
380
|
+
const absent = await receiptDirectoryFailureMeansAbsent(directory, error);
|
|
375
381
|
return {
|
|
376
382
|
receipts: [],
|
|
377
|
-
invalid_evidence_count:
|
|
383
|
+
invalid_evidence_count: absent ? 0 : 1,
|
|
384
|
+
invalid_evidence: absent
|
|
385
|
+
? []
|
|
386
|
+
: [{ evidence_source: evidenceSource, reason: "directory_unreadable" }],
|
|
387
|
+
invalid_evidence_truncated: false,
|
|
378
388
|
};
|
|
379
389
|
}
|
|
380
390
|
const receipts = [];
|
|
381
391
|
let invalidEvidenceCount = 0;
|
|
392
|
+
const invalidEvidence = [];
|
|
393
|
+
const recordInvalidEvidence = (name, reason) => {
|
|
394
|
+
invalidEvidenceCount += 1;
|
|
395
|
+
if (invalidEvidence.length >= RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT)
|
|
396
|
+
return;
|
|
397
|
+
const receiptId = name.slice(0, -".json".length);
|
|
398
|
+
invalidEvidence.push({
|
|
399
|
+
evidence_source: evidenceSource,
|
|
400
|
+
reason,
|
|
401
|
+
...(isSafeReceiptId(receiptId)
|
|
402
|
+
? { receipt_id: receiptId }
|
|
403
|
+
: { candidate_name_hash: sha256Hex(name) }),
|
|
404
|
+
});
|
|
405
|
+
};
|
|
382
406
|
for (const name of names.sort((left, right) => left.localeCompare(right))) {
|
|
383
407
|
if (!name.endsWith(".json"))
|
|
384
408
|
continue;
|
|
409
|
+
const candidate = await inspectReceiptCandidate(directory, name, evidenceSource);
|
|
410
|
+
if (candidate.receipt !== undefined) {
|
|
411
|
+
receipts.push(candidate.receipt);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
recordInvalidEvidence(name, candidate.reason);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
receipts,
|
|
419
|
+
invalid_evidence_count: invalidEvidenceCount,
|
|
420
|
+
invalid_evidence: invalidEvidence,
|
|
421
|
+
invalid_evidence_truncated: invalidEvidenceCount > invalidEvidence.length,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
async function receiptDirectoryFailureMeansAbsent(directory, error, inspectAncestor = stat) {
|
|
425
|
+
if (!isFileMissingError(error))
|
|
426
|
+
return false;
|
|
427
|
+
let ancestor = directory;
|
|
428
|
+
while (true) {
|
|
385
429
|
try {
|
|
386
|
-
|
|
387
|
-
const raw = await readBoundedRegularReceiptFile(receiptPath);
|
|
388
|
-
if (raw === null) {
|
|
389
|
-
invalidEvidenceCount += 1;
|
|
390
|
-
continue;
|
|
391
|
-
}
|
|
392
|
-
const parsed = JSON.parse(raw);
|
|
393
|
-
if (!isMergeDecisionReceipt(parsed, evidenceSource) ||
|
|
394
|
-
name !== receiptFileName(parsed.id)) {
|
|
395
|
-
invalidEvidenceCount += 1;
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const { preferred: legacyPreference, evidence_source: _serializedEvidenceSource, ...receiptWithoutRuntimeKeys } = parsed;
|
|
399
|
-
const normalizedReceipt = {
|
|
400
|
-
...receiptWithoutRuntimeKeys,
|
|
401
|
-
requested_preference: parsed.requested_preference ?? legacyPreference ?? "ours",
|
|
402
|
-
conflict_resolution: parsed.conflict_resolution ?? "preferred_side",
|
|
403
|
-
evidence_source: evidenceSource,
|
|
404
|
-
};
|
|
405
|
-
receipts.push(normalizedReceipt);
|
|
430
|
+
return (await inspectAncestor(ancestor)).isDirectory();
|
|
406
431
|
}
|
|
407
|
-
catch {
|
|
408
|
-
|
|
432
|
+
catch (ancestorError) {
|
|
433
|
+
if (!isFileMissingError(ancestorError))
|
|
434
|
+
return false;
|
|
435
|
+
const parent = path.dirname(ancestor);
|
|
436
|
+
if (parent === ancestor)
|
|
437
|
+
return true;
|
|
438
|
+
ancestor = parent;
|
|
409
439
|
}
|
|
410
440
|
}
|
|
411
|
-
|
|
441
|
+
}
|
|
442
|
+
async function inspectReceiptCandidate(directory, name, evidenceSource) {
|
|
443
|
+
let raw;
|
|
444
|
+
try {
|
|
445
|
+
raw = await readBoundedRegularReceiptFile(path.join(directory, name));
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
return { reason: "candidate_unreadable" };
|
|
449
|
+
}
|
|
450
|
+
if (raw === null)
|
|
451
|
+
return { reason: "candidate_not_bounded_regular_file" };
|
|
452
|
+
let parsed;
|
|
453
|
+
try {
|
|
454
|
+
parsed = JSON.parse(raw);
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
return { reason: "candidate_invalid_json" };
|
|
458
|
+
}
|
|
459
|
+
if (!isMergeDecisionReceipt(parsed, evidenceSource) ||
|
|
460
|
+
name !== receiptFileName(parsed.id)) {
|
|
461
|
+
return { reason: "schema_or_identity_invalid" };
|
|
462
|
+
}
|
|
463
|
+
const { preferred: legacyPreference, evidence_source: _serializedEvidenceSource, ...receiptWithoutRuntimeKeys } = parsed;
|
|
464
|
+
return {
|
|
465
|
+
receipt: {
|
|
466
|
+
...receiptWithoutRuntimeKeys,
|
|
467
|
+
requested_preference: parsed.requested_preference ?? legacyPreference ?? "ours",
|
|
468
|
+
conflict_resolution: parsed.conflict_resolution ?? "preferred_side",
|
|
469
|
+
evidence_source: evidenceSource,
|
|
470
|
+
},
|
|
471
|
+
};
|
|
412
472
|
}
|
|
413
473
|
/** Inspect valid receipts and count invalid evidence without returning untrusted file contents. */
|
|
414
474
|
export async function inspectMergeReceiptEvidence(cwd, options = {}) {
|
|
415
475
|
const directory = await resolveReceiptDirectory(cwd);
|
|
416
476
|
const local = directory === null
|
|
417
|
-
? {
|
|
477
|
+
? {
|
|
478
|
+
receipts: [],
|
|
479
|
+
invalid_evidence_count: 0,
|
|
480
|
+
invalid_evidence: [],
|
|
481
|
+
invalid_evidence_truncated: false,
|
|
482
|
+
}
|
|
418
483
|
: await readReceiptsFromDirectory(directory, "clone_local");
|
|
419
484
|
const trackerRoot = options.pmRoot ?? path.join(cwd, ".agents", "pm");
|
|
420
485
|
const durable = await readReceiptsFromDirectory(durableReceiptDirectory(trackerRoot), "durable");
|
|
421
486
|
const receipts = new Map(durable.receipts.map((receipt) => [receipt.id, receipt]));
|
|
422
487
|
let divergentCopyCount = 0;
|
|
488
|
+
const divergentCopyEvidence = [];
|
|
423
489
|
for (const receipt of local.receipts) {
|
|
424
490
|
const durableCopy = receipts.get(receipt.id);
|
|
425
491
|
if (durableCopy !== undefined &&
|
|
@@ -427,6 +493,16 @@ export async function inspectMergeReceiptEvidence(cwd, options = {}) {
|
|
|
427
493
|
receiptProvenanceFingerprint(receipt)) {
|
|
428
494
|
receipts.delete(receipt.id);
|
|
429
495
|
divergentCopyCount += 1;
|
|
496
|
+
if (local.invalid_evidence.length +
|
|
497
|
+
durable.invalid_evidence.length +
|
|
498
|
+
divergentCopyEvidence.length <
|
|
499
|
+
RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT) {
|
|
500
|
+
divergentCopyEvidence.push({
|
|
501
|
+
evidence_source: "clone_local_and_durable",
|
|
502
|
+
reason: "copy_provenance_mismatch",
|
|
503
|
+
receipt_id: receipt.id,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
430
506
|
continue;
|
|
431
507
|
}
|
|
432
508
|
receipts.set(receipt.id, durableCopy === undefined
|
|
@@ -441,6 +517,17 @@ export async function inspectMergeReceiptEvidence(cwd, options = {}) {
|
|
|
441
517
|
invalid_evidence_count: local.invalid_evidence_count +
|
|
442
518
|
durable.invalid_evidence_count +
|
|
443
519
|
divergentCopyCount,
|
|
520
|
+
invalid_evidence: [
|
|
521
|
+
...local.invalid_evidence,
|
|
522
|
+
...durable.invalid_evidence,
|
|
523
|
+
...divergentCopyEvidence,
|
|
524
|
+
].slice(0, RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT),
|
|
525
|
+
invalid_evidence_truncated: local.invalid_evidence_truncated ||
|
|
526
|
+
durable.invalid_evidence_truncated ||
|
|
527
|
+
local.invalid_evidence_count +
|
|
528
|
+
durable.invalid_evidence_count +
|
|
529
|
+
divergentCopyCount >
|
|
530
|
+
RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT,
|
|
444
531
|
clone_local_evidence_resolved: directory !== null,
|
|
445
532
|
};
|
|
446
533
|
}
|
|
@@ -538,12 +625,17 @@ export async function runMergeReceiptEvidenceReport(options) {
|
|
|
538
625
|
complete,
|
|
539
626
|
count: evidence.receipts.length,
|
|
540
627
|
invalid_evidence_count: evidence.invalid_evidence_count,
|
|
628
|
+
invalid_evidence: evidence.invalid_evidence,
|
|
629
|
+
invalid_evidence_truncated: evidence.invalid_evidence_truncated,
|
|
541
630
|
clone_local_evidence_resolved: evidence.clone_local_evidence_resolved,
|
|
542
631
|
receipts: evidence.receipts,
|
|
543
632
|
generated_at: nowIso(),
|
|
544
633
|
};
|
|
545
634
|
}
|
|
546
635
|
/** Test-only seams for deterministic receipt-boundary fault coverage. */
|
|
547
|
-
export const _testOnlyMergeReceipts = {
|
|
636
|
+
export const _testOnlyMergeReceipts = {
|
|
637
|
+
prepareReceiptSettlement,
|
|
638
|
+
receiptDirectoryFailureMeansAbsent,
|
|
639
|
+
};
|
|
548
640
|
//# sourceMappingURL=receipts.js.map
|
|
549
|
-
//# debugId=
|
|
641
|
+
//# debugId=df7d5bd9-8381-5961-bda1-9e8ed335afc9
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Context Integrity and Recovery Primitives
|
|
2
2
|
|
|
3
|
-
Tracker: [pm-hu92i3](../.agents/pm/issues/pm-hu92i3.toon), [pm-nc94mk](../.agents/pm/issues/pm-nc94mk.toon), [pm-xrjy8o](../.agents/pm/issues/pm-xrjy8o.toon), [pm-f60039](../.agents/pm/issues/pm-f60039.toon), [pm-2qahia](../.agents/pm/issues/pm-2qahia.toon), [pm-z1z96w](../.agents/pm/issues/pm-z1z96w.toon), [pm-yhle2e](../.agents/pm/issues/pm-yhle2e.toon), [pm-t7wl00](../.agents/pm/issues/pm-t7wl00.toon), [pm-hiqlkh](../.agents/pm/issues/pm-hiqlkh.toon), [pm-ntnv4k](../.agents/pm/issues/pm-ntnv4k.toon), [pm-sxg7wl](../.agents/pm/issues/pm-sxg7wl.toon), [pm-xspd](../.agents/pm/chores/pm-xspd.toon)
|
|
3
|
+
Tracker: [pm-dn8rwl](../.agents/pm/issues/pm-dn8rwl.toon), [pm-r97901](../.agents/pm/issues/pm-r97901.toon), [pm-hu92i3](../.agents/pm/issues/pm-hu92i3.toon), [pm-nc94mk](../.agents/pm/issues/pm-nc94mk.toon), [pm-xrjy8o](../.agents/pm/issues/pm-xrjy8o.toon), [pm-f60039](../.agents/pm/issues/pm-f60039.toon), [pm-2qahia](../.agents/pm/issues/pm-2qahia.toon), [pm-z1z96w](../.agents/pm/issues/pm-z1z96w.toon), [pm-yhle2e](../.agents/pm/issues/pm-yhle2e.toon), [pm-t7wl00](../.agents/pm/issues/pm-t7wl00.toon), [pm-hiqlkh](../.agents/pm/issues/pm-hiqlkh.toon), [pm-ntnv4k](../.agents/pm/issues/pm-ntnv4k.toon), [pm-sxg7wl](../.agents/pm/issues/pm-sxg7wl.toon), [pm-xspd](../.agents/pm/chores/pm-xspd.toon)
|
|
4
4
|
|
|
5
5
|
`project management = context management`: a successful command is useful only when the context it records and later returns is truthful, lossless, and actionable. These SDK-owned primitives are shared by the CLI and package integrations.
|
|
6
6
|
|
|
@@ -59,7 +59,16 @@ history.
|
|
|
59
59
|
|
|
60
60
|
Health keeps the metadata-only cache path for clean history streams. A cached hash mismatch, chain mismatch, or writer-version skew is only a candidate: health rereads canonical item sources and verifies stream content hashes before reporting corruption. The `history_drift` details expose `cache_confirmation` candidate, confirmed, and resolved-false-positive item sets, while `cache_hit_verification: metadata_then_content_hash` identifies the authoritative fallback. Drift-cache envelopes carry both their schema version and the current item-hash capability, so changing legacy canonicalization invalidates prior verdicts and a runtime with incompatible hash semantics rebuilds the cache instead of trusting it.
|
|
61
61
|
|
|
62
|
-
Merge reconciliation may consume a durable hash-only receipt without `--force` only when its canonical item path, complete declared-field set, and every merged-value hash exactly match the current item snapshot. Raw discarded values remain clone-local. Any incomplete or mismatched proof fails closed. SDK gates use `inspectMergeReceiptEvidence` or `runMergeReceiptEvidenceReport` to retain the distinction between no evidence, rejected evidence, and clone-local evidence whose Git directory could not be resolved; `clone_local_evidence_resolved=false` makes the loss-aware report incomplete. The list-only and legacy report compatibility projections intentionally return valid receipts only. Diverged history unions also fail closed when deterministic suffix ordering would make any patch operation inapplicable, instead of publishing a rehashed stream with a skipped branch effect.
|
|
62
|
+
Merge reconciliation may consume a durable hash-only receipt without `--force` only when its canonical item path, complete declared-field set, and every merged-value hash exactly match the current item snapshot. Raw discarded values remain clone-local. Any incomplete or mismatched proof fails closed. SDK gates use `inspectMergeReceiptEvidence` or `runMergeReceiptEvidenceReport` to retain the distinction between no evidence, rejected evidence, and clone-local evidence whose Git directory could not be resolved; `clone_local_evidence_resolved=false` makes the loss-aware report incomplete. Rejected evidence carries bounded privacy-safe source, reason, and receipt-id-or-hash locators, while the exact count and truncation receipt preserve completeness under an agent token budget. Cross-platform ancestor inspection distinguishes an absent receipt store from an unreadable or non-directory root. The list-only and legacy report compatibility projections intentionally return valid receipts only. Diverged history unions also fail closed when deterministic suffix ordering would make any patch operation inapplicable, instead of publishing a rehashed stream with a skipped branch effect.
|
|
63
|
+
|
|
64
|
+
History receipt summaries are durable references, not cleanup hints. Health
|
|
65
|
+
checks each `context.merge.receipts[].receipt_id` against valid pending and
|
|
66
|
+
reconciled authoritative evidence. A missing reference is returned with its
|
|
67
|
+
item id and one-based history line; unsafe identifiers are SHA-256 locators
|
|
68
|
+
rather than echoed content. Detail is capped at 100 while the exact count and a
|
|
69
|
+
truncation receipt preserve loss awareness. Recovery means restoring the named
|
|
70
|
+
receipt from an authoritative clone or backup. Rewriting append-only history or
|
|
71
|
+
deleting sibling evidence is never an automatic remediation.
|
|
63
72
|
|
|
64
73
|
## Strict-create recovery
|
|
65
74
|
|
package/docs/MERGE_SAFETY.md
CHANGED
|
@@ -105,8 +105,22 @@ whose candidates were all rejected. Gates and diagnostic integrations should
|
|
|
105
105
|
use `inspectMergeReceiptEvidence`, whose `invalid_evidence_count` preserves
|
|
106
106
|
that distinction without returning malformed contents.
|
|
107
107
|
`runMergeReceiptEvidenceReport` and `pm merge report --json` expose the same
|
|
108
|
-
loss-aware contract through `complete`, `invalid_evidence_count`,
|
|
109
|
-
`
|
|
108
|
+
loss-aware contract through `complete`, `invalid_evidence_count`, bounded
|
|
109
|
+
`invalid_evidence[]`, `invalid_evidence_truncated`, and
|
|
110
|
+
`clone_local_evidence_resolved`. Each rejected candidate reports a stable
|
|
111
|
+
reason plus its `clone_local`, `durable`, or copy-consistency source. A safe
|
|
112
|
+
receipt filename is returned as `receipt_id`; unsafe candidate names are
|
|
113
|
+
represented only by `candidate_name_hash`, and malformed contents are never
|
|
114
|
+
returned. The detail list is capped at 100 rows while the count remains exact,
|
|
115
|
+
so automated gates stay token-bounded. Directory traversal distinguishes a
|
|
116
|
+
truly absent store from a non-directory or unreadable ancestor on Windows and
|
|
117
|
+
POSIX instead of treating platform-specific `ENOENT`/`ENOTDIR` spellings as
|
|
118
|
+
equivalent. Full health also cross-checks the privacy-safe receipt summaries in
|
|
119
|
+
append-only history against valid pending and reconciled evidence. Missing
|
|
120
|
+
evidence emits `merge_receipt_history_reference_missing:<n>` with bounded item,
|
|
121
|
+
history-line, and receipt-id-or-hash coordinates. Its remediation enumerates
|
|
122
|
+
the exact references and directs recovery from an authoritative clone or
|
|
123
|
+
backup; it never recommends deleting receipts or rewriting history. The CLI
|
|
110
124
|
exits nonzero when evidence is incomplete, even when the valid-receipt count is
|
|
111
125
|
zero. Current SDK implementations always emit the new field, while its optional
|
|
112
126
|
type preserves structural compatibility for existing typed adapters and test
|
|
@@ -4,12 +4,12 @@ Tracker: `pm-f05lsg`.
|
|
|
4
4
|
|
|
5
5
|
Every catalog code is listed. An `uncovered` row is an explicit closure obligation, never an omission or implied approval.
|
|
6
6
|
|
|
7
|
-
- Catalog error codes:
|
|
7
|
+
- Catalog error codes: 355
|
|
8
8
|
- Executable error codes: 19
|
|
9
9
|
- Executable-code ratchet floor: 18
|
|
10
10
|
- Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `manifest_unknown_key`, `missing_lifecycle_target`, `missing_required_argument`, `no_version_bounds_declared`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand`
|
|
11
|
-
- Uncovered error codes:
|
|
12
|
-
- Coverage fraction: 0.
|
|
11
|
+
- Uncovered error codes: 336
|
|
12
|
+
- Coverage fraction: 0.053521
|
|
13
13
|
- Closed-domain probes: 19
|
|
14
14
|
- Grammar probes: 94
|
|
15
15
|
|
|
@@ -186,6 +186,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
|
|
|
186
186
|
| `merge_decisions_unreviewed` | `merge_decisions_unreviewed` | uncovered | none | 0 |
|
|
187
187
|
| `merge_git_config_unwritable` | `merge_git_config_unwritable` | uncovered | none | 0 |
|
|
188
188
|
| `merge_receipt_evidence_invalid` | `merge_receipt_evidence_invalid` | uncovered | none | 0 |
|
|
189
|
+
| `merge_receipt_history_reference_missing` | `merge_receipt_history_reference_missing` | uncovered | none | 0 |
|
|
189
190
|
| `merge_receipts_pending` | `merge_receipts_pending` | uncovered | none | 0 |
|
|
190
191
|
| `merge_reconcile_receipt_evidence_untrusted` | `merge_reconcile_receipt_evidence_untrusted` | uncovered | none | 0 |
|
|
191
192
|
| `merge_root_not_found` | `merge_root_not_found` | uncovered | none | 0 |
|
package/marketplace.json
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
|
|
9
|
-
"version": "2026.9.
|
|
9
|
+
"version": "2026.9.2"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "pm-claude",
|
|
14
14
|
"source": "./plugins/pm-claude",
|
|
15
15
|
"description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
|
|
16
|
-
"version": "2026.9.
|
|
16
|
+
"version": "2026.9.2",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "unbrained",
|
|
19
19
|
"url": "https://github.com/unbraind/pm-cli"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbrained/pm-digital-twin",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.2",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Beyond-PM exemplar: a temporal production-facility digital twin built entirely on public pm SDK and extension primitives.",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-claude",
|
|
3
3
|
"description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents (coordinator, delivery-chain, triage, verification), hybrid TUI task tracking (pm as persistent store + Claude Code task panel as live view), session context injection, and full git-based project management without leaving Claude Code.",
|
|
4
|
-
"version": "2026.9.
|
|
4
|
+
"version": "2026.9.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "unbrained",
|
|
7
7
|
"url": "https://github.com/unbraind/pm-cli"
|
package/sdk/public-surface.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"aggregate_completeness": {
|
|
3
|
-
"covered_symbols":
|
|
3
|
+
"covered_symbols": 1825,
|
|
4
4
|
"excluded": [
|
|
5
5
|
{
|
|
6
6
|
"name": "_testOnlyCliContracts",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
}
|
|
9
9
|
],
|
|
10
10
|
"missing": [],
|
|
11
|
-
"required_symbols":
|
|
11
|
+
"required_symbols": 1826
|
|
12
12
|
},
|
|
13
13
|
"breaking_acknowledgements": [
|
|
14
14
|
{
|
|
@@ -1463,6 +1463,16 @@
|
|
|
1463
1463
|
],
|
|
1464
1464
|
"package_version": "2026.8.31",
|
|
1465
1465
|
"reason": "Add optional host-owned cursor integrity key for deployment-stable pagination; existing callers and process-local fallback remain compatible."
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
"changes": [
|
|
1469
|
+
"signature ./sdk:MergeReceiptEvidenceReport",
|
|
1470
|
+
"signature ./sdk:MergeReceiptEvidenceScan",
|
|
1471
|
+
"signature ./sdk/merge:MergeReceiptEvidenceReport",
|
|
1472
|
+
"signature ./sdk/merge:MergeReceiptEvidenceScan"
|
|
1473
|
+
],
|
|
1474
|
+
"package_version": "2026.9.1",
|
|
1475
|
+
"reason": "Expose loss-aware receipt evidence details as required runtime fields so SDK gates cannot silently discard invalid candidates."
|
|
1466
1476
|
}
|
|
1467
1477
|
],
|
|
1468
1478
|
"entrypoints": {
|
|
@@ -9291,13 +9301,19 @@
|
|
|
9291
9301
|
"classification": "supported",
|
|
9292
9302
|
"kind": "interface",
|
|
9293
9303
|
"name": "MergeReceiptEvidenceReport",
|
|
9294
|
-
"signature": "export interface MergeReceiptEvidenceReport { ok: boolean; complete: boolean; count: number; invalid_evidence_count: number; clone_local_evidence_resolved?: boolean; receipts: MergeDecisionReceipt[]; generated_at: string; }"
|
|
9304
|
+
"signature": "export interface MergeReceiptEvidenceReport { ok: boolean; complete: boolean; count: number; invalid_evidence_count: number; invalid_evidence: MergeReceiptInvalidEvidence[]; invalid_evidence_truncated: boolean; clone_local_evidence_resolved?: boolean; receipts: MergeDecisionReceipt[]; generated_at: string; }"
|
|
9295
9305
|
},
|
|
9296
9306
|
{
|
|
9297
9307
|
"classification": "supported",
|
|
9298
9308
|
"kind": "interface",
|
|
9299
9309
|
"name": "MergeReceiptEvidenceScan",
|
|
9300
|
-
"signature": "export interface MergeReceiptEvidenceScan { receipts: MergeDecisionReceipt[]; invalid_evidence_count: number; clone_local_evidence_resolved?: boolean; }"
|
|
9310
|
+
"signature": "export interface MergeReceiptEvidenceScan { receipts: MergeDecisionReceipt[]; invalid_evidence_count: number; invalid_evidence: MergeReceiptInvalidEvidence[]; invalid_evidence_truncated: boolean; clone_local_evidence_resolved?: boolean; }"
|
|
9311
|
+
},
|
|
9312
|
+
{
|
|
9313
|
+
"classification": "supported",
|
|
9314
|
+
"kind": "interface",
|
|
9315
|
+
"name": "MergeReceiptInvalidEvidence",
|
|
9316
|
+
"signature": "export interface MergeReceiptInvalidEvidence { evidence_source: \"clone_local\" | \"durable\" | \"clone_local_and_durable\"; reason: \"directory_unreadable\" | \"candidate_not_bounded_regular_file\" | \"candidate_unreadable\" | \"candidate_invalid_json\" | \"schema_or_identity_invalid\" | \"copy_provenance_mismatch\"; receipt_id?: string; candidate_name_hash?: string; }"
|
|
9301
9317
|
},
|
|
9302
9318
|
{
|
|
9303
9319
|
"classification": "advanced_export",
|
|
@@ -26733,13 +26749,19 @@
|
|
|
26733
26749
|
"classification": "supported",
|
|
26734
26750
|
"kind": "interface",
|
|
26735
26751
|
"name": "MergeReceiptEvidenceReport",
|
|
26736
|
-
"signature": "export interface MergeReceiptEvidenceReport { ok: boolean; complete: boolean; count: number; invalid_evidence_count: number; clone_local_evidence_resolved?: boolean; receipts: MergeDecisionReceipt[]; generated_at: string; }"
|
|
26752
|
+
"signature": "export interface MergeReceiptEvidenceReport { ok: boolean; complete: boolean; count: number; invalid_evidence_count: number; invalid_evidence: MergeReceiptInvalidEvidence[]; invalid_evidence_truncated: boolean; clone_local_evidence_resolved?: boolean; receipts: MergeDecisionReceipt[]; generated_at: string; }"
|
|
26737
26753
|
},
|
|
26738
26754
|
{
|
|
26739
26755
|
"classification": "supported",
|
|
26740
26756
|
"kind": "interface",
|
|
26741
26757
|
"name": "MergeReceiptEvidenceScan",
|
|
26742
|
-
"signature": "export interface MergeReceiptEvidenceScan { receipts: MergeDecisionReceipt[]; invalid_evidence_count: number; clone_local_evidence_resolved?: boolean; }"
|
|
26758
|
+
"signature": "export interface MergeReceiptEvidenceScan { receipts: MergeDecisionReceipt[]; invalid_evidence_count: number; invalid_evidence: MergeReceiptInvalidEvidence[]; invalid_evidence_truncated: boolean; clone_local_evidence_resolved?: boolean; }"
|
|
26759
|
+
},
|
|
26760
|
+
{
|
|
26761
|
+
"classification": "supported",
|
|
26762
|
+
"kind": "interface",
|
|
26763
|
+
"name": "MergeReceiptInvalidEvidence",
|
|
26764
|
+
"signature": "export interface MergeReceiptInvalidEvidence { evidence_source: \"clone_local\" | \"durable\" | \"clone_local_and_durable\"; reason: \"directory_unreadable\" | \"candidate_not_bounded_regular_file\" | \"candidate_unreadable\" | \"candidate_invalid_json\" | \"schema_or_identity_invalid\" | \"copy_provenance_mismatch\"; receipt_id?: string; candidate_name_hash?: string; }"
|
|
26743
26765
|
},
|
|
26744
26766
|
{
|
|
26745
26767
|
"classification": "supported",
|
|
@@ -32095,6 +32117,7 @@
|
|
|
32095
32117
|
"merge_decisions_unreviewed",
|
|
32096
32118
|
"merge_git_config_unwritable",
|
|
32097
32119
|
"merge_receipt_evidence_invalid",
|
|
32120
|
+
"merge_receipt_history_reference_missing",
|
|
32098
32121
|
"merge_receipts_pending",
|
|
32099
32122
|
"merge_reconcile_receipt_evidence_untrusted",
|
|
32100
32123
|
"merge_root_not_found",
|