@unbrained/pm-cli 2026.11.3 → 2026.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/dist/cli/error-guidance.d.ts +14 -35
  4. package/dist/cli/error-guidance.js +2 -2
  5. package/dist/cli/expected-revisions.d.ts +55 -0
  6. package/dist/cli/expected-revisions.js +2 -0
  7. package/dist/cli/main.js +2 -2
  8. package/dist/cli/runtime/invocation-options.js +1 -1
  9. package/dist/cli-bundle/bundle-manifest.json +1 -1
  10. package/dist/cli-bundle/chunks/{chunk-UYNMKUGA.js → chunk-2GW662DP.js} +2 -2
  11. package/dist/cli-bundle/chunks/{chunk-32BCU6HN.js → chunk-3OXQGGRD.js} +46 -46
  12. package/dist/cli-bundle/chunks/chunk-5BVZ32G7.js +2 -0
  13. package/dist/cli-bundle/chunks/chunk-5S6RT5LX.js +9 -0
  14. package/dist/cli-bundle/chunks/chunk-5Z6LWFDL.js +31 -0
  15. package/dist/cli-bundle/chunks/{chunk-MQJXZX3Q.js → chunk-6T2V3UIK.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-5JZMF4M5.js → chunk-7PGNAHNW.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-7RCI7AAA.js +20 -0
  18. package/dist/cli-bundle/chunks/chunk-AQ5UHHQS.js +2 -0
  19. package/dist/cli-bundle/chunks/chunk-BK2XAQVC.js +2 -0
  20. package/dist/cli-bundle/chunks/{chunk-TZ3D3DPQ.js → chunk-BRIPGUAO.js} +2 -2
  21. package/dist/cli-bundle/chunks/chunk-BWAXA6S4.js +6 -0
  22. package/dist/cli-bundle/chunks/{chunk-5IPXDZKU.js → chunk-CERNIZLB.js} +66 -66
  23. package/dist/cli-bundle/chunks/chunk-DSCFJTHB.js +122 -0
  24. package/dist/cli-bundle/chunks/{chunk-JPKIUWLG.js → chunk-L4BKTPJ6.js} +2 -2
  25. package/dist/cli-bundle/chunks/{chunk-Y7H55PCY.js → chunk-NPEDFOVQ.js} +2 -2
  26. package/dist/cli-bundle/chunks/{chunk-2CBHQXYJ.js → chunk-ODMJ3HIB.js} +2 -2
  27. package/dist/cli-bundle/chunks/{chunk-DEJHTFEF.js → chunk-QN7VCOUU.js} +2 -2
  28. package/dist/cli-bundle/chunks/chunk-QQHMNUZT.js +2 -0
  29. package/dist/cli-bundle/chunks/chunk-SRDO2NJU.js +2 -0
  30. package/dist/cli-bundle/chunks/chunk-T56MB6SF.js +2 -0
  31. package/dist/cli-bundle/chunks/chunk-TX2W6G37.js +3 -0
  32. package/dist/cli-bundle/chunks/item-revision-UAZOBP2Q.js +2 -0
  33. package/dist/cli-bundle/chunks/item-transaction-N5F4LXYV.js +2 -0
  34. package/dist/cli-bundle/chunks/mutation-admission-QZQI2NN5.js +2 -0
  35. package/dist/cli-bundle/chunks/{register-list-query-I6AZA3IX.js → register-list-query-P3NOKQUA.js} +2 -2
  36. package/dist/cli-bundle/chunks/{register-mutation-3DAXCLXR.js → register-mutation-A6I5K5N6.js} +2 -2
  37. package/dist/cli-bundle/chunks/register-operations-SPKB3TNM.js +2 -0
  38. package/dist/cli-bundle/chunks/register-setup-ZZRHJ4IS.js +2 -0
  39. package/dist/cli-bundle/chunks/{stage-7H36OTDJ.js → stage-L3T725DS.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/chunk-5NGNO54M.js +44 -0
  41. package/dist/cli-bundle/focused-chunks/{chunk-ZQRCVRGS.js → chunk-A2246ZM7.js} +54 -54
  42. package/dist/cli-bundle/focused-chunks/chunk-B6U44WPW.js +2 -0
  43. package/dist/cli-bundle/focused-chunks/chunk-BAW3DGQO.js +91 -0
  44. package/dist/cli-bundle/focused-chunks/chunk-BHNY3KPJ.js +2 -0
  45. package/dist/cli-bundle/focused-chunks/chunk-C3O6JJPO.js +2 -0
  46. package/dist/cli-bundle/focused-chunks/{chunk-LKN2WGGB.js → chunk-C7UX2ZI3.js} +2 -2
  47. package/dist/cli-bundle/focused-chunks/{chunk-YVLAP3BL.js → chunk-CBG67HUP.js} +2 -2
  48. package/dist/cli-bundle/focused-chunks/{chunk-TYHDZUL4.js → chunk-CO2DNPH7.js} +2 -2
  49. package/dist/cli-bundle/focused-chunks/chunk-CXTDEQ3N.js +8 -0
  50. package/dist/cli-bundle/focused-chunks/chunk-FEPE2CE4.js +2 -0
  51. package/dist/cli-bundle/focused-chunks/{chunk-RY4QEMAE.js → chunk-FFO7RBLN.js} +2 -2
  52. package/dist/cli-bundle/focused-chunks/{chunk-I5FODKYB.js → chunk-FXFDVM5O.js} +2 -2
  53. package/dist/cli-bundle/focused-chunks/chunk-I5LGPUWH.js +2 -0
  54. package/dist/cli-bundle/focused-chunks/chunk-J3YOATXR.js +80 -0
  55. package/dist/cli-bundle/focused-chunks/{chunk-HOXIIZEO.js → chunk-J6FDCAMH.js} +2 -2
  56. package/dist/cli-bundle/focused-chunks/chunk-J7M52SCZ.js +2 -0
  57. package/dist/cli-bundle/focused-chunks/chunk-JQS7TYQ6.js +12 -0
  58. package/dist/cli-bundle/focused-chunks/chunk-MEJKELWC.js +26 -0
  59. package/dist/cli-bundle/focused-chunks/chunk-PMKR4MJI.js +2 -0
  60. package/dist/cli-bundle/focused-chunks/chunk-PNPYQDHU.js +2 -0
  61. package/dist/cli-bundle/focused-chunks/chunk-Q4OIRSKL.js +2 -0
  62. package/dist/cli-bundle/focused-chunks/{chunk-F3X6UWMI.js → chunk-QEVJ3Y67.js} +2 -2
  63. package/dist/cli-bundle/focused-chunks/{chunk-HJ27QLZV.js → chunk-SDLIUZEL.js} +2 -2
  64. package/dist/cli-bundle/focused-chunks/chunk-TFYTTDAK.js +2 -0
  65. package/dist/cli-bundle/focused-chunks/chunk-W3CSX6GI.js +3 -0
  66. package/dist/cli-bundle/focused-chunks/{chunk-D4XQOMG4.js → chunk-Y5GOUUYJ.js} +2 -2
  67. package/dist/cli-bundle/focused-chunks/item-revision-L6GVT42D.js +2 -0
  68. package/dist/cli-bundle/focused-chunks/item-transaction-GYGP264N.js +2 -0
  69. package/dist/cli-bundle/focused-chunks/mutation-admission-UWTH56OD.js +2 -0
  70. package/dist/cli-bundle/focused-chunks/{stage-4SQHVI3O.js → stage-WRSNJ7VI.js} +2 -2
  71. package/dist/cli-bundle/main.js +25 -25
  72. package/dist/cli-bundle/sdk-authoring.js +1 -1
  73. package/dist/cli-bundle/sdk-contracts.js +5 -5
  74. package/dist/cli-bundle/sdk-core.js +1 -1
  75. package/dist/cli-bundle/sdk-governance.js +1 -1
  76. package/dist/cli-bundle/sdk-graph.js +1 -1
  77. package/dist/cli-bundle/sdk-merge.js +57 -57
  78. package/dist/cli-bundle/sdk-query.js +1 -1
  79. package/dist/cli-bundle/sdk-runtime.js +1 -1
  80. package/dist/cli-bundle/sdk-testing.js +1 -1
  81. package/dist/cli-bundle/sdk.js +11 -11
  82. package/dist/core/config/positional-value.d.ts +1 -1
  83. package/dist/core/config/positional-value.js +1 -1
  84. package/dist/core/extensions/reserved-host-flags.js +1 -1
  85. package/dist/core/history/history-rewrite.js +1 -1
  86. package/dist/core/shared/command-types.d.ts +7 -0
  87. package/dist/core/store/item-mutation-precondition.d.ts +70 -6
  88. package/dist/core/store/item-mutation-precondition.js +1 -1
  89. package/dist/core/store/item-store.js +1 -1
  90. package/dist/core/store/settings-validator.js +1 -1
  91. package/dist/core/store/settings.js +1 -1
  92. package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -1
  93. package/dist/sdk/cli-contracts/completeness.js +1 -1
  94. package/dist/sdk/cli-contracts/enum-contracts.d.ts +11 -0
  95. package/dist/sdk/cli-contracts/enum-contracts.js +1 -1
  96. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
  97. package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
  98. package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
  99. package/dist/sdk/cli-contracts/tool-schema.js +1 -1
  100. package/dist/sdk/cli-program.js +1 -1
  101. package/dist/sdk/config.d.ts +1 -1
  102. package/dist/sdk/config.js +1 -1
  103. package/dist/sdk/environment/project-runtime-compatibility.js +1 -1
  104. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
  105. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
  106. package/dist/sdk/governance/validate.js +1 -1
  107. package/dist/sdk/history/salvage.js +3 -3
  108. package/dist/sdk/history-compact.d.ts +7 -1
  109. package/dist/sdk/history-compact.js +1 -1
  110. package/dist/sdk/history-repair.d.ts +2 -1
  111. package/dist/sdk/history-repair.js +1 -1
  112. package/dist/sdk/index.d.ts +3 -0
  113. package/dist/sdk/index.js +1 -1
  114. package/dist/sdk/lifecycle/checkpoint-rollback.d.ts +10 -2
  115. package/dist/sdk/lifecycle/checkpoint-rollback.js +1 -1
  116. package/dist/sdk/lifecycle/claim.js +1 -1
  117. package/dist/sdk/lifecycle/close-many.d.ts +11 -2
  118. package/dist/sdk/lifecycle/close-many.js +1 -1
  119. package/dist/sdk/lifecycle/close.d.ts +15 -0
  120. package/dist/sdk/lifecycle/close.js +1 -1
  121. package/dist/sdk/lifecycle/item-revision.d.ts +162 -0
  122. package/dist/sdk/lifecycle/item-revision.js +2 -0
  123. package/dist/sdk/lifecycle/restore.js +1 -1
  124. package/dist/sdk/lifecycle/start-blockers.d.ts +52 -0
  125. package/dist/sdk/lifecycle/start-blockers.js +2 -0
  126. package/dist/sdk/lifecycle/task-composition.d.ts +11 -0
  127. package/dist/sdk/lifecycle/task-composition.js +1 -1
  128. package/dist/sdk/lifecycle/update-many.d.ts +11 -2
  129. package/dist/sdk/lifecycle/update-many.js +1 -1
  130. package/dist/sdk/lifecycle/update.js +2 -2
  131. package/dist/sdk/public-surface.json +1 -1
  132. package/dist/sdk/query/declared-blockers.d.ts +16 -0
  133. package/dist/sdk/query/declared-blockers.js +2 -0
  134. package/dist/sdk/query/get.d.ts +7 -0
  135. package/dist/sdk/query/get.js +1 -1
  136. package/dist/sdk/query/projection-contracts.js +1 -1
  137. package/dist/sdk/runtime-input.d.ts +12 -0
  138. package/dist/sdk/runtime-input.js +1 -1
  139. package/dist/sdk/runtime.d.ts +10 -0
  140. package/dist/sdk/runtime.js +1 -1
  141. package/dist/sdk/structured-mutations.js +1 -1
  142. package/dist/sdk/test/batch.js +2 -2
  143. package/dist/sdk/test/execution.js +2 -2
  144. package/dist/sdk/test/linked-command-detection.js +1 -1
  145. package/dist/sdk/workspace-transaction.d.ts +17 -6
  146. package/dist/sdk/workspace-transaction.js +1 -1
  147. package/dist/types.d.ts +6 -0
  148. package/dist/types.js +1 -1
  149. package/docs/COMMANDS.md +91 -0
  150. package/docs/CONFIGURATION.md +1 -0
  151. package/docs/SDK.md +110 -1
  152. package/docs/agent-task-token-baseline.json +1 -1
  153. package/docs/generated/FLAG_LEXICON_BUDGETS.md +111 -111
  154. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +12 -3
  155. package/marketplace.json +1 -1
  156. package/package.json +1 -1
  157. package/packages/pm-beads/package.json +1 -1
  158. package/packages/pm-calendar/package.json +1 -1
  159. package/packages/pm-command-kit/package.json +1 -1
  160. package/packages/pm-digital-twin/package.json +1 -1
  161. package/packages/pm-governance-audit/package.json +1 -1
  162. package/packages/pm-guide-shell/package.json +1 -1
  163. package/packages/pm-kanban/package.json +1 -1
  164. package/packages/pm-lifecycle-hooks/package.json +1 -1
  165. package/packages/pm-linked-test-adapters/package.json +1 -1
  166. package/packages/pm-search-advanced/package.json +1 -1
  167. package/packages/pm-templates/package.json +1 -1
  168. package/packages/pm-todos/package.json +1 -1
  169. package/packages/pm-vcs/package.json +1 -1
  170. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  171. package/plugins/pm-claude/package.json +1 -1
  172. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  173. package/plugins/pm-codex/package.json +1 -1
  174. package/plugins/pm-codex/plugin.json +1 -1
  175. package/runtime-dependencies.json +1 -1
  176. package/dist/cli-bundle/chunks/chunk-7ZEFHFAU.js +0 -2
  177. package/dist/cli-bundle/chunks/chunk-B6UTLYLM.js +0 -3
  178. package/dist/cli-bundle/chunks/chunk-HBKD5HZB.js +0 -2
  179. package/dist/cli-bundle/chunks/chunk-L6LCLC37.js +0 -2
  180. package/dist/cli-bundle/chunks/chunk-NR4KABHC.js +0 -31
  181. package/dist/cli-bundle/chunks/chunk-PWD5RY2D.js +0 -2
  182. package/dist/cli-bundle/chunks/chunk-XRMYA4R7.js +0 -20
  183. package/dist/cli-bundle/chunks/chunk-YWS4XV4I.js +0 -6
  184. package/dist/cli-bundle/chunks/chunk-ZOAJNPBL.js +0 -129
  185. package/dist/cli-bundle/chunks/item-transaction-ZHLJTBD7.js +0 -2
  186. package/dist/cli-bundle/chunks/mutation-admission-ZQMRMGIB.js +0 -2
  187. package/dist/cli-bundle/chunks/register-operations-G3QGGQ5Z.js +0 -2
  188. package/dist/cli-bundle/chunks/register-setup-LDXHMNOT.js +0 -2
  189. package/dist/cli-bundle/focused-chunks/chunk-3XGKBVJ3.js +0 -2
  190. package/dist/cli-bundle/focused-chunks/chunk-4HY6EGPB.js +0 -2
  191. package/dist/cli-bundle/focused-chunks/chunk-AK2CI2GI.js +0 -2
  192. package/dist/cli-bundle/focused-chunks/chunk-HUXZCPWT.js +0 -26
  193. package/dist/cli-bundle/focused-chunks/chunk-IKXJ57XA.js +0 -8
  194. package/dist/cli-bundle/focused-chunks/chunk-MOY6KZGJ.js +0 -44
  195. package/dist/cli-bundle/focused-chunks/chunk-PWUTFKSI.js +0 -2
  196. package/dist/cli-bundle/focused-chunks/chunk-PZRB7IXH.js +0 -91
  197. package/dist/cli-bundle/focused-chunks/chunk-WSYPVBKS.js +0 -80
  198. package/dist/cli-bundle/focused-chunks/chunk-WXLG7HZ5.js +0 -3
  199. package/dist/cli-bundle/focused-chunks/chunk-WZDFCVLX.js +0 -12
  200. package/dist/cli-bundle/focused-chunks/chunk-YGO3FWA2.js +0 -2
  201. package/dist/cli-bundle/focused-chunks/chunk-ZYXQACPB.js +0 -2
  202. package/dist/cli-bundle/focused-chunks/item-transaction-PZ2FQ6B2.js +0 -2
  203. package/dist/cli-bundle/focused-chunks/mutation-admission-XOOK6XFH.js +0 -2
@@ -1,2 +1,2 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9ef196b2-3eef-5bac-b949-bcb3e947c44d")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{applyClosureTimestampFix,scanClosureTimestamps}from"./closure-timestamps.js";import{readWorkflowCompletenessCheck}from"./workflow-completeness.js";import fs from"node:fs/promises";import{realpathSync}from"node:fs";import{execFile}from"node:child_process";import path from"node:path";import{promisify}from"node:util";import{buildRemediationCommands}from"../../core/diagnostics/remediation.js";import{getActiveExtensionRegistrations}from"../../core/extensions/index.js";import{collectRegisteredItemFieldNames}from"../../core/extensions/item-fields.js";import{isFileMissingError}from"../../core/fs/fs-utils.js";import{normalizeStatusInput}from"../../core/item/status.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{resolveRuntimeStatusRegistry}from"../../core/schema/runtime-schema.js";import{DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS,DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS,EXIT_CODE,PM_DIRNAME,SETTINGS_DEFAULTS}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{toNonEmptyStringOrUndefined}from"../../core/shared/primitives.js";import{nowIso}from"../../core/shared/time.js";import{CURRENT_ITEM_FORMAT_VERSION,BASELINE_ITEM_FORMAT_VERSION,effectiveItemFormatVersion,scanItemFormatVersions}from"../../core/item/item-format-version.js";import{resolvePmRoot}from"../../core/store/paths.js";import{readSettings}from"../../core/store/settings.js";import{partitionFixesByGrant,planCloseReasonBackfillFixes,planEstimateBackfillFixes,planResolutionBackfillFixes,planStaleLinkPruneFixes,planTerminalParentFixes,resolveGrantedFixScopes,toFixOutputRow}from"../../core/validate/fix-planning.js";import{findDuplicateIssueCodes}from"../../core/governance/issue-codes.js";import{buildMissingByTypeCounts}from"../../core/validate/missing-by-type.js";import{classifyStaleLinkedPaths,summarizeStaleLinkedPathClassifications}from"../../core/validate/stale-file-classification.js";import{isRemoteLinkedArtifactReference}from"../../core/validate/linked-artifact-reference.js";import{assertProjectionModeChoice}from"../output-projection.js";import{collectDanglingDependencyReferences}from"../graph/assembly.js";import{auditMergeAttributeFence,auditMergeDriverConfiguration,findGitWorkspaceRoot,resolveProjectMergeTypeFolders}from"../merge/install.js";import{inspectMergeReceiptEvidence,partitionMergeReceipts}from"../merge/receipts.js";import{buildLinkedFileRepairReport}from"./linked-file-report.js";import{scanStorageIntegrity}from"./storage-integrity.js";import{scanTrackedRuntimeCache}from"./tracked-runtime-cache.js";import{scanHistoryAuthorAttribution}from"../author-attribution.js";import{createRelationshipKindRegistry}from"../relationships.js";import{runDocs}from"../docs.js";import{runFiles}from"../files.js";import{extractReferencedPmItemIdsFromCommand}from"../test/linked-command-detection.js";import{resolveLinkedTestSourceRef,resolveLinkedTestSourceWorkspaceRoot,resolveLinkedTestTrustBatch}from"../test/trust.js";import{readValidateItems}from"./validate-item-reader.js";import{buildValidateHistoryDriftCheck}from"./validate-history-drift.js";import{buildLifecycleParentGraph,detectLifecycleParentCycles,resolveLifecycleDependencyCycleSamplePath}from"./hierarchy-validation.js";import{buildStatusRoleWarnings,inspectStatusRoleAssignments}from"./status-role-diagnostics.js";import{summarizeCommandPreview,normalizeRelativeDirectoryPath,normalizeRelativePath,toMeaningfulString}from"./validate-normalization.js";const FILE_SCAN_DIRECTORIES=["src","tests","docs"],FILE_SCAN_ROOT_FILES=["README.md","PRD.md","CHANGELOG.md","AGENTS.md","CONTRIBUTING.md","SECURITY.md","CODE_OF_CONDUCT.md","LICENSE"],DIRECTORY_IGNORE_SET=new Set(["node_modules",".git",".cursor",".agents","dist","coverage"]),RESOLUTION_FIELD_KEYS=["resolution","expected_result","actual_result"],VALIDATE_FILE_SCAN_MODES=["default","tracked-all","tracked-all-strict"],VALIDATE_METADATA_PROFILE_VALUES=["core","strict","custom"],VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES=["off","warn","error"],CORE_METADATA_REQUIRED_FIELDS=["author","acceptance_criteria","estimated_minutes","close_reason"],STRICT_METADATA_REQUIRED_FIELDS=[...CORE_METADATA_REQUIRED_FIELDS,"reviewer","risk","confidence","sprint","release"],SUPPORTED_METADATA_REQUIRED_FIELDS=Array.from(new Set(STRICT_METADATA_REQUIRED_FIELDS)),METADATA_REQUIRED_FIELD_ALIASES={author:"author",acceptance_criteria:"acceptance_criteria","acceptance-criteria":"acceptance_criteria",estimated_minutes:"estimated_minutes","estimated-minutes":"estimated_minutes",estimate:"estimated_minutes",close_reason:"close_reason","close-reason":"close_reason",reviewer:"reviewer",risk:"risk",confidence:"confidence",sprint:"sprint",release:"release"},METADATA_WARNING_TOKEN_BY_FIELD={author:"validate_metadata_missing_author",acceptance_criteria:"validate_metadata_missing_acceptance_criteria",estimated_minutes:"validate_metadata_missing_estimate",close_reason:"validate_metadata_missing_close_reason",reviewer:"validate_metadata_missing_reviewer",risk:"validate_metadata_missing_risk",confidence:"validate_metadata_missing_confidence",sprint:"validate_metadata_missing_sprint",release:"validate_metadata_missing_release"},METADATA_COUNT_KEY_BY_FIELD={author:"missing_author",acceptance_criteria:"missing_acceptance_criteria",estimated_minutes:"missing_estimated_minutes",close_reason:"closed_missing_close_reason",reviewer:"missing_reviewer",risk:"missing_risk",confidence:"missing_confidence",sprint:"missing_sprint",release:"missing_release"},METADATA_ITEM_IDS_KEY_BY_FIELD={author:"missing_author_item_ids",acceptance_criteria:"missing_acceptance_criteria_item_ids",estimated_minutes:"missing_estimated_minutes_item_ids",close_reason:"closed_missing_close_reason_item_ids",reviewer:"missing_reviewer_item_ids",risk:"missing_risk_item_ids",confidence:"missing_confidence_item_ids",sprint:"missing_sprint_item_ids",release:"missing_release_item_ids"},METADATA_TRUNCATED_KEY_BY_FIELD={author:"missing_author_truncated",acceptance_criteria:"missing_acceptance_criteria_truncated",estimated_minutes:"missing_estimated_minutes_truncated",close_reason:"closed_missing_close_reason_truncated",reviewer:"missing_reviewer_truncated",risk:"missing_risk_truncated",confidence:"missing_confidence_truncated",sprint:"missing_sprint_truncated",release:"missing_release_truncated"},GIT_LS_FILES_MAX_BUFFER=32*1024*1024,GIT_LS_FILES_TIMEOUT_MS=1e4,FILE_LIST_SUMMARY_LIMIT=40,DIAGNOSTIC_LIST_SUMMARY_LIMIT=5,LINKED_ARTIFACT_MAX_PATH_LENGTH=4096,LINKED_ARTIFACT_MAX_SEGMENT_LENGTH=255,execFileAsync=promisify(execFile);function projectValidateCountsRecord(record){const projected={};for(const[key,value]of Object.entries(record))Array.isArray(value)||value===!1&&key.endsWith("_truncated")||(projected[key]=typeof value=="object"&&value!==null?projectValidateCountsRecord(value):value);return projected}function projectValidateCounts(result){return{...result,checks:result.checks.map(check=>({...check,details:projectValidateCountsRecord(check.details)})),...result.fixes?{fixes:{mode:result.fixes.mode,auto_fix:result.fixes.auto_fix,prune_missing:result.fixes.prune_missing,planned_count:result.fixes.planned_count,applied_count:result.fixes.applied_count,gated_count:result.fixes.gated_count,failed_count:result.fixes.failed_count}}:{}}}function normalizeStatusForRegistry(status,statusRegistry){return normalizeStatusInput(status,statusRegistry)??status}function isTerminalStatus(status,statusRegistry){return statusRegistry.terminal_statuses.has(normalizeStatusForRegistry(status,statusRegistry))}function normalizeLifecyclePatternList(values){return[...new Set((values??[]).map(value=>value.trim().toLowerCase()).filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right))}function areSortedStringListsEqual(left,right){return left.length!==right.length?!1:left.every((value,index)=>value===right[index])}function resolveLifecyclePatternPolicy(settings){const defaultStalePatterns=normalizeLifecyclePatternList(DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS),defaultClosureLikePatterns={blocked_reason:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.blocked_reason),resolution:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.resolution),actual_result:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.actual_result)},staleBlockerReasonPatterns=normalizeLifecyclePatternList(settings.validation.lifecycle_stale_blocker_reason_patterns),closureLikePatterns={blocked_reason:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_blocked_reason_patterns),resolution:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_resolution_patterns),actual_result:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_actual_result_patterns)};return{stale_blocker_reason_patterns:staleBlockerReasonPatterns,stale_blocker_reason_pattern_source:areSortedStringListsEqual(staleBlockerReasonPatterns,defaultStalePatterns)?"default":"settings",closure_like_metadata_field_patterns:closureLikePatterns,closure_like_metadata_field_pattern_sources:{blocked_reason:areSortedStringListsEqual(closureLikePatterns.blocked_reason,defaultClosureLikePatterns.blocked_reason)?"default":"settings",resolution:areSortedStringListsEqual(closureLikePatterns.resolution,defaultClosureLikePatterns.resolution)?"default":"settings",actual_result:areSortedStringListsEqual(closureLikePatterns.actual_result,defaultClosureLikePatterns.actual_result)?"default":"settings"}}}function resolveValidateMetadataProfile(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"core";if(VALIDATE_METADATA_PROFILE_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --metadata-profile value "${value}". Supported values: ${VALIDATE_METADATA_PROFILE_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveDependencyCycleSeverity(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"warn";if(VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --dependency-cycle-severity value "${value}". Supported values: ${VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveParentCycleSeverity(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"warn";if(VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --parent-cycle-severity value "${value}". Supported values: ${VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function normalizeMetadataRequiredFieldsFromSettings(values){return[...new Set((values??[]).map(value=>value.trim().toLowerCase().replaceAll("-","_")))].map(value=>METADATA_REQUIRED_FIELD_ALIASES[value]).filter(value=>value!==void 0).sort((left,right)=>left.localeCompare(right))}function resolveValidateMetadataPolicy(profile,profileSource,configuredCustomFields){const normalizedCustomFields=normalizeMetadataRequiredFieldsFromSettings(configuredCustomFields);return profile==="core"?{profile,profile_source:profileSource,required_fields:[...CORE_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:profile==="strict"?{profile,profile_source:profileSource,required_fields:[...STRICT_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:normalizedCustomFields.length>0?{profile,profile_source:profileSource,required_fields:normalizedCustomFields,configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:{profile,profile_source:profileSource,required_fields:[...CORE_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!0,warnings:["validate_metadata_custom_profile_missing_required_fields:0"]}}const TERMINAL_EXEMPT_PLANNING_FIELDS=new Set(["acceptance_criteria","estimated_minutes"]);function isMetadataFieldMissing(item,field,statusRegistry,enforcePlanningFieldsOnTerminal){return!enforcePlanningFieldsOnTerminal&&TERMINAL_EXEMPT_PLANNING_FIELDS.has(field)&&isTerminalStatus(item.status,statusRegistry)?!1:field==="author"?!toNonEmptyStringOrUndefined(item.author):field==="acceptance_criteria"?!toNonEmptyStringOrUndefined(item.acceptance_criteria):field==="estimated_minutes"?!Number.isFinite(item.estimated_minutes):field==="close_reason"?normalizeStatusForRegistry(item.status,statusRegistry)===statusRegistry.close_status&&!toNonEmptyStringOrUndefined(item.close_reason):field==="reviewer"?!toNonEmptyStringOrUndefined(item.reviewer):field==="risk"?!toNonEmptyStringOrUndefined(item.risk):field==="confidence"?typeof item.confidence=="number"?!Number.isFinite(item.confidence):!toNonEmptyStringOrUndefined(item.confidence):field==="sprint"?!toNonEmptyStringOrUndefined(item.sprint):!toNonEmptyStringOrUndefined(item.release)}function resolveFileScanMode(scanMode){if(scanMode===void 0)return"default";const normalized=scanMode.trim().toLowerCase();if(normalized.length===0||normalized==="default")return"default";if(normalized==="tracked-all"||normalized==="tracked_all")return"tracked-all";if(normalized==="tracked-all-strict"||normalized==="tracked_all_strict")return"tracked-all-strict";throw new PmCliError(`Unknown --scan-mode value "${scanMode}". Supported values: ${VALIDATE_FILE_SCAN_MODES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveWorkspaceRoot(pmRoot){const sourceWorkspaceRoot=process.env.PM_SOURCE_WORKSPACE_ROOT?.trim();if(sourceWorkspaceRoot)return path.resolve(sourceWorkspaceRoot);const resolvedPmRoot=path.resolve(pmRoot);if(resolvedPmRoot.replaceAll("\\","/").endsWith("/.agents/pm"))return path.dirname(path.dirname(resolvedPmRoot));const resolvedCwd=path.resolve(process.cwd()),canonicalPmRoot=realpathForWorkspaceRoot(resolvedPmRoot),canonicalCwd=realpathForWorkspaceRoot(resolvedCwd),relativeFromPmRoot=path.relative(canonicalPmRoot,canonicalCwd);return relativeFromPmRoot.length===0||!relativeFromPmRoot.startsWith("..")&&!path.isAbsolute(relativeFromPmRoot)?resolvedPmRoot:resolvedCwd}function realpathForWorkspaceRoot(inputPath){try{return realpathSync.native(inputPath)}catch{return path.resolve(inputPath)}}function hasFilesystemErrorCode(error,acceptedCodes){return typeof error=="object"&&error!==null&&"code"in error&&typeof error.code=="string"&&acceptedCodes.includes(error.code)}async function listFilesRecursive(basePath,relativePath,output){const targetDirectory=relativePath.length>0?path.join(basePath,relativePath):basePath;let entries;try{entries=await fs.readdir(targetDirectory,{withFileTypes:!0})}catch(error){if(isFileMissingError(error))return;throw error}for(const entry of entries){if(entry.name.startsWith("."))continue;const childRelative=relativePath.length>0?path.join(relativePath,entry.name):entry.name;if(entry.isDirectory()){if(DIRECTORY_IGNORE_SET.has(entry.name))continue;await listFilesRecursive(basePath,childRelative,output);continue}entry.isFile()&&output.push(normalizeRelativePath(childRelative))}}async function collectDefaultProjectFileCandidates(workspaceRoot){const discovered=[];for(const directory of FILE_SCAN_DIRECTORIES)await listFilesRecursive(workspaceRoot,directory,discovered);for(const candidate of FILE_SCAN_ROOT_FILES){const absolute=path.join(workspaceRoot,candidate);try{(await fs.stat(absolute)).isFile()&&discovered.push(normalizeRelativePath(candidate))}catch{}}return[...new Set(discovered)].sort((left,right)=>left.localeCompare(right))}async function collectTrackedGitFileCandidates(workspaceRoot){try{const{stdout}=await execFileAsync("git",["ls-files","-z"],{cwd:workspaceRoot,encoding:"utf8",maxBuffer:GIT_LS_FILES_MAX_BUFFER,windowsHide:!0,timeout:GIT_LS_FILES_TIMEOUT_MS}),discovered=stdout.split("\0").map(value=>normalizeRelativePath(value)).filter(value=>value.length>0);return[...new Set(discovered)].sort((left,right)=>left.localeCompare(right))}catch{return null}}function resolvePmInternalCandidatePrefixes(pmRoot,workspaceRoot){const prefixes=new Set,configuredDefault=normalizeRelativeDirectoryPath(PM_DIRNAME);configuredDefault.length>0&&prefixes.add(configuredDefault);const relativePmRoot=normalizeRelativeDirectoryPath(path.relative(workspaceRoot,pmRoot));return relativePmRoot.length>0&&!relativePmRoot.startsWith("..")&&prefixes.add(relativePmRoot),[...prefixes].sort((left,right)=>left.localeCompare(right))}function hasPathPrefix(candidate,prefixes){for(const prefix of prefixes)if(candidate===prefix||candidate.startsWith(`${prefix}/`))return!0;return!1}async function collectProjectFileCandidates(workspaceRoot,scanMode){if(scanMode==="tracked-all"||scanMode==="tracked-all-strict"){const trackedCandidates=await collectTrackedGitFileCandidates(workspaceRoot);if(trackedCandidates)return{requestedMode:scanMode,appliedMode:scanMode,source:"tracked-git",candidateFiles:trackedCandidates,candidateTotal:trackedCandidates.length,candidateScanned:trackedCandidates.length};const fallbackCandidates=await collectDefaultProjectFileCandidates(workspaceRoot);return{requestedMode:scanMode,appliedMode:"default",source:"tracked-all-fallback-default",candidateFiles:fallbackCandidates,candidateTotal:fallbackCandidates.length,candidateScanned:fallbackCandidates.length}}const defaultCandidates=await collectDefaultProjectFileCandidates(workspaceRoot);return{requestedMode:scanMode,appliedMode:"default",source:"default-curated",candidateFiles:defaultCandidates,candidateTotal:defaultCandidates.length,candidateScanned:defaultCandidates.length}}function summarizeList(values,limit=DIAGNOSTIC_LIST_SUMMARY_LIMIT){return values.length<=limit?{values,truncated:!1}:{values:values.slice(0,limit),truncated:!0}}function summarizeFileList(values,verboseFileLists){if(verboseFileLists)return{values,truncated:!1,total:values.length};const summary=summarizeList(values,FILE_LIST_SUMMARY_LIMIT);return{values:summary.values,truncated:summary.truncated,total:values.length}}const RESOLUTION_REMEDIATION_FLAG_BY_FIELD={resolution:"--resolution",expected_result:"--expected-result",actual_result:"--actual-result"},RESOLUTION_REMEDIATION_PLACEHOLDER_BY_FIELD={resolution:"Describe how this item was resolved",expected_result:"Describe the expected result",actual_result:"Describe the actual result"};function buildResolutionRemediationCommand(row){const fieldArguments=row.missing_fields.map(field=>`${RESOLUTION_REMEDIATION_FLAG_BY_FIELD[field]} "${RESOLUTION_REMEDIATION_PLACEHOLDER_BY_FIELD[field]}"`).join(" ");return`pm update ${row.id} ${fieldArguments} --message "Backfill resolution metadata"`}function attachValidateFixHints(check,checkWarnings){const existingResolutionHints=check.details?.missing_resolution_remediation_hints,aliasedResolution=Array.isArray(existingResolutionHints)&&existingResolutionHints.length>0,fixHints=aliasedResolution?existingResolutionHints.filter(hint=>typeof hint=="string"):buildRemediationCommands(checkWarnings);if(fixHints.length===0)return;const truncated=aliasedResolution&&check.details?.missing_resolution_remediation_hints_truncated===!0;check.details={...check.details,fix_hints:fixHints,...truncated?{fix_hints_truncated:!0}:{}}}function resolveRequestedChecks(options){const requested=new Set;return options.checkCompleteness&&requested.add("completeness"),options.checkMetadata&&requested.add("metadata"),options.checkResolution&&requested.add("resolution"),(options.checkLifecycle||options.checkStaleBlockers)&&requested.add("lifecycle"),options.checkFiles&&requested.add("files"),options.checkHistoryDrift&&requested.add("history_drift"),options.checkCommandReferences&&requested.add("command_references"),options.checkStorageIntegrity&&requested.add("storage_integrity"),requested.size===0?(options.autoFix&&(requested.add("metadata"),requested.add("resolution"),requested.add("lifecycle")),options.pruneMissing&&requested.add("files"),requested.size===0&&(requested.add("metadata"),requested.add("resolution"),requested.add("lifecycle"),requested.add("files"),requested.add("command_references"),requested.add("history_drift"),requested.add("format_version"),requested.add("completeness"),requested.add("storage_integrity")),requested):(options.pruneMissing&&requested.add("files"),requested)}const DUPLICATE_ISSUE_CODE_WARNING_TOKEN="validate_metadata_duplicate_issue_codes";function summarizeDuplicateIssueCodes(duplicates,verboseDiagnostics){if(duplicates.length===0)return{rows:[],truncated:!1,warnings:[]};const limit=verboseDiagnostics?duplicates.length:DIAGNOSTIC_LIST_SUMMARY_LIMIT,shown=duplicates.slice(0,limit);return{rows:shown.map(duplicate=>({code:duplicate.code,count:duplicate.count,ids:duplicate.ids,titles:duplicate.titles,remediation_hint:`Items ${duplicate.ids.join(", ")} share issue code "${duplicate.code}"; rename or merge so each logical code maps to one item.`})),truncated:shown.length<duplicates.length,warnings:[`${DUPLICATE_ISSUE_CODE_WARNING_TOKEN}:${duplicates.length}`]}}function collectMissingMetadataByField(items,statusRegistry,enforcePlanningFieldsOnTerminal){const missingByField=Object.fromEntries(SUPPORTED_METADATA_REQUIRED_FIELDS.map(field=>[field,[]]));for(const item of items)for(const field of SUPPORTED_METADATA_REQUIRED_FIELDS)isMetadataFieldMissing(item,field,statusRegistry,enforcePlanningFieldsOnTerminal)&&missingByField[field].push(item.id);return missingByField}function buildMetadataWarningTokens(metadataPolicy,missingByField,duplicateWarnings){const warningTokens=[...metadataPolicy.warnings];for(const field of metadataPolicy.required_fields){const missingItems=missingByField[field];missingItems.length>0&&warningTokens.push(`${METADATA_WARNING_TOKEN_BY_FIELD[field]}:${missingItems.length}`)}return warningTokens.push(...duplicateWarnings),warningTokens}function buildMetadataCounts(metadataPolicy,missingByField){const counts={};for(const field of metadataPolicy.required_fields){const missing=missingByField[field],value=missing?missing.length:0,countKey=METADATA_COUNT_KEY_BY_FIELD[field];counts[countKey]=value}return counts}function buildMissingFieldOccurrences(metadataPolicy,missingByField,itemsById){const occurrences=[];for(const field of metadataPolicy.required_fields){const missing=missingByField[field];if(missing)for(const itemId of missing){const itemType=itemsById.get(itemId)?.type,normalizedItemType=typeof itemType=="string"&&itemType.length>0?itemType:"Unknown";occurrences.push({item_type:normalizedItemType,field})}}return occurrences}function attachMissingMetadataItemIds(details,metadataPolicy,missingByField,verboseDiagnostics){for(const field of metadataPolicy.required_fields){const missing=missingByField[field];if(!missing||missing.length===0)continue;const idsKey=METADATA_ITEM_IDS_KEY_BY_FIELD[field],truncatedKey=METADATA_TRUNCATED_KEY_BY_FIELD[field];if(!idsKey||!truncatedKey)continue;const summarized=summarizeList(missing,verboseDiagnostics?missing.length:DIAGNOSTIC_LIST_SUMMARY_LIMIT);details[idsKey]=summarized.values,details[truncatedKey]=summarized.truncated}}function buildCloseReasonBackfillRows(metadataPolicy,missingByField,itemsById){if(!metadataPolicy.required_fields.includes("close_reason"))return[];const missing=missingByField.close_reason;return missing?missing.map(itemId=>({id:itemId,resolution:toNonEmptyStringOrUndefined(itemsById.get(itemId)?.resolution)})):[]}function buildEstimateBackfillRows(metadataPolicy,missingByField,itemsById){if(!metadataPolicy.required_fields.includes("estimated_minutes"))return[];const missing=missingByField.estimated_minutes;return missing?missing.map(itemId=>({id:itemId,type:toNonEmptyStringOrUndefined(itemsById.get(itemId)?.type)})):[]}function buildMetadataCheck(items,metadataPolicy,statusRegistry,verboseDiagnostics,configuredIssueCodePrefixes){const itemsById=new Map(items.map(item=>[item.id,item])),enforcePlanningFieldsOnTerminal=metadataPolicy.profile==="strict",missingByField=collectMissingMetadataByField(items,statusRegistry,enforcePlanningFieldsOnTerminal),duplicateIssueCodes=findDuplicateIssueCodes(items,{configuredPrefixes:configuredIssueCodePrefixes}),duplicateIssueCodeSummary=summarizeDuplicateIssueCodes(duplicateIssueCodes,verboseDiagnostics),warningTokens=buildMetadataWarningTokens(metadataPolicy,missingByField,duplicateIssueCodeSummary.warnings),counts=buildMetadataCounts(metadataPolicy,missingByField),missingFieldOccurrences=buildMissingFieldOccurrences(metadataPolicy,missingByField,itemsById),missingByType=buildMissingByTypeCounts(missingFieldOccurrences),details={checked_items:items.length,metadata_profile:metadataPolicy.profile,metadata_profile_source:metadataPolicy.profile_source,metadata_profile_fallback_to_core:metadataPolicy.fallback_to_core,required_fields:[...metadataPolicy.required_fields],supported_required_fields:[...SUPPORTED_METADATA_REQUIRED_FIELDS],counts,missing_by_type:missingByType,duplicate_issue_codes_count:duplicateIssueCodes.length,duplicate_issue_codes:duplicateIssueCodeSummary.rows,duplicate_issue_codes_truncated:duplicateIssueCodeSummary.truncated};metadataPolicy.configured_custom_fields.length>0&&(details.configured_custom_required_fields=[...metadataPolicy.configured_custom_fields]),attachMissingMetadataItemIds(details,metadataPolicy,missingByField,verboseDiagnostics);const closeReasonBackfillRows=buildCloseReasonBackfillRows(metadataPolicy,missingByField,itemsById),estimateBackfillRows=buildEstimateBackfillRows(metadataPolicy,missingByField,itemsById);return{check:{name:"metadata",status:warningTokens.length===0?"ok":"warn",ok:warningTokens.length===0,details},warnings:warningTokens,closeReasonBackfillRows,estimateBackfillRows}}function buildResolutionCheck(items,statusRegistry,verboseDiagnostics){const terminalDoneStatuses=new Set(statusRegistry.terminal_done_statuses);terminalDoneStatuses.add(statusRegistry.close_status);const closedItems=items.filter(item=>terminalDoneStatuses.has(normalizeStatusForRegistry(item.status,statusRegistry))),missingResolutionRows=[],resolutionBackfillRows=[];for(const item of closedItems){const missingFields=RESOLUTION_FIELD_KEYS.filter(field=>!toNonEmptyStringOrUndefined(item[field]));missingFields.length!==0&&(missingResolutionRows.push({id:item.id,missing_fields:missingFields}),resolutionBackfillRows.push({id:item.id,missing_fields:missingFields,close_reason:toNonEmptyStringOrUndefined(item.close_reason)}))}const warnings=missingResolutionRows.length>0?[`validate_resolution_missing_fields:${missingResolutionRows.length}`]:[],diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(missingResolutionRows.map(row=>`${row.id}:${row.missing_fields.join(",")}`),diagnosticLimit),remediationHints=missingResolutionRows.map(row=>buildResolutionRemediationCommand(row)),summarizedHints=summarizeList(remediationHints,diagnosticLimit);return{check:{name:"resolution",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{checked_closed_items:closedItems.length,missing_resolution_items:missingResolutionRows.length,missing_resolution_rows:summarizedRows.values,missing_resolution_rows_truncated:summarizedRows.truncated,missing_resolution_remediation_hints:summarizedHints.values,missing_resolution_remediation_hints_truncated:summarizedHints.truncated}},warnings,resolutionBackfillRows}}function escapeRegExp(value){return value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function buildLifecycleDependencyGraph(activeItems,idPrefix="pm",relationshipRegistry=createRelationshipKindRegistry()){const activeItemIds=new Set(activeItems.map(item=>item.id)),sortedItems=[...activeItems].sort((left,right)=>left.id.localeCompare(right.id));return new Map(sortedItems.map(item=>{const edges=new Set,blockedBy=toMeaningfulString(item.blocked_by);blockedBy&&activeItemIds.has(blockedBy)&&edges.add(blockedBy),(item.dependencies??[]).filter(dependency=>{const dependencyKind=toMeaningfulString(dependency.kind);return dependencyKind!==void 0&&relationshipRegistry.resolve(dependencyKind)?.ordering===!0}).map(dependency=>toMeaningfulString(dependency.id)).filter(dependencyId=>dependencyId!==void 0&&activeItemIds.has(dependencyId)).forEach(dependencyId=>edges.add(dependencyId));const definitionOfReady=toMeaningfulString(item.definition_of_ready);return extractItemIds(definitionOfReady??"",idPrefix).filter(referencedId=>activeItemIds.has(referencedId)).forEach(referencedId=>edges.add(referencedId)),[item.id,[...edges].sort((left,right)=>left.localeCompare(right))]}))}function buildDependencyReferencesCheck(items,verboseDiagnostics,statusRegistry){const classified=collectDanglingDependencyReferences(items,statusRegistry?status=>isTerminalStatus(status,statusRegistry):void 0),activeRows=classified.active.map(row=>`${row.holder_id}:${row.target_id}:${row.kind}`),legacyRows=classified.legacy_terminal.map(row=>`${row.holder_id}:${row.target_id}:${row.kind}:${row.holder_status}`),diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(activeRows,diagnosticLimit),summarizedLegacyRows=summarizeList(legacyRows,diagnosticLimit),hints=summarizeList(classified.active.map(row=>row.source==="parent"?`pm update ${row.holder_id} --unset parent`:row.source==="blocked_by"?`pm update ${row.holder_id} --unset blocked_by`:`pm update ${row.holder_id} --replace-deps '<correct dependency edges>'`),diagnosticLimit);return{check:{name:"dependency_references",status:activeRows.length===0?"ok":"warn",ok:activeRows.length===0,details:{checked_items:items.length,dangling_reference_count:activeRows.length+legacyRows.length,active_dangling_reference_count:activeRows.length,dangling_reference_rows:summarizedRows.values,dangling_reference_rows_truncated:summarizedRows.truncated,legacy_terminal_dangling_reference_count:legacyRows.length,legacy_closed_dangling_reference_count:classified.legacy_terminal.filter(row=>row.holder_status==="closed").length,legacy_terminal_dangling_reference_rows:summarizedLegacyRows.values,legacy_terminal_dangling_reference_rows_truncated:summarizedLegacyRows.truncated,no_active_blocker_sentinel_count:classified.no_active_blocker_sentinels.length,remediation_hints:hints.values,remediation_hints_truncated:hints.truncated}},warnings:activeRows.length>0?[`validate_dangling_dependency_references:${activeRows.length}`]:[]}}function extractItemIds(value,idPrefix="pm"){const normalizedPrefix=(idPrefix.trim().toLowerCase()||"pm").replace(/-+$/g,""),pattern=new RegExp(`(?:^|[^a-z0-9-])(${escapeRegExp(normalizedPrefix)}-[a-z0-9][a-z0-9-]*)`,"gi");return[...new Set([...value.matchAll(pattern)].map(match=>match[1].toLowerCase()))].sort((left,right)=>left.localeCompare(right))}function findLifecycleDependencyCycleComponents(graph){let nextIndex=0;const indexById=new Map,lowLinkById=new Map,stack=[],inStack=new Set,components=[],visit=id=>{indexById.set(id,nextIndex),lowLinkById.set(id,nextIndex),nextIndex+=1,stack.push(id),inStack.add(id);for(const dependencyId of graph.get(id)??[])indexById.has(dependencyId)?inStack.has(dependencyId)&&lowLinkById.set(id,Math.min(lowLinkById.get(id),indexById.get(dependencyId))):(visit(dependencyId),lowLinkById.set(id,Math.min(lowLinkById.get(id),lowLinkById.get(dependencyId))));if(lowLinkById.get(id)!==indexById.get(id))return;const component=[];for(;stack.length>0;){const member=stack.pop();if(inStack.delete(member),component.push(member),member===id)break}component.sort((left,right)=>left.localeCompare(right)),components.push(component)},sortedNodeIds=[...graph.keys()].sort((left,right)=>left.localeCompare(right));for(const id of sortedNodeIds)indexById.has(id)||visit(id);return components.filter(component=>{if(component.length>1)return!0;const selfId=component[0];return(graph.get(selfId)??[]).includes(selfId)}).sort((left,right)=>left[0].localeCompare(right[0])||left.length-right.length||left.join(",").localeCompare(right.join(",")))}function detectLifecycleDependencyCycles(activeItems,idPrefix="pm"){const graph=buildLifecycleDependencyGraph(activeItems,idPrefix),cycleComponents=findLifecycleDependencyCycleComponents(graph),cycleItemIds=[...new Set(cycleComponents.flat())].sort((left,right)=>left.localeCompare(right)),cycleSamplePaths=cycleComponents.map(component=>resolveLifecycleDependencyCycleSamplePath(component,graph).join("->"));return{cycle_count:cycleComponents.length,cycle_item_ids:cycleItemIds,cycle_sample_paths:cycleSamplePaths}}function classifyOrphanedPath(pathValue){return pathValue.startsWith("docs/")?"docs_unowned":pathValue.startsWith("tests/")?"tests_unowned":pathValue.startsWith("src/")?"source_unowned":pathValue.endsWith(".md")?"docs_unowned":"unlinked_existing"}function directoryOf(relativePath){const slash=relativePath.lastIndexOf("/");return slash===-1?"":relativePath.slice(0,slash)}function sharedDirectoryPrefixLength(left,right){const leftParts=directoryOf(left).split("/").filter(Boolean),rightParts=directoryOf(right).split("/").filter(Boolean);let count=0;for(;count<leftParts.length&&count<rightParts.length&&leftParts[count]===rightParts[count];)count+=1;return count}function scoreOrphanOwnerCandidate(pathValue,linkedPath){const linkedDir=directoryOf(linkedPath),orphanDir=directoryOf(pathValue),directoryPrefix=linkedPath.endsWith("/")?linkedPath:`${linkedPath}/`,isDirectoryPrefix=pathValue.startsWith(directoryPrefix),sameDirectory=linkedDir.length>0&&linkedDir===orphanDir,sharedPrefixLength=sharedDirectoryPrefixLength(pathValue,linkedPath);return!isDirectoryPrefix&&!sameDirectory&&sharedPrefixLength===0?null:isDirectoryPrefix?{score:linkedPath.length+1e3,confidence:"path_prefix"}:sameDirectory?{score:sharedPrefixLength+500,confidence:"same_directory"}:{score:sharedPrefixLength,confidence:"shared_directory"}}function shouldReplaceOrphanOwnerCandidate(best,item,score){return best===void 0||score>best.score||score===best.score&&item.id.localeCompare(best.item.id)<0}function findOrphanOwnerCandidate(pathValue,classification,items){const linkKind=classification==="docs_unowned"?"docs":"files";let best;return items.flatMap(item=>(linkKind==="docs"?item.docs??[]:item.files??[]).map(link=>({item,link}))).forEach(({item,link})=>{if(link.scope!=="project")return;const linkedPath=normalizeRelativePath(link.path);if(linkedPath.length===0||linkedPath===pathValue)return;const scored=scoreOrphanOwnerCandidate(pathValue,linkedPath);scored!==null&&shouldReplaceOrphanOwnerCandidate(best,item,scored.score)&&(best={item,score:scored.score,confidence:scored.confidence})}),best?{id:best.item.id,type:best.item.type,title:best.item.title,status:best.item.status,confidence:best.confidence}:null}function buildOrphanedPathRows(orphanedFiles,items){return orphanedFiles.map(pathValue=>{const classification=classifyOrphanedPath(pathValue),linkCommand=classification==="docs_unowned"?"docs":"files",ownerCandidate=findOrphanOwnerCandidate(pathValue,classification,items),target=ownerCandidate?.id??"<id>";return{path:pathValue,classification,owner_candidate:ownerCandidate,remediation_hint:`pm ${linkCommand} ${target} --add path=${pathValue},scope=project,note="<why this artifact belongs to the item>"`}})}function summarizeOrphanedPathRows(rows){return rows.map(row=>`${row.path}:${row.classification} owner_candidate=${row.owner_candidate?.id??"unowned"} hint=${JSON.stringify(row.remediation_hint)}`)}function closureLikeFieldsForItem(item,lifecyclePatternPolicy){return Object.entries(lifecyclePatternPolicy.closure_like_metadata_field_patterns).filter(([field,patterns])=>{const value=toMeaningfulString(item[field]);return value?patterns.some(pattern=>value.toLowerCase().includes(pattern)):!1}).map(([field])=>field).sort((left,right)=>left.localeCompare(right))}function buildTerminalParentFixRow(item,parent,itemsById,canonicalIdByLowercase,statusRegistry){const grandparentId=toMeaningfulString(parent.parent),grandparent=grandparentId?itemsById.get(canonicalIdByLowercase.get(grandparentId.toLowerCase())??grandparentId):void 0;return{id:item.id,parent_id:parent.id,grandparent_id:grandparent?.id,grandparent_active:grandparent!==void 0&&!isTerminalStatus(grandparent.status,statusRegistry)}}function staleBlockerReasonsForItem(item,blockedStatuses,statusRegistry,lifecyclePatternPolicy){const blockedBy=toMeaningfulString(item.blocked_by),blockedReason=toMeaningfulString(item.blocked_reason),blockedReasonNormalized=blockedReason?.toLowerCase(),normalizedStatus=normalizeStatusForRegistry(item.status,statusRegistry),reasons=[];return blockedStatuses.has(normalizedStatus)?(!blockedBy&&!blockedReason&&reasons.push("blocked_status_missing_blocker_context"),blockedReasonNormalized?.includes("no active blocker")&&reasons.push("blocked_status_reason_reports_no_active_blocker"),blockedReasonNormalized&&lifecyclePatternPolicy.stale_blocker_reason_patterns.some(pattern=>blockedReasonNormalized.includes(pattern))&&reasons.push("blocked_status_reason_matches_stale_pattern"),reasons):(blockedBy&&reasons.push("non_blocked_status_has_blocked_by"),blockedReason&&reasons.push("non_blocked_status_has_blocked_reason"),reasons)}function collectLifecycleScanRows(items,includeStaleBlockers,statusRegistry,lifecyclePatternPolicy){const itemsById=new Map(items.map(item=>[item.id,item])),canonicalIdByLowercase=new Map(items.map(item=>[item.id.toLowerCase(),item.id])),blockedStatuses=statusRegistry.blocked_statuses.size>0?statusRegistry.blocked_statuses:new Set(["blocked"]),rows={activeItems:items.filter(item=>!isTerminalStatus(item.status,statusRegistry)),closureLikeRows:[],terminalParentRows:[],terminalParentFixRows:[],staleBlockerRows:[]};for(const item of rows.activeItems){const closureLikeFields=closureLikeFieldsForItem(item,lifecyclePatternPolicy);closureLikeFields.length>0&&rows.closureLikeRows.push({id:item.id,fields:closureLikeFields});const parentId=toMeaningfulString(item.parent),parent=parentId?itemsById.get(canonicalIdByLowercase.get(parentId.toLowerCase())??parentId):void 0;if(parent&&isTerminalStatus(parent.status,statusRegistry)&&(rows.terminalParentRows.push({id:item.id,parent_id:parent.id,parent_status:parent.status}),rows.terminalParentFixRows.push(buildTerminalParentFixRow(item,parent,itemsById,canonicalIdByLowercase,statusRegistry))),includeStaleBlockers){const reasons=staleBlockerReasonsForItem(item,blockedStatuses,statusRegistry,lifecyclePatternPolicy);reasons.length>0&&rows.staleBlockerRows.push({id:item.id,status:item.status,reasons:[...new Set(reasons)].sort((left,right)=>left.localeCompare(right))})}}return rows}function sortLifecycleScanRows(rows){rows.closureLikeRows.sort((left,right)=>left.id.localeCompare(right.id)),rows.terminalParentRows.sort((left,right)=>left.id.localeCompare(right.id)||left.parent_id.localeCompare(right.parent_id)),rows.terminalParentFixRows.sort((left,right)=>left.id.localeCompare(right.id)||left.parent_id.localeCompare(right.parent_id)),rows.staleBlockerRows.sort((left,right)=>left.id.localeCompare(right.id))}function lifecycleCycleWarningToken(prefix,severity,count){return count<=0||severity==="off"?null:`${severity==="error"?`${prefix}_error`:prefix}:${count}`}function lifecycleAdvisoryWarningToken(prefix,severity,count){return count>0&&severity!=="off"?`${prefix}:${count}`:null}function buildLifecycleWarnings(rows,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,counts){const warnings=[];rows.closureLikeRows.length>0&&warnings.push(`validate_lifecycle_active_closure_like_metadata:${rows.closureLikeRows.length}`),rows.terminalParentRows.length>0&&warnings.push(`validate_lifecycle_active_terminal_parent:${rows.terminalParentRows.length}`),includeStaleBlockers&&rows.staleBlockerRows.length>0&&warnings.push(`validate_lifecycle_stale_blockers:${rows.staleBlockerRows.length}`);const dependencyWarning=lifecycleCycleWarningToken("validate_lifecycle_dependency_cycles",dependencyCycleSeverity,counts.dependencyCycles),parentWarning=lifecycleCycleWarningToken("validate_hierarchy_parent_cycle",parentCycleSeverity,counts.activeHierarchyCycles),cardinalityWarning=lifecycleCycleWarningToken("validate_hierarchy_cardinality_violation",parentCycleSeverity,counts.activeHierarchyCardinality),divergenceWarning=lifecycleCycleWarningToken("validate_hierarchy_parent_divergence",parentCycleSeverity,counts.activeHierarchyDivergence),legacyCycleWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_parent_cycle",parentCycleSeverity,counts.legacyHierarchyCycles),legacyCardinalityWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_cardinality_violation",parentCycleSeverity,counts.legacyHierarchyCardinality),legacyDivergenceWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_parent_divergence",parentCycleSeverity,counts.legacyHierarchyDivergence);return[...warnings,...dependencyWarning?[dependencyWarning]:[],...parentWarning?[parentWarning]:[],...cardinalityWarning?[cardinalityWarning]:[],...divergenceWarning?[divergenceWarning]:[],...legacyCycleWarning?[legacyCycleWarning]:[],...legacyCardinalityWarning?[legacyCardinalityWarning]:[],...legacyDivergenceWarning?[legacyDivergenceWarning]:[]]}function linkedArtifactPathExceedsFilesystemLimits(artifactPath){const normalized=normalizeRelativePath(artifactPath);return normalized.length>LINKED_ARTIFACT_MAX_PATH_LENGTH||normalized.split(/[\\/]/).some(segment=>segment.length>LINKED_ARTIFACT_MAX_SEGMENT_LENGTH)}async function linkedArtifactIsMissing(workspaceRoot,artifactPath){const absolutePath=path.isAbsolute(artifactPath)?artifactPath:path.resolve(workspaceRoot,artifactPath);if(linkedArtifactPathExceedsFilesystemLimits(absolutePath))return!1;try{const stats=await fs.stat(absolutePath);return!stats.isFile()&&!stats.isDirectory()}catch(error){return hasFilesystemErrorCode(error,["ENOENT","ENOTDIR"])}}async function collectLinkedPathScanState(items,workspaceRoot){const state={linkedProjectPaths:new Set,remoteLinkedPaths:new Set,missingLinkedPaths:[],staleLinkRows:[]},linkedArtifacts=items.flatMap(item=>[...(item.files??[]).map(artifact=>({item,artifact,link_kind:"files"})),...(item.docs??[]).map(artifact=>({item,artifact,link_kind:"docs"}))]);for(const{item,artifact,link_kind}of linkedArtifacts){if(artifact.scope!=="project")continue;if(isRemoteLinkedArtifactReference(artifact.path)){state.remoteLinkedPaths.add(artifact.path.trim());continue}const normalizedPath=normalizeRelativePath(artifact.path);normalizedPath.length!==0&&(state.linkedProjectPaths.add(normalizedPath),await linkedArtifactIsMissing(workspaceRoot,artifact.path)&&(state.missingLinkedPaths.push(normalizedPath),state.staleLinkRows.push({item_id:item.id,path:normalizedPath,link_kind})))}return state}function partitionFileCandidates(fileCandidates,pmRoot,workspaceRoot,fileScanMode,includePmInternals,verboseFileLists){const strictTrackedAllMode=fileScanMode==="tracked-all-strict",strictModeForcesPmInternals=strictTrackedAllMode&&!includePmInternals,includePmInternalsEffective=includePmInternals||strictTrackedAllMode,pmInternalCandidatePrefixes=includePmInternalsEffective?[]:resolvePmInternalCandidatePrefixes(pmRoot,workspaceRoot),excludedPmInternalPaths=pmInternalCandidatePrefixes.length===0?[]:fileCandidates.candidateFiles.filter(candidate=>hasPathPrefix(candidate,pmInternalCandidatePrefixes)),candidateFiles=pmInternalCandidatePrefixes.length===0?fileCandidates.candidateFiles:fileCandidates.candidateFiles.filter(candidate=>!hasPathPrefix(candidate,pmInternalCandidatePrefixes)),excludedByReason={};if(excludedPmInternalPaths.length>0){const summarizedPmInternalPaths=summarizeFileList(excludedPmInternalPaths,verboseFileLists);excludedByReason.pm_internals={count:excludedPmInternalPaths.length,paths:summarizedPmInternalPaths.values,paths_truncated:summarizedPmInternalPaths.truncated,paths_total:summarizedPmInternalPaths.total}}return{strictTrackedAllMode,strictModeForcesPmInternals,includePmInternalsEffective,pmInternalCandidatePrefixes,excludedPmInternalPaths,candidateFiles,excludedByReason}}function buildLifecycleCheck(items,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,statusRegistry,lifecyclePatternPolicy,verboseDiagnostics,idPrefix="pm"){const rows=collectLifecycleScanRows(items,includeStaleBlockers,statusRegistry,lifecyclePatternPolicy);sortLifecycleScanRows(rows);const dependencyCycleDiagnostics=detectLifecycleDependencyCycles(rows.activeItems,idPrefix),parentCycleDiagnostics=detectLifecycleParentCycles(items,statusRegistry),statusRoleDiagnostics=inspectStatusRoleAssignments(statusRegistry,items,verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT),warnings=[...buildLifecycleWarnings(rows,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,{dependencyCycles:dependencyCycleDiagnostics.cycle_count,activeHierarchyCycles:parentCycleDiagnostics.active_cycle_count,activeHierarchyCardinality:parentCycleDiagnostics.active_cardinality_violation_count,activeHierarchyDivergence:parentCycleDiagnostics.active_parent_divergence_count,legacyHierarchyCycles:parentCycleDiagnostics.legacy_cycle_count,legacyHierarchyCardinality:parentCycleDiagnostics.legacy_cardinality_violation_count,legacyHierarchyDivergence:parentCycleDiagnostics.legacy_parent_divergence_count}),...buildStatusRoleWarnings(statusRoleDiagnostics)],diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedClosureLikeRows=summarizeList(rows.closureLikeRows.map(row=>`${row.id}:${row.fields.join(",")}`),diagnosticLimit),summarizedTerminalParentRows=summarizeList(rows.terminalParentRows.map(row=>`${row.id}:${row.parent_id}:${row.parent_status}`),diagnosticLimit),summarizedStaleBlockerRows=summarizeList(rows.staleBlockerRows.map(row=>`${row.id}:${row.status}:${row.reasons.join(",")}`),diagnosticLimit),summarizedDependencyCycleItemIds=summarizeList(dependencyCycleDiagnostics.cycle_item_ids,diagnosticLimit),summarizedDependencyCycleSamplePaths=summarizeList(dependencyCycleDiagnostics.cycle_sample_paths,diagnosticLimit),summarizedParentCycleItemIds=summarizeList(parentCycleDiagnostics.cycle_item_ids,diagnosticLimit),summarizedParentCycleSamplePaths=summarizeList(parentCycleDiagnostics.cycle_sample_paths,diagnosticLimit),summarizedHierarchyCardinalityRows=summarizeList(parentCycleDiagnostics.cardinality_violation_rows,diagnosticLimit),summarizedHierarchyDivergenceRows=summarizeList(parentCycleDiagnostics.parent_divergence_rows,diagnosticLimit),hasErrorSeverityCycle=dependencyCycleDiagnostics.cycle_count>0&&dependencyCycleSeverity==="error"||(parentCycleDiagnostics.active_cycle_count>0||parentCycleDiagnostics.active_cardinality_violation_count>0||parentCycleDiagnostics.active_parent_divergence_count>0)&&parentCycleSeverity==="error";return{check:{name:"lifecycle",status:hasErrorSeverityCycle?"error":warnings.length===0?"ok":"warn",ok:!hasErrorSeverityCycle&&warnings.length===0,details:{checked_active_items:rows.activeItems.length,lifecycle_status_roles:statusRoleDiagnostics,active_closure_like_metadata_items:rows.closureLikeRows.length,active_closure_like_metadata_rows:summarizedClosureLikeRows.values,active_closure_like_metadata_rows_truncated:summarizedClosureLikeRows.truncated,active_terminal_parent_items:rows.terminalParentRows.length,active_terminal_parent_rows:summarizedTerminalParentRows.values,active_terminal_parent_rows_truncated:summarizedTerminalParentRows.truncated,stale_blocker_checks_enabled:includeStaleBlockers,stale_blocker_items:rows.staleBlockerRows.length,stale_blocker_rows:summarizedStaleBlockerRows.values,stale_blocker_rows_truncated:summarizedStaleBlockerRows.truncated,dependency_cycle_severity_policy:dependencyCycleSeverity,dependency_cycle_count:dependencyCycleDiagnostics.cycle_count,dependency_cycle_item_count:dependencyCycleDiagnostics.cycle_item_ids.length,dependency_cycle_item_ids:summarizedDependencyCycleItemIds.values,dependency_cycle_item_ids_truncated:summarizedDependencyCycleItemIds.truncated,dependency_cycle_sample_paths:summarizedDependencyCycleSamplePaths.values,dependency_cycle_sample_paths_truncated:summarizedDependencyCycleSamplePaths.truncated,parent_cycle_severity_policy:parentCycleSeverity,parent_cycle_count:parentCycleDiagnostics.cycle_count,active_parent_cycle_count:parentCycleDiagnostics.active_cycle_count,legacy_parent_cycle_count:parentCycleDiagnostics.legacy_cycle_count,parent_cycle_item_count:parentCycleDiagnostics.cycle_item_ids.length,parent_cycle_item_ids:summarizedParentCycleItemIds.values,parent_cycle_item_ids_truncated:summarizedParentCycleItemIds.truncated,parent_cycle_sample_paths:summarizedParentCycleSamplePaths.values,parent_cycle_sample_paths_truncated:summarizedParentCycleSamplePaths.truncated,hierarchy_cardinality_violation_count:parentCycleDiagnostics.cardinality_violation_count,active_hierarchy_cardinality_violation_count:parentCycleDiagnostics.active_cardinality_violation_count,legacy_hierarchy_cardinality_violation_count:parentCycleDiagnostics.legacy_cardinality_violation_count,hierarchy_cardinality_violation_rows:summarizedHierarchyCardinalityRows.values,hierarchy_cardinality_violation_rows_truncated:summarizedHierarchyCardinalityRows.truncated,hierarchy_parent_divergence_count:parentCycleDiagnostics.parent_divergence_count,active_hierarchy_parent_divergence_count:parentCycleDiagnostics.active_parent_divergence_count,legacy_hierarchy_parent_divergence_count:parentCycleDiagnostics.legacy_parent_divergence_count,hierarchy_parent_divergence_rows:summarizedHierarchyDivergenceRows.values,hierarchy_parent_divergence_rows_truncated:summarizedHierarchyDivergenceRows.truncated,stale_blocker_reason_patterns:[...lifecyclePatternPolicy.stale_blocker_reason_patterns],stale_blocker_reason_pattern_source:lifecyclePatternPolicy.stale_blocker_reason_pattern_source,closure_like_blocked_reason_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.blocked_reason],closure_like_blocked_reason_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.blocked_reason,closure_like_resolution_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.resolution],closure_like_resolution_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.resolution,closure_like_actual_result_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.actual_result],closure_like_actual_result_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.actual_result}},warnings,terminalParentFixRows:rows.terminalParentFixRows}}async function buildFilesCheck(items,workspaceRoot,pmRoot,fileScanMode,includePmInternals,verboseFileLists,statusRegistry=resolveRuntimeStatusRegistry(SETTINGS_DEFAULTS.schema)){const linkedPathState=await collectLinkedPathScanState(items,workspaceRoot),itemsById=new Map(items.map(item=>[item.id,item])),uniqueMissingLinkedPaths=[...new Set(linkedPathState.missingLinkedPaths)].sort((left,right)=>left.localeCompare(right)),fileCandidates=await collectProjectFileCandidates(workspaceRoot,fileScanMode),partition=partitionFileCandidates(fileCandidates,pmRoot,workspaceRoot,fileScanMode,includePmInternals,verboseFileLists),orphanedFiles=partition.candidateFiles.filter(candidate=>!linkedPathState.linkedProjectPaths.has(candidate)),orphanedPathRows=buildOrphanedPathRows(orphanedFiles,items),classifiedStalePaths=classifyStaleLinkedPaths(uniqueMissingLinkedPaths,partition.candidateFiles),classificationByPath=new Map(classifiedStalePaths.map(entry=>[entry.path,entry.classification])),movedStalePathCount=classifiedStalePaths.filter(entry=>entry.classification==="moved").length,staleLinkPruneRows=linkedPathState.staleLinkRows.map(row=>({...row,classification:classificationByPath.get(row.path)??"deleted"})).sort((left,right)=>left.item_id.localeCompare(right.item_id)||left.path.localeCompare(right.path)||left.link_kind.localeCompare(right.link_kind)),warnings=[];partition.strictModeForcesPmInternals&&warnings.push("validate_files_tracked_all_strict_forces_pm_internals"),orphanedFiles.length>0&&warnings.push(`validate_files_orphaned_paths:${orphanedFiles.length}`);const uniqueRemoteLinkedPaths=[...linkedPathState.remoteLinkedPaths].sort((left,right)=>left.localeCompare(right)),summarizedRemote=summarizeFileList(uniqueRemoteLinkedPaths,verboseFileLists),summarizedMissing=summarizeFileList(uniqueMissingLinkedPaths,verboseFileLists),summarizedOrphaned=summarizeFileList(orphanedFiles,verboseFileLists),summarizedOrphanedClassifications=summarizeFileList(orphanedPathRows.map(row=>`${row.path}:${row.classification}:owner_candidate=${row.owner_candidate?.id??"unowned"}`),verboseFileLists),orphanedPathRowDetail=verboseFileLists?orphanedPathRows:summarizeFileList(summarizeOrphanedPathRows(orphanedPathRows),!1).values,summarizedClassifications=summarizeFileList(summarizeStaleLinkedPathClassifications(classifiedStalePaths),verboseFileLists),repairReport=buildLinkedFileRepairReport(staleLinkPruneRows,classifiedStalePaths,id=>itemsById.get(id),statusRegistry,verboseFileLists?1/0:FILE_LIST_SUMMARY_LIMIT);return repairReport.active_missing_linked_paths_count>0&&warnings.push(`validate_files_missing_linked_paths:${repairReport.active_missing_linked_paths_count}`),{check:{name:"files",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{workspace_root:workspaceRoot,scan_mode_requested:fileCandidates.requestedMode,scan_mode_applied:fileCandidates.appliedMode,strict_tracked_all_mode:partition.strictTrackedAllMode,strict_mode_forces_pm_internals:partition.strictModeForcesPmInternals,strict_mode_forces_pm_internals_notice:partition.strictModeForcesPmInternals?"tracked-all-strict force-enables PM internals; pass --include-pm-internals to make inclusion explicit.":null,file_list_detail_mode:verboseFileLists?"full":"summary",file_list_summary_limit:FILE_LIST_SUMMARY_LIMIT,candidate_scan_source:fileCandidates.source,include_pm_internals:partition.includePmInternalsEffective,include_pm_internals_requested:includePmInternals,pm_internal_candidate_prefixes:partition.pmInternalCandidatePrefixes,pm_internal_excluded_count:partition.excludedPmInternalPaths.length,excluded_total:partition.excludedPmInternalPaths.length,excluded_by_reason:partition.excludedByReason,linked_project_paths:linkedPathState.linkedProjectPaths.size,remote_linked_paths_count:uniqueRemoteLinkedPaths.length,remote_linked_paths_total:summarizedRemote.total,remote_linked_paths:summarizedRemote.values,remote_linked_paths_truncated:summarizedRemote.truncated,candidate_total_raw:fileCandidates.candidateTotal,candidate_scanned_raw:fileCandidates.candidateScanned,candidate_total:partition.candidateFiles.length,candidate_scanned:partition.candidateFiles.length,scanned_candidate_files:partition.candidateFiles.length,missing_linked_paths_count:uniqueMissingLinkedPaths.length,missing_linked_paths_total:summarizedMissing.total,missing_linked_paths:summarizedMissing.values,missing_linked_paths_truncated:summarizedMissing.truncated,missing_linked_paths_moved_count:movedStalePathCount,missing_linked_paths_deleted_count:classifiedStalePaths.filter(entry=>entry.classification==="deleted").length,missing_linked_paths_malformed_count:classifiedStalePaths.filter(entry=>entry.classification==="malformed").length,missing_linked_path_classifications:summarizedClassifications.values,missing_linked_path_classifications_truncated:summarizedClassifications.truncated,...repairReport,orphaned_paths_count:orphanedFiles.length,orphaned_paths_total:summarizedOrphaned.total,orphaned_paths:summarizedOrphaned.values,orphaned_paths_truncated:summarizedOrphaned.truncated,orphaned_path_classifications:summarizedOrphanedClassifications.values,orphaned_path_classifications_truncated:summarizedOrphanedClassifications.truncated,orphaned_path_rows_count:orphanedPathRows.length,orphaned_path_rows:orphanedPathRowDetail}},warnings,staleLinkPruneRows}}function buildUntrustedLinkedTestRows(linkedTests,trustDecisions){const rows=[];return linkedTests.forEach(({item,linkedTest},index)=>{const trust=trustDecisions[index];if(trust.trusted)return;const command=summarizeCommandPreview(linkedTest.command??"");rows.push(`${item.id}:${trust.source_ref??"unknown"}->${trust.current_source_ref??"unknown"}:${command}`)}),rows}async function buildCommandReferencesCheck(items,idPrefix,verboseDiagnostics,pmRoot){const knownIds=new Set(items.map(item=>item.id.toLowerCase()));let linkedCommandsScanned=0,referencedPmIdCount=0;const referencedPmIds=new Set,staleReferenceRows=[],linkedTests=items.flatMap(item=>(item.tests??[]).map(linkedTest=>({item,linkedTest}))),currentSourceRef=await resolveLinkedTestSourceRef(resolveLinkedTestSourceWorkspaceRoot()),trustDecisions=await resolveLinkedTestTrustBatch(pmRoot,linkedTests.map(({linkedTest})=>linkedTest),currentSourceRef),untrustedRows=buildUntrustedLinkedTestRows(linkedTests,trustDecisions);for(const{item,linkedTest}of linkedTests){if(typeof linkedTest.command!="string"||linkedTest.command.trim().length===0)continue;linkedCommandsScanned+=1;const referencedIds=extractReferencedPmItemIdsFromCommand(linkedTest.command,idPrefix);if(referencedIds.length!==0){referencedPmIdCount+=referencedIds.length;for(const referencedId of referencedIds)referencedPmIds.add(referencedId),knownIds.has(referencedId.toLowerCase())||staleReferenceRows.push(`${item.id}:${referencedId}:${summarizeCommandPreview(linkedTest.command)}`)}}const uniqueStaleReferenceRows=[...new Set(staleReferenceRows)].sort((left,right)=>left.localeCompare(right)),stalePmIds=[...new Set(uniqueStaleReferenceRows.map(row=>row.split(":")[1]??""))].filter(value=>value.length>0).sort((left,right)=>left.localeCompare(right)),warnings=[];uniqueStaleReferenceRows.length>0&&warnings.push(`validate_command_references_stale_pm_ids:${uniqueStaleReferenceRows.length}`),untrustedRows.length>0&&warnings.push(`validate_linked_test_trust_unacknowledged:${untrustedRows.length}`);const diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(uniqueStaleReferenceRows,diagnosticLimit),summarizedStalePmIds=summarizeList(stalePmIds,diagnosticLimit),summarizedReferencedPmIds=summarizeList([...referencedPmIds].sort((left,right)=>left.localeCompare(right)),diagnosticLimit),summarizedUntrustedRows=summarizeList(untrustedRows,diagnosticLimit);return{check:{name:"command_references",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{checked_items:items.length,linked_commands_scanned:linkedCommandsScanned,referenced_pm_ids_count:referencedPmIdCount,unique_referenced_pm_ids_count:referencedPmIds.size,unique_referenced_pm_ids:summarizedReferencedPmIds.values,unique_referenced_pm_ids_truncated:summarizedReferencedPmIds.truncated,linked_test_trust_current_source_ref:currentSourceRef??null,untrusted_linked_tests_count:untrustedRows.length,untrusted_linked_tests:summarizedUntrustedRows.values,untrusted_linked_tests_truncated:summarizedUntrustedRows.truncated,stale_pm_id_references_count:uniqueStaleReferenceRows.length,stale_pm_ids_count:stalePmIds.length,stale_pm_ids:summarizedStalePmIds.values,stale_pm_ids_truncated:summarizedStalePmIds.truncated,stale_pm_id_reference_rows:summarizedRows.values,stale_pm_id_reference_rows_truncated:summarizedRows.truncated}},warnings}}function buildFormatVersionCheck(items,verboseDiagnostics){const scan=scanItemFormatVersions(items.map(item=>({ref:item.id,version:effectiveItemFormatVersion(item)})),CURRENT_ITEM_FORMAT_VERSION,BASELINE_ITEM_FORMAT_VERSION),warnings=[];scan.outdated.length>0&&warnings.push(`validate_format_version_outdated_items:${scan.outdated.length}`),scan.ahead.length>0&&warnings.push(`validate_format_version_ahead_items:${scan.ahead.length}`);const diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedOutdated=summarizeList(scan.outdated,diagnosticLimit),summarizedAhead=summarizeList(scan.ahead,diagnosticLimit),status=scan.ahead.length>0?"error":scan.outdated.length>0?"warn":"ok";return{check:{name:"format_version",status,ok:status==="ok",details:{checked_items:items.length,current_format_version:CURRENT_ITEM_FORMAT_VERSION,outdated_items_count:scan.outdated.length,outdated_items:summarizedOutdated.values,outdated_items_truncated:summarizedOutdated.truncated,ahead_items_count:scan.ahead.length,ahead_items:summarizedAhead.values,ahead_items_truncated:summarizedAhead.truncated}},warnings}}const VALIDATE_AUTO_FIX_MESSAGE="pm validate auto-fix";async function applyValidateFix(fix,global2,services){switch(fix.kind){case"set_closed_at":await applyClosureTimestampFix(fix,global2);return;case"set_resolution":case"set_close_reason":case"set_estimate":case"reparent":case"unset_parent":{const updateOptions={message:VALIDATE_AUTO_FIX_MESSAGE};if(fix.kind==="set_resolution"?updateOptions.resolution=fix.value:fix.kind==="set_close_reason"?updateOptions.closeReason=fix.value:fix.kind==="set_estimate"?updateOptions.estimatedMinutes=fix.value:fix.kind==="reparent"?updateOptions.parent=fix.parent_id:updateOptions.unset=["parent"],!services.runUpdate)throw new PmCliError("Applying validate metadata/lifecycle fixes requires a runUpdate mutation service.",EXIT_CODE.USAGE);await services.runUpdate(fix.item_id,updateOptions,global2);return}case"prune_file_link":throw new Error(`Unsupported non-batched fix kind: ${fix.kind}`);case"prune_doc_link":throw new Error(`Unsupported non-batched fix kind: ${fix.kind}`)}}function pruneBatchKey(fix){return fix.kind!=="prune_file_link"&&fix.kind!=="prune_doc_link"?null:`${fix.kind}:${fix.item_id}`}async function applyValidateFixes(applicable,global2,services){const applied=[],failed=[],pruneBatches=new Map;for(const fix of applicable.filter(candidate=>pruneBatchKey(candidate)===null))try{await applyValidateFix(fix,global2,services),applied.push(fix)}catch(error){failed.push({fix,error})}for(const fix of applicable.filter(candidate=>pruneBatchKey(candidate)!==null)){const batchKey=pruneBatchKey(fix),existing=pruneBatches.get(batchKey);existing?existing.push(fix):pruneBatches.set(batchKey,[fix])}for(const batch of pruneBatches.values()){const first=batch[0];if(!first)continue;const remove=batch.map(fix=>fix.path).filter(value=>typeof value=="string"&&value.length>0);try{first.kind==="prune_file_link"?await runFiles(first.item_id,{remove,message:VALIDATE_AUTO_FIX_MESSAGE},global2):await runDocs(first.item_id,{remove,message:VALIDATE_AUTO_FIX_MESSAGE},global2),applied.push(...batch)}catch(error){failed.push(...batch.map(fix=>({fix,error})))}}return{applied,failed}}const _testOnlyValidateCommand={applyValidateFix,applyValidateFixes,attachValidateFixHints,buildCommandReferencesCheck,buildDependencyReferencesCheck,buildCloseReasonBackfillRows,buildFilesCheck,buildLifecycleCheck,buildLifecycleDependencyGraph,buildLifecycleParentGraph,buildEstimateBackfillRows,buildMetadataCounts,buildMissingFieldOccurrences,buildOrphanedPathRows,classifyOrphanedPath,collectDefaultProjectFileCandidates,collectTrackedGitFileCandidates,detectLifecycleDependencyCycles,detectLifecycleParentCycles,escapeRegExp,extractItemIds,findLifecycleDependencyCycleComponents,isMetadataFieldMissing,linkedArtifactPathExceedsFilesystemLimits,listFilesRecursive,resolveDependencyCycleSeverity,resolveParentCycleSeverity,resolveFileScanMode,resolveLifecycleDependencyCycleSamplePath,resolveRequestedChecks,resolveValidateMetadataProfile,resolveWorkspaceRoot,sharedDirectoryPrefixLength,summarizeOrphanedPathRows,summarizeDuplicateIssueCodes,toMeaningfulString};function appendInvalidMergeReceiptEvidenceWarning(warnings,invalidEvidenceCount){invalidEvidenceCount>0&&warnings.push(`merge_receipt_evidence_invalid:${invalidEvidenceCount}`)}async function buildStorageIntegrityCheck(pmRoot,items,typeToFolder,settings){const scan=await scanStorageIntegrity(pmRoot,new Set(items.map(item=>item.id)),typeToFolder,{schema:settings.schema,extensionFieldNames:collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}),warnings=[];scan.unreadable_item_files.length>0&&warnings.push(`validate_storage_unreadable_items:${scan.unreadable_item_files.length}`),scan.duplicate_item_ids.length>0&&warnings.push(`validate_storage_duplicate_item_ids:${scan.duplicate_item_ids.length}`),scan.history_conflict_marker_streams.length>0&&warnings.push(`validate_storage_history_conflict_markers:${scan.history_conflict_marker_streams.length}`),scan.history_unparseable_streams.length>0&&warnings.push(`validate_storage_unparseable_history:${scan.history_unparseable_streams.length}`),scan.resurrected_items.length>0&&warnings.push(`validate_storage_resurrected_items:${scan.resurrected_items.length}`),scan.unparseable_config_files.length>0&&warnings.push(`validate_storage_unparseable_config:${scan.unparseable_config_files.length}`);const errorCount=warnings.length,trackedRuntimeCache=await scanTrackedRuntimeCache(pmRoot);trackedRuntimeCache.tracked_path_count>0&&warnings.push(`validate_storage_tracked_runtime_cache_files:${trackedRuntimeCache.tracked_path_count}`);const fenceAudit=await auditMergeAttributeFence(pmRoot,resolveProjectMergeTypeFolders(settings));fenceAudit.status==="drift"&&warnings.push(`validate_merge_fence_drift:${fenceAudit.missing_patterns.length+fenceAudit.stale_patterns.length}`);const gitWorkspaceRoot=await findGitWorkspaceRoot(pmRoot),mergeDriverAudit=gitWorkspaceRoot===null?null:await auditMergeDriverConfiguration(gitWorkspaceRoot);mergeDriverAudit!==null&&mergeDriverAudit.status!=="ok"&&warnings.push(`validate_merge_driver_configuration:${mergeDriverAudit.missing_keys.length+mergeDriverAudit.drifted_keys.length}`);const mergeReceiptEvidence=await inspectMergeReceiptEvidence(gitWorkspaceRoot??pmRoot,{includeLossless:!0,pmRoot}),pendingMergeReceipts=mergeReceiptEvidence.receipts,{pendingDecisions:pendingMergeDecisions,lossless:losslessMergeReceipts}=partitionMergeReceipts(pendingMergeReceipts);pendingMergeDecisions.length>0&&warnings.push(`validate_merge_decisions_unreviewed:${pendingMergeDecisions.length}`),appendInvalidMergeReceiptEvidenceWarning(warnings,mergeReceiptEvidence.invalid_evidence_count);const status=errorCount>0?"error":warnings.length>0?"warn":"ok";return{check:{name:"storage_integrity",status,ok:status==="ok",details:{...scan,merge_fence:fenceAudit,merge_driver_configuration:mergeDriverAudit,pending_merge_decision_count:pendingMergeDecisions.length,pending_merge_decision_items:[...new Set(pendingMergeDecisions.map(receipt=>receipt.item_id))].sort((left,right)=>left.localeCompare(right)),lossless_merge_receipt_count:losslessMergeReceipts.length,invalid_merge_receipt_evidence_count:mergeReceiptEvidence.invalid_evidence_count,invalid_merge_receipt_evidence_details:mergeReceiptEvidence.invalid_evidence,invalid_merge_receipt_evidence_details_truncated:mergeReceiptEvidence.invalid_evidence_truncated,lossless_merge_receipt_items:[...new Set(losslessMergeReceipts.map(receipt=>receipt.item_id))].sort((left,right)=>left.localeCompare(right)),tracked_runtime_cache:{tracker_relative_root:trackedRuntimeCache.tracker_relative_root,tracked_paths:trackedRuntimeCache.tracked_paths,tracked_path_count:trackedRuntimeCache.tracked_path_count,remediation_command:trackedRuntimeCache.remediation_command}}},warnings}}function recordValidateCheck(state,built,fixHintsEnabled){fixHintsEnabled&&attachValidateFixHints(built.check,built.warnings),state.checks.push(built.check),state.warnings.push(...built.warnings)}async function executeRequestedValidateChecks(params){const state={closureTimestampFixes:[],checks:[],warnings:[...params.initialWarnings],closeReasonBackfillRows:[],estimateBackfillRows:[],resolutionBackfillRows:[],terminalParentFixRows:[],staleLinkPruneRows:[]},fixHintsEnabled=params.options.fixHints===!0,fullDiagnostics=params.options.verboseDiagnostics===!0||params.options.allAffectedIds===!0||params.global.json===!0;if(params.requestedChecks.has("completeness")){const built=await readWorkflowCompletenessCheck(params.pmRoot,params.items,fullDiagnostics?1/0:DIAGNOSTIC_LIST_SUMMARY_LIMIT,params.sourceIncomplete);recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("metadata")){const built=buildMetadataCheck(params.items,params.metadataPolicy,params.statusRegistry,fullDiagnostics,[params.settings.id_prefix]);state.closeReasonBackfillRows=built.closeReasonBackfillRows,state.estimateBackfillRows=built.estimateBackfillRows;const timestamps=await scanClosureTimestamps(params.pmRoot,params.items,params.statusRegistry,params.options.autoFix===!0||fixHintsEnabled,fullDiagnostics?1/0:DIAGNOSTIC_LIST_SUMMARY_LIMIT);state.closureTimestampFixes=timestamps.fixes,Object.assign(built.check.details,timestamps.details),built.warnings.push(...timestamps.warnings),built.check.ok=built.warnings.length===0,built.check.status=built.check.ok?"ok":"warn",recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("resolution")){const built=buildResolutionCheck(params.items,params.statusRegistry,fullDiagnostics);state.resolutionBackfillRows=built.resolutionBackfillRows,recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("lifecycle")){const built=buildLifecycleCheck(params.items,!!params.options.checkStaleBlockers,params.dependencyCycleSeverity,params.parentCycleSeverity,params.statusRegistry,params.lifecyclePatternPolicy,fullDiagnostics,params.settings.id_prefix);state.terminalParentFixRows=built.terminalParentFixRows,recordValidateCheck(state,built,fixHintsEnabled),recordValidateCheck(state,buildDependencyReferencesCheck(params.items,fullDiagnostics,params.statusRegistry),fixHintsEnabled)}if(params.requestedChecks.has("files")){const built=await buildFilesCheck(params.items,params.workspaceRoot,params.pmRoot,params.fileScanMode,!!params.options.includePmInternals,!!params.options.verboseFileLists,params.statusRegistry);state.staleLinkPruneRows=built.staleLinkPruneRows,recordValidateCheck(state,built,fixHintsEnabled)}return params.requestedChecks.has("command_references")&&recordValidateCheck(state,await buildCommandReferencesCheck(params.items,params.settings.id_prefix,fullDiagnostics,params.pmRoot),fixHintsEnabled),params.requestedChecks.has("history_drift")&&recordValidateCheck(state,await buildValidateHistoryDriftCheck(params.pmRoot,params.items,fullDiagnostics),fixHintsEnabled),params.requestedChecks.has("format_version")&&recordValidateCheck(state,buildFormatVersionCheck(params.items,fullDiagnostics),fixHintsEnabled),params.requestedChecks.has("storage_integrity")&&recordValidateCheck(state,await buildStorageIntegrityCheck(params.pmRoot,params.items,resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,params.settings),fixHintsEnabled),state}function planValidateFixes(options,state,settings){const planned=[];return options.autoFix===!0&&(planned.push(...state.closureTimestampFixes),planned.push(...planCloseReasonBackfillFixes(state.closeReasonBackfillRows)),planned.push(...planResolutionBackfillFixes(state.resolutionBackfillRows)),planned.push(...planEstimateBackfillFixes(state.estimateBackfillRows,settings.validation.estimate_defaults_by_type)),planned.push(...planTerminalParentFixes(state.terminalParentFixRows))),options.pruneMissing===!0&&planned.push(...planStaleLinkPruneFixes(state.staleLinkPruneRows)),planned}async function buildValidateFixesSummary(options,state,settings,grantedFixScopes,global2,services){if(options.autoFix!==!0&&options.pruneMissing!==!0)return;const planned=planValidateFixes(options,state,settings),{applicable,gated}=partitionFixesByGrant(planned,grantedFixScopes),dryRun=options.dryRun===!0,appliedFixRows=[],failedFixRows=[];if(!dryRun){const applied=await applyValidateFixes(applicable,global2,services);appliedFixRows.push(...applied.applied.map(toFixOutputRow)),failedFixRows.push(...applied.failed.map(({fix,error})=>({...toFixOutputRow(fix),error:error instanceof Error?error.message:String(error)})))}return{mode:dryRun?"dry_run":"apply",auto_fix:options.autoFix===!0,prune_missing:options.pruneMissing===!0,granted_fix_scopes:[...grantedFixScopes].sort((left,right)=>left.localeCompare(right)),planned_count:planned.length,applied_count:appliedFixRows.length,gated_count:gated.length,failed_count:failedFixRows.length,planned_fixes:planned.map(toFixOutputRow),applied_fixes:appliedFixRows,gated_fixes:gated.map(fix=>({...toFixOutputRow(fix),gate_hint:`Withheld: re-run with --fix-scope ${fix.gate} to apply.`})),failed_fixes:failedFixRows}}async function runValidate(options,global2,services={}){assertProjectionModeChoice(options.counts===!0,options.full===!0,"--counts");const fixesRequested=options.autoFix===!0||options.pruneMissing===!0;if(options.dryRun===!0&&!fixesRequested)throw new PmCliError("--dry-run requires --auto-fix or --prune-missing (there is nothing to preview otherwise).",EXIT_CODE.USAGE);if(options.fixScope!==void 0&&options.fixScope.length>0&&options.autoFix!==!0)throw new PmCliError("--fix-scope requires --auto-fix.",EXIT_CODE.USAGE);const grantedFixScopes=resolveGrantedFixScopes(options.fixScope),pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),requestedChecks=resolveRequestedChecks(options),itemReadWarnings=[],items=await readValidateItems({includeBody:["history_drift","metadata","completeness"].some(check=>requestedChecks.has(check)),pmRoot,settings,typeToFolder:typeRegistry.type_to_folder,warnings:itemReadWarnings}),sourceIncomplete=itemReadWarnings.length>0;if(requestedChecks.has("history_drift")){const authorAttribution=await scanHistoryAuthorAttribution(pmRoot);authorAttribution.actionable_unknown_event_count>0&&itemReadWarnings.push(`validate_history_unknown_author_events:${authorAttribution.actionable_unknown_event_count}`)}const metadataProfileSource=typeof options.metadataProfile=="string"?"option":"settings",metadataProfile=resolveValidateMetadataProfile(typeof options.metadataProfile=="string"?options.metadataProfile:settings.validation.metadata_profile),metadataPolicy=resolveValidateMetadataPolicy(metadataProfile,metadataProfileSource,settings.validation.metadata_required_fields),lifecyclePatternPolicy=resolveLifecyclePatternPolicy(settings),dependencyCycleSeverity=resolveDependencyCycleSeverity(options.dependencyCycleSeverity),parentCycleSeverity=resolveParentCycleSeverity(options.parentCycleSeverity),fileScanMode=resolveFileScanMode(options.scanMode),workspaceRoot=resolveWorkspaceRoot(pmRoot),state=await executeRequestedValidateChecks({requestedChecks,options,global:global2,pmRoot,workspaceRoot,settings,items,statusRegistry,metadataPolicy,lifecyclePatternPolicy,dependencyCycleSeverity,parentCycleSeverity,fileScanMode,initialWarnings:[...new Set(itemReadWarnings)],sourceIncomplete}),fixes=fixesRequested?await buildValidateFixesSummary(options,state,settings,grantedFixScopes,global2,services):void 0,normalizedWarnings=[...new Set(state.warnings)].sort((left,right)=>left.localeCompare(right)),result={ok:!state.checks.some(check=>check.status==="error"),has_warnings:normalizedWarnings.length>0,checks:state.checks,warnings:normalizedWarnings,...fixes!==void 0?{fixes}:{},generated_at:nowIso(),projection:{mode:"full",declared_field_groups:[{name:"diagnostic_rows",restore_with:"--full"}],included_field_groups:["diagnostic_rows"]}};return options.counts!==!0?result:{...projectValidateCounts(result),projection:{mode:"counts",declared_field_groups:[{name:"diagnostic_rows",restore_with:"--full"}],included_field_groups:[]}}}export{_testOnlyValidateCommand,projectValidateCounts,runValidate};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3ff209da-9855-53ee-8ae4-8c6ec7d5f964")}catch{}})();import{throwFirstItemRevisionConflict}from"../lifecycle/item-revision.js";import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{applyClosureTimestampFix,scanClosureTimestamps}from"./closure-timestamps.js";import{readWorkflowCompletenessCheck}from"./workflow-completeness.js";import fs from"node:fs/promises";import{realpathSync}from"node:fs";import{execFile}from"node:child_process";import path from"node:path";import{promisify}from"node:util";import{buildRemediationCommands}from"../../core/diagnostics/remediation.js";import{getActiveExtensionRegistrations}from"../../core/extensions/index.js";import{collectRegisteredItemFieldNames}from"../../core/extensions/item-fields.js";import{isFileMissingError}from"../../core/fs/fs-utils.js";import{normalizeStatusInput}from"../../core/item/status.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{resolveRuntimeStatusRegistry}from"../../core/schema/runtime-schema.js";import{DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS,DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS,EXIT_CODE,PM_DIRNAME,SETTINGS_DEFAULTS}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{toNonEmptyStringOrUndefined}from"../../core/shared/primitives.js";import{nowIso}from"../../core/shared/time.js";import{CURRENT_ITEM_FORMAT_VERSION,BASELINE_ITEM_FORMAT_VERSION,effectiveItemFormatVersion,scanItemFormatVersions}from"../../core/item/item-format-version.js";import{resolvePmRoot}from"../../core/store/paths.js";import{readSettings}from"../../core/store/settings.js";import{partitionFixesByGrant,planCloseReasonBackfillFixes,planEstimateBackfillFixes,planResolutionBackfillFixes,planStaleLinkPruneFixes,planTerminalParentFixes,resolveGrantedFixScopes,toFixOutputRow}from"../../core/validate/fix-planning.js";import{findDuplicateIssueCodes}from"../../core/governance/issue-codes.js";import{buildMissingByTypeCounts}from"../../core/validate/missing-by-type.js";import{classifyStaleLinkedPaths,summarizeStaleLinkedPathClassifications}from"../../core/validate/stale-file-classification.js";import{isRemoteLinkedArtifactReference}from"../../core/validate/linked-artifact-reference.js";import{assertProjectionModeChoice}from"../output-projection.js";import{collectDanglingDependencyReferences}from"../graph/assembly.js";import{auditMergeAttributeFence,auditMergeDriverConfiguration,findGitWorkspaceRoot,resolveProjectMergeTypeFolders}from"../merge/install.js";import{inspectMergeReceiptEvidence,partitionMergeReceipts}from"../merge/receipts.js";import{buildLinkedFileRepairReport}from"./linked-file-report.js";import{scanStorageIntegrity}from"./storage-integrity.js";import{scanTrackedRuntimeCache}from"./tracked-runtime-cache.js";import{scanHistoryAuthorAttribution}from"../author-attribution.js";import{createRelationshipKindRegistry}from"../relationships.js";import{runDocs}from"../docs.js";import{runFiles}from"../files.js";import{extractReferencedPmItemIdsFromCommand}from"../test/linked-command-detection.js";import{resolveLinkedTestSourceRef,resolveLinkedTestSourceWorkspaceRoot,resolveLinkedTestTrustBatch}from"../test/trust.js";import{readValidateItems}from"./validate-item-reader.js";import{buildValidateHistoryDriftCheck}from"./validate-history-drift.js";import{buildLifecycleParentGraph,detectLifecycleParentCycles,resolveLifecycleDependencyCycleSamplePath}from"./hierarchy-validation.js";import{buildStatusRoleWarnings,inspectStatusRoleAssignments}from"./status-role-diagnostics.js";import{summarizeCommandPreview,normalizeRelativeDirectoryPath,normalizeRelativePath,toMeaningfulString}from"./validate-normalization.js";const FILE_SCAN_DIRECTORIES=["src","tests","docs"],FILE_SCAN_ROOT_FILES=["README.md","PRD.md","CHANGELOG.md","AGENTS.md","CONTRIBUTING.md","SECURITY.md","CODE_OF_CONDUCT.md","LICENSE"],DIRECTORY_IGNORE_SET=new Set(["node_modules",".git",".cursor",".agents","dist","coverage"]),RESOLUTION_FIELD_KEYS=["resolution","expected_result","actual_result"],VALIDATE_FILE_SCAN_MODES=["default","tracked-all","tracked-all-strict"],VALIDATE_METADATA_PROFILE_VALUES=["core","strict","custom"],VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES=["off","warn","error"],CORE_METADATA_REQUIRED_FIELDS=["author","acceptance_criteria","estimated_minutes","close_reason"],STRICT_METADATA_REQUIRED_FIELDS=[...CORE_METADATA_REQUIRED_FIELDS,"reviewer","risk","confidence","sprint","release"],SUPPORTED_METADATA_REQUIRED_FIELDS=Array.from(new Set(STRICT_METADATA_REQUIRED_FIELDS)),METADATA_REQUIRED_FIELD_ALIASES={author:"author",acceptance_criteria:"acceptance_criteria","acceptance-criteria":"acceptance_criteria",estimated_minutes:"estimated_minutes","estimated-minutes":"estimated_minutes",estimate:"estimated_minutes",close_reason:"close_reason","close-reason":"close_reason",reviewer:"reviewer",risk:"risk",confidence:"confidence",sprint:"sprint",release:"release"},METADATA_WARNING_TOKEN_BY_FIELD={author:"validate_metadata_missing_author",acceptance_criteria:"validate_metadata_missing_acceptance_criteria",estimated_minutes:"validate_metadata_missing_estimate",close_reason:"validate_metadata_missing_close_reason",reviewer:"validate_metadata_missing_reviewer",risk:"validate_metadata_missing_risk",confidence:"validate_metadata_missing_confidence",sprint:"validate_metadata_missing_sprint",release:"validate_metadata_missing_release"},METADATA_COUNT_KEY_BY_FIELD={author:"missing_author",acceptance_criteria:"missing_acceptance_criteria",estimated_minutes:"missing_estimated_minutes",close_reason:"closed_missing_close_reason",reviewer:"missing_reviewer",risk:"missing_risk",confidence:"missing_confidence",sprint:"missing_sprint",release:"missing_release"},METADATA_ITEM_IDS_KEY_BY_FIELD={author:"missing_author_item_ids",acceptance_criteria:"missing_acceptance_criteria_item_ids",estimated_minutes:"missing_estimated_minutes_item_ids",close_reason:"closed_missing_close_reason_item_ids",reviewer:"missing_reviewer_item_ids",risk:"missing_risk_item_ids",confidence:"missing_confidence_item_ids",sprint:"missing_sprint_item_ids",release:"missing_release_item_ids"},METADATA_TRUNCATED_KEY_BY_FIELD={author:"missing_author_truncated",acceptance_criteria:"missing_acceptance_criteria_truncated",estimated_minutes:"missing_estimated_minutes_truncated",close_reason:"closed_missing_close_reason_truncated",reviewer:"missing_reviewer_truncated",risk:"missing_risk_truncated",confidence:"missing_confidence_truncated",sprint:"missing_sprint_truncated",release:"missing_release_truncated"},GIT_LS_FILES_MAX_BUFFER=32*1024*1024,GIT_LS_FILES_TIMEOUT_MS=1e4,FILE_LIST_SUMMARY_LIMIT=40,DIAGNOSTIC_LIST_SUMMARY_LIMIT=5,LINKED_ARTIFACT_MAX_PATH_LENGTH=4096,LINKED_ARTIFACT_MAX_SEGMENT_LENGTH=255,execFileAsync=promisify(execFile);function projectValidateCountsRecord(record){const projected={};for(const[key,value]of Object.entries(record))Array.isArray(value)||value===!1&&key.endsWith("_truncated")||(projected[key]=typeof value=="object"&&value!==null?projectValidateCountsRecord(value):value);return projected}function projectValidateCounts(result){return{...result,checks:result.checks.map(check=>({...check,details:projectValidateCountsRecord(check.details)})),...result.fixes?{fixes:{mode:result.fixes.mode,auto_fix:result.fixes.auto_fix,prune_missing:result.fixes.prune_missing,planned_count:result.fixes.planned_count,applied_count:result.fixes.applied_count,gated_count:result.fixes.gated_count,failed_count:result.fixes.failed_count}}:{}}}function normalizeStatusForRegistry(status,statusRegistry){return normalizeStatusInput(status,statusRegistry)??status}function isTerminalStatus(status,statusRegistry){return statusRegistry.terminal_statuses.has(normalizeStatusForRegistry(status,statusRegistry))}function normalizeLifecyclePatternList(values){return[...new Set((values??[]).map(value=>value.trim().toLowerCase()).filter(value=>value.length>0))].sort((left,right)=>left.localeCompare(right))}function areSortedStringListsEqual(left,right){return left.length!==right.length?!1:left.every((value,index)=>value===right[index])}function resolveLifecyclePatternPolicy(settings){const defaultStalePatterns=normalizeLifecyclePatternList(DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS),defaultClosureLikePatterns={blocked_reason:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.blocked_reason),resolution:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.resolution),actual_result:normalizeLifecyclePatternList(DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS.actual_result)},staleBlockerReasonPatterns=normalizeLifecyclePatternList(settings.validation.lifecycle_stale_blocker_reason_patterns),closureLikePatterns={blocked_reason:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_blocked_reason_patterns),resolution:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_resolution_patterns),actual_result:normalizeLifecyclePatternList(settings.validation.lifecycle_closure_like_actual_result_patterns)};return{stale_blocker_reason_patterns:staleBlockerReasonPatterns,stale_blocker_reason_pattern_source:areSortedStringListsEqual(staleBlockerReasonPatterns,defaultStalePatterns)?"default":"settings",closure_like_metadata_field_patterns:closureLikePatterns,closure_like_metadata_field_pattern_sources:{blocked_reason:areSortedStringListsEqual(closureLikePatterns.blocked_reason,defaultClosureLikePatterns.blocked_reason)?"default":"settings",resolution:areSortedStringListsEqual(closureLikePatterns.resolution,defaultClosureLikePatterns.resolution)?"default":"settings",actual_result:areSortedStringListsEqual(closureLikePatterns.actual_result,defaultClosureLikePatterns.actual_result)?"default":"settings"}}}function resolveValidateMetadataProfile(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"core";if(VALIDATE_METADATA_PROFILE_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --metadata-profile value "${value}". Supported values: ${VALIDATE_METADATA_PROFILE_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveDependencyCycleSeverity(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"warn";if(VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --dependency-cycle-severity value "${value}". Supported values: ${VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveParentCycleSeverity(value){const normalized=value?.trim().toLowerCase();if(!normalized||normalized.length===0)return"warn";if(VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown --parent-cycle-severity value "${value}". Supported values: ${VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function normalizeMetadataRequiredFieldsFromSettings(values){return[...new Set((values??[]).map(value=>value.trim().toLowerCase().replaceAll("-","_")))].map(value=>METADATA_REQUIRED_FIELD_ALIASES[value]).filter(value=>value!==void 0).sort((left,right)=>left.localeCompare(right))}function resolveValidateMetadataPolicy(profile,profileSource,configuredCustomFields){const normalizedCustomFields=normalizeMetadataRequiredFieldsFromSettings(configuredCustomFields);return profile==="core"?{profile,profile_source:profileSource,required_fields:[...CORE_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:profile==="strict"?{profile,profile_source:profileSource,required_fields:[...STRICT_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:normalizedCustomFields.length>0?{profile,profile_source:profileSource,required_fields:normalizedCustomFields,configured_custom_fields:normalizedCustomFields,fallback_to_core:!1,warnings:[]}:{profile,profile_source:profileSource,required_fields:[...CORE_METADATA_REQUIRED_FIELDS],configured_custom_fields:normalizedCustomFields,fallback_to_core:!0,warnings:["validate_metadata_custom_profile_missing_required_fields:0"]}}const TERMINAL_EXEMPT_PLANNING_FIELDS=new Set(["acceptance_criteria","estimated_minutes"]);function isMetadataFieldMissing(item,field,statusRegistry,enforcePlanningFieldsOnTerminal){return!enforcePlanningFieldsOnTerminal&&TERMINAL_EXEMPT_PLANNING_FIELDS.has(field)&&isTerminalStatus(item.status,statusRegistry)?!1:field==="author"?!toNonEmptyStringOrUndefined(item.author):field==="acceptance_criteria"?!toNonEmptyStringOrUndefined(item.acceptance_criteria):field==="estimated_minutes"?!Number.isFinite(item.estimated_minutes):field==="close_reason"?normalizeStatusForRegistry(item.status,statusRegistry)===statusRegistry.close_status&&!toNonEmptyStringOrUndefined(item.close_reason):field==="reviewer"?!toNonEmptyStringOrUndefined(item.reviewer):field==="risk"?!toNonEmptyStringOrUndefined(item.risk):field==="confidence"?typeof item.confidence=="number"?!Number.isFinite(item.confidence):!toNonEmptyStringOrUndefined(item.confidence):field==="sprint"?!toNonEmptyStringOrUndefined(item.sprint):!toNonEmptyStringOrUndefined(item.release)}function resolveFileScanMode(scanMode){if(scanMode===void 0)return"default";const normalized=scanMode.trim().toLowerCase();if(normalized.length===0||normalized==="default")return"default";if(normalized==="tracked-all"||normalized==="tracked_all")return"tracked-all";if(normalized==="tracked-all-strict"||normalized==="tracked_all_strict")return"tracked-all-strict";throw new PmCliError(`Unknown --scan-mode value "${scanMode}". Supported values: ${VALIDATE_FILE_SCAN_MODES.join(", ")}.`,EXIT_CODE.USAGE)}function resolveWorkspaceRoot(pmRoot){const sourceWorkspaceRoot=process.env.PM_SOURCE_WORKSPACE_ROOT?.trim();if(sourceWorkspaceRoot)return path.resolve(sourceWorkspaceRoot);const resolvedPmRoot=path.resolve(pmRoot);if(resolvedPmRoot.replaceAll("\\","/").endsWith("/.agents/pm"))return path.dirname(path.dirname(resolvedPmRoot));const resolvedCwd=path.resolve(process.cwd()),canonicalPmRoot=realpathForWorkspaceRoot(resolvedPmRoot),canonicalCwd=realpathForWorkspaceRoot(resolvedCwd),relativeFromPmRoot=path.relative(canonicalPmRoot,canonicalCwd);return relativeFromPmRoot.length===0||!relativeFromPmRoot.startsWith("..")&&!path.isAbsolute(relativeFromPmRoot)?resolvedPmRoot:resolvedCwd}function realpathForWorkspaceRoot(inputPath){try{return realpathSync.native(inputPath)}catch{return path.resolve(inputPath)}}function hasFilesystemErrorCode(error,acceptedCodes){return typeof error=="object"&&error!==null&&"code"in error&&typeof error.code=="string"&&acceptedCodes.includes(error.code)}async function listFilesRecursive(basePath,relativePath,output){const targetDirectory=relativePath.length>0?path.join(basePath,relativePath):basePath;let entries;try{entries=await fs.readdir(targetDirectory,{withFileTypes:!0})}catch(error){if(isFileMissingError(error))return;throw error}for(const entry of entries){if(entry.name.startsWith("."))continue;const childRelative=relativePath.length>0?path.join(relativePath,entry.name):entry.name;if(entry.isDirectory()){if(DIRECTORY_IGNORE_SET.has(entry.name))continue;await listFilesRecursive(basePath,childRelative,output);continue}entry.isFile()&&output.push(normalizeRelativePath(childRelative))}}async function collectDefaultProjectFileCandidates(workspaceRoot){const discovered=[];for(const directory of FILE_SCAN_DIRECTORIES)await listFilesRecursive(workspaceRoot,directory,discovered);for(const candidate of FILE_SCAN_ROOT_FILES){const absolute=path.join(workspaceRoot,candidate);try{(await fs.stat(absolute)).isFile()&&discovered.push(normalizeRelativePath(candidate))}catch{}}return[...new Set(discovered)].sort((left,right)=>left.localeCompare(right))}async function collectTrackedGitFileCandidates(workspaceRoot){try{const{stdout}=await execFileAsync("git",["ls-files","-z"],{cwd:workspaceRoot,encoding:"utf8",maxBuffer:GIT_LS_FILES_MAX_BUFFER,windowsHide:!0,timeout:GIT_LS_FILES_TIMEOUT_MS}),discovered=stdout.split("\0").map(value=>normalizeRelativePath(value)).filter(value=>value.length>0);return[...new Set(discovered)].sort((left,right)=>left.localeCompare(right))}catch{return null}}function resolvePmInternalCandidatePrefixes(pmRoot,workspaceRoot){const prefixes=new Set,configuredDefault=normalizeRelativeDirectoryPath(PM_DIRNAME);configuredDefault.length>0&&prefixes.add(configuredDefault);const relativePmRoot=normalizeRelativeDirectoryPath(path.relative(workspaceRoot,pmRoot));return relativePmRoot.length>0&&!relativePmRoot.startsWith("..")&&prefixes.add(relativePmRoot),[...prefixes].sort((left,right)=>left.localeCompare(right))}function hasPathPrefix(candidate,prefixes){for(const prefix of prefixes)if(candidate===prefix||candidate.startsWith(`${prefix}/`))return!0;return!1}async function collectProjectFileCandidates(workspaceRoot,scanMode){if(scanMode==="tracked-all"||scanMode==="tracked-all-strict"){const trackedCandidates=await collectTrackedGitFileCandidates(workspaceRoot);if(trackedCandidates)return{requestedMode:scanMode,appliedMode:scanMode,source:"tracked-git",candidateFiles:trackedCandidates,candidateTotal:trackedCandidates.length,candidateScanned:trackedCandidates.length};const fallbackCandidates=await collectDefaultProjectFileCandidates(workspaceRoot);return{requestedMode:scanMode,appliedMode:"default",source:"tracked-all-fallback-default",candidateFiles:fallbackCandidates,candidateTotal:fallbackCandidates.length,candidateScanned:fallbackCandidates.length}}const defaultCandidates=await collectDefaultProjectFileCandidates(workspaceRoot);return{requestedMode:scanMode,appliedMode:"default",source:"default-curated",candidateFiles:defaultCandidates,candidateTotal:defaultCandidates.length,candidateScanned:defaultCandidates.length}}function summarizeList(values,limit=DIAGNOSTIC_LIST_SUMMARY_LIMIT){return values.length<=limit?{values,truncated:!1}:{values:values.slice(0,limit),truncated:!0}}function summarizeFileList(values,verboseFileLists){if(verboseFileLists)return{values,truncated:!1,total:values.length};const summary=summarizeList(values,FILE_LIST_SUMMARY_LIMIT);return{values:summary.values,truncated:summary.truncated,total:values.length}}const RESOLUTION_REMEDIATION_FLAG_BY_FIELD={resolution:"--resolution",expected_result:"--expected-result",actual_result:"--actual-result"},RESOLUTION_REMEDIATION_PLACEHOLDER_BY_FIELD={resolution:"Describe how this item was resolved",expected_result:"Describe the expected result",actual_result:"Describe the actual result"};function buildResolutionRemediationCommand(row){const fieldArguments=row.missing_fields.map(field=>`${RESOLUTION_REMEDIATION_FLAG_BY_FIELD[field]} "${RESOLUTION_REMEDIATION_PLACEHOLDER_BY_FIELD[field]}"`).join(" ");return`pm update ${row.id} ${fieldArguments} --message "Backfill resolution metadata"`}function attachValidateFixHints(check,checkWarnings){const existingResolutionHints=check.details?.missing_resolution_remediation_hints,aliasedResolution=Array.isArray(existingResolutionHints)&&existingResolutionHints.length>0,fixHints=aliasedResolution?existingResolutionHints.filter(hint=>typeof hint=="string"):buildRemediationCommands(checkWarnings);if(fixHints.length===0)return;const truncated=aliasedResolution&&check.details?.missing_resolution_remediation_hints_truncated===!0;check.details={...check.details,fix_hints:fixHints,...truncated?{fix_hints_truncated:!0}:{}}}function resolveRequestedChecks(options){const requested=new Set;return options.checkCompleteness&&requested.add("completeness"),options.checkMetadata&&requested.add("metadata"),options.checkResolution&&requested.add("resolution"),(options.checkLifecycle||options.checkStaleBlockers)&&requested.add("lifecycle"),options.checkFiles&&requested.add("files"),options.checkHistoryDrift&&requested.add("history_drift"),options.checkCommandReferences&&requested.add("command_references"),options.checkStorageIntegrity&&requested.add("storage_integrity"),requested.size===0?(options.autoFix&&(requested.add("metadata"),requested.add("resolution"),requested.add("lifecycle")),options.pruneMissing&&requested.add("files"),requested.size===0&&(requested.add("metadata"),requested.add("resolution"),requested.add("lifecycle"),requested.add("files"),requested.add("command_references"),requested.add("history_drift"),requested.add("format_version"),requested.add("completeness"),requested.add("storage_integrity")),requested):(options.pruneMissing&&requested.add("files"),requested)}const DUPLICATE_ISSUE_CODE_WARNING_TOKEN="validate_metadata_duplicate_issue_codes";function summarizeDuplicateIssueCodes(duplicates,verboseDiagnostics){if(duplicates.length===0)return{rows:[],truncated:!1,warnings:[]};const limit=verboseDiagnostics?duplicates.length:DIAGNOSTIC_LIST_SUMMARY_LIMIT,shown=duplicates.slice(0,limit);return{rows:shown.map(duplicate=>({code:duplicate.code,count:duplicate.count,ids:duplicate.ids,titles:duplicate.titles,remediation_hint:`Items ${duplicate.ids.join(", ")} share issue code "${duplicate.code}"; rename or merge so each logical code maps to one item.`})),truncated:shown.length<duplicates.length,warnings:[`${DUPLICATE_ISSUE_CODE_WARNING_TOKEN}:${duplicates.length}`]}}function collectMissingMetadataByField(items,statusRegistry,enforcePlanningFieldsOnTerminal){const missingByField=Object.fromEntries(SUPPORTED_METADATA_REQUIRED_FIELDS.map(field=>[field,[]]));for(const item of items)for(const field of SUPPORTED_METADATA_REQUIRED_FIELDS)isMetadataFieldMissing(item,field,statusRegistry,enforcePlanningFieldsOnTerminal)&&missingByField[field].push(item.id);return missingByField}function buildMetadataWarningTokens(metadataPolicy,missingByField,duplicateWarnings){const warningTokens=[...metadataPolicy.warnings];for(const field of metadataPolicy.required_fields){const missingItems=missingByField[field];missingItems.length>0&&warningTokens.push(`${METADATA_WARNING_TOKEN_BY_FIELD[field]}:${missingItems.length}`)}return warningTokens.push(...duplicateWarnings),warningTokens}function buildMetadataCounts(metadataPolicy,missingByField){const counts={};for(const field of metadataPolicy.required_fields){const missing=missingByField[field],value=missing?missing.length:0,countKey=METADATA_COUNT_KEY_BY_FIELD[field];counts[countKey]=value}return counts}function buildMissingFieldOccurrences(metadataPolicy,missingByField,itemsById){const occurrences=[];for(const field of metadataPolicy.required_fields){const missing=missingByField[field];if(missing)for(const itemId of missing){const itemType=itemsById.get(itemId)?.type,normalizedItemType=typeof itemType=="string"&&itemType.length>0?itemType:"Unknown";occurrences.push({item_type:normalizedItemType,field})}}return occurrences}function attachMissingMetadataItemIds(details,metadataPolicy,missingByField,verboseDiagnostics){for(const field of metadataPolicy.required_fields){const missing=missingByField[field];if(!missing||missing.length===0)continue;const idsKey=METADATA_ITEM_IDS_KEY_BY_FIELD[field],truncatedKey=METADATA_TRUNCATED_KEY_BY_FIELD[field];if(!idsKey||!truncatedKey)continue;const summarized=summarizeList(missing,verboseDiagnostics?missing.length:DIAGNOSTIC_LIST_SUMMARY_LIMIT);details[idsKey]=summarized.values,details[truncatedKey]=summarized.truncated}}function buildCloseReasonBackfillRows(metadataPolicy,missingByField,itemsById){if(!metadataPolicy.required_fields.includes("close_reason"))return[];const missing=missingByField.close_reason;return missing?missing.map(itemId=>({id:itemId,resolution:toNonEmptyStringOrUndefined(itemsById.get(itemId)?.resolution)})):[]}function buildEstimateBackfillRows(metadataPolicy,missingByField,itemsById){if(!metadataPolicy.required_fields.includes("estimated_minutes"))return[];const missing=missingByField.estimated_minutes;return missing?missing.map(itemId=>({id:itemId,type:toNonEmptyStringOrUndefined(itemsById.get(itemId)?.type)})):[]}function buildMetadataCheck(items,metadataPolicy,statusRegistry,verboseDiagnostics,configuredIssueCodePrefixes){const itemsById=new Map(items.map(item=>[item.id,item])),enforcePlanningFieldsOnTerminal=metadataPolicy.profile==="strict",missingByField=collectMissingMetadataByField(items,statusRegistry,enforcePlanningFieldsOnTerminal),duplicateIssueCodes=findDuplicateIssueCodes(items,{configuredPrefixes:configuredIssueCodePrefixes}),duplicateIssueCodeSummary=summarizeDuplicateIssueCodes(duplicateIssueCodes,verboseDiagnostics),warningTokens=buildMetadataWarningTokens(metadataPolicy,missingByField,duplicateIssueCodeSummary.warnings),counts=buildMetadataCounts(metadataPolicy,missingByField),missingFieldOccurrences=buildMissingFieldOccurrences(metadataPolicy,missingByField,itemsById),missingByType=buildMissingByTypeCounts(missingFieldOccurrences),details={checked_items:items.length,metadata_profile:metadataPolicy.profile,metadata_profile_source:metadataPolicy.profile_source,metadata_profile_fallback_to_core:metadataPolicy.fallback_to_core,required_fields:[...metadataPolicy.required_fields],supported_required_fields:[...SUPPORTED_METADATA_REQUIRED_FIELDS],counts,missing_by_type:missingByType,duplicate_issue_codes_count:duplicateIssueCodes.length,duplicate_issue_codes:duplicateIssueCodeSummary.rows,duplicate_issue_codes_truncated:duplicateIssueCodeSummary.truncated};metadataPolicy.configured_custom_fields.length>0&&(details.configured_custom_required_fields=[...metadataPolicy.configured_custom_fields]),attachMissingMetadataItemIds(details,metadataPolicy,missingByField,verboseDiagnostics);const closeReasonBackfillRows=buildCloseReasonBackfillRows(metadataPolicy,missingByField,itemsById),estimateBackfillRows=buildEstimateBackfillRows(metadataPolicy,missingByField,itemsById);return{check:{name:"metadata",status:warningTokens.length===0?"ok":"warn",ok:warningTokens.length===0,details},warnings:warningTokens,closeReasonBackfillRows,estimateBackfillRows}}function buildResolutionCheck(items,statusRegistry,verboseDiagnostics){const terminalDoneStatuses=new Set(statusRegistry.terminal_done_statuses);terminalDoneStatuses.add(statusRegistry.close_status);const closedItems=items.filter(item=>terminalDoneStatuses.has(normalizeStatusForRegistry(item.status,statusRegistry))),missingResolutionRows=[],resolutionBackfillRows=[];for(const item of closedItems){const missingFields=RESOLUTION_FIELD_KEYS.filter(field=>!toNonEmptyStringOrUndefined(item[field]));missingFields.length!==0&&(missingResolutionRows.push({id:item.id,missing_fields:missingFields}),resolutionBackfillRows.push({id:item.id,missing_fields:missingFields,close_reason:toNonEmptyStringOrUndefined(item.close_reason)}))}const warnings=missingResolutionRows.length>0?[`validate_resolution_missing_fields:${missingResolutionRows.length}`]:[],diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(missingResolutionRows.map(row=>`${row.id}:${row.missing_fields.join(",")}`),diagnosticLimit),remediationHints=missingResolutionRows.map(row=>buildResolutionRemediationCommand(row)),summarizedHints=summarizeList(remediationHints,diagnosticLimit);return{check:{name:"resolution",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{checked_closed_items:closedItems.length,missing_resolution_items:missingResolutionRows.length,missing_resolution_rows:summarizedRows.values,missing_resolution_rows_truncated:summarizedRows.truncated,missing_resolution_remediation_hints:summarizedHints.values,missing_resolution_remediation_hints_truncated:summarizedHints.truncated}},warnings,resolutionBackfillRows}}function escapeRegExp(value){return value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function buildLifecycleDependencyGraph(activeItems,idPrefix="pm",relationshipRegistry=createRelationshipKindRegistry()){const activeItemIds=new Set(activeItems.map(item=>item.id)),sortedItems=[...activeItems].sort((left,right)=>left.id.localeCompare(right.id));return new Map(sortedItems.map(item=>{const edges=new Set,blockedBy=toMeaningfulString(item.blocked_by);blockedBy&&activeItemIds.has(blockedBy)&&edges.add(blockedBy),(item.dependencies??[]).filter(dependency=>{const dependencyKind=toMeaningfulString(dependency.kind);return dependencyKind!==void 0&&relationshipRegistry.resolve(dependencyKind)?.ordering===!0}).map(dependency=>toMeaningfulString(dependency.id)).filter(dependencyId=>dependencyId!==void 0&&activeItemIds.has(dependencyId)).forEach(dependencyId=>edges.add(dependencyId));const definitionOfReady=toMeaningfulString(item.definition_of_ready);return extractItemIds(definitionOfReady??"",idPrefix).filter(referencedId=>activeItemIds.has(referencedId)).forEach(referencedId=>edges.add(referencedId)),[item.id,[...edges].sort((left,right)=>left.localeCompare(right))]}))}function buildDependencyReferencesCheck(items,verboseDiagnostics,statusRegistry){const classified=collectDanglingDependencyReferences(items,statusRegistry?status=>isTerminalStatus(status,statusRegistry):void 0),activeRows=classified.active.map(row=>`${row.holder_id}:${row.target_id}:${row.kind}`),legacyRows=classified.legacy_terminal.map(row=>`${row.holder_id}:${row.target_id}:${row.kind}:${row.holder_status}`),diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(activeRows,diagnosticLimit),summarizedLegacyRows=summarizeList(legacyRows,diagnosticLimit),hints=summarizeList(classified.active.map(row=>row.source==="parent"?`pm update ${row.holder_id} --unset parent`:row.source==="blocked_by"?`pm update ${row.holder_id} --unset blocked_by`:`pm update ${row.holder_id} --replace-deps '<correct dependency edges>'`),diagnosticLimit);return{check:{name:"dependency_references",status:activeRows.length===0?"ok":"warn",ok:activeRows.length===0,details:{checked_items:items.length,dangling_reference_count:activeRows.length+legacyRows.length,active_dangling_reference_count:activeRows.length,dangling_reference_rows:summarizedRows.values,dangling_reference_rows_truncated:summarizedRows.truncated,legacy_terminal_dangling_reference_count:legacyRows.length,legacy_closed_dangling_reference_count:classified.legacy_terminal.filter(row=>row.holder_status==="closed").length,legacy_terminal_dangling_reference_rows:summarizedLegacyRows.values,legacy_terminal_dangling_reference_rows_truncated:summarizedLegacyRows.truncated,no_active_blocker_sentinel_count:classified.no_active_blocker_sentinels.length,remediation_hints:hints.values,remediation_hints_truncated:hints.truncated}},warnings:activeRows.length>0?[`validate_dangling_dependency_references:${activeRows.length}`]:[]}}function extractItemIds(value,idPrefix="pm"){const normalizedPrefix=(idPrefix.trim().toLowerCase()||"pm").replace(/-+$/g,""),pattern=new RegExp(`(?:^|[^a-z0-9-])(${escapeRegExp(normalizedPrefix)}-[a-z0-9][a-z0-9-]*)`,"gi");return[...new Set([...value.matchAll(pattern)].map(match=>match[1].toLowerCase()))].sort((left,right)=>left.localeCompare(right))}function findLifecycleDependencyCycleComponents(graph){let nextIndex=0;const indexById=new Map,lowLinkById=new Map,stack=[],inStack=new Set,components=[],visit=id=>{indexById.set(id,nextIndex),lowLinkById.set(id,nextIndex),nextIndex+=1,stack.push(id),inStack.add(id);for(const dependencyId of graph.get(id)??[])indexById.has(dependencyId)?inStack.has(dependencyId)&&lowLinkById.set(id,Math.min(lowLinkById.get(id),indexById.get(dependencyId))):(visit(dependencyId),lowLinkById.set(id,Math.min(lowLinkById.get(id),lowLinkById.get(dependencyId))));if(lowLinkById.get(id)!==indexById.get(id))return;const component=[];for(;stack.length>0;){const member=stack.pop();if(inStack.delete(member),component.push(member),member===id)break}component.sort((left,right)=>left.localeCompare(right)),components.push(component)},sortedNodeIds=[...graph.keys()].sort((left,right)=>left.localeCompare(right));for(const id of sortedNodeIds)indexById.has(id)||visit(id);return components.filter(component=>{if(component.length>1)return!0;const selfId=component[0];return(graph.get(selfId)??[]).includes(selfId)}).sort((left,right)=>left[0].localeCompare(right[0])||left.length-right.length||left.join(",").localeCompare(right.join(",")))}function detectLifecycleDependencyCycles(activeItems,idPrefix="pm"){const graph=buildLifecycleDependencyGraph(activeItems,idPrefix),cycleComponents=findLifecycleDependencyCycleComponents(graph),cycleItemIds=[...new Set(cycleComponents.flat())].sort((left,right)=>left.localeCompare(right)),cycleSamplePaths=cycleComponents.map(component=>resolveLifecycleDependencyCycleSamplePath(component,graph).join("->"));return{cycle_count:cycleComponents.length,cycle_item_ids:cycleItemIds,cycle_sample_paths:cycleSamplePaths}}function classifyOrphanedPath(pathValue){return pathValue.startsWith("docs/")?"docs_unowned":pathValue.startsWith("tests/")?"tests_unowned":pathValue.startsWith("src/")?"source_unowned":pathValue.endsWith(".md")?"docs_unowned":"unlinked_existing"}function directoryOf(relativePath){const slash=relativePath.lastIndexOf("/");return slash===-1?"":relativePath.slice(0,slash)}function sharedDirectoryPrefixLength(left,right){const leftParts=directoryOf(left).split("/").filter(Boolean),rightParts=directoryOf(right).split("/").filter(Boolean);let count=0;for(;count<leftParts.length&&count<rightParts.length&&leftParts[count]===rightParts[count];)count+=1;return count}function scoreOrphanOwnerCandidate(pathValue,linkedPath){const linkedDir=directoryOf(linkedPath),orphanDir=directoryOf(pathValue),directoryPrefix=linkedPath.endsWith("/")?linkedPath:`${linkedPath}/`,isDirectoryPrefix=pathValue.startsWith(directoryPrefix),sameDirectory=linkedDir.length>0&&linkedDir===orphanDir,sharedPrefixLength=sharedDirectoryPrefixLength(pathValue,linkedPath);return!isDirectoryPrefix&&!sameDirectory&&sharedPrefixLength===0?null:isDirectoryPrefix?{score:linkedPath.length+1e3,confidence:"path_prefix"}:sameDirectory?{score:sharedPrefixLength+500,confidence:"same_directory"}:{score:sharedPrefixLength,confidence:"shared_directory"}}function shouldReplaceOrphanOwnerCandidate(best,item,score){return best===void 0||score>best.score||score===best.score&&item.id.localeCompare(best.item.id)<0}function findOrphanOwnerCandidate(pathValue,classification,items){const linkKind=classification==="docs_unowned"?"docs":"files";let best;return items.flatMap(item=>(linkKind==="docs"?item.docs??[]:item.files??[]).map(link=>({item,link}))).forEach(({item,link})=>{if(link.scope!=="project")return;const linkedPath=normalizeRelativePath(link.path);if(linkedPath.length===0||linkedPath===pathValue)return;const scored=scoreOrphanOwnerCandidate(pathValue,linkedPath);scored!==null&&shouldReplaceOrphanOwnerCandidate(best,item,scored.score)&&(best={item,score:scored.score,confidence:scored.confidence})}),best?{id:best.item.id,type:best.item.type,title:best.item.title,status:best.item.status,confidence:best.confidence}:null}function buildOrphanedPathRows(orphanedFiles,items){return orphanedFiles.map(pathValue=>{const classification=classifyOrphanedPath(pathValue),linkCommand=classification==="docs_unowned"?"docs":"files",ownerCandidate=findOrphanOwnerCandidate(pathValue,classification,items),target=ownerCandidate?.id??"<id>";return{path:pathValue,classification,owner_candidate:ownerCandidate,remediation_hint:`pm ${linkCommand} ${target} --add path=${pathValue},scope=project,note="<why this artifact belongs to the item>"`}})}function summarizeOrphanedPathRows(rows){return rows.map(row=>`${row.path}:${row.classification} owner_candidate=${row.owner_candidate?.id??"unowned"} hint=${JSON.stringify(row.remediation_hint)}`)}function closureLikeFieldsForItem(item,lifecyclePatternPolicy){return Object.entries(lifecyclePatternPolicy.closure_like_metadata_field_patterns).filter(([field,patterns])=>{const value=toMeaningfulString(item[field]);return value?patterns.some(pattern=>value.toLowerCase().includes(pattern)):!1}).map(([field])=>field).sort((left,right)=>left.localeCompare(right))}function buildTerminalParentFixRow(item,parent,itemsById,canonicalIdByLowercase,statusRegistry){const grandparentId=toMeaningfulString(parent.parent),grandparent=grandparentId?itemsById.get(canonicalIdByLowercase.get(grandparentId.toLowerCase())??grandparentId):void 0;return{id:item.id,parent_id:parent.id,grandparent_id:grandparent?.id,grandparent_active:grandparent!==void 0&&!isTerminalStatus(grandparent.status,statusRegistry)}}function staleBlockerReasonsForItem(item,blockedStatuses,statusRegistry,lifecyclePatternPolicy){const blockedBy=toMeaningfulString(item.blocked_by),blockedReason=toMeaningfulString(item.blocked_reason),blockedReasonNormalized=blockedReason?.toLowerCase(),normalizedStatus=normalizeStatusForRegistry(item.status,statusRegistry),reasons=[];return blockedStatuses.has(normalizedStatus)?(!blockedBy&&!blockedReason&&reasons.push("blocked_status_missing_blocker_context"),blockedReasonNormalized?.includes("no active blocker")&&reasons.push("blocked_status_reason_reports_no_active_blocker"),blockedReasonNormalized&&lifecyclePatternPolicy.stale_blocker_reason_patterns.some(pattern=>blockedReasonNormalized.includes(pattern))&&reasons.push("blocked_status_reason_matches_stale_pattern"),reasons):(blockedBy&&reasons.push("non_blocked_status_has_blocked_by"),blockedReason&&reasons.push("non_blocked_status_has_blocked_reason"),reasons)}function collectLifecycleScanRows(items,includeStaleBlockers,statusRegistry,lifecyclePatternPolicy){const itemsById=new Map(items.map(item=>[item.id,item])),canonicalIdByLowercase=new Map(items.map(item=>[item.id.toLowerCase(),item.id])),blockedStatuses=statusRegistry.blocked_statuses.size>0?statusRegistry.blocked_statuses:new Set(["blocked"]),rows={activeItems:items.filter(item=>!isTerminalStatus(item.status,statusRegistry)),closureLikeRows:[],terminalParentRows:[],terminalParentFixRows:[],staleBlockerRows:[]};for(const item of rows.activeItems){const closureLikeFields=closureLikeFieldsForItem(item,lifecyclePatternPolicy);closureLikeFields.length>0&&rows.closureLikeRows.push({id:item.id,fields:closureLikeFields});const parentId=toMeaningfulString(item.parent),parent=parentId?itemsById.get(canonicalIdByLowercase.get(parentId.toLowerCase())??parentId):void 0;if(parent&&isTerminalStatus(parent.status,statusRegistry)&&(rows.terminalParentRows.push({id:item.id,parent_id:parent.id,parent_status:parent.status}),rows.terminalParentFixRows.push(buildTerminalParentFixRow(item,parent,itemsById,canonicalIdByLowercase,statusRegistry))),includeStaleBlockers){const reasons=staleBlockerReasonsForItem(item,blockedStatuses,statusRegistry,lifecyclePatternPolicy);reasons.length>0&&rows.staleBlockerRows.push({id:item.id,status:item.status,reasons:[...new Set(reasons)].sort((left,right)=>left.localeCompare(right))})}}return rows}function sortLifecycleScanRows(rows){rows.closureLikeRows.sort((left,right)=>left.id.localeCompare(right.id)),rows.terminalParentRows.sort((left,right)=>left.id.localeCompare(right.id)||left.parent_id.localeCompare(right.parent_id)),rows.terminalParentFixRows.sort((left,right)=>left.id.localeCompare(right.id)||left.parent_id.localeCompare(right.parent_id)),rows.staleBlockerRows.sort((left,right)=>left.id.localeCompare(right.id))}function lifecycleCycleWarningToken(prefix,severity,count){return count<=0||severity==="off"?null:`${severity==="error"?`${prefix}_error`:prefix}:${count}`}function lifecycleAdvisoryWarningToken(prefix,severity,count){return count>0&&severity!=="off"?`${prefix}:${count}`:null}function buildLifecycleWarnings(rows,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,counts){const warnings=[];rows.closureLikeRows.length>0&&warnings.push(`validate_lifecycle_active_closure_like_metadata:${rows.closureLikeRows.length}`),rows.terminalParentRows.length>0&&warnings.push(`validate_lifecycle_active_terminal_parent:${rows.terminalParentRows.length}`),includeStaleBlockers&&rows.staleBlockerRows.length>0&&warnings.push(`validate_lifecycle_stale_blockers:${rows.staleBlockerRows.length}`);const dependencyWarning=lifecycleCycleWarningToken("validate_lifecycle_dependency_cycles",dependencyCycleSeverity,counts.dependencyCycles),parentWarning=lifecycleCycleWarningToken("validate_hierarchy_parent_cycle",parentCycleSeverity,counts.activeHierarchyCycles),cardinalityWarning=lifecycleCycleWarningToken("validate_hierarchy_cardinality_violation",parentCycleSeverity,counts.activeHierarchyCardinality),divergenceWarning=lifecycleCycleWarningToken("validate_hierarchy_parent_divergence",parentCycleSeverity,counts.activeHierarchyDivergence),legacyCycleWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_parent_cycle",parentCycleSeverity,counts.legacyHierarchyCycles),legacyCardinalityWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_cardinality_violation",parentCycleSeverity,counts.legacyHierarchyCardinality),legacyDivergenceWarning=lifecycleAdvisoryWarningToken("validate_legacy_hierarchy_parent_divergence",parentCycleSeverity,counts.legacyHierarchyDivergence);return[...warnings,...dependencyWarning?[dependencyWarning]:[],...parentWarning?[parentWarning]:[],...cardinalityWarning?[cardinalityWarning]:[],...divergenceWarning?[divergenceWarning]:[],...legacyCycleWarning?[legacyCycleWarning]:[],...legacyCardinalityWarning?[legacyCardinalityWarning]:[],...legacyDivergenceWarning?[legacyDivergenceWarning]:[]]}function linkedArtifactPathExceedsFilesystemLimits(artifactPath){const normalized=normalizeRelativePath(artifactPath);return normalized.length>LINKED_ARTIFACT_MAX_PATH_LENGTH||normalized.split(/[\\/]/).some(segment=>segment.length>LINKED_ARTIFACT_MAX_SEGMENT_LENGTH)}async function linkedArtifactIsMissing(workspaceRoot,artifactPath){const absolutePath=path.isAbsolute(artifactPath)?artifactPath:path.resolve(workspaceRoot,artifactPath);if(linkedArtifactPathExceedsFilesystemLimits(absolutePath))return!1;try{const stats=await fs.stat(absolutePath);return!stats.isFile()&&!stats.isDirectory()}catch(error){return hasFilesystemErrorCode(error,["ENOENT","ENOTDIR"])}}async function collectLinkedPathScanState(items,workspaceRoot){const state={linkedProjectPaths:new Set,remoteLinkedPaths:new Set,missingLinkedPaths:[],staleLinkRows:[]},linkedArtifacts=items.flatMap(item=>[...(item.files??[]).map(artifact=>({item,artifact,link_kind:"files"})),...(item.docs??[]).map(artifact=>({item,artifact,link_kind:"docs"}))]);for(const{item,artifact,link_kind}of linkedArtifacts){if(artifact.scope!=="project")continue;if(isRemoteLinkedArtifactReference(artifact.path)){state.remoteLinkedPaths.add(artifact.path.trim());continue}const normalizedPath=normalizeRelativePath(artifact.path);normalizedPath.length!==0&&(state.linkedProjectPaths.add(normalizedPath),await linkedArtifactIsMissing(workspaceRoot,artifact.path)&&(state.missingLinkedPaths.push(normalizedPath),state.staleLinkRows.push({item_id:item.id,path:normalizedPath,link_kind})))}return state}function partitionFileCandidates(fileCandidates,pmRoot,workspaceRoot,fileScanMode,includePmInternals,verboseFileLists){const strictTrackedAllMode=fileScanMode==="tracked-all-strict",strictModeForcesPmInternals=strictTrackedAllMode&&!includePmInternals,includePmInternalsEffective=includePmInternals||strictTrackedAllMode,pmInternalCandidatePrefixes=includePmInternalsEffective?[]:resolvePmInternalCandidatePrefixes(pmRoot,workspaceRoot),excludedPmInternalPaths=pmInternalCandidatePrefixes.length===0?[]:fileCandidates.candidateFiles.filter(candidate=>hasPathPrefix(candidate,pmInternalCandidatePrefixes)),candidateFiles=pmInternalCandidatePrefixes.length===0?fileCandidates.candidateFiles:fileCandidates.candidateFiles.filter(candidate=>!hasPathPrefix(candidate,pmInternalCandidatePrefixes)),excludedByReason={};if(excludedPmInternalPaths.length>0){const summarizedPmInternalPaths=summarizeFileList(excludedPmInternalPaths,verboseFileLists);excludedByReason.pm_internals={count:excludedPmInternalPaths.length,paths:summarizedPmInternalPaths.values,paths_truncated:summarizedPmInternalPaths.truncated,paths_total:summarizedPmInternalPaths.total}}return{strictTrackedAllMode,strictModeForcesPmInternals,includePmInternalsEffective,pmInternalCandidatePrefixes,excludedPmInternalPaths,candidateFiles,excludedByReason}}function buildLifecycleCheck(items,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,statusRegistry,lifecyclePatternPolicy,verboseDiagnostics,idPrefix="pm"){const rows=collectLifecycleScanRows(items,includeStaleBlockers,statusRegistry,lifecyclePatternPolicy);sortLifecycleScanRows(rows);const dependencyCycleDiagnostics=detectLifecycleDependencyCycles(rows.activeItems,idPrefix),parentCycleDiagnostics=detectLifecycleParentCycles(items,statusRegistry),statusRoleDiagnostics=inspectStatusRoleAssignments(statusRegistry,items,verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT),warnings=[...buildLifecycleWarnings(rows,includeStaleBlockers,dependencyCycleSeverity,parentCycleSeverity,{dependencyCycles:dependencyCycleDiagnostics.cycle_count,activeHierarchyCycles:parentCycleDiagnostics.active_cycle_count,activeHierarchyCardinality:parentCycleDiagnostics.active_cardinality_violation_count,activeHierarchyDivergence:parentCycleDiagnostics.active_parent_divergence_count,legacyHierarchyCycles:parentCycleDiagnostics.legacy_cycle_count,legacyHierarchyCardinality:parentCycleDiagnostics.legacy_cardinality_violation_count,legacyHierarchyDivergence:parentCycleDiagnostics.legacy_parent_divergence_count}),...buildStatusRoleWarnings(statusRoleDiagnostics)],diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedClosureLikeRows=summarizeList(rows.closureLikeRows.map(row=>`${row.id}:${row.fields.join(",")}`),diagnosticLimit),summarizedTerminalParentRows=summarizeList(rows.terminalParentRows.map(row=>`${row.id}:${row.parent_id}:${row.parent_status}`),diagnosticLimit),summarizedStaleBlockerRows=summarizeList(rows.staleBlockerRows.map(row=>`${row.id}:${row.status}:${row.reasons.join(",")}`),diagnosticLimit),summarizedDependencyCycleItemIds=summarizeList(dependencyCycleDiagnostics.cycle_item_ids,diagnosticLimit),summarizedDependencyCycleSamplePaths=summarizeList(dependencyCycleDiagnostics.cycle_sample_paths,diagnosticLimit),summarizedParentCycleItemIds=summarizeList(parentCycleDiagnostics.cycle_item_ids,diagnosticLimit),summarizedParentCycleSamplePaths=summarizeList(parentCycleDiagnostics.cycle_sample_paths,diagnosticLimit),summarizedHierarchyCardinalityRows=summarizeList(parentCycleDiagnostics.cardinality_violation_rows,diagnosticLimit),summarizedHierarchyDivergenceRows=summarizeList(parentCycleDiagnostics.parent_divergence_rows,diagnosticLimit),hasErrorSeverityCycle=dependencyCycleDiagnostics.cycle_count>0&&dependencyCycleSeverity==="error"||(parentCycleDiagnostics.active_cycle_count>0||parentCycleDiagnostics.active_cardinality_violation_count>0||parentCycleDiagnostics.active_parent_divergence_count>0)&&parentCycleSeverity==="error";return{check:{name:"lifecycle",status:hasErrorSeverityCycle?"error":warnings.length===0?"ok":"warn",ok:!hasErrorSeverityCycle&&warnings.length===0,details:{checked_active_items:rows.activeItems.length,lifecycle_status_roles:statusRoleDiagnostics,active_closure_like_metadata_items:rows.closureLikeRows.length,active_closure_like_metadata_rows:summarizedClosureLikeRows.values,active_closure_like_metadata_rows_truncated:summarizedClosureLikeRows.truncated,active_terminal_parent_items:rows.terminalParentRows.length,active_terminal_parent_rows:summarizedTerminalParentRows.values,active_terminal_parent_rows_truncated:summarizedTerminalParentRows.truncated,stale_blocker_checks_enabled:includeStaleBlockers,stale_blocker_items:rows.staleBlockerRows.length,stale_blocker_rows:summarizedStaleBlockerRows.values,stale_blocker_rows_truncated:summarizedStaleBlockerRows.truncated,dependency_cycle_severity_policy:dependencyCycleSeverity,dependency_cycle_count:dependencyCycleDiagnostics.cycle_count,dependency_cycle_item_count:dependencyCycleDiagnostics.cycle_item_ids.length,dependency_cycle_item_ids:summarizedDependencyCycleItemIds.values,dependency_cycle_item_ids_truncated:summarizedDependencyCycleItemIds.truncated,dependency_cycle_sample_paths:summarizedDependencyCycleSamplePaths.values,dependency_cycle_sample_paths_truncated:summarizedDependencyCycleSamplePaths.truncated,parent_cycle_severity_policy:parentCycleSeverity,parent_cycle_count:parentCycleDiagnostics.cycle_count,active_parent_cycle_count:parentCycleDiagnostics.active_cycle_count,legacy_parent_cycle_count:parentCycleDiagnostics.legacy_cycle_count,parent_cycle_item_count:parentCycleDiagnostics.cycle_item_ids.length,parent_cycle_item_ids:summarizedParentCycleItemIds.values,parent_cycle_item_ids_truncated:summarizedParentCycleItemIds.truncated,parent_cycle_sample_paths:summarizedParentCycleSamplePaths.values,parent_cycle_sample_paths_truncated:summarizedParentCycleSamplePaths.truncated,hierarchy_cardinality_violation_count:parentCycleDiagnostics.cardinality_violation_count,active_hierarchy_cardinality_violation_count:parentCycleDiagnostics.active_cardinality_violation_count,legacy_hierarchy_cardinality_violation_count:parentCycleDiagnostics.legacy_cardinality_violation_count,hierarchy_cardinality_violation_rows:summarizedHierarchyCardinalityRows.values,hierarchy_cardinality_violation_rows_truncated:summarizedHierarchyCardinalityRows.truncated,hierarchy_parent_divergence_count:parentCycleDiagnostics.parent_divergence_count,active_hierarchy_parent_divergence_count:parentCycleDiagnostics.active_parent_divergence_count,legacy_hierarchy_parent_divergence_count:parentCycleDiagnostics.legacy_parent_divergence_count,hierarchy_parent_divergence_rows:summarizedHierarchyDivergenceRows.values,hierarchy_parent_divergence_rows_truncated:summarizedHierarchyDivergenceRows.truncated,stale_blocker_reason_patterns:[...lifecyclePatternPolicy.stale_blocker_reason_patterns],stale_blocker_reason_pattern_source:lifecyclePatternPolicy.stale_blocker_reason_pattern_source,closure_like_blocked_reason_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.blocked_reason],closure_like_blocked_reason_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.blocked_reason,closure_like_resolution_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.resolution],closure_like_resolution_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.resolution,closure_like_actual_result_patterns:[...lifecyclePatternPolicy.closure_like_metadata_field_patterns.actual_result],closure_like_actual_result_pattern_source:lifecyclePatternPolicy.closure_like_metadata_field_pattern_sources.actual_result}},warnings,terminalParentFixRows:rows.terminalParentFixRows}}async function buildFilesCheck(items,workspaceRoot,pmRoot,fileScanMode,includePmInternals,verboseFileLists,statusRegistry=resolveRuntimeStatusRegistry(SETTINGS_DEFAULTS.schema)){const linkedPathState=await collectLinkedPathScanState(items,workspaceRoot),itemsById=new Map(items.map(item=>[item.id,item])),uniqueMissingLinkedPaths=[...new Set(linkedPathState.missingLinkedPaths)].sort((left,right)=>left.localeCompare(right)),fileCandidates=await collectProjectFileCandidates(workspaceRoot,fileScanMode),partition=partitionFileCandidates(fileCandidates,pmRoot,workspaceRoot,fileScanMode,includePmInternals,verboseFileLists),orphanedFiles=partition.candidateFiles.filter(candidate=>!linkedPathState.linkedProjectPaths.has(candidate)),orphanedPathRows=buildOrphanedPathRows(orphanedFiles,items),classifiedStalePaths=classifyStaleLinkedPaths(uniqueMissingLinkedPaths,partition.candidateFiles),classificationByPath=new Map(classifiedStalePaths.map(entry=>[entry.path,entry.classification])),movedStalePathCount=classifiedStalePaths.filter(entry=>entry.classification==="moved").length,staleLinkPruneRows=linkedPathState.staleLinkRows.map(row=>({...row,classification:classificationByPath.get(row.path)??"deleted"})).sort((left,right)=>left.item_id.localeCompare(right.item_id)||left.path.localeCompare(right.path)||left.link_kind.localeCompare(right.link_kind)),warnings=[];partition.strictModeForcesPmInternals&&warnings.push("validate_files_tracked_all_strict_forces_pm_internals"),orphanedFiles.length>0&&warnings.push(`validate_files_orphaned_paths:${orphanedFiles.length}`);const uniqueRemoteLinkedPaths=[...linkedPathState.remoteLinkedPaths].sort((left,right)=>left.localeCompare(right)),summarizedRemote=summarizeFileList(uniqueRemoteLinkedPaths,verboseFileLists),summarizedMissing=summarizeFileList(uniqueMissingLinkedPaths,verboseFileLists),summarizedOrphaned=summarizeFileList(orphanedFiles,verboseFileLists),summarizedOrphanedClassifications=summarizeFileList(orphanedPathRows.map(row=>`${row.path}:${row.classification}:owner_candidate=${row.owner_candidate?.id??"unowned"}`),verboseFileLists),orphanedPathRowDetail=verboseFileLists?orphanedPathRows:summarizeFileList(summarizeOrphanedPathRows(orphanedPathRows),!1).values,summarizedClassifications=summarizeFileList(summarizeStaleLinkedPathClassifications(classifiedStalePaths),verboseFileLists),repairReport=buildLinkedFileRepairReport(staleLinkPruneRows,classifiedStalePaths,id=>itemsById.get(id),statusRegistry,verboseFileLists?1/0:FILE_LIST_SUMMARY_LIMIT);return repairReport.active_missing_linked_paths_count>0&&warnings.push(`validate_files_missing_linked_paths:${repairReport.active_missing_linked_paths_count}`),{check:{name:"files",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{workspace_root:workspaceRoot,scan_mode_requested:fileCandidates.requestedMode,scan_mode_applied:fileCandidates.appliedMode,strict_tracked_all_mode:partition.strictTrackedAllMode,strict_mode_forces_pm_internals:partition.strictModeForcesPmInternals,strict_mode_forces_pm_internals_notice:partition.strictModeForcesPmInternals?"tracked-all-strict force-enables PM internals; pass --include-pm-internals to make inclusion explicit.":null,file_list_detail_mode:verboseFileLists?"full":"summary",file_list_summary_limit:FILE_LIST_SUMMARY_LIMIT,candidate_scan_source:fileCandidates.source,include_pm_internals:partition.includePmInternalsEffective,include_pm_internals_requested:includePmInternals,pm_internal_candidate_prefixes:partition.pmInternalCandidatePrefixes,pm_internal_excluded_count:partition.excludedPmInternalPaths.length,excluded_total:partition.excludedPmInternalPaths.length,excluded_by_reason:partition.excludedByReason,linked_project_paths:linkedPathState.linkedProjectPaths.size,remote_linked_paths_count:uniqueRemoteLinkedPaths.length,remote_linked_paths_total:summarizedRemote.total,remote_linked_paths:summarizedRemote.values,remote_linked_paths_truncated:summarizedRemote.truncated,candidate_total_raw:fileCandidates.candidateTotal,candidate_scanned_raw:fileCandidates.candidateScanned,candidate_total:partition.candidateFiles.length,candidate_scanned:partition.candidateFiles.length,scanned_candidate_files:partition.candidateFiles.length,missing_linked_paths_count:uniqueMissingLinkedPaths.length,missing_linked_paths_total:summarizedMissing.total,missing_linked_paths:summarizedMissing.values,missing_linked_paths_truncated:summarizedMissing.truncated,missing_linked_paths_moved_count:movedStalePathCount,missing_linked_paths_deleted_count:classifiedStalePaths.filter(entry=>entry.classification==="deleted").length,missing_linked_paths_malformed_count:classifiedStalePaths.filter(entry=>entry.classification==="malformed").length,missing_linked_path_classifications:summarizedClassifications.values,missing_linked_path_classifications_truncated:summarizedClassifications.truncated,...repairReport,orphaned_paths_count:orphanedFiles.length,orphaned_paths_total:summarizedOrphaned.total,orphaned_paths:summarizedOrphaned.values,orphaned_paths_truncated:summarizedOrphaned.truncated,orphaned_path_classifications:summarizedOrphanedClassifications.values,orphaned_path_classifications_truncated:summarizedOrphanedClassifications.truncated,orphaned_path_rows_count:orphanedPathRows.length,orphaned_path_rows:orphanedPathRowDetail}},warnings,staleLinkPruneRows}}function buildUntrustedLinkedTestRows(linkedTests,trustDecisions){const rows=[];return linkedTests.forEach(({item,linkedTest},index)=>{const trust=trustDecisions[index];if(trust.trusted)return;const command=summarizeCommandPreview(linkedTest.command??"");rows.push(`${item.id}:${trust.source_ref??"unknown"}->${trust.current_source_ref??"unknown"}:${command}`)}),rows}async function buildCommandReferencesCheck(items,idPrefix,verboseDiagnostics,pmRoot){const knownIds=new Set(items.map(item=>item.id.toLowerCase()));let linkedCommandsScanned=0,referencedPmIdCount=0;const referencedPmIds=new Set,staleReferenceRows=[],linkedTests=items.flatMap(item=>(item.tests??[]).map(linkedTest=>({item,linkedTest}))),currentSourceRef=await resolveLinkedTestSourceRef(resolveLinkedTestSourceWorkspaceRoot()),trustDecisions=await resolveLinkedTestTrustBatch(pmRoot,linkedTests.map(({linkedTest})=>linkedTest),currentSourceRef),untrustedRows=buildUntrustedLinkedTestRows(linkedTests,trustDecisions);for(const{item,linkedTest}of linkedTests){if(typeof linkedTest.command!="string"||linkedTest.command.trim().length===0)continue;linkedCommandsScanned+=1;const referencedIds=extractReferencedPmItemIdsFromCommand(linkedTest.command,idPrefix);if(referencedIds.length!==0){referencedPmIdCount+=referencedIds.length;for(const referencedId of referencedIds)referencedPmIds.add(referencedId),knownIds.has(referencedId.toLowerCase())||staleReferenceRows.push(`${item.id}:${referencedId}:${summarizeCommandPreview(linkedTest.command)}`)}}const uniqueStaleReferenceRows=[...new Set(staleReferenceRows)].sort((left,right)=>left.localeCompare(right)),stalePmIds=[...new Set(uniqueStaleReferenceRows.map(row=>row.split(":")[1]??""))].filter(value=>value.length>0).sort((left,right)=>left.localeCompare(right)),warnings=[];uniqueStaleReferenceRows.length>0&&warnings.push(`validate_command_references_stale_pm_ids:${uniqueStaleReferenceRows.length}`),untrustedRows.length>0&&warnings.push(`validate_linked_test_trust_unacknowledged:${untrustedRows.length}`);const diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedRows=summarizeList(uniqueStaleReferenceRows,diagnosticLimit),summarizedStalePmIds=summarizeList(stalePmIds,diagnosticLimit),summarizedReferencedPmIds=summarizeList([...referencedPmIds].sort((left,right)=>left.localeCompare(right)),diagnosticLimit),summarizedUntrustedRows=summarizeList(untrustedRows,diagnosticLimit);return{check:{name:"command_references",status:warnings.length===0?"ok":"warn",ok:warnings.length===0,details:{checked_items:items.length,linked_commands_scanned:linkedCommandsScanned,referenced_pm_ids_count:referencedPmIdCount,unique_referenced_pm_ids_count:referencedPmIds.size,unique_referenced_pm_ids:summarizedReferencedPmIds.values,unique_referenced_pm_ids_truncated:summarizedReferencedPmIds.truncated,linked_test_trust_current_source_ref:currentSourceRef??null,untrusted_linked_tests_count:untrustedRows.length,untrusted_linked_tests:summarizedUntrustedRows.values,untrusted_linked_tests_truncated:summarizedUntrustedRows.truncated,stale_pm_id_references_count:uniqueStaleReferenceRows.length,stale_pm_ids_count:stalePmIds.length,stale_pm_ids:summarizedStalePmIds.values,stale_pm_ids_truncated:summarizedStalePmIds.truncated,stale_pm_id_reference_rows:summarizedRows.values,stale_pm_id_reference_rows_truncated:summarizedRows.truncated}},warnings}}function buildFormatVersionCheck(items,verboseDiagnostics){const scan=scanItemFormatVersions(items.map(item=>({ref:item.id,version:effectiveItemFormatVersion(item)})),CURRENT_ITEM_FORMAT_VERSION,BASELINE_ITEM_FORMAT_VERSION),warnings=[];scan.outdated.length>0&&warnings.push(`validate_format_version_outdated_items:${scan.outdated.length}`),scan.ahead.length>0&&warnings.push(`validate_format_version_ahead_items:${scan.ahead.length}`);const diagnosticLimit=verboseDiagnostics?Number.POSITIVE_INFINITY:DIAGNOSTIC_LIST_SUMMARY_LIMIT,summarizedOutdated=summarizeList(scan.outdated,diagnosticLimit),summarizedAhead=summarizeList(scan.ahead,diagnosticLimit),status=scan.ahead.length>0?"error":scan.outdated.length>0?"warn":"ok";return{check:{name:"format_version",status,ok:status==="ok",details:{checked_items:items.length,current_format_version:CURRENT_ITEM_FORMAT_VERSION,outdated_items_count:scan.outdated.length,outdated_items:summarizedOutdated.values,outdated_items_truncated:summarizedOutdated.truncated,ahead_items_count:scan.ahead.length,ahead_items:summarizedAhead.values,ahead_items_truncated:summarizedAhead.truncated}},warnings}}const VALIDATE_AUTO_FIX_MESSAGE="pm validate auto-fix";async function applyValidateFix(fix,global2,services){switch(fix.kind){case"set_closed_at":await applyClosureTimestampFix(fix,global2);return;case"set_resolution":case"set_close_reason":case"set_estimate":case"reparent":case"unset_parent":{const updateOptions={message:VALIDATE_AUTO_FIX_MESSAGE};if(fix.kind==="set_resolution"?updateOptions.resolution=fix.value:fix.kind==="set_close_reason"?updateOptions.closeReason=fix.value:fix.kind==="set_estimate"?updateOptions.estimatedMinutes=fix.value:fix.kind==="reparent"?updateOptions.parent=fix.parent_id:updateOptions.unset=["parent"],!services.runUpdate)throw new PmCliError("Applying validate metadata/lifecycle fixes requires a runUpdate mutation service.",EXIT_CODE.USAGE);await services.runUpdate(fix.item_id,updateOptions,global2);return}case"prune_file_link":throw new Error(`Unsupported non-batched fix kind: ${fix.kind}`);case"prune_doc_link":throw new Error(`Unsupported non-batched fix kind: ${fix.kind}`)}}function pruneBatchKey(fix){return fix.kind!=="prune_file_link"&&fix.kind!=="prune_doc_link"?null:`${fix.kind}:${fix.item_id}`}async function applyValidateFixes(applicable,global2,services){const applied=[],failed=[],pruneBatches=new Map;for(const fix of applicable.filter(candidate=>pruneBatchKey(candidate)===null))try{await applyValidateFix(fix,global2,services),applied.push(fix)}catch(error){failed.push({fix,error})}for(const fix of applicable.filter(candidate=>pruneBatchKey(candidate)!==null)){const batchKey=pruneBatchKey(fix),existing=pruneBatches.get(batchKey);existing?existing.push(fix):pruneBatches.set(batchKey,[fix])}for(const batch of pruneBatches.values()){const first=batch[0];if(!first)continue;const remove=batch.map(fix=>fix.path).filter(value=>typeof value=="string"&&value.length>0);try{first.kind==="prune_file_link"?await runFiles(first.item_id,{remove,message:VALIDATE_AUTO_FIX_MESSAGE},global2):await runDocs(first.item_id,{remove,message:VALIDATE_AUTO_FIX_MESSAGE},global2),applied.push(...batch)}catch(error){failed.push(...batch.map(fix=>({fix,error})))}}return throwFirstItemRevisionConflict(failed.map(entry=>entry.error)),{applied,failed}}const _testOnlyValidateCommand={applyValidateFix,applyValidateFixes,attachValidateFixHints,buildCommandReferencesCheck,buildDependencyReferencesCheck,buildCloseReasonBackfillRows,buildFilesCheck,buildLifecycleCheck,buildLifecycleDependencyGraph,buildLifecycleParentGraph,buildEstimateBackfillRows,buildMetadataCounts,buildMissingFieldOccurrences,buildOrphanedPathRows,classifyOrphanedPath,collectDefaultProjectFileCandidates,collectTrackedGitFileCandidates,detectLifecycleDependencyCycles,detectLifecycleParentCycles,escapeRegExp,extractItemIds,findLifecycleDependencyCycleComponents,isMetadataFieldMissing,linkedArtifactPathExceedsFilesystemLimits,listFilesRecursive,resolveDependencyCycleSeverity,resolveParentCycleSeverity,resolveFileScanMode,resolveLifecycleDependencyCycleSamplePath,resolveRequestedChecks,resolveValidateMetadataProfile,resolveWorkspaceRoot,sharedDirectoryPrefixLength,summarizeOrphanedPathRows,summarizeDuplicateIssueCodes,toMeaningfulString};function appendInvalidMergeReceiptEvidenceWarning(warnings,invalidEvidenceCount){invalidEvidenceCount>0&&warnings.push(`merge_receipt_evidence_invalid:${invalidEvidenceCount}`)}async function buildStorageIntegrityCheck(pmRoot,items,typeToFolder,settings){const scan=await scanStorageIntegrity(pmRoot,new Set(items.map(item=>item.id)),typeToFolder,{schema:settings.schema,extensionFieldNames:collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}),warnings=[];scan.unreadable_item_files.length>0&&warnings.push(`validate_storage_unreadable_items:${scan.unreadable_item_files.length}`),scan.duplicate_item_ids.length>0&&warnings.push(`validate_storage_duplicate_item_ids:${scan.duplicate_item_ids.length}`),scan.history_conflict_marker_streams.length>0&&warnings.push(`validate_storage_history_conflict_markers:${scan.history_conflict_marker_streams.length}`),scan.history_unparseable_streams.length>0&&warnings.push(`validate_storage_unparseable_history:${scan.history_unparseable_streams.length}`),scan.resurrected_items.length>0&&warnings.push(`validate_storage_resurrected_items:${scan.resurrected_items.length}`),scan.unparseable_config_files.length>0&&warnings.push(`validate_storage_unparseable_config:${scan.unparseable_config_files.length}`);const errorCount=warnings.length,trackedRuntimeCache=await scanTrackedRuntimeCache(pmRoot);trackedRuntimeCache.tracked_path_count>0&&warnings.push(`validate_storage_tracked_runtime_cache_files:${trackedRuntimeCache.tracked_path_count}`);const fenceAudit=await auditMergeAttributeFence(pmRoot,resolveProjectMergeTypeFolders(settings));fenceAudit.status==="drift"&&warnings.push(`validate_merge_fence_drift:${fenceAudit.missing_patterns.length+fenceAudit.stale_patterns.length}`);const gitWorkspaceRoot=await findGitWorkspaceRoot(pmRoot),mergeDriverAudit=gitWorkspaceRoot===null?null:await auditMergeDriverConfiguration(gitWorkspaceRoot);mergeDriverAudit!==null&&mergeDriverAudit.status!=="ok"&&warnings.push(`validate_merge_driver_configuration:${mergeDriverAudit.missing_keys.length+mergeDriverAudit.drifted_keys.length}`);const mergeReceiptEvidence=await inspectMergeReceiptEvidence(gitWorkspaceRoot??pmRoot,{includeLossless:!0,pmRoot}),pendingMergeReceipts=mergeReceiptEvidence.receipts,{pendingDecisions:pendingMergeDecisions,lossless:losslessMergeReceipts}=partitionMergeReceipts(pendingMergeReceipts);pendingMergeDecisions.length>0&&warnings.push(`validate_merge_decisions_unreviewed:${pendingMergeDecisions.length}`),appendInvalidMergeReceiptEvidenceWarning(warnings,mergeReceiptEvidence.invalid_evidence_count);const status=errorCount>0?"error":warnings.length>0?"warn":"ok";return{check:{name:"storage_integrity",status,ok:status==="ok",details:{...scan,merge_fence:fenceAudit,merge_driver_configuration:mergeDriverAudit,pending_merge_decision_count:pendingMergeDecisions.length,pending_merge_decision_items:[...new Set(pendingMergeDecisions.map(receipt=>receipt.item_id))].sort((left,right)=>left.localeCompare(right)),lossless_merge_receipt_count:losslessMergeReceipts.length,invalid_merge_receipt_evidence_count:mergeReceiptEvidence.invalid_evidence_count,invalid_merge_receipt_evidence_details:mergeReceiptEvidence.invalid_evidence,invalid_merge_receipt_evidence_details_truncated:mergeReceiptEvidence.invalid_evidence_truncated,lossless_merge_receipt_items:[...new Set(losslessMergeReceipts.map(receipt=>receipt.item_id))].sort((left,right)=>left.localeCompare(right)),tracked_runtime_cache:{tracker_relative_root:trackedRuntimeCache.tracker_relative_root,tracked_paths:trackedRuntimeCache.tracked_paths,tracked_path_count:trackedRuntimeCache.tracked_path_count,remediation_command:trackedRuntimeCache.remediation_command}}},warnings}}function recordValidateCheck(state,built,fixHintsEnabled){fixHintsEnabled&&attachValidateFixHints(built.check,built.warnings),state.checks.push(built.check),state.warnings.push(...built.warnings)}async function executeRequestedValidateChecks(params){const state={closureTimestampFixes:[],checks:[],warnings:[...params.initialWarnings],closeReasonBackfillRows:[],estimateBackfillRows:[],resolutionBackfillRows:[],terminalParentFixRows:[],staleLinkPruneRows:[]},fixHintsEnabled=params.options.fixHints===!0,fullDiagnostics=params.options.verboseDiagnostics===!0||params.options.allAffectedIds===!0||params.global.json===!0;if(params.requestedChecks.has("completeness")){const built=await readWorkflowCompletenessCheck(params.pmRoot,params.items,fullDiagnostics?1/0:DIAGNOSTIC_LIST_SUMMARY_LIMIT,params.sourceIncomplete);recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("metadata")){const built=buildMetadataCheck(params.items,params.metadataPolicy,params.statusRegistry,fullDiagnostics,[params.settings.id_prefix]);state.closeReasonBackfillRows=built.closeReasonBackfillRows,state.estimateBackfillRows=built.estimateBackfillRows;const timestamps=await scanClosureTimestamps(params.pmRoot,params.items,params.statusRegistry,params.options.autoFix===!0||fixHintsEnabled,fullDiagnostics?1/0:DIAGNOSTIC_LIST_SUMMARY_LIMIT);state.closureTimestampFixes=timestamps.fixes,Object.assign(built.check.details,timestamps.details),built.warnings.push(...timestamps.warnings),built.check.ok=built.warnings.length===0,built.check.status=built.check.ok?"ok":"warn",recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("resolution")){const built=buildResolutionCheck(params.items,params.statusRegistry,fullDiagnostics);state.resolutionBackfillRows=built.resolutionBackfillRows,recordValidateCheck(state,built,fixHintsEnabled)}if(params.requestedChecks.has("lifecycle")){const built=buildLifecycleCheck(params.items,!!params.options.checkStaleBlockers,params.dependencyCycleSeverity,params.parentCycleSeverity,params.statusRegistry,params.lifecyclePatternPolicy,fullDiagnostics,params.settings.id_prefix);state.terminalParentFixRows=built.terminalParentFixRows,recordValidateCheck(state,built,fixHintsEnabled),recordValidateCheck(state,buildDependencyReferencesCheck(params.items,fullDiagnostics,params.statusRegistry),fixHintsEnabled)}if(params.requestedChecks.has("files")){const built=await buildFilesCheck(params.items,params.workspaceRoot,params.pmRoot,params.fileScanMode,!!params.options.includePmInternals,!!params.options.verboseFileLists,params.statusRegistry);state.staleLinkPruneRows=built.staleLinkPruneRows,recordValidateCheck(state,built,fixHintsEnabled)}return params.requestedChecks.has("command_references")&&recordValidateCheck(state,await buildCommandReferencesCheck(params.items,params.settings.id_prefix,fullDiagnostics,params.pmRoot),fixHintsEnabled),params.requestedChecks.has("history_drift")&&recordValidateCheck(state,await buildValidateHistoryDriftCheck(params.pmRoot,params.items,fullDiagnostics),fixHintsEnabled),params.requestedChecks.has("format_version")&&recordValidateCheck(state,buildFormatVersionCheck(params.items,fullDiagnostics),fixHintsEnabled),params.requestedChecks.has("storage_integrity")&&recordValidateCheck(state,await buildStorageIntegrityCheck(params.pmRoot,params.items,resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,params.settings),fixHintsEnabled),state}function planValidateFixes(options,state,settings){const planned=[];return options.autoFix===!0&&(planned.push(...state.closureTimestampFixes),planned.push(...planCloseReasonBackfillFixes(state.closeReasonBackfillRows)),planned.push(...planResolutionBackfillFixes(state.resolutionBackfillRows)),planned.push(...planEstimateBackfillFixes(state.estimateBackfillRows,settings.validation.estimate_defaults_by_type)),planned.push(...planTerminalParentFixes(state.terminalParentFixRows))),options.pruneMissing===!0&&planned.push(...planStaleLinkPruneFixes(state.staleLinkPruneRows)),planned}async function buildValidateFixesSummary(options,state,settings,grantedFixScopes,global2,services){if(options.autoFix!==!0&&options.pruneMissing!==!0)return;const planned=planValidateFixes(options,state,settings),{applicable,gated}=partitionFixesByGrant(planned,grantedFixScopes),dryRun=options.dryRun===!0,appliedFixRows=[],failedFixRows=[];if(!dryRun){const applied=await applyValidateFixes(applicable,global2,services);appliedFixRows.push(...applied.applied.map(toFixOutputRow)),failedFixRows.push(...applied.failed.map(({fix,error})=>({...toFixOutputRow(fix),error:error instanceof Error?error.message:String(error)})))}return{mode:dryRun?"dry_run":"apply",auto_fix:options.autoFix===!0,prune_missing:options.pruneMissing===!0,granted_fix_scopes:[...grantedFixScopes].sort((left,right)=>left.localeCompare(right)),planned_count:planned.length,applied_count:appliedFixRows.length,gated_count:gated.length,failed_count:failedFixRows.length,planned_fixes:planned.map(toFixOutputRow),applied_fixes:appliedFixRows,gated_fixes:gated.map(fix=>({...toFixOutputRow(fix),gate_hint:`Withheld: re-run with --fix-scope ${fix.gate} to apply.`})),failed_fixes:failedFixRows}}async function runValidate(options,global2,services={}){assertProjectionModeChoice(options.counts===!0,options.full===!0,"--counts");const fixesRequested=options.autoFix===!0||options.pruneMissing===!0;if(options.dryRun===!0&&!fixesRequested)throw new PmCliError("--dry-run requires --auto-fix or --prune-missing (there is nothing to preview otherwise).",EXIT_CODE.USAGE);if(options.fixScope!==void 0&&options.fixScope.length>0&&options.autoFix!==!0)throw new PmCliError("--fix-scope requires --auto-fix.",EXIT_CODE.USAGE);const grantedFixScopes=resolveGrantedFixScopes(options.fixScope),pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),requestedChecks=resolveRequestedChecks(options),itemReadWarnings=[],items=await readValidateItems({includeBody:["history_drift","metadata","completeness"].some(check=>requestedChecks.has(check)),pmRoot,settings,typeToFolder:typeRegistry.type_to_folder,warnings:itemReadWarnings}),sourceIncomplete=itemReadWarnings.length>0;if(requestedChecks.has("history_drift")){const authorAttribution=await scanHistoryAuthorAttribution(pmRoot);authorAttribution.actionable_unknown_event_count>0&&itemReadWarnings.push(`validate_history_unknown_author_events:${authorAttribution.actionable_unknown_event_count}`)}const metadataProfileSource=typeof options.metadataProfile=="string"?"option":"settings",metadataProfile=resolveValidateMetadataProfile(typeof options.metadataProfile=="string"?options.metadataProfile:settings.validation.metadata_profile),metadataPolicy=resolveValidateMetadataPolicy(metadataProfile,metadataProfileSource,settings.validation.metadata_required_fields),lifecyclePatternPolicy=resolveLifecyclePatternPolicy(settings),dependencyCycleSeverity=resolveDependencyCycleSeverity(options.dependencyCycleSeverity),parentCycleSeverity=resolveParentCycleSeverity(options.parentCycleSeverity),fileScanMode=resolveFileScanMode(options.scanMode),workspaceRoot=resolveWorkspaceRoot(pmRoot),state=await executeRequestedValidateChecks({requestedChecks,options,global:global2,pmRoot,workspaceRoot,settings,items,statusRegistry,metadataPolicy,lifecyclePatternPolicy,dependencyCycleSeverity,parentCycleSeverity,fileScanMode,initialWarnings:[...new Set(itemReadWarnings)],sourceIncomplete}),fixes=fixesRequested?await buildValidateFixesSummary(options,state,settings,grantedFixScopes,global2,services):void 0,normalizedWarnings=[...new Set(state.warnings)].sort((left,right)=>left.localeCompare(right)),result={ok:!state.checks.some(check=>check.status==="error"),has_warnings:normalizedWarnings.length>0,checks:state.checks,warnings:normalizedWarnings,...fixes!==void 0?{fixes}:{},generated_at:nowIso(),projection:{mode:"full",declared_field_groups:[{name:"diagnostic_rows",restore_with:"--full"}],included_field_groups:["diagnostic_rows"]}};return options.counts!==!0?result:{...projectValidateCounts(result),projection:{mode:"counts",declared_field_groups:[{name:"diagnostic_rows",restore_with:"--full"}],included_field_groups:[]}}}export{_testOnlyValidateCommand,projectValidateCounts,runValidate};
2
2
  //# sourceMappingURL=validate.js.map
@@ -1,4 +1,4 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cca38e64-dd53-5086-8825-dc1c8f1cc587")}catch{}})();import{isUtf8}from"node:buffer";import{resolveHistoryHashAlgorithm}from"../../core/history/digest.js";import{readFile}from"node:fs/promises";import{isFileMissingError,readFileIfExists}from"../../core/fs/fs-utils.js";import{acquireLock}from"../../core/lock/lock.js";import{createHistoryEntry,sealHistoryRecord}from"../../core/history/history.js";import{checkHistoryRewriteOwnership,writeHistoryRawWithRollback}from"../../core/history/history-rewrite.js";import{replayHistoryToTarget}from"../../core/history/projection.js";import{replayToItemDocument,verifyHistoryChainWithVersion}from"../../core/history/replay.js";import{findFirstMergeConflictMarker}from"../../core/shared/conflict-markers.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{sha256Hex}from"../../core/shared/serialization.js";import{nowIso}from"../../core/shared/time.js";import{runActiveOnReadHooks,runActiveOnWriteHooks}from"../../core/extensions/index.js";import{locateItem,readLocatedItemSnapshot}from"../../core/store/item-store.js";function decodeSalvageLine(line){let parsed;try{parsed=JSON.parse(line)}catch{if(line.trimStart().startsWith("{")&&line.includes("}"))throw new PmCliError("History salvage cannot discard a potentially complete record with trailing corruption.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return null}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))throw new PmCliError("History salvage would conceal interior corruption or a malformed record.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const entry=parsed;if(!Array.isArray(entry.patch)||![entry.ts,entry.author,entry.op,entry.before_hash,entry.after_hash].every(field=>typeof field=="string"))throw new PmCliError("History salvage requires complete history records before the invalid tail.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return entry}function inspectHistoryTail(raw){if(findFirstMergeConflictMarker(raw))throw new PmCliError("Resolve history merge conflicts before salvage.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const entries=[];let offset=0,invalidOffset,invalidLine=0;for(const[index,line]of raw.split(`
2
- `).entries()){if(!line.trim()){offset+=line.length+1;continue}const parsed=decodeSalvageLine(line);if(parsed===null){invalidOffset===void 0&&(invalidOffset=offset,invalidLine=index+1),offset+=line.length+1;continue}if(invalidOffset!==void 0)throw new PmCliError("History salvage would discard a record or conceal interior corruption.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused",required:"Recover the damaged record from version control or a backup; no bytes were changed."});entries.push(parsed),offset+=line.length+1}const verification=verifyHistoryChainWithVersion(entries);if(!verification.ok||verification.item_hash_version===void 0)throw new PmCliError("History salvage requires a nonempty verified prefix.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused",verification_errors:verification.errors,required:"Recover an intact history prefix from version control or a backup."});return{entries,itemHashVersion:verification.item_hash_version,prefix:invalidOffset===void 0?raw:raw.slice(0,invalidOffset),receipt:invalidOffset===void 0?null:{first_invalid_line:invalidLine,discarded_bytes:Buffer.byteLength(raw.slice(invalidOffset)),discarded_sha256:sha256Hex(raw.slice(invalidOffset)),retained_entries:entries.length}}}async function readSalvageOwnership(subject,settings,fallback){if(!subject.located)return{itemRaw:null,document:fallback};const snapshot=await readLocatedItemSnapshot(subject.located,{schema:settings.schema});return{itemRaw:snapshot.raw,document:snapshot.document??fallback}}async function readSalvageStream(historyPath){let bytes;try{bytes=await readFile(historyPath)}catch(error){if(isFileMissingError(error))return null;throw error}if(!isUtf8(bytes))throw new PmCliError("History salvage requires UTF-8 input; recover binary corruption from a byte-preserving backup.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return bytes.toString("utf8")}async function salvageHistoryTail(params){const{subject,settings,options,author}=params;if([options.normalizeProvenance,options.auditOperation,options.auditContext,options.auditContextById,options.forceAuditEntry,options.mergeReceiptProof,options.mergeReceiptProofById].some(Boolean))throw new PmCliError("Tail salvage cannot be combined with other repair modes.",EXIT_CODE.USAGE);const raw=await readSalvageStream(subject.historyPath);if(raw===null)throw new PmCliError(`No history stream exists for ${subject.id}.`,EXIT_CODE.NOT_FOUND);await runActiveOnReadHooks({path:subject.historyPath,scope:"project"});const selected=inspectHistoryTail(raw),replay=replayHistoryToTarget(selected.entries,selected.entries.length-1),document=replayToItemDocument(replay);if(typeof replay.metadata.id=="string"&&replay.metadata.id!==subject.id)throw new PmCliError("History belongs to another item; salvage refused.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const ownership=await readSalvageOwnership(subject,settings,document),warnings=checkHistoryRewriteOwnership({itemDocument:ownership.document,subjectId:subject.id,author,force:options.force,settings}),version=selected.itemHashVersion,dryRun=options.dryRun===!0,changed=selected.receipt!==null;if(changed&&!dryRun){const release=await acquireLock(params.pmRoot,subject.id,settings.locks.ttl_seconds,author,!!options.force,settings.governance.force_required_for_stale_lock,settings.locks.wait_ms);try{const currentRaw=await readSalvageStream(subject.historyPath),located=await locateItem(params.pmRoot,subject.id,settings.id_prefix,settings.item_format,params.typeRegistry.type_to_folder),currentItem=located?await readFileIfExists(located.itemPath):null;if(currentRaw!==raw||currentItem!==ownership.itemRaw)throw new PmCliError("History or item changed while waiting for salvage lock; retry.",EXIT_CODE.CONFLICT);const audit=sealHistoryRecord({...createHistoryEntry({hashAlgorithm:resolveHistoryHashAlgorithm(selected.entries.at(-1).hash_algorithm),nowIso:nowIso(),author,op:"history_salvage",before:document,after:document,message:options.message,context:{history_salvage:selected.receipt}}),before_hash:selected.entries.at(-1).after_hash,after_hash:selected.entries.at(-1).after_hash,item_hash_version:version});await writeHistoryRawWithRollback({historyPath:subject.historyPath,historyRawUnderLock:raw,nextHistoryRaw:`${selected.prefix}${JSON.stringify(audit)}
3
- `}),warnings.push(...await runActiveOnWriteHooks({path:subject.historyPath,scope:"project",op:"history_salvage:history"}))}finally{await release()}}return{id:subject.id,dry_run:dryRun,changed,history:{path:subject.historyPath,entries_scanned:selected.entries.length,chain_drift_before:!1,entries_rehashed:0,entries_patch_repaired:0,converted_replace_to_add:0,skipped_ops:0,reconciled_with_item:!1,audit_entry_added:changed&&!dryRun,verify_ok:!0,verify_errors:[],item_hash_version_before:version,item_hash_version_after:version,version_disposition:"preserved"},item:{exists:subject.located!==null,path:subject.located?.itemPath??null,matched_chain_before:null},provenance_normalization:{requested:!1,changed:!1,events_changed:0,observations_removed:0,invalid_values:[]},...selected.receipt?{salvage:selected.receipt}:{},warnings,generated_at:nowIso()}}export{inspectHistoryTail,salvageHistoryTail};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6fc9a054-8905-522e-a166-049730d0e1ae")}catch{}})();import{isUtf8}from"node:buffer";import{resolveHistoryHashAlgorithm}from"../../core/history/digest.js";import{readFile}from"node:fs/promises";import{isFileMissingError,readFileIfExists}from"../../core/fs/fs-utils.js";import{acquireLock}from"../../core/lock/lock.js";import{createHistoryEntry,sealHistoryRecord}from"../../core/history/history.js";import{checkHistoryRewriteOwnership,writeHistoryRawWithRollback}from"../../core/history/history-rewrite.js";import{replayHistoryToTarget}from"../../core/history/projection.js";import{replayToItemDocument,verifyHistoryChainWithVersion}from"../../core/history/replay.js";import{findFirstMergeConflictMarker}from"../../core/shared/conflict-markers.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE}from"../../core/shared/constants.js";import{advanceItemMutationPreconditions,assertItemMutationPreconditions,assertItemRevisionExpectationsOnUnreadable}from"../../core/store/item-mutation-precondition.js";import{PmCliError}from"../../core/shared/errors.js";import{sha256Hex}from"../../core/shared/serialization.js";import{nowIso}from"../../core/shared/time.js";import{runActiveOnReadHooks,runActiveOnWriteHooks}from"../../core/extensions/index.js";import{locateItem,readLocatedItemSnapshot}from"../../core/store/item-store.js";function decodeSalvageLine(line){let parsed;try{parsed=JSON.parse(line)}catch{if(line.trimStart().startsWith("{")&&line.includes("}"))throw new PmCliError("History salvage cannot discard a potentially complete record with trailing corruption.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return null}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))throw new PmCliError("History salvage would conceal interior corruption or a malformed record.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const entry=parsed;if(!Array.isArray(entry.patch)||![entry.ts,entry.author,entry.op,entry.before_hash,entry.after_hash].every(field=>typeof field=="string"))throw new PmCliError("History salvage requires complete history records before the invalid tail.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return entry}function inspectHistoryTail(raw){if(findFirstMergeConflictMarker(raw))throw new PmCliError("Resolve history merge conflicts before salvage.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const entries=[];let offset=0,invalidOffset,invalidLine=0;for(const[index,line]of raw.split(`
2
+ `).entries()){if(!line.trim()){offset+=line.length+1;continue}const parsed=decodeSalvageLine(line);if(parsed===null){invalidOffset===void 0&&(invalidOffset=offset,invalidLine=index+1),offset+=line.length+1;continue}if(invalidOffset!==void 0)throw new PmCliError("History salvage would discard a record or conceal interior corruption.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused",required:"Recover the damaged record from version control or a backup; no bytes were changed."});entries.push(parsed),offset+=line.length+1}const verification=verifyHistoryChainWithVersion(entries);if(!verification.ok||verification.item_hash_version===void 0)throw new PmCliError("History salvage requires a nonempty verified prefix.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused",verification_errors:verification.errors,required:"Recover an intact history prefix from version control or a backup."});return{entries,itemHashVersion:verification.item_hash_version,prefix:invalidOffset===void 0?raw:raw.slice(0,invalidOffset),receipt:invalidOffset===void 0?null:{first_invalid_line:invalidLine,discarded_bytes:Buffer.byteLength(raw.slice(invalidOffset)),discarded_sha256:sha256Hex(raw.slice(invalidOffset)),retained_entries:entries.length}}}async function readSalvageOwnership(located,settings,fallback){if(!located)return{itemRaw:null,document:fallback,live:null};const snapshot=await readLocatedItemSnapshot(located,{schema:settings.schema});return{itemRaw:snapshot.raw,document:snapshot.document??fallback,live:snapshot.document}}function assertSalvageRevision(pmRoot,id,ownership){ownership.itemRaw!==null&&ownership.live===null&&assertItemRevisionExpectationsOnUnreadable(pmRoot,id,ownership.itemRaw);const live=ownership.live??EMPTY_CANONICAL_DOCUMENT;return assertItemMutationPreconditions(pmRoot,live,id),live}async function readSalvageStream(historyPath){let bytes;try{bytes=await readFile(historyPath)}catch(error){if(isFileMissingError(error))return null;throw error}if(!isUtf8(bytes))throw new PmCliError("History salvage requires UTF-8 input; recover binary corruption from a byte-preserving backup.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});return bytes.toString("utf8")}async function salvageHistoryTail(params){const{subject,settings,options,author}=params;if([options.normalizeProvenance,options.auditOperation,options.auditContext,options.auditContextById,options.forceAuditEntry,options.mergeReceiptProof,options.mergeReceiptProofById].some(Boolean))throw new PmCliError("Tail salvage cannot be combined with other repair modes.",EXIT_CODE.USAGE);const raw=await readSalvageStream(subject.historyPath);if(raw===null)throw new PmCliError(`No history stream exists for ${subject.id}.`,EXIT_CODE.NOT_FOUND);await runActiveOnReadHooks({path:subject.historyPath,scope:"project"});const selected=inspectHistoryTail(raw),replay=replayHistoryToTarget(selected.entries,selected.entries.length-1),document=replayToItemDocument(replay);if(typeof replay.metadata.id=="string"&&replay.metadata.id!==subject.id)throw new PmCliError("History belongs to another item; salvage refused.",EXIT_CODE.CONFLICT,{code:"history_salvage_refused"});const ownership=await readSalvageOwnership(subject.located,settings,document),warnings=checkHistoryRewriteOwnership({itemDocument:ownership.document,subjectId:subject.id,author,force:options.force,settings}),version=selected.itemHashVersion,dryRun=options.dryRun===!0,changed=selected.receipt!==null;if(changed&&!dryRun){const release=await acquireLock(params.pmRoot,subject.id,settings.locks.ttl_seconds,author,!!options.force,settings.governance.force_required_for_stale_lock,settings.locks.wait_ms);try{const currentRaw=await readSalvageStream(subject.historyPath),located=await locateItem(params.pmRoot,subject.id,settings.id_prefix,settings.item_format,params.typeRegistry.type_to_folder),currentItem=located?await readFileIfExists(located.itemPath):null;if(currentRaw!==raw||currentItem!==ownership.itemRaw)throw assertSalvageRevision(params.pmRoot,subject.id,await readSalvageOwnership(located,settings,document)),new PmCliError("History or item changed while waiting for salvage lock; retry.",EXIT_CODE.CONFLICT);const live=assertSalvageRevision(params.pmRoot,subject.id,ownership),audit=sealHistoryRecord({...createHistoryEntry({hashAlgorithm:resolveHistoryHashAlgorithm(selected.entries.at(-1).hash_algorithm),nowIso:nowIso(),author,op:"history_salvage",before:document,after:document,message:options.message,context:{history_salvage:selected.receipt}}),before_hash:selected.entries.at(-1).after_hash,after_hash:selected.entries.at(-1).after_hash,item_hash_version:version});await writeHistoryRawWithRollback({historyPath:subject.historyPath,historyRawUnderLock:raw,nextHistoryRaw:`${selected.prefix}${JSON.stringify(audit)}
3
+ `}),advanceItemMutationPreconditions(params.pmRoot,live,subject.id),warnings.push(...await runActiveOnWriteHooks({path:subject.historyPath,scope:"project",op:"history_salvage:history"}))}finally{await release()}}return{id:subject.id,dry_run:dryRun,changed,history:{path:subject.historyPath,entries_scanned:selected.entries.length,chain_drift_before:!1,entries_rehashed:0,entries_patch_repaired:0,converted_replace_to_add:0,skipped_ops:0,reconciled_with_item:!1,audit_entry_added:changed&&!dryRun,verify_ok:!0,verify_errors:[],item_hash_version_before:version,item_hash_version_after:version,version_disposition:"preserved"},item:{exists:subject.located!==null,path:subject.located?.itemPath??null,matched_chain_before:null},provenance_normalization:{requested:!1,changed:!1,events_changed:0,observations_removed:0,invalid_values:[]},...selected.receipt?{salvage:selected.receipt}:{},warnings,generated_at:nowIso()}}export{inspectHistoryTail,salvageHistoryTail};
4
4
  //# sourceMappingURL=salvage.js.map
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @module sdk/history-compact
3
+ *
4
+ * Implements the pm history compact command surface and its agent-facing runtime behavior.
5
+ */
6
+ import { type ItemRevisionConflictRowFields } from "./lifecycle/item-revision.js";
1
7
  import { type HistoryCompactBulkSkipReason,type HistoryCompactScope } from "../core/history/history-compact-bulk.js";
2
8
  import { type BulkIdsValue } from "../core/io/bulk-ids-input.js";
3
9
  import type { GlobalOptions } from "../core/shared/command-types.js";
@@ -76,7 +82,7 @@ message?:string;
76
82
  force?:boolean;
77
83
  }
78
84
  /** Per-item outcome row in a bulk compaction pass. */
79
- export interface HistoryCompactBulkItemResult {
85
+ export interface HistoryCompactBulkItemResult extends ItemRevisionConflictRowFields {
80
86
  /** Stable identifier used to reference this record across commands and storage. */
81
87
  id:string;
82
88
  /** Value that configures or reports outcome for this contract. */
@@ -1,2 +1,2 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c6009e5f-840e-5e3a-b8b9-6e9d42d63410")}catch{}})();import fs from"node:fs/promises";import{resolveHistoryHashAlgorithm}from"../core/history/digest.js";import path from"node:path";import{createHistoryEntry,hashHistoryStream,sealHistoryRecord,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS}from"../core/history/history.js";import{selectHistoryCompactBulkTargets}from"../core/history/history-compact-bulk.js";import{cloneEmptyReplayDocument,replayHashVerificationCandidates,replayToItemDocument,toReplayDocument}from"../core/history/replay.js";import{applyHistoryPatch}from"../core/history/projection.js";import{historyVersionOffset}from"../core/history/version-address.js";import{lifecycleClassifierFromStatusRegistry}from"../core/governance/metadata-coverage.js";import{resolveRuntimeStatusRegistry}from"../core/schema/runtime-schema.js";import{listAllItemMetadataLight}from"../core/store/item-store.js";import{pathExists}from"../core/fs/fs-utils.js";import{normalizeBulkIdsValue,parseBulkIdsText}from"../core/io/bulk-ids-input.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{nowIso}from"../core/shared/time.js";import{runActiveOnReadHooks}from"../core/extensions/index.js";import{resolveHistoryWorkspace,resolveHistorySubject}from"./history/subject.js";import{runHistoryMaintenance}from"./history/maintenance.js";function parseBeforeBoundary(before,entries){if(before===void 0)return{kind:"default",raw:null,compactCount:entries.length,retainedCount:0};const raw=before.trim();if(raw.length===0)throw new PmCliError("history-compact --before requires a non-empty value.",EXIT_CODE.USAGE);if(/^\d+$/.test(raw)){const version=Number.parseInt(raw,10),offset=historyVersionOffset(entries);if(!Number.isSafeInteger(version)||version<offset+1||version>offset+entries.length+1)throw new PmCliError(`history-compact --before version must be between ${offset+1} and ${offset+entries.length+1}.`,EXIT_CODE.USAGE);const compactCount2=version-offset-1;return{kind:"version",raw,compactCount:compactCount2,retainedCount:entries.length-compactCount2}}const beforeTs=Date.parse(raw);if(!Number.isFinite(beforeTs))throw new PmCliError(`Invalid history-compact --before value "${before}". Use a version number or ISO timestamp.`,EXIT_CODE.USAGE);let compactCount=0;for(const[index,entry]of entries.entries()){const entryTs=Date.parse(entry.ts);if(!Number.isFinite(entryTs))throw new PmCliError(`History for this item contains invalid timestamp at entry ${index+1}.`,EXIT_CODE.GENERIC_FAILURE);if(entryTs>=beforeTs)break;compactCount+=1}return{kind:"timestamp",raw,compactCount,retainedCount:entries.length-compactCount}}function replayHistoryAndResolveCheckpoint(entries,compactCount){let replay=cloneEmptyReplayDocument(),checkpoint=cloneEmptyReplayDocument();for(let index=0;index<entries.length;index+=1){const entry=entries[index];replay=applyHistoryPatch(replay,entry.patch,index+1,entry.op),index+1===compactCount&&(checkpoint=structuredClone(replay))}return{checkpoint,finalReplay:replay}}function describeHistoryCompactCurrentItem(loadedItem,historyEntries){if(!loadedItem)return{loadedItem:null,currentItemRawBeforeLock:null,matchedChainBefore:null};const lastEntry=historyEntries[historyEntries.length-1];return{loadedItem,currentItemRawBeforeLock:loadedItem.raw,matchedChainBefore:SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(version=>(lastEntry.item_hash_version===void 0||lastEntry.item_hash_version===version)&&replayHashVerificationCandidates(toReplayDocument(loadedItem.document),version,resolveHistoryHashAlgorithm(lastEntry.hash_algorithm)).includes(lastEntry.after_hash))}}function buildHistoryCompactMessage(options,boundary){return typeof options.message=="string"&&options.message.trim().length>0?options.message:boundary.raw===null?`history-compact compacted full stream (${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"}).`:`history-compact compacted ${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"} before ${boundary.raw}.`}function buildHistoryCompactBaselineMessage(boundary){return boundary.raw===null?`history-compact baseline snapshot after compacting ${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"}.`:`history-compact baseline snapshot before ${boundary.raw}.`}function buildHistoryCompactEntries(params){if(!params.changed)return{rewrittenEntries:params.historyEntries,baselineEntryAdded:!1,auditEntryAdded:!1};const{checkpoint,finalReplay}=replayHistoryAndResolveCheckpoint(params.historyEntries,params.boundary.compactCount),retained=params.historyEntries.slice(params.boundary.compactCount),offset=historyVersionOffset(params.historyEntries,!0),checkpointEntry=params.historyEntries[params.boundary.compactCount-1],baselineEntry=createHistoryEntry({hashAlgorithm:resolveHistoryHashAlgorithm(checkpointEntry.hash_algorithm),nowIso:params.historyEntries[params.boundary.compactCount-1].ts,author:params.author,op:"history_compact_baseline",before:replayToItemDocument(cloneEmptyReplayDocument()),after:replayToItemDocument(checkpoint),message:buildHistoryCompactBaselineMessage(params.boundary),context:{history_compaction:{contract_version:1,version_offset:offset===null?null:offset+params.boundary.compactCount-1,checkpoint_timestamp_semantics:"last_compacted_entry",pruned_entry_count:params.boundary.compactCount,pruned_stream_digest:hashHistoryStream(params.historyEntries.slice(0,params.boundary.compactCount)),retained_proof:"stream_digest_and_checkpoint",limitation:"individual_pruned_entries_require_pre_compaction_stream"}}}),rewrittenEntries=[sealHistoryRecord({...baselineEntry,before_hash:replayHashVerificationCandidates(cloneEmptyReplayDocument(),checkpointEntry.item_hash_version??1,resolveHistoryHashAlgorithm(checkpointEntry.hash_algorithm))[0],after_hash:checkpointEntry.after_hash,item_hash_version:checkpointEntry.item_hash_version}),...retained];return params.dryRun||rewrittenEntries.push(createHistoryEntry({nowIso:nowIso(),author:params.author,op:"history_compact",before:replayToItemDocument(finalReplay),after:replayToItemDocument(finalReplay),message:buildHistoryCompactMessage(params.options,params.boundary)})),{rewrittenEntries,baselineEntryAdded:!0,auditEntryAdded:!params.dryRun}}async function runHistoryCompact(id,options,global2){const{pmRoot,settings,typeRegistry}=await resolveHistoryWorkspace(global2.path),subject=await resolveHistorySubject(pmRoot,id,settings,typeRegistry.type_to_folder);return runHistoryMaintenance({pmRoot,subject,settings,typeRegistry,operation:"history-compact",options,transform:snapshot=>buildHistoryCompactPlan(subject,options,snapshot)})}function buildHistoryCompactPlan(subject,options,snapshot){const historyPath=subject.historyPath,historyEntries=snapshot.entries,chainVerification=snapshot.verification;if(!chainVerification.ok)throw new PmCliError(`history-compact requires a valid history chain (${chainVerification.errors.join(", ")}). Run pm history-repair ${subject.id} first.`,EXIT_CODE.CONFLICT);const boundary=parseBeforeBoundary(options.before,historyEntries),changed=boundary.compactCount>0,dryRun=!!options.dryRun,author=snapshot.author,warnings=[];changed||warnings.push("history_compact_noop_before_boundary");const currentItem=describeHistoryCompactCurrentItem(snapshot.loadedItem,historyEntries);currentItem.matchedChainBefore===!1&&warnings.push("history_compact_item_chain_mismatch");const{rewrittenEntries,baselineEntryAdded,auditEntryAdded}=buildHistoryCompactEntries({historyEntries,boundary,changed,dryRun,author,options}),offset=historyVersionOffset(historyEntries,!0),firstRetainedEntry=boundary.retainedCount>0&&offset!==null?offset+boundary.compactCount+1:null;return{changed,rewrittenEntries,report:({verification:rewrittenVerify,warnings:writeWarnings})=>({id:subject.id,dry_run:dryRun,changed,compact_boundary:{kind:boundary.kind,before:boundary.raw,entries_compacted:boundary.compactCount,entries_retained:boundary.retainedCount,first_retained_entry:firstRetainedEntry},history:{path:historyPath,entries_scanned:historyEntries.length,entries_after:rewrittenEntries.length,baseline_entry_added:baselineEntryAdded,audit_entry_added:auditEntryAdded,verify_ok:rewrittenVerify.ok,verify_errors:rewrittenVerify.errors},item:{exists:subject.located!==null,path:subject.located?.itemPath??null,matched_chain_before:currentItem.matchedChainBefore},warnings:[...new Set([...warnings,...writeWarnings])].sort((left,right)=>left.localeCompare(right)),generated_at:nowIso()})}}const HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES=3;function normalizeHistoryCompactBulkOptions(options){for(const key of["allOver","minEntries"]){const value=options[key];if(value!==void 0&&(!Number.isSafeInteger(value)||value<0))throw new PmCliError(`history-compact ${key} must be a non-negative safe integer.`,EXIT_CODE.USAGE)}const normalizedIdsText=normalizeBulkIdsValue(options.ids);if(options.ids!==void 0&&normalizedIdsText==="")throw new PmCliError("history-compact ids requires at least one valid item ID.",EXIT_CODE.USAGE,{code:"bulk_ids_input_empty",required:"Provide one or more string or finite numeric IDs; non-finite and unsupported selector values are rejected."});return{...options,ids:normalizedIdsText===void 0?void 0:parseBulkIdsText(normalizedIdsText)}}function assertHistoryCompactTarget(id,bulk){const hasIds=bulk.ids!==void 0&&bulk.ids.length>0,hasScan=bulk.allOver!==void 0||bulk.scope!==void 0;if((id!==void 0?1:0)+(hasIds?1:0)+(hasScan?1:0)==0)throw new PmCliError("history-compact: provide an item <id>, or a bulk selector (--ids, --all-over <N>, --closed, or --all-streams).",EXIT_CODE.USAGE);if(id!==void 0&&(hasIds||hasScan))throw new PmCliError("history-compact: <id> and bulk selectors (--ids/--all-over/--closed/--all-streams) are mutually exclusive; pass one item id, or use bulk mode without a positional id.",EXIT_CODE.USAGE);if(hasIds&&hasScan)throw new PmCliError("history-compact: --ids is mutually exclusive with --all-over/--closed/--all-streams; pass an explicit id list or a scan selector, not both.",EXIT_CODE.USAGE)}function countHistoryStreamEntries(raw){let count=0;for(const line of raw.split(/\r?\n/))line.trim().length>0&&(count+=1);return count}async function collectHistoryCompactBulkCandidates(params){const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),classifier=lifecycleClassifierFromStatusRegistry(statusRegistry),items=await listAllItemMetadataLight(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema),bucketById=new Map(items.map(item=>[item.id,classifier.classify(item.status)])),historyDir=path.join(params.pmRoot,"history"),candidates=[],preselectionErrors=[];if(!await pathExists(historyDir))return{candidates,preselectionErrors};const historyFiles=(await fs.readdir(historyDir)).filter(entry=>entry.endsWith(".jsonl")).sort((left,right)=>left.localeCompare(right));for(const fileName of historyFiles){const historyPath=path.join(historyDir,fileName),id=fileName.slice(0,-6);try{const raw=await fs.readFile(historyPath,"utf8");await runActiveOnReadHooks({path:historyPath,scope:"project"}),candidates.push({id,entries:countHistoryStreamEntries(raw),bucket:bucketById.get(id)??null})}catch(error){preselectionErrors.push({id,outcome:"errored",entries_before:0,entries_after:null,skip_reason:null,changed:!1,error:error instanceof Error?error.message:String(error)})}}return{candidates,preselectionErrors}}async function runHistoryCompactBulkRow(params){if(!params.row.selected)return{selected:!1,compacted:!1,errored:!1,result:{id:params.row.id,outcome:"skipped",entries_before:params.row.entries,entries_after:null,skip_reason:params.row.skip_reason,changed:!1,error:null}};try{const result=await runHistoryCompact(params.row.id,{dryRun:params.dryRun,author:params.options.author,message:params.options.message,force:params.options.force},params.global);return{selected:!0,compacted:!0,errored:!1,result:{id:params.row.id,outcome:"compacted",entries_before:params.row.entries,entries_after:result.history.entries_after,skip_reason:null,changed:result.changed,error:null}}}catch(error){return{selected:!0,compacted:!1,errored:!0,result:{id:params.row.id,outcome:"errored",entries_before:params.row.entries,entries_after:null,skip_reason:null,changed:!1,error:error instanceof Error?error.message:String(error)}}}}async function runHistoryCompactBulk(options,global2){const normalizedOptions=normalizeHistoryCompactBulkOptions(options),{pmRoot,settings,typeRegistry}=await resolveHistoryWorkspace(global2.path),{candidates,preselectionErrors}=await collectHistoryCompactBulkCandidates({pmRoot,settings,typeToFolder:typeRegistry.type_to_folder}),mode=normalizedOptions.ids!==void 0&&normalizedOptions.ids.length>0?"ids":"scan",minEntries=options.minEntries??HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES,policy=settings.history.compact_policy,policyThresholdApplied=mode==="scan"&&options.allOver===void 0&&policy.enabled,allOver=options.allOver??(policyThresholdApplied?policy.max_entries:void 0),selection=selectHistoryCompactBulkTargets(candidates,{ids:normalizedOptions.ids,scope:options.scope,minEntries,allOver}),dryRun=!!options.dryRun,results=[...preselectionErrors],totals={streams_considered:candidates.length+preselectionErrors.length,selected:0,items_compacted:0,items_skipped:0,items_errored:preselectionErrors.length};for(const row of selection){const outcome=await runHistoryCompactBulkRow({row,options:normalizedOptions,dryRun,global:global2});if(results.push(outcome.result),!outcome.selected){totals.items_skipped+=1;continue}totals.selected+=1,outcome.compacted&&(totals.items_compacted+=1),outcome.errored&&(totals.items_errored+=1)}return{bulk:!0,dry_run:dryRun,mode,scope:options.scope??null,criteria:{min_entries:minEntries,all_over:allOver??null,policy_threshold_applied:policyThresholdApplied},totals,results,generated_at:nowIso()}}export{HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES,assertHistoryCompactTarget,runHistoryCompact,runHistoryCompactBulk};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8e3e7c46-1929-5ff4-84b0-d4c0605148c2")}catch{}})();import{itemRevisionConflictRowFields}from"./lifecycle/item-revision.js";import fs from"node:fs/promises";import{resolveHistoryHashAlgorithm}from"../core/history/digest.js";import path from"node:path";import{createHistoryEntry,hashHistoryStream,sealHistoryRecord,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS}from"../core/history/history.js";import{selectHistoryCompactBulkTargets}from"../core/history/history-compact-bulk.js";import{cloneEmptyReplayDocument,replayHashVerificationCandidates,replayToItemDocument,toReplayDocument}from"../core/history/replay.js";import{applyHistoryPatch}from"../core/history/projection.js";import{historyVersionOffset}from"../core/history/version-address.js";import{lifecycleClassifierFromStatusRegistry}from"../core/governance/metadata-coverage.js";import{resolveRuntimeStatusRegistry}from"../core/schema/runtime-schema.js";import{listAllItemMetadataLight}from"../core/store/item-store.js";import{pathExists}from"../core/fs/fs-utils.js";import{normalizeBulkIdsValue,parseBulkIdsText}from"../core/io/bulk-ids-input.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{nowIso}from"../core/shared/time.js";import{runActiveOnReadHooks}from"../core/extensions/index.js";import{resolveHistoryWorkspace,resolveHistorySubject}from"./history/subject.js";import{runHistoryMaintenance}from"./history/maintenance.js";function parseBeforeBoundary(before,entries){if(before===void 0)return{kind:"default",raw:null,compactCount:entries.length,retainedCount:0};const raw=before.trim();if(raw.length===0)throw new PmCliError("history-compact --before requires a non-empty value.",EXIT_CODE.USAGE);if(/^\d+$/.test(raw)){const version=Number.parseInt(raw,10),offset=historyVersionOffset(entries);if(!Number.isSafeInteger(version)||version<offset+1||version>offset+entries.length+1)throw new PmCliError(`history-compact --before version must be between ${offset+1} and ${offset+entries.length+1}.`,EXIT_CODE.USAGE);const compactCount2=version-offset-1;return{kind:"version",raw,compactCount:compactCount2,retainedCount:entries.length-compactCount2}}const beforeTs=Date.parse(raw);if(!Number.isFinite(beforeTs))throw new PmCliError(`Invalid history-compact --before value "${before}". Use a version number or ISO timestamp.`,EXIT_CODE.USAGE);let compactCount=0;for(const[index,entry]of entries.entries()){const entryTs=Date.parse(entry.ts);if(!Number.isFinite(entryTs))throw new PmCliError(`History for this item contains invalid timestamp at entry ${index+1}.`,EXIT_CODE.GENERIC_FAILURE);if(entryTs>=beforeTs)break;compactCount+=1}return{kind:"timestamp",raw,compactCount,retainedCount:entries.length-compactCount}}function replayHistoryAndResolveCheckpoint(entries,compactCount){let replay=cloneEmptyReplayDocument(),checkpoint=cloneEmptyReplayDocument();for(let index=0;index<entries.length;index+=1){const entry=entries[index];replay=applyHistoryPatch(replay,entry.patch,index+1,entry.op),index+1===compactCount&&(checkpoint=structuredClone(replay))}return{checkpoint,finalReplay:replay}}function describeHistoryCompactCurrentItem(loadedItem,historyEntries){if(!loadedItem)return{loadedItem:null,currentItemRawBeforeLock:null,matchedChainBefore:null};const lastEntry=historyEntries[historyEntries.length-1];return{loadedItem,currentItemRawBeforeLock:loadedItem.raw,matchedChainBefore:SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(version=>(lastEntry.item_hash_version===void 0||lastEntry.item_hash_version===version)&&replayHashVerificationCandidates(toReplayDocument(loadedItem.document),version,resolveHistoryHashAlgorithm(lastEntry.hash_algorithm)).includes(lastEntry.after_hash))}}function buildHistoryCompactMessage(options,boundary){return typeof options.message=="string"&&options.message.trim().length>0?options.message:boundary.raw===null?`history-compact compacted full stream (${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"}).`:`history-compact compacted ${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"} before ${boundary.raw}.`}function buildHistoryCompactBaselineMessage(boundary){return boundary.raw===null?`history-compact baseline snapshot after compacting ${boundary.compactCount} entr${boundary.compactCount===1?"y":"ies"}.`:`history-compact baseline snapshot before ${boundary.raw}.`}function buildHistoryCompactEntries(params){if(!params.changed)return{rewrittenEntries:params.historyEntries,baselineEntryAdded:!1,auditEntryAdded:!1};const{checkpoint,finalReplay}=replayHistoryAndResolveCheckpoint(params.historyEntries,params.boundary.compactCount),retained=params.historyEntries.slice(params.boundary.compactCount),offset=historyVersionOffset(params.historyEntries,!0),checkpointEntry=params.historyEntries[params.boundary.compactCount-1],baselineEntry=createHistoryEntry({hashAlgorithm:resolveHistoryHashAlgorithm(checkpointEntry.hash_algorithm),nowIso:params.historyEntries[params.boundary.compactCount-1].ts,author:params.author,op:"history_compact_baseline",before:replayToItemDocument(cloneEmptyReplayDocument()),after:replayToItemDocument(checkpoint),message:buildHistoryCompactBaselineMessage(params.boundary),context:{history_compaction:{contract_version:1,version_offset:offset===null?null:offset+params.boundary.compactCount-1,checkpoint_timestamp_semantics:"last_compacted_entry",pruned_entry_count:params.boundary.compactCount,pruned_stream_digest:hashHistoryStream(params.historyEntries.slice(0,params.boundary.compactCount)),retained_proof:"stream_digest_and_checkpoint",limitation:"individual_pruned_entries_require_pre_compaction_stream"}}}),rewrittenEntries=[sealHistoryRecord({...baselineEntry,before_hash:replayHashVerificationCandidates(cloneEmptyReplayDocument(),checkpointEntry.item_hash_version??1,resolveHistoryHashAlgorithm(checkpointEntry.hash_algorithm))[0],after_hash:checkpointEntry.after_hash,item_hash_version:checkpointEntry.item_hash_version}),...retained];return params.dryRun||rewrittenEntries.push(createHistoryEntry({nowIso:nowIso(),author:params.author,op:"history_compact",before:replayToItemDocument(finalReplay),after:replayToItemDocument(finalReplay),message:buildHistoryCompactMessage(params.options,params.boundary)})),{rewrittenEntries,baselineEntryAdded:!0,auditEntryAdded:!params.dryRun}}async function runHistoryCompact(id,options,global2){const{pmRoot,settings,typeRegistry}=await resolveHistoryWorkspace(global2.path),subject=await resolveHistorySubject(pmRoot,id,settings,typeRegistry.type_to_folder);return runHistoryMaintenance({pmRoot,subject,settings,typeRegistry,operation:"history-compact",options,transform:snapshot=>buildHistoryCompactPlan(subject,options,snapshot)})}function buildHistoryCompactPlan(subject,options,snapshot){const historyPath=subject.historyPath,historyEntries=snapshot.entries,chainVerification=snapshot.verification;if(!chainVerification.ok)throw new PmCliError(`history-compact requires a valid history chain (${chainVerification.errors.join(", ")}). Run pm history-repair ${subject.id} first.`,EXIT_CODE.CONFLICT);const boundary=parseBeforeBoundary(options.before,historyEntries),changed=boundary.compactCount>0,dryRun=!!options.dryRun,author=snapshot.author,warnings=[];changed||warnings.push("history_compact_noop_before_boundary");const currentItem=describeHistoryCompactCurrentItem(snapshot.loadedItem,historyEntries);currentItem.matchedChainBefore===!1&&warnings.push("history_compact_item_chain_mismatch");const{rewrittenEntries,baselineEntryAdded,auditEntryAdded}=buildHistoryCompactEntries({historyEntries,boundary,changed,dryRun,author,options}),offset=historyVersionOffset(historyEntries,!0),firstRetainedEntry=boundary.retainedCount>0&&offset!==null?offset+boundary.compactCount+1:null;return{changed,rewrittenEntries,report:({verification:rewrittenVerify,warnings:writeWarnings})=>({id:subject.id,dry_run:dryRun,changed,compact_boundary:{kind:boundary.kind,before:boundary.raw,entries_compacted:boundary.compactCount,entries_retained:boundary.retainedCount,first_retained_entry:firstRetainedEntry},history:{path:historyPath,entries_scanned:historyEntries.length,entries_after:rewrittenEntries.length,baseline_entry_added:baselineEntryAdded,audit_entry_added:auditEntryAdded,verify_ok:rewrittenVerify.ok,verify_errors:rewrittenVerify.errors},item:{exists:subject.located!==null,path:subject.located?.itemPath??null,matched_chain_before:currentItem.matchedChainBefore},warnings:[...new Set([...warnings,...writeWarnings])].sort((left,right)=>left.localeCompare(right)),generated_at:nowIso()})}}const HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES=3;function normalizeHistoryCompactBulkOptions(options){for(const key of["allOver","minEntries"]){const value=options[key];if(value!==void 0&&(!Number.isSafeInteger(value)||value<0))throw new PmCliError(`history-compact ${key} must be a non-negative safe integer.`,EXIT_CODE.USAGE)}const normalizedIdsText=normalizeBulkIdsValue(options.ids);if(options.ids!==void 0&&normalizedIdsText==="")throw new PmCliError("history-compact ids requires at least one valid item ID.",EXIT_CODE.USAGE,{code:"bulk_ids_input_empty",required:"Provide one or more string or finite numeric IDs; non-finite and unsupported selector values are rejected."});return{...options,ids:normalizedIdsText===void 0?void 0:parseBulkIdsText(normalizedIdsText)}}function assertHistoryCompactTarget(id,bulk){const hasIds=bulk.ids!==void 0&&bulk.ids.length>0,hasScan=bulk.allOver!==void 0||bulk.scope!==void 0;if((id!==void 0?1:0)+(hasIds?1:0)+(hasScan?1:0)==0)throw new PmCliError("history-compact: provide an item <id>, or a bulk selector (--ids, --all-over <N>, --closed, or --all-streams).",EXIT_CODE.USAGE);if(id!==void 0&&(hasIds||hasScan))throw new PmCliError("history-compact: <id> and bulk selectors (--ids/--all-over/--closed/--all-streams) are mutually exclusive; pass one item id, or use bulk mode without a positional id.",EXIT_CODE.USAGE);if(hasIds&&hasScan)throw new PmCliError("history-compact: --ids is mutually exclusive with --all-over/--closed/--all-streams; pass an explicit id list or a scan selector, not both.",EXIT_CODE.USAGE)}function countHistoryStreamEntries(raw){let count=0;for(const line of raw.split(/\r?\n/))line.trim().length>0&&(count+=1);return count}async function collectHistoryCompactBulkCandidates(params){const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),classifier=lifecycleClassifierFromStatusRegistry(statusRegistry),items=await listAllItemMetadataLight(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema),bucketById=new Map(items.map(item=>[item.id,classifier.classify(item.status)])),historyDir=path.join(params.pmRoot,"history"),candidates=[],preselectionErrors=[];if(!await pathExists(historyDir))return{candidates,preselectionErrors};const historyFiles=(await fs.readdir(historyDir)).filter(entry=>entry.endsWith(".jsonl")).sort((left,right)=>left.localeCompare(right));for(const fileName of historyFiles){const historyPath=path.join(historyDir,fileName),id=fileName.slice(0,-6);try{const raw=await fs.readFile(historyPath,"utf8");await runActiveOnReadHooks({path:historyPath,scope:"project"}),candidates.push({id,entries:countHistoryStreamEntries(raw),bucket:bucketById.get(id)??null})}catch(error){preselectionErrors.push({id,outcome:"errored",entries_before:0,entries_after:null,skip_reason:null,changed:!1,error:error instanceof Error?error.message:String(error)})}}return{candidates,preselectionErrors}}async function runHistoryCompactBulkRow(params){if(!params.row.selected)return{selected:!1,compacted:!1,errored:!1,result:{id:params.row.id,outcome:"skipped",entries_before:params.row.entries,entries_after:null,skip_reason:params.row.skip_reason,changed:!1,error:null}};try{const result=await runHistoryCompact(params.row.id,{dryRun:params.dryRun,author:params.options.author,message:params.options.message,force:params.options.force},params.global);return{selected:!0,compacted:!0,errored:!1,result:{id:params.row.id,outcome:"compacted",entries_before:params.row.entries,entries_after:result.history.entries_after,skip_reason:null,changed:result.changed,error:null}}}catch(error){return{selected:!0,compacted:!1,errored:!0,result:{id:params.row.id,outcome:"errored",entries_before:params.row.entries,entries_after:null,skip_reason:null,changed:!1,error:error instanceof Error?error.message:String(error),...await itemRevisionConflictRowFields(error,params.pmRoot)}}}}async function runHistoryCompactBulk(options,global2){const normalizedOptions=normalizeHistoryCompactBulkOptions(options),{pmRoot,settings,typeRegistry}=await resolveHistoryWorkspace(global2.path),{candidates,preselectionErrors}=await collectHistoryCompactBulkCandidates({pmRoot,settings,typeToFolder:typeRegistry.type_to_folder}),mode=normalizedOptions.ids!==void 0&&normalizedOptions.ids.length>0?"ids":"scan",minEntries=options.minEntries??HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES,policy=settings.history.compact_policy,policyThresholdApplied=mode==="scan"&&options.allOver===void 0&&policy.enabled,allOver=options.allOver??(policyThresholdApplied?policy.max_entries:void 0),selection=selectHistoryCompactBulkTargets(candidates,{ids:normalizedOptions.ids,scope:options.scope,minEntries,allOver}),dryRun=!!options.dryRun,results=[...preselectionErrors],totals={streams_considered:candidates.length+preselectionErrors.length,selected:0,items_compacted:0,items_skipped:0,items_errored:preselectionErrors.length};for(const row of selection){const outcome=await runHistoryCompactBulkRow({pmRoot,row,options:normalizedOptions,dryRun,global:global2});if(results.push(outcome.result),!outcome.selected){totals.items_skipped+=1;continue}totals.selected+=1,outcome.compacted&&(totals.items_compacted+=1),outcome.errored&&(totals.items_errored+=1)}return{bulk:!0,dry_run:dryRun,mode,scope:options.scope??null,criteria:{min_entries:minEntries,all_over:allOver??null,policy_threshold_applied:policyThresholdApplied},totals,results,generated_at:nowIso()}}export{HISTORY_COMPACT_BULK_DEFAULT_MIN_ENTRIES,assertHistoryCompactTarget,runHistoryCompact,runHistoryCompactBulk};
2
2
  //# sourceMappingURL=history-compact.js.map
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Implements the pm history repair command surface and its agent-facing runtime behavior.
5
5
  */
6
+ import { type ItemRevisionConflictRowFields } from "./lifecycle/item-revision.js";
6
7
  import { type HistorySalvageReceipt } from "./history/salvage.js";
7
8
  import { type ReplayDocument } from "../core/history/replay.js";
8
9
  import type { GlobalOptions } from "../core/shared/command-types.js";
@@ -147,7 +148,7 @@ export declare function analyzeReconciliationDiscard(entries:HistoryEntry[],fina
147
148
  /** Implements run history repair for the public runtime surface of this module. */
148
149
  export declare function runHistoryRepair(id:string,options:HistoryRepairCommandOptions,global:GlobalOptions):Promise<HistoryRepairResult>;
149
150
  /** Documents the history repair all stream result payload exchanged by command, SDK, and package integrations. */
150
- export interface HistoryRepairAllStreamResult {
151
+ export interface HistoryRepairAllStreamResult extends ItemRevisionConflictRowFields {
151
152
  /** Stable identifier used to reference this record across commands and storage. */
152
153
  id:string;
153
154
  /** Value that configures or reports outcome for this contract. */