@unbrained/pm-cli 2026.8.21 → 2026.8.23
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 +44 -0
- package/dist/cli/error-guidance.d.ts +22 -4
- package/dist/cli/error-guidance.js +73 -16
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.js +51 -9
- package/dist/cli/register-mutation.js +6 -6
- package/dist/cli/register-operations.d.ts +73 -0
- package/dist/cli/register-operations.js +39 -14
- package/dist/cli/register-setup.js +3 -3
- package/dist/cli/schema-registration-helpers.d.ts +8 -1
- package/dist/cli/schema-registration-helpers.js +14 -5
- package/dist/cli-bundle/bundle-manifest.json +149 -149
- package/dist/cli-bundle/chunks/chunk-3ENVHX6C.js +36 -0
- package/dist/cli-bundle/chunks/{chunk-LOVTQ52Z.js → chunk-DW2CGEMU.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-EG6CLDZT.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-LARJJ3RK.js → chunk-F3AI2JFL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-N3DSV4CH.js → chunk-HWZ6CELB.js} +8 -8
- package/dist/cli-bundle/chunks/chunk-HZBMLSZI.js +201 -0
- package/dist/cli-bundle/chunks/chunk-JB4KZWBF.js +3 -0
- package/dist/cli-bundle/chunks/chunk-KPH73XXJ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-BKYB45NQ.js → chunk-KXPMB2YL.js} +50 -50
- package/dist/cli-bundle/chunks/{chunk-BUNIEJNE.js → chunk-QDVHNHAQ.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TFI5V5N2.js +13 -0
- package/dist/cli-bundle/chunks/{register-list-query-F57EWDEF.js → register-list-query-UJB5FMV2.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-NX5XE4VX.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-RXIJIYXC.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-HXU7IZZD.js → register-setup-GFUZEKRE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-F4YEW5I2.js → chunk-37Z4OEAP.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3UPTYG44.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-5S7E72FY.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4ERLO7QD.js → chunk-AUFH5H35.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-E7X25GC3.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-FQCSTBWE.js +4 -0
- package/dist/cli-bundle/focused-chunks/{chunk-FH6DYED3.js → chunk-FZS4H32O.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-IFLWKY2R.js +156 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YKBKIEAJ.js → chunk-JOWDB2MH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-LYVSW5VM.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MRCNF3U6.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-UZE7XUZK.js → chunk-OFVUGTLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FJ22HNRP.js → chunk-OGLQBL46.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-OY7QAV4Y.js +51 -0
- package/dist/cli-bundle/focused-chunks/chunk-QGFNI65N.js +26 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KDNG7TKQ.js → chunk-R27IDGHD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-UYRFYCDQ.js +5 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2NIY5NKG.js → chunk-ZHVA42R5.js} +9 -9
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- 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 +33 -32
- 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 +5 -5
- package/dist/core/config/nested-settings.js +8 -2
- package/dist/core/config/positional-value.d.ts +1 -1
- package/dist/core/config/positional-value.js +5 -2
- package/dist/core/extensions/extension-hook-runtime.js +22 -20
- package/dist/core/extensions/extension-types.d.ts +8 -1
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/extensions/loader.js +7 -3
- package/dist/core/extensions/service-ownership.d.ts +8 -0
- package/dist/core/extensions/service-ownership.js +20 -0
- package/dist/core/history/history.js +3 -3
- package/dist/core/item/id.js +20 -5
- package/dist/core/item/item-format.js +81 -2
- package/dist/core/reproducibility/context.d.ts +4 -0
- package/dist/core/reproducibility/context.js +14 -8
- package/dist/core/shared/author.d.ts +55 -1
- package/dist/core/shared/author.js +333 -16
- package/dist/core/shared/constants.js +3 -2
- package/dist/core/shared/errors.d.ts +4 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/settings-validator.d.ts +1 -0
- package/dist/core/store/settings-validator.js +6 -3
- package/dist/core/store/settings.js +5 -2
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +30 -9
- package/dist/sdk/agent/identity-config.d.ts +63 -0
- package/dist/sdk/agent/identity-config.js +107 -0
- package/dist/sdk/agent/refusal-corpus-contracts.d.ts +76 -0
- package/dist/sdk/agent/refusal-corpus-contracts.js +194 -0
- package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
- package/dist/sdk/authoring.d.ts +1 -1
- package/dist/sdk/authoring.js +2 -2
- package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +77 -0
- package/dist/sdk/cli-contracts/agent-output-contracts.js +326 -2
- package/dist/sdk/cli-contracts/commander-mutation-options.js +3 -3
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
- package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +4 -4
- package/dist/sdk/cli-contracts/registration-helpers.js +5 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +4 -3
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +22 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +1 -1
- package/dist/sdk/cli-contracts/tool-schema.js +14 -3
- package/dist/sdk/cli-contracts.d.ts +4 -4
- package/dist/sdk/cli-contracts.js +5 -5
- package/dist/sdk/config.d.ts +6 -1
- package/dist/sdk/config.js +119 -14
- package/dist/sdk/context-intent-contracts.js +4 -2
- package/dist/sdk/core-governance.d.ts +1 -1
- package/dist/sdk/core-governance.js +3 -3
- package/dist/sdk/extension/install-sources.d.ts +1 -1
- package/dist/sdk/extension/install-sources.js +6 -3
- package/dist/sdk/extension/output-ownership.d.ts +1 -0
- package/dist/sdk/extension/output-ownership.js +3 -2
- package/dist/sdk/extension/scaffold.js +11 -5
- package/dist/sdk/flag-invocation-contracts.js +4 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +74 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +87 -26
- package/dist/sdk/governance/assurance-action.js +30 -10
- package/dist/sdk/governance/health.d.ts +3 -0
- package/dist/sdk/governance/health.js +39 -7
- package/dist/sdk/governance/hierarchy-validation.d.ts +29 -0
- package/dist/sdk/governance/hierarchy-validation.js +109 -0
- package/dist/sdk/governance/validate.d.ts +3 -9
- package/dist/sdk/governance/validate.js +84 -111
- package/dist/sdk/graph/assembly.d.ts +6 -1
- package/dist/sdk/graph/assembly.js +16 -22
- package/dist/sdk/graph/governance-contracts.d.ts +1 -1
- package/dist/sdk/graph/governance-contracts.js +8 -2
- package/dist/sdk/graph/governance.js +46 -2
- package/dist/sdk/graph/hierarchy-integrity.d.ts +94 -0
- package/dist/sdk/graph/hierarchy-integrity.js +311 -0
- package/dist/sdk/graph/index.d.ts +2 -1
- package/dist/sdk/graph/index.js +3 -2
- package/dist/sdk/graph/remediation.js +32 -2
- package/dist/sdk/graph/run.d.ts +31 -2
- package/dist/sdk/graph/run.js +80 -31
- package/dist/sdk/graph/workspace-relationship-kind-registry.d.ts +8 -0
- package/dist/sdk/graph/workspace-relationship-kind-registry.js +28 -0
- package/dist/sdk/index.d.ts +8 -3
- package/dist/sdk/index.js +9 -4
- package/dist/sdk/item-children.js +21 -8
- package/dist/sdk/lifecycle/create.js +129 -97
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.d.ts +15 -0
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +25 -0
- package/dist/sdk/lifecycle/update.d.ts +2 -0
- package/dist/sdk/lifecycle/update.js +174 -84
- package/dist/sdk/merge/three-way.js +105 -26
- package/dist/sdk/query/complete-list.d.ts +3 -3
- package/dist/sdk/query/complete-list.js +46 -3
- package/dist/sdk/query/list.d.ts +4 -3
- package/dist/sdk/query/list.js +89 -49
- package/dist/sdk/read-output-budget.d.ts +21 -0
- package/dist/sdk/read-output-budget.js +39 -2
- package/dist/sdk/read-output-contracts.d.ts +10 -4
- package/dist/sdk/read-output-contracts.js +105 -32
- package/dist/sdk/relationship-context.js +3 -4
- package/dist/sdk/relationships.js +17 -10
- package/dist/sdk/reproducibility/process.d.ts +19 -0
- package/dist/sdk/reproducibility/process.js +88 -0
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.d.ts +3 -2
- package/dist/sdk/runtime.js +7 -5
- package/dist/sdk/test/batch.d.ts +6 -0
- package/dist/sdk/test/batch.js +26 -6
- package/dist/sdk/test/entry.d.ts +1 -1
- package/dist/sdk/test/entry.js +3 -2
- package/dist/sdk/test/execution.d.ts +28 -3
- package/dist/sdk/test/execution.js +201 -34
- package/dist/sdk/test/parsers.d.ts +6 -0
- package/dist/sdk/test/parsers.js +21 -2
- package/dist/sdk/test/trust.d.ts +33 -0
- package/dist/sdk/test/trust.js +207 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_PROVENANCE_ADR.md +41 -5
- package/docs/AGENT_UX_CONTRACTS.md +20 -4
- package/docs/COMMANDS.md +29 -14
- package/docs/CONFIGURATION.md +4 -0
- package/docs/DEPENDENCY_KIND_CONTRACT.md +31 -3
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +115 -0
- package/docs/EXTENSIONS.md +2 -1
- package/docs/MERGE_SAFETY.md +15 -1
- package/docs/README.md +1 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +19 -2
- package/docs/RELATIONSHIP_GRAPH.md +6 -3
- package/docs/REPRODUCIBLE_WORKSPACES.md +42 -8
- package/docs/SDK.md +9 -0
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +6 -4
- package/docs/SDK_EVIDENCE_TRACEABILITY.md +1 -1
- package/docs/TESTING.md +83 -1
- package/docs/agent-task-token-baseline.json +2 -2
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +2 -2
- package/marketplace.json +2 -2
- package/package.json +2 -2
- 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 +1021 -53
- package/dist/cli-bundle/chunks/chunk-2MA6ZQVZ.js +0 -197
- package/dist/cli-bundle/chunks/chunk-3AFAUHUE.js +0 -2
- package/dist/cli-bundle/chunks/chunk-7VHZS727.js +0 -5
- package/dist/cli-bundle/chunks/chunk-JSLOFXGA.js +0 -3
- package/dist/cli-bundle/chunks/chunk-OCLPLFAY.js +0 -35
- package/dist/cli-bundle/chunks/chunk-S4IRYKBU.js +0 -13
- package/dist/cli-bundle/chunks/register-mutation-7IY2D5KO.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-FALL3YTU.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7WZRLCYF.js +0 -50
- package/dist/cli-bundle/focused-chunks/chunk-CKKQSJNN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-EEFKYMDR.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-F2A56DHV.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-FV5ACOK7.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-JEAVFOWM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-NJ63LOP6.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-NXRTQ7HI.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-TJ7EMJ46.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-ZOSEELYJ.js +0 -26
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm update 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]="c88f01be-6abe-5fa2-9792-3f54e61bb282")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
9
9
|
import { COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, normalizeItemId, toItemRecord, buildInvalidTypeError, assertParentReferenceIsNotSelf, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, applyAcceptanceCriteriaMutations, applyTagRemovals, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, isTerminalStatus, collectRuntimeUpdateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, describeAllowedTransitions, evaluateTransition, resolveTypeWorkflows, EXIT_CODE, PmCliError, stableValueEquals, resolveIsoOrRelative, getActiveExtensionRegistrations, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, buildItemNotFoundError, listAllItemMetadataLight, locateItem, readLocatedItem, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
10
10
|
import { mutateItemWithHistoryContextResolver } from "../../core/store/item-store.js";
|
|
@@ -17,8 +17,12 @@ import { assertDependencyEdgesAllowed, assertDependencyTargetsResolvable, assert
|
|
|
17
17
|
import { normalizeDependencySeedId, normalizeDependencySourceKind, } from "../dependency-provenance.js";
|
|
18
18
|
import { resolveCanonicalRelationshipKind } from "../relationships.js";
|
|
19
19
|
import { collectNewOrderingCycleWarnings } from "../graph/mutation-advisory.js";
|
|
20
|
+
import { assertHierarchyMutationAllowed } from "../graph/hierarchy-integrity.js";
|
|
21
|
+
import { resolveWorkspaceRelationshipKindRegistry } from "../graph/assembly.js";
|
|
22
|
+
import { acquireHierarchyMutationLock } from "./hierarchy-mutation-lock.js";
|
|
20
23
|
import { DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RISK_VALUES, } from "../../types/index.js";
|
|
21
24
|
import { parseDocs, parseFiles, parseLogSeed, parseTests, requireStringOption, } from "./create.js";
|
|
25
|
+
import { attachLinkedTestMutationProvenance } from "../test/trust.js";
|
|
22
26
|
import { COMMON_UNSET_FIELD_DEFINITIONS_AFTER_CLOSE_REASON_BEFORE_AUTHOR, COMMON_UNSET_FIELD_DEFINITIONS_AFTER_AUTHOR, COMMON_UNSET_FIELD_DEFINITIONS_BEFORE_CLOSE_REASON, parseCommandUnsetTargets, resolveRuntimeUnsetFieldDefinition, } from "./shared-unset-fields.js";
|
|
23
27
|
const UPDATE_UNSET_FIELD_DEFINITIONS = [
|
|
24
28
|
...COMMON_UNSET_FIELD_DEFINITIONS_BEFORE_CLOSE_REASON,
|
|
@@ -355,6 +359,9 @@ function parseDependencyCreatedAt(value, currentIso) {
|
|
|
355
359
|
if (!value || value.trim() === "" || value.trim().toLowerCase() === "now") {
|
|
356
360
|
return currentIso;
|
|
357
361
|
}
|
|
362
|
+
return normalizeDependencyTimestamp(value);
|
|
363
|
+
}
|
|
364
|
+
function normalizeDependencyTimestamp(value) {
|
|
358
365
|
const parsed = Date.parse(value);
|
|
359
366
|
if (!Number.isFinite(parsed)) {
|
|
360
367
|
throw new PmCliError(`Invalid dependency created_at timestamp "${value}"`, EXIT_CODE.USAGE);
|
|
@@ -377,7 +384,14 @@ const DEP_ADDITION_KEYS = [
|
|
|
377
384
|
"source_kind",
|
|
378
385
|
];
|
|
379
386
|
/** Allowed CSV/markdown keys for the `--dep-remove` selector (GH-258). */
|
|
380
|
-
const DEP_REMOVE_KEYS = [
|
|
387
|
+
const DEP_REMOVE_KEYS = [
|
|
388
|
+
"id",
|
|
389
|
+
"kind",
|
|
390
|
+
"type",
|
|
391
|
+
"author",
|
|
392
|
+
"created_at",
|
|
393
|
+
"source_kind",
|
|
394
|
+
];
|
|
381
395
|
function looksLikeStructuredDependencyEntry(raw) {
|
|
382
396
|
if (raw.startsWith("```") || raw.includes("\n")) {
|
|
383
397
|
return true;
|
|
@@ -455,12 +469,18 @@ function parseDependencyRemovals(raw, prefix) {
|
|
|
455
469
|
}
|
|
456
470
|
const kindRaw = normalizeDependencyKindInput(parseOptionalDependencyString(kv.kind ?? kv.type));
|
|
457
471
|
const sourceKind = normalizeDependencySourceKind(parseOptionalDependencyString(kv.source_kind));
|
|
472
|
+
const author = parseOptionalDependencyString(kv.author);
|
|
473
|
+
const createdAt = parseOptionalDependencyString(kv.created_at);
|
|
458
474
|
return {
|
|
459
475
|
id: normalizeDependencySeedId(idRaw, prefix, sourceKind),
|
|
460
476
|
kind: kindRaw
|
|
461
477
|
? ensureEnum(kindRaw, DEPENDENCY_KIND_VALUES, "dependency kind")
|
|
462
478
|
: undefined,
|
|
463
479
|
source_kind: sourceKind,
|
|
480
|
+
author,
|
|
481
|
+
created_at: createdAt
|
|
482
|
+
? normalizeDependencyTimestamp(createdAt)
|
|
483
|
+
: undefined,
|
|
464
484
|
};
|
|
465
485
|
}
|
|
466
486
|
if (trimmed.toLowerCase() === "undefined") {
|
|
@@ -473,7 +493,24 @@ function parseDependencyRemovals(raw, prefix) {
|
|
|
473
493
|
}
|
|
474
494
|
function dependencyKey(value) {
|
|
475
495
|
const sourceKind = value.source_kind?.trim().toLowerCase() ?? "";
|
|
476
|
-
return
|
|
496
|
+
return [value.id.trim().toLowerCase(), value.kind, sourceKind].join("\u0000");
|
|
497
|
+
}
|
|
498
|
+
/** Return the complete normalized identity of one stored dependency row. */
|
|
499
|
+
function storedDependencyIdentityKey(value) {
|
|
500
|
+
const sourceKind = value.source_kind?.trim().toLowerCase() ?? "";
|
|
501
|
+
const author = value.author?.trim().toLowerCase() ?? "";
|
|
502
|
+
const rawCreatedAt = value.created_at?.trim() ?? "";
|
|
503
|
+
const parsedCreatedAt = Date.parse(rawCreatedAt);
|
|
504
|
+
const createdAt = Number.isFinite(parsedCreatedAt)
|
|
505
|
+
? new Date(parsedCreatedAt).toISOString()
|
|
506
|
+
: rawCreatedAt;
|
|
507
|
+
return [
|
|
508
|
+
value.id.trim().toLowerCase(),
|
|
509
|
+
value.kind,
|
|
510
|
+
sourceKind,
|
|
511
|
+
author,
|
|
512
|
+
createdAt,
|
|
513
|
+
].join("\u0000");
|
|
477
514
|
}
|
|
478
515
|
// pm-kyd6: `--blocked-by` writes the `blocked_by` scalar, but the dependency
|
|
479
516
|
// graph (`pm deps`) is built only from the `dependencies` array. Mirror the
|
|
@@ -554,7 +591,7 @@ function docKey(value) {
|
|
|
554
591
|
return `${value.path}::${value.scope}`;
|
|
555
592
|
}
|
|
556
593
|
function testKey(value) {
|
|
557
|
-
return `${value.command}::${value.path ?? ""}::${value.scope}::${value.pm_context_mode ?? ""}`;
|
|
594
|
+
return `${value.command}::${value.path ?? ""}::${value.scope}::${value.pm_context_mode ?? ""}::${value.workspace_context_mode ?? ""}`;
|
|
558
595
|
}
|
|
559
596
|
function matchesDependencySelector(value, selector) {
|
|
560
597
|
if (value.id.trim().toLowerCase() !== selector.id.trim().toLowerCase()) {
|
|
@@ -568,6 +605,17 @@ function matchesDependencySelector(value, selector) {
|
|
|
568
605
|
selector.source_kind.trim().toLowerCase()) {
|
|
569
606
|
return false;
|
|
570
607
|
}
|
|
608
|
+
if (selector.author !== undefined &&
|
|
609
|
+
value.author?.trim().toLowerCase() !== selector.author.trim().toLowerCase()) {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
if (selector.created_at !== undefined &&
|
|
613
|
+
(value.created_at === undefined ||
|
|
614
|
+
!Number.isFinite(Date.parse(value.created_at)) ||
|
|
615
|
+
new Date(Date.parse(value.created_at)).toISOString() !==
|
|
616
|
+
selector.created_at)) {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
571
619
|
return true;
|
|
572
620
|
}
|
|
573
621
|
function ensurePriority(raw) {
|
|
@@ -1082,6 +1130,19 @@ async function buildNoopUpdateResult(params) {
|
|
|
1082
1130
|
warnings: ["noop_no_update_fields"],
|
|
1083
1131
|
};
|
|
1084
1132
|
}
|
|
1133
|
+
async function loadUpdateRelationshipGraph(params) {
|
|
1134
|
+
if (!params.fieldFlags.dep &&
|
|
1135
|
+
!params.fieldFlags.blockedBy &&
|
|
1136
|
+
!params.fieldFlags.parent &&
|
|
1137
|
+
!params.clearedMetadataKeys.has("parent"))
|
|
1138
|
+
return undefined;
|
|
1139
|
+
return listAllItemMetadataLight(params.pmRoot, params.settings.item_format, params.typeToFolder, undefined, params.settings.schema);
|
|
1140
|
+
}
|
|
1141
|
+
function assertUpdateHierarchyIntegrity(params) {
|
|
1142
|
+
if (!params.before)
|
|
1143
|
+
return;
|
|
1144
|
+
assertHierarchyMutationAllowed(params.before, params.before.map((item) => item.id === params.document.metadata.id ? params.document.metadata : item), params.document.metadata.id, (status) => isTerminalStatus(status, params.statusRegistry), resolveWorkspaceRelationshipKindRegistry());
|
|
1145
|
+
}
|
|
1085
1146
|
async function assertUpdateTrackerInitialized(pmRoot) {
|
|
1086
1147
|
await assertInitializedTracker(pmRoot);
|
|
1087
1148
|
}
|
|
@@ -1315,16 +1376,16 @@ function applyTypeOptionMutation(document, context, activeTypeName, changedField
|
|
|
1315
1376
|
/** Collapse duplicate rows only for identities explicitly touched by this mutation. */
|
|
1316
1377
|
function normalizeTouchedDependencyIdentities(current, additions) {
|
|
1317
1378
|
const touchedKeys = new Set(additions.map((entry) => dependencyKey(entry)));
|
|
1318
|
-
const
|
|
1379
|
+
const retainedStoredIdentities = new Set();
|
|
1319
1380
|
return current.filter((entry) => {
|
|
1320
|
-
|
|
1321
|
-
if (!touchedKeys.has(key)) {
|
|
1381
|
+
if (!touchedKeys.has(dependencyKey(entry))) {
|
|
1322
1382
|
return true;
|
|
1323
1383
|
}
|
|
1324
|
-
|
|
1384
|
+
const storedIdentity = storedDependencyIdentityKey(entry);
|
|
1385
|
+
if (retainedStoredIdentities.has(storedIdentity)) {
|
|
1325
1386
|
return false;
|
|
1326
1387
|
}
|
|
1327
|
-
|
|
1388
|
+
retainedStoredIdentities.add(storedIdentity);
|
|
1328
1389
|
return true;
|
|
1329
1390
|
});
|
|
1330
1391
|
}
|
|
@@ -1342,11 +1403,13 @@ function assertDependencyRemovalSelectorsMatch(current, selectors, itemId) {
|
|
|
1342
1403
|
id: entry.id,
|
|
1343
1404
|
kind: entry.kind,
|
|
1344
1405
|
source_kind: entry.source_kind,
|
|
1406
|
+
author: entry.author,
|
|
1407
|
+
created_at: entry.created_at,
|
|
1345
1408
|
})),
|
|
1346
1409
|
why: "Failing on a zero-match selector prevents a mistyped dependency removal from being reported as successful.",
|
|
1347
1410
|
nextSteps: [
|
|
1348
1411
|
`Inspect the current item with: pm get ${itemId} --full`,
|
|
1349
|
-
"Retry --dep-remove with the exact id
|
|
1412
|
+
"Retry --dep-remove with the exact id plus any kind, source_kind, author, or created_at selectors needed to identify one stored row.",
|
|
1350
1413
|
],
|
|
1351
1414
|
});
|
|
1352
1415
|
}
|
|
@@ -1809,6 +1872,7 @@ async function runUpdateWithContext(id, options, global, execution = {}) {
|
|
|
1809
1872
|
const learningUpdates = parseLogSeed("--learning", options.learning, nowIso, author);
|
|
1810
1873
|
const fileUpdates = parseFiles(options.file);
|
|
1811
1874
|
const testUpdates = parseTests(options.test);
|
|
1875
|
+
testUpdates.values = await attachLinkedTestMutationProvenance(testUpdates.values, author, nowIso);
|
|
1812
1876
|
const docUpdates = parseDocs(options.doc);
|
|
1813
1877
|
const workflowTransitionWarnings = [];
|
|
1814
1878
|
const parentReference = await resolveParentReferenceForUpdate({
|
|
@@ -1857,82 +1921,108 @@ async function runUpdateWithContext(id, options, global, execution = {}) {
|
|
|
1857
1921
|
return routedClose;
|
|
1858
1922
|
}
|
|
1859
1923
|
assertMatchingOrderRank(options);
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
let recurrenceHistoryContext;
|
|
1865
|
-
const result = await mutateItemWithHistoryContextResolver({
|
|
1924
|
+
const relationshipRegistry = resolveWorkspaceRelationshipKindRegistry();
|
|
1925
|
+
const hierarchyMutationRequired = (fieldFlags.parent && !clearItemMetadataKeys.has("parent")) ||
|
|
1926
|
+
dependencyUpdates.additions.some((dependency) => relationshipRegistry.resolve(dependency.kind)?.hierarchy);
|
|
1927
|
+
const releaseHierarchyMutationLock = await acquireHierarchyMutationLock({
|
|
1866
1928
|
pmRoot,
|
|
1867
|
-
settings,
|
|
1868
|
-
typeToFolder: typeRegistry.type_to_folder,
|
|
1869
|
-
id,
|
|
1870
|
-
op: resolveUpdateHistoryOperation(options, execution),
|
|
1871
1929
|
author,
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
|
|
1876
|
-
options.ownershipDependencyBypass === true,
|
|
1877
|
-
extensionFieldNames,
|
|
1878
|
-
skipNoop: true,
|
|
1879
|
-
mutate(document) {
|
|
1880
|
-
lifecycleTransition = prepareRecurrenceTransition({
|
|
1881
|
-
document,
|
|
1882
|
-
recurrenceReason: execution.recurrenceReason,
|
|
1883
|
-
requestedStatus: options.status,
|
|
1884
|
-
statusRegistry,
|
|
1885
|
-
});
|
|
1886
|
-
recurrenceHistoryContext = lifecycleTransition
|
|
1887
|
-
? { recurrence: lifecycleTransition }
|
|
1888
|
-
: undefined;
|
|
1889
|
-
graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
|
|
1890
|
-
? structuredClone(document.metadata)
|
|
1891
|
-
: item);
|
|
1892
|
-
return mutateUpdateDocument(document, {
|
|
1893
|
-
options,
|
|
1894
|
-
settings,
|
|
1895
|
-
typeRegistry,
|
|
1896
|
-
statusRegistry,
|
|
1897
|
-
runtimeFieldRegistry,
|
|
1898
|
-
extensionRegistrations,
|
|
1899
|
-
extensionFieldNames,
|
|
1900
|
-
clearItemMetadataKeys,
|
|
1901
|
-
dependencyUpdates,
|
|
1902
|
-
dependencyRemovals,
|
|
1903
|
-
commentUpdates,
|
|
1904
|
-
noteUpdates,
|
|
1905
|
-
learningUpdates,
|
|
1906
|
-
fileUpdates,
|
|
1907
|
-
testUpdates,
|
|
1908
|
-
docUpdates,
|
|
1909
|
-
resolvedParentValue: parentReference.resolvedParentValue,
|
|
1910
|
-
resolvedBlockedByDependencyId,
|
|
1911
|
-
runtimeFieldUpdates,
|
|
1912
|
-
nowValue,
|
|
1913
|
-
nowIso,
|
|
1914
|
-
author,
|
|
1915
|
-
pmRoot,
|
|
1916
|
-
});
|
|
1917
|
-
},
|
|
1930
|
+
ttlSeconds: settings.locks.ttl_seconds,
|
|
1931
|
+
waitMs: settings.locks.wait_ms,
|
|
1932
|
+
required: hierarchyMutationRequired,
|
|
1918
1933
|
});
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
:
|
|
1935
|
-
|
|
1934
|
+
try {
|
|
1935
|
+
let graphBeforeUpdate = await loadUpdateRelationshipGraph({
|
|
1936
|
+
fieldFlags,
|
|
1937
|
+
clearedMetadataKeys: clearItemMetadataKeys,
|
|
1938
|
+
pmRoot,
|
|
1939
|
+
settings,
|
|
1940
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
1941
|
+
});
|
|
1942
|
+
let lifecycleTransition;
|
|
1943
|
+
let recurrenceHistoryContext;
|
|
1944
|
+
const result = await mutateItemWithHistoryContextResolver({
|
|
1945
|
+
pmRoot,
|
|
1946
|
+
settings,
|
|
1947
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
1948
|
+
id,
|
|
1949
|
+
op: resolveUpdateHistoryOperation(options, execution),
|
|
1950
|
+
author,
|
|
1951
|
+
message: options.message,
|
|
1952
|
+
resolveHistoryContext: () => recurrenceHistoryContext,
|
|
1953
|
+
force: options.force,
|
|
1954
|
+
bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
|
|
1955
|
+
options.ownershipDependencyBypass === true,
|
|
1956
|
+
extensionFieldNames,
|
|
1957
|
+
skipNoop: true,
|
|
1958
|
+
mutate(document) {
|
|
1959
|
+
lifecycleTransition = prepareRecurrenceTransition({
|
|
1960
|
+
document,
|
|
1961
|
+
recurrenceReason: execution.recurrenceReason,
|
|
1962
|
+
requestedStatus: options.status,
|
|
1963
|
+
statusRegistry,
|
|
1964
|
+
});
|
|
1965
|
+
recurrenceHistoryContext = lifecycleTransition
|
|
1966
|
+
? { recurrence: lifecycleTransition }
|
|
1967
|
+
: undefined;
|
|
1968
|
+
graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
|
|
1969
|
+
? structuredClone(document.metadata)
|
|
1970
|
+
: item);
|
|
1971
|
+
const mutation = mutateUpdateDocument(document, {
|
|
1972
|
+
options,
|
|
1973
|
+
settings,
|
|
1974
|
+
typeRegistry,
|
|
1975
|
+
statusRegistry,
|
|
1976
|
+
runtimeFieldRegistry,
|
|
1977
|
+
extensionRegistrations,
|
|
1978
|
+
extensionFieldNames,
|
|
1979
|
+
clearItemMetadataKeys,
|
|
1980
|
+
dependencyUpdates,
|
|
1981
|
+
dependencyRemovals,
|
|
1982
|
+
commentUpdates,
|
|
1983
|
+
noteUpdates,
|
|
1984
|
+
learningUpdates,
|
|
1985
|
+
fileUpdates,
|
|
1986
|
+
testUpdates,
|
|
1987
|
+
docUpdates,
|
|
1988
|
+
resolvedParentValue: parentReference.resolvedParentValue,
|
|
1989
|
+
resolvedBlockedByDependencyId,
|
|
1990
|
+
runtimeFieldUpdates,
|
|
1991
|
+
nowValue,
|
|
1992
|
+
nowIso,
|
|
1993
|
+
author,
|
|
1994
|
+
pmRoot,
|
|
1995
|
+
});
|
|
1996
|
+
assertUpdateHierarchyIntegrity({
|
|
1997
|
+
before: graphBeforeUpdate,
|
|
1998
|
+
document,
|
|
1999
|
+
statusRegistry,
|
|
2000
|
+
});
|
|
2001
|
+
return mutation;
|
|
2002
|
+
},
|
|
2003
|
+
});
|
|
2004
|
+
await releaseHierarchyMutationLock();
|
|
2005
|
+
const orderingCycleWarnings = graphBeforeUpdate
|
|
2006
|
+
? collectNewOrderingCycleWarnings(graphBeforeUpdate, graphBeforeUpdate.map((item) => item.id === result.item.id ? result.item : item), result.item.id)
|
|
2007
|
+
: [];
|
|
2008
|
+
return {
|
|
2009
|
+
item: toItemRecord(result.item),
|
|
2010
|
+
changed_fields: result.changedFields,
|
|
2011
|
+
warnings: [
|
|
2012
|
+
...workflowTransitionWarnings,
|
|
2013
|
+
...parentReferenceWarnings,
|
|
2014
|
+
...dependencyTargetWarnings,
|
|
2015
|
+
...orderingCycleWarnings,
|
|
2016
|
+
...result.warnings,
|
|
2017
|
+
],
|
|
2018
|
+
...(lifecycleTransition === undefined
|
|
2019
|
+
? {}
|
|
2020
|
+
: { lifecycle_transition: lifecycleTransition }),
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
finally {
|
|
2024
|
+
await releaseHierarchyMutationLock();
|
|
2025
|
+
}
|
|
1936
2026
|
}
|
|
1937
2027
|
/** Resolve the immutable operation name for ordinary, bypass, and recurrence updates. */
|
|
1938
2028
|
function resolveUpdateHistoryOperation(options, execution) {
|
|
@@ -2021,4 +2111,4 @@ export const _testOnlyUpdateCommand = {
|
|
|
2021
2111
|
resolveRuntimeUnsetDefinition: (token, registry) => resolveRuntimeUnsetFieldDefinition(token, "update", registry),
|
|
2022
2112
|
};
|
|
2023
2113
|
//# sourceMappingURL=update.js.map
|
|
2024
|
-
//# debugId=
|
|
2114
|
+
//# debugId=c88f01be-6abe-5fa2-9792-3f54e61bb282
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* definition for multi-branch agent workflows.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
!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]="
|
|
12
|
+
!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]="393f6460-bf8b-5479-8e3e-cac6f2680823")}catch(e){}}();
|
|
13
13
|
import { historyEntriesToRaw, reanchorHistoryEntries, } from "../../core/history/replay.js";
|
|
14
14
|
import { canonicalDocument, parseItemDocument, serializeItemDocument, } from "../../core/item/item-format.js";
|
|
15
15
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
@@ -318,6 +318,58 @@ function unionCollection(base, ours, theirs) {
|
|
|
318
318
|
}
|
|
319
319
|
return merged;
|
|
320
320
|
}
|
|
321
|
+
function linkedTestDefinitionIdentity(value) {
|
|
322
|
+
/* c8 ignore start -- canonical item parsing normalizes linked-test entries to object records */
|
|
323
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
324
|
+
return stableStringify(value);
|
|
325
|
+
}
|
|
326
|
+
/* c8 ignore stop */
|
|
327
|
+
const { provenance: _provenance, ...definition } = value;
|
|
328
|
+
return stableStringify(definition);
|
|
329
|
+
}
|
|
330
|
+
function markMergedLinkedTest(value) {
|
|
331
|
+
/* c8 ignore start -- canonical item parsing normalizes linked-test entries to object records */
|
|
332
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
333
|
+
return value;
|
|
334
|
+
}
|
|
335
|
+
/* c8 ignore stop */
|
|
336
|
+
const test = value;
|
|
337
|
+
if (!test.provenance) {
|
|
338
|
+
return {
|
|
339
|
+
...test,
|
|
340
|
+
// Legacy entries contributed by another branch must not regain implicit
|
|
341
|
+
// local trust. This incomplete merge marker is preserved by normalization
|
|
342
|
+
// and refused until an operator acknowledges it in the receiving clone.
|
|
343
|
+
provenance: { source_kind: "merge_union" },
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
...test,
|
|
348
|
+
provenance: {
|
|
349
|
+
...test.provenance,
|
|
350
|
+
source_kind: "merge_union",
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function unionLinkedTests(base, ours, theirs) {
|
|
355
|
+
const toEntries = (value) => Array.isArray(value) ? value : [];
|
|
356
|
+
const baseIds = new Set(toEntries(base).map(linkedTestDefinitionIdentity));
|
|
357
|
+
const oursEntries = toEntries(ours);
|
|
358
|
+
const oursIds = new Set(oursEntries.map(linkedTestDefinitionIdentity));
|
|
359
|
+
const theirsEntries = toEntries(theirs);
|
|
360
|
+
const theirsIds = new Set(theirsEntries.map(linkedTestDefinitionIdentity));
|
|
361
|
+
const merged = oursEntries.filter((entry) => {
|
|
362
|
+
const identity = linkedTestDefinitionIdentity(entry);
|
|
363
|
+
return !baseIds.has(identity) || theirsIds.has(identity);
|
|
364
|
+
});
|
|
365
|
+
for (const entry of theirsEntries) {
|
|
366
|
+
const identity = linkedTestDefinitionIdentity(entry);
|
|
367
|
+
if (!oursIds.has(identity) && !baseIds.has(identity)) {
|
|
368
|
+
merged.push(markMergedLinkedTest(entry));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return merged;
|
|
372
|
+
}
|
|
321
373
|
function latestTimestamp(ours, theirs) {
|
|
322
374
|
return compareTimestampStrings(String(ours), String(theirs)) >= 0
|
|
323
375
|
? ours
|
|
@@ -362,6 +414,40 @@ function parseItemMergeSide(raw, label, options) {
|
|
|
362
414
|
throw new PmCliError(`Item merge input (${label}) is not a readable item document: ${String(error)}`, EXIT_CODE.GENERIC_FAILURE);
|
|
363
415
|
}
|
|
364
416
|
}
|
|
417
|
+
/** Merge one collection field and report whether the field was handled. */
|
|
418
|
+
function mergeItemUnionField(params) {
|
|
419
|
+
if (!params.unionFieldSet.has(params.field))
|
|
420
|
+
return false;
|
|
421
|
+
const union = params.field === "tests"
|
|
422
|
+
? unionLinkedTests(params.baseValue, params.oursValue, params.theirsValue)
|
|
423
|
+
: unionCollection(params.baseValue, params.oursValue, params.theirsValue);
|
|
424
|
+
params.accumulator.merged[params.field] = union;
|
|
425
|
+
if (!jsonEquals(union, params.oursValue)) {
|
|
426
|
+
params.accumulator.unionFields.push(params.field);
|
|
427
|
+
}
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
/** Merge one scalar field while preserving conflict evidence. */
|
|
431
|
+
function mergeItemScalarField(params) {
|
|
432
|
+
const outcome = mergeItemScalarThreeWay(params.baseValue, params.oursValue, params.theirsValue, params.preferred, params.conflictResolution);
|
|
433
|
+
if (outcome.value !== undefined) {
|
|
434
|
+
params.accumulator.merged[params.field] = outcome.value;
|
|
435
|
+
}
|
|
436
|
+
if (outcome.conflict) {
|
|
437
|
+
params.accumulator.conflictFields.push(params.field);
|
|
438
|
+
params.accumulator.conflictDecisions.push({
|
|
439
|
+
field: params.field,
|
|
440
|
+
base: params.baseValue,
|
|
441
|
+
ours: params.oursValue,
|
|
442
|
+
theirs: params.theirsValue,
|
|
443
|
+
retained: outcome.value,
|
|
444
|
+
discarded: outcome.from_theirs ? params.oursValue : params.theirsValue,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
else if (outcome.from_theirs) {
|
|
448
|
+
params.accumulator.fieldsFromTheirs.push(params.field);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
365
451
|
function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferred, conflictResolution) {
|
|
366
452
|
const unionFieldSet = new Set(ITEM_UNION_COLLECTION_FIELDS);
|
|
367
453
|
const latestFieldSet = new Set(ITEM_LATEST_TIMESTAMP_FIELDS);
|
|
@@ -379,39 +465,32 @@ function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferre
|
|
|
379
465
|
const baseValue = baseRecord[field];
|
|
380
466
|
const oursValue = oursRecord[field];
|
|
381
467
|
const theirsValue = theirsRecord[field];
|
|
382
|
-
if (
|
|
383
|
-
|
|
468
|
+
if (mergeItemUnionField({
|
|
469
|
+
field,
|
|
470
|
+
baseValue,
|
|
471
|
+
oursValue,
|
|
472
|
+
theirsValue,
|
|
473
|
+
unionFieldSet,
|
|
474
|
+
accumulator,
|
|
475
|
+
})) {
|
|
384
476
|
// `fieldNames` is derived from both records' own keys, so a collection
|
|
385
477
|
// reached here is declared by at least one side. Preserve even an empty
|
|
386
478
|
// result (`tags` is required) so serialization never drops it.
|
|
387
|
-
accumulator.merged[field] = union;
|
|
388
|
-
if (!jsonEquals(union, oursValue)) {
|
|
389
|
-
accumulator.unionFields.push(field);
|
|
390
|
-
}
|
|
391
479
|
continue;
|
|
392
480
|
}
|
|
393
481
|
if (latestFieldSet.has(field)) {
|
|
394
482
|
accumulator.merged[field] = latestTimestamp(oursValue, theirsValue);
|
|
395
483
|
continue;
|
|
396
484
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
ours: oursValue,
|
|
407
|
-
theirs: theirsValue,
|
|
408
|
-
retained: outcome.value,
|
|
409
|
-
discarded: outcome.from_theirs ? oursValue : theirsValue,
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
else if (outcome.from_theirs) {
|
|
413
|
-
accumulator.fieldsFromTheirs.push(field);
|
|
414
|
-
}
|
|
485
|
+
mergeItemScalarField({
|
|
486
|
+
field,
|
|
487
|
+
baseValue,
|
|
488
|
+
oursValue,
|
|
489
|
+
theirsValue,
|
|
490
|
+
preferred,
|
|
491
|
+
conflictResolution,
|
|
492
|
+
accumulator,
|
|
493
|
+
});
|
|
415
494
|
}
|
|
416
495
|
return accumulator;
|
|
417
496
|
}
|
|
@@ -625,4 +704,4 @@ export function mergeJsonDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
|
|
|
625
704
|
};
|
|
626
705
|
}
|
|
627
706
|
//# sourceMappingURL=three-way.js.map
|
|
628
|
-
//# debugId=
|
|
707
|
+
//# debugId=393f6460-bf8b-5479-8e3e-cac6f2680823
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { PmReadOutputReceipt } from "../read-output-contracts.js";
|
|
7
7
|
import type { ListFullResult, ListOptions } from "./list.js";
|
|
8
8
|
/** Stable reasons a purported whole-workspace list cannot be trusted. */
|
|
9
|
-
export declare const PM_COMPLETE_LIST_FINDING_CODES: readonly ["invalid_envelope", "source_incomplete", "source_unchecked", "filtered_corpus", "terminal_items_excluded", "strict_read_unproven", "page_incomplete", "count_mismatch", "projection_incomplete", "field_omission", "budget_compaction", "budget_omission", "session_projection", "invalid_item_id", "duplicate_item_id"];
|
|
9
|
+
export declare const PM_COMPLETE_LIST_FINDING_CODES: readonly ["invalid_envelope", "source_incomplete", "source_unchecked", "filtered_corpus", "terminal_items_excluded", "strict_read_unproven", "page_incomplete", "count_mismatch", "projection_incomplete", "field_omission", "omission_receipt_missing", "omission_receipt_invalid", "read_output_missing", "read_output_invalid", "read_output_dimensions_incomplete", "budget_compaction", "budget_omission", "session_projection", "invalid_item_id", "duplicate_item_id"];
|
|
10
10
|
/** Machine-readable reason a complete-list candidate failed certification. */
|
|
11
11
|
export type PmCompleteListFindingCode = (typeof PM_COMPLETE_LIST_FINDING_CODES)[number];
|
|
12
12
|
/** One independently actionable complete-list contract violation. */
|
|
@@ -39,8 +39,8 @@ export interface PmCompleteListCertificate {
|
|
|
39
39
|
export interface PmCompleteListResult extends ListFullResult {
|
|
40
40
|
/** Exact proof that the returned rows represent the full tracker corpus. */
|
|
41
41
|
complete_list: PmCompleteListCertificate;
|
|
42
|
-
/**
|
|
43
|
-
read_output
|
|
42
|
+
/** Mandatory universal read receipt proving unbounded, uncompacted delivery. */
|
|
43
|
+
read_output: PmReadOutputReceipt;
|
|
44
44
|
}
|
|
45
45
|
/** Inspection report returned without throwing for policy and UI consumers. */
|
|
46
46
|
export interface PmCompleteListInspection {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Stable reasons a purported whole-workspace list cannot be trusted. */
|
|
2
2
|
|
|
3
|
-
!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]="
|
|
3
|
+
!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]="c14a67b4-102d-5219-b2b3-15d39da36627")}catch(e){}}();
|
|
4
4
|
export const PM_COMPLETE_LIST_FINDING_CODES = [
|
|
5
5
|
"invalid_envelope",
|
|
6
6
|
"source_incomplete",
|
|
@@ -12,6 +12,11 @@ export const PM_COMPLETE_LIST_FINDING_CODES = [
|
|
|
12
12
|
"count_mismatch",
|
|
13
13
|
"projection_incomplete",
|
|
14
14
|
"field_omission",
|
|
15
|
+
"omission_receipt_missing",
|
|
16
|
+
"omission_receipt_invalid",
|
|
17
|
+
"read_output_missing",
|
|
18
|
+
"read_output_invalid",
|
|
19
|
+
"read_output_dimensions_incomplete",
|
|
15
20
|
"budget_compaction",
|
|
16
21
|
"budget_omission",
|
|
17
22
|
"session_projection",
|
|
@@ -31,7 +36,7 @@ export class PmCompleteListValidationError extends Error {
|
|
|
31
36
|
contract: "complete_list",
|
|
32
37
|
findings,
|
|
33
38
|
recovery: {
|
|
34
|
-
suggested_retry: "pm list
|
|
39
|
+
suggested_retry: "pm list --all --output-include full --strict-read --no-truncate --output-budget unbounded --output-limit unbounded --json",
|
|
35
40
|
sdk: "await client.listAllComplete()",
|
|
36
41
|
},
|
|
37
42
|
};
|
|
@@ -67,6 +72,17 @@ function inspectSourceScope(candidate, findings) {
|
|
|
67
72
|
: {};
|
|
68
73
|
addFinding(findings, completeness.status === "partial", "source_incomplete", "The source scan reported unreadable tracker artifacts.");
|
|
69
74
|
addFinding(findings, completeness.status !== "complete" && completeness.status !== "partial", "source_unchecked", "The source scan did not prove completeness.");
|
|
75
|
+
const unreadableItemCount = completeness.unreadable_item_count;
|
|
76
|
+
const unreadableDirectoryCount = completeness.unreadable_directory_count;
|
|
77
|
+
addFinding(findings, completeness.status === "complete" &&
|
|
78
|
+
(unreadableItemCount !== 0 || unreadableDirectoryCount !== 0) &&
|
|
79
|
+
Number.isSafeInteger(unreadableItemCount) &&
|
|
80
|
+
Number.isSafeInteger(unreadableDirectoryCount), "source_incomplete", "The source scan reports unreadable tracker artifacts despite a complete status.");
|
|
81
|
+
addFinding(findings, completeness.status === "complete" &&
|
|
82
|
+
(!Number.isSafeInteger(unreadableItemCount) ||
|
|
83
|
+
!Number.isSafeInteger(unreadableDirectoryCount) ||
|
|
84
|
+
Number(unreadableItemCount) < 0 ||
|
|
85
|
+
Number(unreadableDirectoryCount) < 0), "source_unchecked", "The source scan did not report safe non-negative unreadable counts.");
|
|
70
86
|
const filters = isRecord(candidate.filters) ? candidate.filters : {};
|
|
71
87
|
const runtimeFilters = isRecord(filters.runtime_filters)
|
|
72
88
|
? filters.runtime_filters
|
|
@@ -100,13 +116,40 @@ function inspectEnvelopeShape(candidate, filters, findings) {
|
|
|
100
116
|
const omissionReceipt = isRecord(candidate.omission_receipt)
|
|
101
117
|
? candidate.omission_receipt
|
|
102
118
|
: undefined;
|
|
119
|
+
addFinding(findings, omissionReceipt === undefined, "omission_receipt_missing", "The result carries no field-omission receipt.");
|
|
120
|
+
addFinding(findings, omissionReceipt !== undefined &&
|
|
121
|
+
(omissionReceipt.has_omissions !== false ||
|
|
122
|
+
omissionReceipt.omitted_field_group_count !== 0 ||
|
|
123
|
+
!Number.isSafeInteger(omissionReceipt.omitted_field_group_count) ||
|
|
124
|
+
!Array.isArray(omissionReceipt.omitted_field_groups) ||
|
|
125
|
+
omissionReceipt.omitted_field_groups.length !== 0), "omission_receipt_invalid", "The field-omission receipt is malformed or contradicts its no-omission claim.");
|
|
103
126
|
addFinding(findings, omissionReceipt?.has_omissions === true, "field_omission", "The omission receipt reports withheld field groups.");
|
|
104
127
|
}
|
|
128
|
+
/** Return whether a universal read receipt cannot prove an intact list result. */
|
|
129
|
+
function isInvalidCompleteListReadOutput(readOutput) {
|
|
130
|
+
return (readOutput.contract_version !== 1 ||
|
|
131
|
+
readOutput.command !== "list" ||
|
|
132
|
+
readOutput.within_budget !== true ||
|
|
133
|
+
readOutput.strings_compacted !== false ||
|
|
134
|
+
readOutput.rows_compacted !== false ||
|
|
135
|
+
readOutput.result_omitted !== false);
|
|
136
|
+
}
|
|
137
|
+
/** Return whether the receipt proves every dimension required for an unbounded full read. */
|
|
138
|
+
function hasCompleteListReadOutputDimensions(readOutput) {
|
|
139
|
+
if (!Array.isArray(readOutput.requested_dimensions))
|
|
140
|
+
return false;
|
|
141
|
+
const requestedDimensions = new Set(readOutput.requested_dimensions);
|
|
142
|
+
return ["include", "amount", "cost"].every((dimension) => requestedDimensions.has(dimension));
|
|
143
|
+
}
|
|
105
144
|
/** Append universal-output and cross-call-session findings. */
|
|
106
145
|
function inspectOutputScope(candidate, findings) {
|
|
107
146
|
const readOutput = isRecord(candidate.read_output)
|
|
108
147
|
? candidate.read_output
|
|
109
148
|
: undefined;
|
|
149
|
+
addFinding(findings, readOutput === undefined, "read_output_missing", "The result carries no universal read-output receipt.");
|
|
150
|
+
addFinding(findings, readOutput !== undefined && isInvalidCompleteListReadOutput(readOutput), "read_output_invalid", "The universal read-output receipt does not prove an intact list result.");
|
|
151
|
+
addFinding(findings, readOutput !== undefined &&
|
|
152
|
+
!hasCompleteListReadOutputDimensions(readOutput), "read_output_dimensions_incomplete", "The universal read-output receipt does not prove full, unbounded include, amount, and cost dimensions.");
|
|
110
153
|
addFinding(findings, readOutput?.strings_compacted === true ||
|
|
111
154
|
readOutput?.rows_compacted === true ||
|
|
112
155
|
candidate.output_budget_truncation !== undefined, "budget_compaction", "Universal output shaping compacted the result.");
|
|
@@ -170,4 +213,4 @@ export function assertCompleteListResult(candidate) {
|
|
|
170
213
|
certifyCompleteListResult(candidate);
|
|
171
214
|
}
|
|
172
215
|
//# sourceMappingURL=complete-list.js.map
|
|
173
|
-
//# debugId=
|
|
216
|
+
//# debugId=c14a67b4-102d-5219-b2b3-15d39da36627
|