@unbrained/pm-cli 2026.10.15 → 2026.10.18

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 (275) hide show
  1. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/AGENTS.md +1 -0
  4. package/CHANGELOG.md +45 -0
  5. package/dist/cli/extension-command-options.d.ts +3 -1
  6. package/dist/cli/extension-command-options.js +1 -1
  7. package/dist/cli/help-content.js +2 -2
  8. package/dist/cli/register-list-query.js +2 -2
  9. package/dist/cli/register-mutation.js +2 -2
  10. package/dist/cli/register-operations.js +1 -1
  11. package/dist/cli/register-structured-mutation.d.ts +0 -5
  12. package/dist/cli/register-structured-mutation.js +1 -1
  13. package/dist/cli/runtime/invocation-options.js +1 -1
  14. package/dist/cli-bundle/bundle-manifest.json +1 -1
  15. package/dist/cli-bundle/chunks/{chunk-7VHINXZP.js → chunk-4GA4MUTE.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-RJ5N44WY.js → chunk-4V6ONLI6.js} +2 -2
  17. package/dist/cli-bundle/chunks/{chunk-LNKLQYBG.js → chunk-6VZKYJW7.js} +2 -2
  18. package/dist/cli-bundle/chunks/chunk-7PATQWTH.js +20 -0
  19. package/dist/cli-bundle/chunks/chunk-7WIEAGDS.js +2 -0
  20. package/dist/cli-bundle/chunks/{chunk-52EZH2QQ.js → chunk-AETP4JEM.js} +2 -2
  21. package/dist/cli-bundle/chunks/{chunk-WBBW3WQX.js → chunk-FIJOSX2C.js} +28 -28
  22. package/dist/cli-bundle/chunks/chunk-LUKVNL72.js +2 -0
  23. package/dist/cli-bundle/chunks/{chunk-NC3QVGDD.js → chunk-OJ77ZQN3.js} +2 -2
  24. package/dist/cli-bundle/chunks/chunk-PYRREEUB.js +30 -0
  25. package/dist/cli-bundle/chunks/chunk-RHQJ6VWC.js +237 -0
  26. package/dist/cli-bundle/chunks/{chunk-N56CAQBU.js → chunk-RNABUEFB.js} +52 -52
  27. package/dist/cli-bundle/chunks/chunk-TO6CIV4C.js +2 -0
  28. package/dist/cli-bundle/chunks/{chunk-JGKTOBVB.js → chunk-ZZED447K.js} +4 -4
  29. package/dist/cli-bundle/chunks/{register-list-query-FKKFQ66D.js → register-list-query-PUCVYYBD.js} +7 -7
  30. package/dist/cli-bundle/chunks/register-mutation-GGGVBXD5.js +20 -0
  31. package/dist/cli-bundle/chunks/{register-operations-GEQ2H7PS.js → register-operations-NRZ6Q4QE.js} +2 -2
  32. package/dist/cli-bundle/chunks/{register-setup-PSJTQBBO.js → register-setup-MV3P3YSF.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-2MPQUMTF.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/{chunk-H3P77KVU.js → chunk-5UKCSZWT.js} +2 -2
  35. package/dist/cli-bundle/focused-chunks/{chunk-4KQFMOM7.js → chunk-A4ZHHTEX.js} +5 -5
  36. package/dist/cli-bundle/focused-chunks/{chunk-5OO54BIV.js → chunk-B4YLP5ZB.js} +3 -3
  37. package/dist/cli-bundle/focused-chunks/chunk-BFEMT5U3.js +20 -0
  38. package/dist/cli-bundle/focused-chunks/{chunk-THYQR3ON.js → chunk-FW7CSSKL.js} +61 -61
  39. package/dist/cli-bundle/focused-chunks/{chunk-3RNUMVK4.js → chunk-HYPRPSYD.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-FQKPOZKS.js → chunk-IRVL4UXR.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/{chunk-Q4VNCTR2.js → chunk-L55KQ2KT.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/{chunk-52I2SNKJ.js → chunk-MASIOFPG.js} +2 -2
  43. package/dist/cli-bundle/focused-chunks/chunk-RJ3EIHDU.js +26 -0
  44. package/dist/cli-bundle/focused-chunks/chunk-SEL4Z2OO.js +167 -0
  45. package/dist/cli-bundle/focused-chunks/{chunk-TYLG5VEB.js → chunk-TB7F4FCR.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/{chunk-KIIFVULU.js → chunk-TZUIBG3P.js} +2 -2
  47. package/dist/cli-bundle/focused-chunks/{chunk-N6FUKTZS.js → chunk-Z7YIFCNE.js} +2 -2
  48. package/dist/cli-bundle/focused-chunks/{chunk-5KRACGBK.js → chunk-ZDBS2DCT.js} +3 -3
  49. package/dist/cli-bundle/main.js +27 -27
  50. package/dist/cli-bundle/sdk-authoring.js +1 -1
  51. package/dist/cli-bundle/sdk-contracts.js +2 -2
  52. package/dist/cli-bundle/sdk-core.js +23 -23
  53. package/dist/cli-bundle/sdk-governance.js +1 -1
  54. package/dist/cli-bundle/sdk-graph.js +1 -1
  55. package/dist/cli-bundle/sdk-merge.js +55 -54
  56. package/dist/cli-bundle/sdk-query.js +1 -1
  57. package/dist/cli-bundle/sdk-runtime.js +1 -1
  58. package/dist/cli-bundle/sdk-testing.js +1 -1
  59. package/dist/cli-bundle/sdk.js +7 -7
  60. package/dist/core/extensions/extension-types.d.ts +15 -0
  61. package/dist/core/extensions/extension-types.js +1 -1
  62. package/dist/core/extensions/flag-value-types.d.ts +16 -0
  63. package/dist/core/extensions/flag-value-types.js +1 -1
  64. package/dist/core/extensions/registration-contracts.js +1 -1
  65. package/dist/core/history/event-index.d.ts +8 -1
  66. package/dist/core/history/event-index.js +19 -18
  67. package/dist/core/item/item-format.js +3 -3
  68. package/dist/core/lock/lock.d.ts +8 -1
  69. package/dist/core/lock/lock.js +3 -3
  70. package/dist/core/output/mutation-projection.d.ts +0 -21
  71. package/dist/core/output/mutation-projection.js +1 -1
  72. package/dist/core/output/output.js +2 -2
  73. package/dist/core/schema/type-workflows.d.ts +1 -1
  74. package/dist/core/schema/type-workflows.js +1 -1
  75. package/dist/core/shared/text-normalization.d.ts +2 -0
  76. package/dist/core/shared/text-normalization.js +1 -1
  77. package/dist/core/store/item-mutation-precondition.d.ts +11 -0
  78. package/dist/core/store/item-mutation-precondition.js +2 -0
  79. package/dist/core/store/item-store.js +1 -1
  80. package/dist/core/store/paths.js +1 -1
  81. package/dist/core/telemetry/policy.d.ts +2 -0
  82. package/dist/core/telemetry/policy.js +1 -1
  83. package/dist/core/telemetry/runtime.d.ts +5 -3
  84. package/dist/core/telemetry/runtime.js +3 -3
  85. package/dist/mcp/server.js +1 -1
  86. package/dist/mcp/tool-definitions.js +1 -1
  87. package/dist/sdk/cli-contracts/agent-output-contracts.js +1 -1
  88. package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
  89. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
  90. package/dist/sdk/cli-contracts/registration-helpers.d.ts +1 -1
  91. package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
  92. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  93. package/dist/sdk/cli-contracts/tool-schema.js +1 -1
  94. package/dist/sdk/context-intent-contracts.js +1 -1
  95. package/dist/sdk/core.d.ts +2 -1
  96. package/dist/sdk/core.js +1 -1
  97. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
  98. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
  99. package/dist/sdk/governance/health/projection.d.ts +37 -0
  100. package/dist/sdk/governance/health/projection.js +2 -0
  101. package/dist/sdk/governance/health.d.ts +7 -18
  102. package/dist/sdk/governance/health.js +2 -2
  103. package/dist/sdk/guide-topics.js +1 -1
  104. package/dist/sdk/index.d.ts +2 -1
  105. package/dist/sdk/index.js +1 -1
  106. package/dist/sdk/item-transaction.d.ts +72 -9
  107. package/dist/sdk/item-transaction.js +1 -1
  108. package/dist/sdk/lifecycle/claim.d.ts +15 -1
  109. package/dist/sdk/lifecycle/claim.js +1 -1
  110. package/dist/sdk/lifecycle/close.d.ts +2 -8
  111. package/dist/sdk/lifecycle/close.js +1 -1
  112. package/dist/sdk/lifecycle/core-item-fields.d.ts +6 -0
  113. package/dist/sdk/lifecycle/core-item-fields.js +2 -0
  114. package/dist/sdk/lifecycle/mcp-actions.js +1 -1
  115. package/dist/sdk/lifecycle/mutation-option-validation.d.ts +2 -0
  116. package/dist/sdk/lifecycle/mutation-option-validation.js +2 -0
  117. package/dist/sdk/lifecycle/release-handoff.d.ts +12 -0
  118. package/dist/sdk/lifecycle/release-handoff.js +2 -0
  119. package/dist/sdk/lifecycle/structured-mutation-plan.d.ts +33 -0
  120. package/dist/sdk/lifecycle/structured-mutation-plan.js +2 -0
  121. package/dist/sdk/lifecycle/task-composition.d.ts +2 -2
  122. package/dist/sdk/lifecycle/task-composition.js +1 -1
  123. package/dist/sdk/lifecycle/update.d.ts +3 -11
  124. package/dist/sdk/lifecycle/update.js +1 -1
  125. package/dist/sdk/lifecycle/workflow-transition.d.ts +13 -0
  126. package/dist/sdk/lifecycle/workflow-transition.js +2 -0
  127. package/dist/sdk/lifecycle-policy.d.ts +12 -2
  128. package/dist/sdk/lifecycle-policy.js +1 -1
  129. package/dist/sdk/mutation-events.js +1 -1
  130. package/dist/sdk/public-surface.json +1 -1
  131. package/dist/sdk/query/list.d.ts +2 -0
  132. package/dist/sdk/query/list.js +1 -1
  133. package/dist/sdk/read-output-budget.js +1 -1
  134. package/dist/sdk/runtime-input.js +1 -1
  135. package/dist/sdk/runtime-primitives.d.ts +1 -1
  136. package/dist/sdk/runtime-primitives.js +1 -1
  137. package/dist/sdk/runtime.d.ts +8 -8
  138. package/dist/sdk/runtime.js +1 -1
  139. package/dist/sdk/structured-mutations.d.ts +52 -1
  140. package/dist/sdk/structured-mutations.js +1 -1
  141. package/dist/sdk/workspace-transaction.js +2 -2
  142. package/dist/types.d.ts +2 -2
  143. package/dist/types.js +1 -1
  144. package/docs/AGENT_GUIDE.md +33 -4
  145. package/docs/CLOSE_EVIDENCE_RECOVERY.md +16 -7
  146. package/docs/COMMANDS.md +111 -10
  147. package/docs/CONFIGURATION.md +22 -1
  148. package/docs/DEVELOPMENT_DEPENDENCY_SECURITY.md +22 -3
  149. package/docs/ECOSYSTEM_PLANNING_REVIEW.md +5 -1
  150. package/docs/EXTENSIONS.md +1 -1
  151. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +10 -0
  152. package/docs/RELEASING.md +8 -1
  153. package/docs/SDK.md +114 -2
  154. package/docs/SDK_CONTEXT_COORDINATION.md +71 -7
  155. package/docs/SDK_STORAGE_LIFECYCLE.md +24 -2
  156. package/docs/TESTING.md +23 -0
  157. package/docs/examples/ci/github-actions-pm-extension-gate.yml +1 -1
  158. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +1 -1
  159. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +1 -1
  160. package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -1
  161. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +16 -3
  162. package/marketplace.json +1 -1
  163. package/node_modules/@opentelemetry/core/package.json +2 -1
  164. package/node_modules/@opentelemetry/instrumentation/package.json +2 -1
  165. package/node_modules/@opentelemetry/resources/package.json +2 -1
  166. package/node_modules/@opentelemetry/sdk-trace/package.json +2 -1
  167. package/node_modules/@opentelemetry/sdk-trace-base/package.json +2 -1
  168. package/node_modules/@sentry/core/build/cjs/client.js +5 -4
  169. package/node_modules/@sentry/core/build/cjs/tracing/ai/gen-ai-attributes.js +0 -4
  170. package/node_modules/@sentry/core/build/cjs/tracing/ai/utils.js +33 -23
  171. package/node_modules/@sentry/core/build/cjs/tracing/anthropic-ai/index.js +7 -6
  172. package/node_modules/@sentry/core/build/cjs/tracing/anthropic-ai/streaming.js +3 -1
  173. package/node_modules/@sentry/core/build/cjs/tracing/google-genai/index.js +13 -14
  174. package/node_modules/@sentry/core/build/cjs/tracing/google-genai/streaming.js +6 -1
  175. package/node_modules/@sentry/core/build/cjs/tracing/langchain/utils.js +71 -21
  176. package/node_modules/@sentry/core/build/cjs/tracing/langgraph/utils.js +23 -33
  177. package/node_modules/@sentry/core/build/cjs/tracing/openai/streaming.js +6 -0
  178. package/node_modules/@sentry/core/build/cjs/tracing/openai/utils.js +11 -0
  179. package/node_modules/@sentry/core/build/cjs/tracing/workers-ai/utils.js +1 -1
  180. package/node_modules/@sentry/core/build/cjs/utils/eventUtils.js +4 -0
  181. package/node_modules/@sentry/core/build/cjs/utils/prepareEvent.js +2 -2
  182. package/node_modules/@sentry/core/build/cjs/utils/version.js +1 -1
  183. package/node_modules/@sentry/core/build/esm/client.js +6 -5
  184. package/node_modules/@sentry/core/build/esm/package.json +1 -1
  185. package/node_modules/@sentry/core/build/esm/tracing/ai/gen-ai-attributes.js +1 -3
  186. package/node_modules/@sentry/core/build/esm/tracing/ai/utils.js +34 -24
  187. package/node_modules/@sentry/core/build/esm/tracing/anthropic-ai/index.js +8 -7
  188. package/node_modules/@sentry/core/build/esm/tracing/anthropic-ai/streaming.js +3 -1
  189. package/node_modules/@sentry/core/build/esm/tracing/google-genai/index.js +15 -16
  190. package/node_modules/@sentry/core/build/esm/tracing/google-genai/streaming.js +6 -1
  191. package/node_modules/@sentry/core/build/esm/tracing/langchain/utils.js +73 -24
  192. package/node_modules/@sentry/core/build/esm/tracing/langgraph/utils.js +24 -34
  193. package/node_modules/@sentry/core/build/esm/tracing/openai/streaming.js +6 -0
  194. package/node_modules/@sentry/core/build/esm/tracing/openai/utils.js +11 -0
  195. package/node_modules/@sentry/core/build/esm/tracing/workers-ai/utils.js +2 -2
  196. package/node_modules/@sentry/core/build/esm/utils/eventUtils.js +4 -1
  197. package/node_modules/@sentry/core/build/esm/utils/prepareEvent.js +2 -2
  198. package/node_modules/@sentry/core/build/esm/utils/version.js +1 -1
  199. package/node_modules/@sentry/core/build/types/tracing/ai/utils.d.ts +3 -7
  200. package/node_modules/@sentry/core/build/types/tracing/anthropic-ai/types.d.ts +2 -2
  201. package/node_modules/@sentry/core/build/types/tracing/langchain/types.d.ts +15 -0
  202. package/node_modules/@sentry/core/build/types/tracing/langchain/utils.d.ts +1 -0
  203. package/node_modules/@sentry/core/build/types/tracing/langgraph/utils.d.ts +2 -0
  204. package/node_modules/@sentry/core/build/types/tracing/openai/types.d.ts +2 -0
  205. package/node_modules/@sentry/core/build/types/utils/eventUtils.d.ts +2 -1
  206. package/node_modules/@sentry/core/build/types-ts3.8/tracing/ai/utils.d.ts +3 -7
  207. package/node_modules/@sentry/core/build/types-ts3.8/tracing/anthropic-ai/types.d.ts +2 -2
  208. package/node_modules/@sentry/core/build/types-ts3.8/tracing/langchain/types.d.ts +15 -0
  209. package/node_modules/@sentry/core/build/types-ts3.8/tracing/langchain/utils.d.ts +1 -0
  210. package/node_modules/@sentry/core/build/types-ts3.8/tracing/langgraph/utils.d.ts +2 -0
  211. package/node_modules/@sentry/core/build/types-ts3.8/tracing/openai/types.d.ts +2 -0
  212. package/node_modules/@sentry/core/build/types-ts3.8/utils/eventUtils.d.ts +2 -1
  213. package/node_modules/@sentry/core/package.json +1 -1
  214. package/node_modules/@sentry/node/build/esm/package.json +1 -1
  215. package/node_modules/@sentry/node/package.json +5 -5
  216. package/node_modules/@sentry/node-core/build/cjs/integrations/anr/index.js +1 -1
  217. package/node_modules/@sentry/node-core/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
  218. package/node_modules/@sentry/node-core/build/esm/integrations/anr/index.js +1 -1
  219. package/node_modules/@sentry/node-core/build/esm/integrations/anr/worker-script.js +2 -2
  220. package/node_modules/@sentry/node-core/build/esm/integrations/local-variables/local-variables-async.js +1 -1
  221. package/node_modules/@sentry/node-core/build/esm/integrations/local-variables/worker-script.js +1 -1
  222. package/node_modules/@sentry/node-core/build/esm/package.json +1 -1
  223. package/node_modules/@sentry/node-core/package.json +10 -4
  224. package/node_modules/@sentry/opentelemetry/build/esm/package.json +1 -1
  225. package/node_modules/@sentry/opentelemetry/package.json +5 -2
  226. package/node_modules/@sentry/server-utils/build/THIRD-PARTY-LICENSES.txt +55 -55
  227. package/node_modules/@sentry/server-utils/build/esm/package.json +1 -1
  228. package/node_modules/@sentry/server-utils/package.json +2 -2
  229. package/node_modules/@toon-format/toon/README.md +10 -41
  230. package/node_modules/@toon-format/toon/dist/index.d.mts +12 -36
  231. package/node_modules/@toon-format/toon/dist/index.mjs +134 -202
  232. package/node_modules/@toon-format/toon/package.json +2 -2
  233. package/node_modules/debug/package.json +3 -0
  234. package/node_modules/fdir/package.json +3 -0
  235. package/node_modules/has-flag/index.d.ts +39 -0
  236. package/node_modules/has-flag/index.js +8 -0
  237. package/node_modules/has-flag/license +9 -0
  238. package/node_modules/has-flag/package.json +46 -0
  239. package/node_modules/has-flag/readme.md +89 -0
  240. package/node_modules/supports-color/browser.js +5 -0
  241. package/node_modules/supports-color/index.js +135 -0
  242. package/node_modules/supports-color/license +9 -0
  243. package/node_modules/supports-color/package.json +53 -0
  244. package/node_modules/supports-color/readme.md +76 -0
  245. package/package.json +5 -4
  246. package/packages/pm-beads/package.json +1 -1
  247. package/packages/pm-calendar/package.json +1 -1
  248. package/packages/pm-command-kit/package.json +1 -1
  249. package/packages/pm-digital-twin/package.json +1 -1
  250. package/packages/pm-governance-audit/package.json +1 -1
  251. package/packages/pm-guide-shell/package.json +1 -1
  252. package/packages/pm-kanban/package.json +1 -1
  253. package/packages/pm-lifecycle-hooks/package.json +1 -1
  254. package/packages/pm-linked-test-adapters/package.json +1 -1
  255. package/packages/pm-search-advanced/package.json +1 -1
  256. package/packages/pm-templates/package.json +1 -1
  257. package/packages/pm-todos/package.json +1 -1
  258. package/packages/pm-vcs/package.json +1 -1
  259. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  260. package/plugins/pm-claude/package.json +1 -1
  261. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  262. package/plugins/pm-codex/package.json +1 -1
  263. package/plugins/pm-codex/plugin.json +1 -1
  264. package/runtime-dependencies.json +1 -1
  265. package/dist/cli-bundle/chunks/chunk-7OEGNA4X.js +0 -20
  266. package/dist/cli-bundle/chunks/chunk-EMEEHV2Y.js +0 -2
  267. package/dist/cli-bundle/chunks/chunk-JSUJWIHQ.js +0 -30
  268. package/dist/cli-bundle/chunks/chunk-VIMQCFCK.js +0 -2
  269. package/dist/cli-bundle/chunks/chunk-X2H6UR26.js +0 -236
  270. package/dist/cli-bundle/chunks/register-mutation-EWMMVZJB.js +0 -20
  271. package/dist/cli-bundle/focused-chunks/chunk-5TBAVZDR.js +0 -20
  272. package/dist/cli-bundle/focused-chunks/chunk-HTA3TNC3.js +0 -26
  273. package/dist/cli-bundle/focused-chunks/chunk-JKBH7YGX.js +0 -2
  274. package/dist/cli-bundle/focused-chunks/chunk-PDYE7QDX.js +0 -166
  275. package/docs/ecosystem-review-2026-09-28.json +0 -1
@@ -1,13 +1,15 @@
1
1
  # Recovering missing close evidence
2
2
 
3
- Tracked by [pm-ub1ott](../.agents/pm/issues/pm-ub1ott.toon).
3
+ Tracked by [pm-ub1ott](../.agents/pm/issues/pm-ub1ott.toon) and
4
+ [pm-gh1464](../.agents/pm/issues/pm-gh1464.toon).
4
5
 
5
6
  `pm close --validate-close warn` can close an item while reporting missing
6
7
  resolution, expected outcome, or actual outcome. Its SDK result and compact CLI
7
- output now include `recovery.missing`, `suggested_retry`, and
8
- `suggested_retry_args` when evidence is incomplete. The argument vector selects
8
+ output include an optional `follow_up` with `kind: complete_close_evidence`,
9
+ `missing`, `suggested_command`, and `suggested_command_args` when evidence is
10
+ incomplete. The close succeeded; do not retry it. The argument vector selects
9
11
  the same tracker and uses `pm update` to add only the missing evidence fields.
10
- Use `recovery.suggested_retry_args` as the authoritative argument vector. Replace
12
+ Use `follow_up.suggested_command_args` as the authoritative argument vector. Replace
11
13
  each `<value>` with the observed outcome before executing it; retain its tracker
12
14
  selection and only the flags it supplies for missing fields. Do not add flags
13
15
  for evidence already present, because `pm update` would overwrite that evidence.
@@ -25,11 +27,18 @@ recovery when applicable. `--force` is reserved for an intentional repeated
25
27
  lifecycle transition. Adding evidence with `pm update` preserves the original
26
28
  close timestamp, close reason, and immutable history event, then appends a
27
29
  normal update event. It does not retroactively claim that evidence existed at
28
- the original close. Complete closes have no extra recovery payload.
30
+ the original close. Failed terminal retries retain `recovery.suggested_retry_args`;
31
+ successful closes never emit failure recovery. Complete closes have no follow-up.
29
32
 
30
33
  The update flags for the other missing fields are `--resolution` and
31
34
  `--expected-result`; include them only when the generated recovery requests them.
32
35
 
33
36
  For new work, include all three fields in the original close command so its
34
- immutable event contains the full evidence. Warning-mode recovery exists for
35
- incomplete historical or interrupted workflows.
37
+ immutable event contains the full evidence:
38
+
39
+ ```bash
40
+ pm close <item-id> "Delivered and verified" --resolution "What changed" \
41
+ --expected "Required outcome" --actual "Observed outcome" --validate-close warn
42
+ ```
43
+
44
+ Warning-mode follow-up exists for incomplete historical or interrupted workflows.
package/docs/COMMANDS.md CHANGED
@@ -209,6 +209,32 @@ Each aggregate row carries an explicit `group_label`: a blank/null group value (
209
209
  pm list --all --sort updated --order desc
210
210
  ```
211
211
 
212
+ Brief list rows include an explicitly selected sort field (including normalized
213
+ aliases such as `updated_at`) and declare it in `projection.fields`. Explicit
214
+ `--fields`, compact and full projections retain their requested fields.
215
+ This rule is shared by SDK list queries.
216
+
217
+ Lifecycle filters such as `--all` and `--status all` retain the canonical `list`
218
+ command's brief default; they select rows without expanding item fields. Use
219
+ `--full`, `--compact`, `--brief`, `--fields` or `--include-body` to choose more
220
+ evidence explicitly. Raw SDK list calls keep their full default, and explicit
221
+ `--all --full --strict-read` remains a complete corpus read.
222
+ The implementation records
223
+ [pm-gh1481](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1481.toon)
224
+ and [pm-gh1489](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1489.toon)
225
+ are repository-only tracker files, excluded from the npm package.
226
+
227
+ New dependency writes record `created_at`. Supplied values must be calendar-valid
228
+ RFC 3339 date-times. SDK dependency reads expose this field as optional because
229
+ legacy rows without a timestamp remain readable: they sort before timestamped
230
+ rows, with deterministic id/kind/source
231
+ tie-breakers and no invented provenance. An invalid supplied timestamp produces
232
+ `item_document_invalid` with the item path and dependency field.
233
+ `pm validate --check-storage-integrity` and `pm health --check-only --full` expose
234
+ that malformed item. The implementation record
235
+ [pm-gh1482](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1482.toon)
236
+ is a repository-only tracker file, excluded from the npm package.
237
+
212
238
  ### Incremental "what changed since" filters
213
239
 
214
240
  Every `list*` command accepts `--updated-after`/`--updated-before`/`--created-after`/`--created-before`. `pm search` now supports the SAME filter surface as `pm list` (full parity): `--status`, `--type`, `--tag`, `--priority`, `--deadline-before`/`--deadline-after`, `--updated-after`/`--updated-before`, `--created-after`/`--created-before`, `--assignee`, `--sprint`, `--release`, and `--parent`, all with identical semantics. These keep a long-running agent's context focused on the slice it cares about instead of re-scanning the whole tracker:
@@ -620,14 +646,19 @@ row summaries. See tracker item [pm-awe3t6](../.agents/pm/issues/pm-awe3t6.toon)
620
646
  Tracked by [pm-o8z748](../.agents/pm/issues/pm-o8z748.toon) and
621
647
  [pm-cyn0y6](../.agents/pm/issues/pm-cyn0y6.toon).
622
648
 
623
- `pm item mutate` is the noun-first CLI adapter over the public SDK resolver and
624
- `commitItemMutations` primitive. Pipe either the legacy non-empty JSON array or
625
- a versioned `{ "schema_version": 1, "mutations": [...] }` document, provide one
626
- stable transaction id, and mix create/update/close/release operations in order.
627
- Create rows may declare a unique `ref` and omit `id`; exact `@ref` values work
628
- in target ids, `parent`, `blockedBy`, and dependency `id` fields. The resolver
629
- derives replay-stable ids before the writer lock and returns a `references`
630
- receipt:
649
+ `pm item mutate` is the noun-first CLI adapter over the public SDK planner
650
+ (`planItemMutationDocument`) and `commitItemMutations` primitive. Pipe either
651
+ the legacy non-empty JSON array, a versioned
652
+ `{ "schema_version": 1, "mutations": [...] }` document, or JSON Lines (one
653
+ record per line), or read any of them from a file with `--from <path>`. Mix
654
+ create/update/close/release operations in order. Create rows may declare a
655
+ unique `ref` and omit `id`; exact `@ref` values work in target ids, `parent`,
656
+ `blockedBy`, and dependency `id` fields. The resolver derives replay-stable ids
657
+ before the writer lock and returns a `references` receipt plus an input-ordered
658
+ `rows` receipt (`index`, `ref`, `id`, `op`, `upserted`). When `--transaction-id`
659
+ is omitted the id is derived from the exact document bytes
660
+ (`transaction_id_source: "derived"`), so identical bytes select the same
661
+ journal. Replaying a committed import also requires an unchanged resolved plan:
631
662
 
632
663
  ```bash
633
664
  pm item mutate \
@@ -644,13 +675,83 @@ pm item mutate \
644
675
  JSON
645
676
  ```
646
677
 
678
+ `--from <path>` selects a file and rejects an explicitly supplied `--stdin-json`.
679
+ Default stdin input, explicit `--stdin-json` without a file, and `--from -`
680
+ remain supported.
681
+
647
682
  Use `--dry-run` to validate and preview without acquiring a writer lock. Reuse
648
683
  the exact transaction id and deterministic batch after interruption: the SDK
649
684
  journal resumes pending steps and never duplicates a successfully applied
650
- step. `--create-compensation close|delete`, `--lock-ttl-seconds`, and
651
- `--lock-wait-ms` expose the transaction safety controls. The equivalent MCP
685
+ step. A different plan under a committed or resumable journal refuses with
686
+ `transaction_plan_mismatch`; pass a new `--transaction-id` to commit that changed
687
+ plan as its own transaction. A fully compensated attempt has nothing left to
688
+ resume and may accept a new plan under the same transaction id. Formatting-only
689
+ edits change a derived id; pass the original id explicitly to replay them when
690
+ the resolved plan is unchanged. `--create-compensation close|delete`,
691
+ `--lock-ttl-seconds`, and `--lock-wait-ms` expose the transaction safety controls. The equivalent MCP
652
692
  surface is `pm_mutate`.
653
693
 
694
+ Raw mutation `options` use command option types: write `estimatedMinutes: "45"`.
695
+ Item documents may instead use numeric `estimated_minutes: 45`. A non-string
696
+ raw estimate refuses before journal or item writes with
697
+ `mutation_option_value_invalid` (exit 2), identifying the row and option.
698
+ Corrupt durable journals, including a wrong stored schema version or transaction
699
+ identity, refuse with `transaction_journal_invalid`; preserve
700
+ the journal and inspect or restore verified state before retrying. Changing the
701
+ transaction id does not safely recover unknown previously applied work.
702
+
703
+ #### Bulk creation (`pm create many` route)
704
+
705
+ Tracked by [pm-gh1456](../.agents/pm/features/pm-gh1456.toon). `pm create many`
706
+ is not a command; it refuses with `bulk_create_route` and points here. A record
707
+ without `op` is a create document that uses the same field names as
708
+ `pm create` flags or their JSON equivalents (`title`, `type`, `description`,
709
+ `body`, `tags`, `parent`, `priority`, declared custom fields, ...); a create
710
+ row may also carry that document under `item` instead of `options`. Records
711
+ without `ref` or `id` receive `row-<n>` aliases so the receipt and `@row-<n>`
712
+ references stay addressable. One process, one workspace transaction: every
713
+ record is created or none.
714
+
715
+ ```bash
716
+ cat > items.jsonl <<'JSONL'
717
+ {"title":"Imported A","type":"Task","external_id":"ext-1","tags":["import"]}
718
+ {"ref":"b","title":"Imported B","type":"Feature","external_id":"ext-2","parent":"@row-1"}
719
+ JSONL
720
+ pm item mutate --from items.jsonl --dry-run --json # validate, derived transaction id
721
+ pm item mutate --from items.jsonl --json # commit; re-running replays (recovered: true)
722
+ ```
723
+
724
+ `--upsert-key <field>` makes a re-run safe for changed data: a create record
725
+ whose field value matches exactly one existing item (core field such as
726
+ `title`, or a declared custom field such as `external_id`) becomes an update
727
+ of that item and is reported with `upserted: true`. Matching and lock-held
728
+ guards use the field's stored metadata key; core option names such as
729
+ `acceptanceCriteria`, declared field keys and their SDK option targets
730
+ (for example `externalId`) resolve to that
731
+ same stored key. The record keeps its
732
+ `ref` in the receipt, and later records may still address it as `@ref`, which
733
+ then resolves to the matched item. A record missing the key, two records
734
+ sharing a key value, or a key value matching several existing items refuses
735
+ before any write (`upsert_key_missing`, `upsert_key_duplicate`,
736
+ `upsert_key_ambiguous`). Matching happens before the writer lock, so every
737
+ record that matched nothing carries its key into the commit, which re-checks
738
+ it under the lock: when another writer created an item with that key value
739
+ after planning, the transaction refuses with `upsert_key_conflict` before any
740
+ write, and a re-run plans the record as an update of that item. A record that
741
+ did match is committed as an update that re-reads the key under the lock and
742
+ refuses with `upsert_match_changed` when the key was changed or removed after
743
+ planning. Either refusal rolls the attempt back completely, and a rolled-back
744
+ attempt leaves its derived transaction id reusable, so re-running the same
745
+ document simply starts a fresh attempt from the current key values.
746
+
747
+ ```bash
748
+ printf '%s\n' '{"title":"Imported A (renamed)","type":"Task","external_id":"ext-1"}' \
749
+ | pm item mutate --upsert-key external_id --json
750
+ ```
751
+
752
+ Over MCP, `pm_mutate` accepts the same document rows as `{ref?, item: {...}}`
753
+ entries, `upsertKey`, and an optional `transactionId`.
754
+
654
755
  `pm item complete` composes evidence, governed closure, and claim release into
655
756
  one compensating SDK transaction. It accepts the normal repeatable evidence
656
757
  flags and can preview the exact ordered mutations before writing:
@@ -148,6 +148,18 @@ For command-level tracker targeting, prefer `--pm-path <tracker-root>`. The old
148
148
  itself, not the repository workspace. During `pm init`, explicit tracker paths
149
149
  that look like workspace roots are rejected unless `--force` is provided.
150
150
 
151
+ Implicit discovery checks the current directory and its ancestors up to the
152
+ nearest `.git` directory or file, including worktrees and submodules. An
153
+ uninitialized repository selects its own `.agents/pm` and returns initialization
154
+ recovery instead of reading or changing an enclosing repository's tracker.
155
+ Ordinary subdirectories still share their repository's tracker, including
156
+ root-layout trackers. To deliberately share a tracker across repository
157
+ boundaries, pass `--pm-path <tracker-root>` or set `PM_PATH` explicitly.
158
+ This shared SDK discovery policy also applies to CLI and MCP commands.
159
+ Directory aliases follow physical ancestry, including missing descendants of
160
+ an existing alias. Unexpected directory or `.git` lookup errors stop discovery
161
+ instead of falling through to an enclosing tracker.
162
+
151
163
  Tests should set both `PM_PATH` and `PM_GLOBAL_PATH` to temporary directories. The wrapper `node scripts/run-tests.mjs ...` does that automatically.
152
164
 
153
165
  ### Telemetry environment variables
@@ -212,7 +224,16 @@ Interaction rules:
212
224
  - `pm health --check-telemetry --json` surfaces flush and OTLP export diagnostics (`pending_otel_spans`, `last_otel_attempt_at`, `last_otel_success_at`, `last_otel_failure_at`, `last_otel_failure_error`) and the active `env_overrides` (including `telemetry_inline_flush` and `telemetry_source_context`) so agents can self-diagnose a stalled endpoint.
213
225
  - An explicit `PM_AUTHOR` override adds a privacy-preserving agent-identity dimension to `command_start`/`command_finish` events so overridden invocations can be segmented in dashboards without leaking the raw author string. At `redacted`/`max` capture the events carry `author_context_hash` — the same installation-id-keyed one-way SHA-256 used for `pm_root_hash`/`cwd_hash`, so the same author hashes consistently within an installation but differently across installations. At `minimal` capture only a boolean `has_author_context` is emitted. The raw `PM_AUTHOR` value is never exported.
214
226
 
215
- Test environments inferred from `VITEST`, `VITEST_WORKER_ID`, or `NODE_ENV=test` suppress telemetry before identity creation. A valid explicit `PM_TELEMETRY_SOURCE_CONTEXT` or `PM_TELEMETRY_SEND_TEST_EVENTS=1` permits intentional test delivery. Point such tests at a local collector. Neither setting overrides a hard opt-out. `pm telemetry status` exposes effective `enabled`, persisted `configured_enabled`, and `env_overrides` so an empty queue is distinguishable from disabled delivery.
227
+ Test environments inferred from `VITEST`, `VITEST_WORKER_ID`, `NODE_TEST_CONTEXT`
228
+ (native `node --test` children), or `NODE_ENV=test` suppress telemetry and Sentry
229
+ before identity creation. A valid explicit `PM_TELEMETRY_SOURCE_CONTEXT` or
230
+ `PM_TELEMETRY_SEND_TEST_EVENTS=1` permits intentional test delivery. Point such
231
+ tests at a local collector. Inferred tests use inline telemetry flushing even
232
+ after an opt in, so CLI delivery settles before process exit and disposable-root
233
+ cleanup. SDK telemetry completion also awaits inline delivery before returning.
234
+ Neither setting overrides a hard opt-out. `pm telemetry status` exposes effective `enabled`, persisted
235
+ `configured_enabled`, and `env_overrides` so an empty queue is distinguishable
236
+ from disabled delivery.
216
237
 
217
238
  SDK consumers that previously used `TelemetryStatusSummary.enabled` to display the saved preference should read `configured_enabled` instead. Use `enabled` to determine whether this process permits delivery.
218
239
 
@@ -20,6 +20,13 @@ nightly quality and release paths enforce it. The registry-owned local
20
20
  preflight also requires the static gate and permits no skip. Trivy separately
21
21
  includes development dependencies in its required repository scan.
22
22
 
23
+ Composite action refs and their executed tool versions need separate review.
24
+ [pm-38w3ii](../.agents/pm/chores/pm-38w3ii.toon) pins TruffleHog's action
25
+ commit and explicitly selects scanner version `3.98.0`; the action otherwise
26
+ defaults to the `latest` image. The workflow contract checks both values on
27
+ every TruffleHog step. Recheck the action's executable selectors when renewing
28
+ its commit pin.
29
+
23
30
  ## Indexed source-map offsets
24
31
 
25
32
  [pm-dba47](../.agents/pm/issues/pm-dba47.toon) tracks Dependabot alert 47 and
@@ -109,9 +116,21 @@ program matches the reviewed [shim templates](../config/codspeed-shims/), with
109
116
  targets and module paths derived from the audited installed dependency. Arbitrary
110
117
  names, nested payloads, links, altered programs and forged target markers fail;
111
118
  these shims are outside the twelve package-owned hashes but are independently
112
- validated. The shell template records pnpm 11.10.0's installed output; the CMD
113
- and PowerShell templates come from `@zkochan/cmd-shim` 9.0.7. Template changes
114
- require renewed real installation evidence on both POSIX and native Windows.
119
+ validated. [pm-rnpmtp](../.agents/pm/chores/pm-rnpmtp.toon) renews the installer
120
+ to pnpm 11.28.5 and its bundled `bins/cmd-shim` generator. Separate complete shell
121
+ templates describe POSIX and Windows installations; only the host's template is
122
+ accepted. Windows shells pass Windows `NODE_PATH` values to native Node, and
123
+ Cygwin targets use Windows paths. CMD and PowerShell programs retain their
124
+ complete comparisons. Template changes require renewed real installation and
125
+ dependency-resolution evidence on POSIX, Git Bash and Cygwin, plus CMD and
126
+ PowerShell. The Windows script cohort downloads the archived Cygwin setup 2.937
127
+ installer and verifies its pinned SHA-512 before execution. To renew it, select
128
+ an eligible version from the official [setup archive](https://cygwin.com/setup/),
129
+ verify the executable against the archive's `sha512.sum`, and update the
130
+ versioned URL, pinned digest and workflow contract together. Preserve setup's
131
+ default package-signature verification and repeat native launcher acceptance.
132
+ Literal percent paths are exercised in disposable launcher fixtures;
133
+ the audited CodSpeed installation still refuses shell interpolation paths.
115
134
  The CMD suffix follows the installed `PATHEXT` spelling, including `.CMD`;
116
135
  format lookup folds its case while validating the complete program. All three
117
136
  shell launchers are required, together with the CMD and PowerShell sets on
@@ -27,12 +27,16 @@ it is not silently equated with the earlier item snapshot. History-drift
27
27
  validation passed across all 2,826 current items. The public SDK independently
28
28
  verified hash chains for all 2,841 collected streams with zero failures.
29
29
 
30
- [The per-item census](ecosystem-review-2026-09-28.json) records every snapshot
30
+ [The per-item census](https://github.com/unbraind/pm-cli/blob/main/docs/ecosystem-review-2026-09-28.json) records every snapshot
31
31
  ID, status, content fingerprint, structural classification, missing planning
32
32
  fields, historical evidence gaps, and remediation owner. These are mechanical
33
33
  findings, not invented historical estimates, outcomes, or review approvals.
34
34
  The full raw corpus stays outside public documentation.
35
35
 
36
+ The census is intentionally excluded from npm. This packaged page uses its
37
+ canonical GitHub file URL under the [documentation policy](../AGENTS.md#documentation-policy),
38
+ so installed readers can access the data without a broken package-relative path.
39
+
36
40
  | Measure | Initial observation | Interpretation |
37
41
  | --- | ---: | --- |
38
42
  | Directed graph edges | 14,097 | Deduplicated directed basis |
@@ -305,7 +305,7 @@ Use the public SDK barrel. Do not deep-import from `src/core` or `dist/core`.
305
305
 
306
306
  - `api.extension` is a read-only identity (`name`, `layer`, `version`, `capabilities`, `pm_min_version?`, `pm_max_version?`, `source_package?`) for self-identifying logs and version gating without re-reading the manifest.
307
307
  - `api.registerCommand(definition)` adds package-owned commands; `read_output` opts readers into the [SDK output contract](SDK.md#minimal-command-extension).
308
- - `api.registerFlags(command, flags)` adds runtime command flags. A flag may declare `value_type` (canonical; the legacy `type` alias is honored only when `value_type` is absent), `list: true` to accumulate repeated/comma-joined values like core `--tags`, and a `default` applied when the flag is omitted.
308
+ - `api.registerFlags(command, flags)` adds runtime command flags. A flag may declare `value_type` (canonical; the legacy `type` alias is honored only when `value_type` is absent), `list: true` to accumulate repeated/comma-joined values like core `--tags`, a `default` applied when the flag is omitted, and `value_validation: "strict"` to refuse malformed `number`/`boolean` tokens before the handler runs (the default `"coerce"` forwards the raw token). See [Flag Contracts](SDK.md#flag-contracts).
309
309
  - `api.registerItemFields(fields)` adds custom metadata fields. Agents can set declared fields with repeatable `pm create --field name=value` and `pm update <id> --field name=value`; undeclared names are rejected. `SchemaFieldDefinition.type` is the same closed union used by `pm schema add-field`: `string | number | boolean | string_array | array | object`. Unsupported values fail at compile time for TypeScript authors and at activation for JavaScript packages, with a did-you-mean hint on typos. `string_array` is the repeatable string collection; `array` and `object` require JSON containers.
310
310
  - Custom fields whose camel-case option name is already owned by a canonical MCP input remain usable through `options.<name>`, but authoring surfaces report the collision instead of allowing silent top-level shadowing. `pm schema add-field`, `pm profile lint`, and `pm package doctor` name the field, canonical `mcp_tool_input` owner, and nested recovery path. SDK authors can preflight the same rule with `resolvePmToolCustomFieldCollision`.
311
311
  - `api.registerItemTypes(types)` adds custom item types.
@@ -1,5 +1,15 @@
1
1
  # Output Projection and Omission Contracts
2
2
 
3
+ Passing extension health defaults are tracked by
4
+ [pm-gh1486](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1486.toon),
5
+ a repository-only tracker file excluded from the npm package. Standard `pm health` output
6
+ reports healthy extension counts and `restore_with: "pm health --full"` rather
7
+ than the command registry. Its `standard` projection declares the omitted full
8
+ check details. Warning and failure details remain available by default.
9
+ `--full` restores structured evidence; `--brief` never expands an individual
10
+ check's serialized detail beyond the standard projection. Summary and check-only
11
+ verdict semantics remain unchanged. SDK `runHealth` and MCP use the same engine.
12
+
3
13
  Tracker references: [pm-p258tx](../.agents/pm/features/pm-p258tx.toon),
4
14
  [pm-cyrfjq](../.agents/pm/issues/pm-cyrfjq.toon), and
5
15
  [pm-qhnq6t](../.agents/pm/issues/pm-qhnq6t.toon). The universal row and
package/docs/RELEASING.md CHANGED
@@ -304,7 +304,14 @@ The release workflow publishes this staged tarball with provenance; CI and
304
304
  packed smoke tests use the same staging command. Application distribution and
305
305
  bundled runtime have separate committed size and file-count limits, so runtime
306
306
  payload cannot hide application growth. The ledger ships with the tarball for
307
- installed-version verification. npm 12 ignores published shrinkwraps; shipping
307
+ installed-version verification. [pm-iceees](../.agents/pm/issues/pm-iceees.toon)
308
+ keeps selected optional-peer subtrees complete: npm deliberately skips peer edges
309
+ when gathering bundled files, so staged runtime manifests record the exact tested
310
+ peer bindings as ordinary or optional dependency entries. Package code, source
311
+ and installed manifests, peer declarations, and the root public dependency
312
+ inventory remain intact. A real archive regression resolves the peer's descendant
313
+ from an extracted package and the installed-runtime verifier still refuses any
314
+ missing locked package. npm 12 ignores published shrinkwraps; shipping
308
315
  a shrinkwrap alone therefore cannot enforce this contract. SDK consumers
309
316
  supply the bounded optional Node types peer themselves.
310
317
 
package/docs/SDK.md CHANGED
@@ -483,6 +483,12 @@ not renderer-specific code, so package authors can reuse
483
483
  `resolvePmCommandOutputBudget`, and
484
484
  `estimatePmOutputTokens` in custom transports.
485
485
 
486
+ Read-output, context-intent, recurrence and diagnostic string compaction retain
487
+ Unicode-safe prefixes. A cutoff through a surrogate pair backs up one UTF-16
488
+ code unit before adding its suffix. Rendering and token receipts use the actual
489
+ retained text; unbounded reads and preserved-string exceptions are unchanged.
490
+ Tracked by [pm-gh1478](../.agents/pm/issues/pm-gh1478.toon).
491
+
486
492
  ```ts
487
493
  import {
488
494
  definePmCommandOutputBudget,
@@ -946,6 +952,27 @@ recurrence reason, accepts only the workspace open or in-progress target, and
946
952
  returns the terminal evidence captured atomically before the update path clears
947
953
  it from active metadata.
948
954
 
955
+ Lifecycle handoff and receipt guidance are tracked by
956
+ [pm-gh1465](../.agents/pm/features/pm-gh1465.toon) and
957
+ [pm-gh1464](../.agents/pm/issues/pm-gh1464.toon). Register a project-specific
958
+ queue with `client.schemaAddStatus("review", { role: ["active"] })`, then call
959
+ `client.release(id, { handoff: "review", message: "Implemented; run linked verification" })`.
960
+ The SDK atomically changes status and clears ownership in one release history
961
+ event, applying project ownership, type-transition, and workflow policies.
962
+ `ReleaseMutationOptions` declares the handoff option; `ReleaseResult.handoff`
963
+ identifies the source and destination states and evidence. `client.list({ status:
964
+ "review" })` selects the verifier queue; context preserves its status without
965
+ counting it as in-progress work. The destination must already exist, be
966
+ non-terminal, and differ from the configured in-progress status. Handoff needs
967
+ a claimed source and evidence message, and cannot be combined with pause.
968
+
969
+ A successful warning-mode close with missing evidence returns optional
970
+ `follow_up: CloseEvidenceFollowUp`. Its `kind` is `complete_close_evidence` and
971
+ `suggested_command_args` selects an evidence-only update of the same item and
972
+ tracker. Consumers migrating from successful-close `recovery` should read
973
+ `follow_up` instead; a successful close never asks for a retry. Failed close
974
+ commands retain failure recovery. See [close evidence guidance](CLOSE_EVIDENCE_RECOVERY.md).
975
+
949
976
  ### Atomic workspace transactions
950
977
 
951
978
  Tracked by [pm-4e12](../.agents/pm/features/pm-4e12.toon), with the VCS
@@ -1103,7 +1130,14 @@ bulk sync), `commitItemMutations` wraps the coordinator so callers describe
1103
1130
  the mutations instead of hand-writing a step array. The helper wires the
1104
1131
  crash-consistency contract for you: creates use their resolved stable `id` as
1105
1132
  the idempotency key (exists-by-id inspection) and are compensated by closing
1106
- the item (or deleting it with `createCompensation: "delete"`); updates stamp a
1133
+ the item (or deleting it with `createCompensation: "delete"`). A retry refuses
1134
+ with `transaction_create_compensated` while a creation's latest closure belongs
1135
+ to compensation, even if its close prose was edited. Review its immutable history
1136
+ and explicitly reopen it before retrying; the SDK preserves later lifecycle
1137
+ decisions instead of silently reopening the item or reporting it committed.
1138
+ A later explicit user close or status update takes precedence over the earlier
1139
+ compensation close and is preserved when the transaction resumes.
1140
+ Updates stamp a
1107
1141
  durable history marker for applied-detection and are compensated by restoring
1108
1142
  the captured pre-mutation version; closes treat an already-terminal target as
1109
1143
  applied and are likewise compensated by version restore; releases restore the
@@ -1241,6 +1275,70 @@ await commitItemMutations({
1241
1275
  });
1242
1276
  ```
1243
1277
 
1278
+ For imports, use `planItemMutationDocument` (tracked by
1279
+ [pm-gh1456](../.agents/pm/features/pm-gh1456.toon)). It reads the workspace
1280
+ schema so declared custom fields route through their option targets, accepts
1281
+ JSON Lines and op-less create documents (records shaped like `pm create
1282
+ --stdin-json` input, optionally wrapped as `{ ref, item }`), synthesizes
1283
+ `row-<n>` aliases for records without `ref`/`id`, derives a stable
1284
+ `transaction_id` from the document bytes when none is supplied, and resolves
1285
+ `upsertKey` against existing items so matching create records become updates;
1286
+ core camelCase option names (such as `acceptanceCriteria`) and declared field
1287
+ keys or option targets resolve to the stored metadata key before candidate
1288
+ reads and lock-held guards.
1289
+ An explicitly supplied blank `upsertKey` is a usage error; omit it to select plain creation.
1290
+ Unrelated extension metadata keys retain their exact spelling, including camelCase.
1291
+ Item documents also accept known core camelCase option names, including inside
1292
+ `{ item }` wrappers. Exact stored metadata keys win when both spellings appear.
1293
+ Records that match nothing carry a `unique` guard that `commitItemMutations`
1294
+ re-checks under the writer lock and refuses with `upsert_key_conflict` when a
1295
+ concurrent writer created the key value after planning; matched records become
1296
+ updates carrying a `match` guard checked against the locked target document,
1297
+ after acquiring its item lock. It refuses with `upsert_match_changed` when the
1298
+ target's key changed in between, including changes made by ordinary item updates.
1299
+ Successful update, close and release steps invalidate cached unique-key scans
1300
+ inside a mixed batch, so subsequent creates see the current persisted values,
1301
+ including changes to earlier creates in that batch.
1302
+ Every create also advances cached scans from its returned metadata, including
1303
+ unguarded creates and records guarded on a different key, without a new project scan.
1304
+ The returned `rows` receipt maps every input record, in order, to its resolved
1305
+ `id` and `op`:
1306
+
1307
+ ```ts
1308
+ import {
1309
+ commitItemMutations,
1310
+ planItemMutationDocument,
1311
+ } from "@unbrained/pm-cli/sdk";
1312
+
1313
+ const plan = await planItemMutationDocument({
1314
+ pmRoot,
1315
+ input: [
1316
+ '{"title":"Imported A","type":"Task","external_id":"ext-1"}',
1317
+ '{"ref":"b","title":"Imported B","type":"Feature","parent":"@row-1","external_id":"ext-2"}',
1318
+ ].join("\n"),
1319
+ upsertKey: "external_id",
1320
+ });
1321
+ const result = await commitItemMutations({
1322
+ pmRoot,
1323
+ author: "import-agent",
1324
+ transactionId: plan.transaction_id,
1325
+ mutations: plan.mutations,
1326
+ });
1327
+ console.log(plan.transaction_id_source, plan.rows, result.recovered);
1328
+ ```
1329
+
1330
+ After a successful commit, reuse its transaction id and unchanged resolved
1331
+ mutation plan to replay it (`recovered: true`). A formatting-only edit changes
1332
+ the derived id; pass the original id explicitly to replay an unchanged plan.
1333
+ The planner excludes items created by that transaction from upsert matching,
1334
+ retaining those create rows.
1335
+ If document edits, external matches, or schema context change the resolved
1336
+ plan under that committed id, the coordinator refuses with
1337
+ `transaction_plan_mismatch`; use a new transaction id for the changed import.
1338
+ Corrupt journal JSON, stored schema version/transaction identity, lifecycle state or metadata instead refuses with
1339
+ `transaction_journal_invalid`. Preserve and inspect or restore the journal;
1340
+ starting a new id can duplicate work whose durable state cannot be verified.
1341
+
1244
1342
  `buildItemCompletionMutations` creates the ordered evidence/update, close, and
1245
1343
  release plan for inspection. `commitItemCompletion` executes that plan through
1246
1344
  the same durable coordinator, restoring annotations, linked artifacts,
@@ -2225,6 +2323,20 @@ same list/default semantics as core flags:
2225
2323
  `default: "a,b"` or `default: ["a,b", "c"]`) are split into elements. A default
2226
2324
  that would not cleanly coerce under the declared `value_type` (e.g.
2227
2325
  `value_type: "number", default: "abc"`) is rejected at registration.
2326
+ - `value_validation` (`"coerce"` | `"strict"`, tracked by
2327
+ [pm-extension-scalar-validation](../.agents/pm/features/pm-extension-scalar-validation.toon))
2328
+ decides what happens to a `number`/`boolean` token that does not coerce.
2329
+ `coerce` is the compatible default: the raw token reaches the handler for its
2330
+ own validation (`--limit abc` arrives as `"abc"`). `strict` refuses the
2331
+ invocation before dispatch with `extension_flag_value_invalid` (exit 2),
2332
+ naming the flag, the command, the expected grammar, and the received token;
2333
+ list entries are checked one by one, including attached values on boolean
2334
+ list switches. CSV boolean lists accept `true,false`; repeatable boolean
2335
+ lists keep each occurrence as one value. Switch presence (`--verbose`,
2336
+ `--no-verbose`), the legacy `bool` optional-value grammar (`--enabled` alone
2337
+ is `true`), declared defaults, and string flags are unaffected. `strict` on a
2338
+ `string` or untyped flag is rejected at registration because there is nothing
2339
+ to validate.
2228
2340
 
2229
2341
  ```ts
2230
2342
  api.registerFlags("report", [
@@ -2235,7 +2347,7 @@ api.registerFlags("report", [
2235
2347
  list: true,
2236
2348
  default: "all",
2237
2349
  },
2238
- { long: "--limit", value_type: "number", default: 20 },
2350
+ { long: "--limit", value_type: "number", default: 20, value_validation: "strict" },
2239
2351
  ]);
2240
2352
  ```
2241
2353
 
@@ -1,6 +1,8 @@
1
1
  # SDK context coordination primitives
2
2
 
3
- Trackers: [pm-e200](../.agents/pm/features/pm-e200.toon), [pm-ez1dfg](../.agents/pm/tasks/pm-ez1dfg.toon), [pm-4ri6](../.agents/pm/features/pm-4ri6.toon), and [pm-hcrmye](../.agents/pm/issues/pm-hcrmye.toon).
3
+ Trackers: [pm-e200](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-e200.toon), [pm-ez1dfg](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/tasks/pm-ez1dfg.toon), [pm-4ri6](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-4ri6.toon), [pm-hcrmye](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-hcrmye.toon), [pm-gh1485](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1485.toon), and [pm-xj80p9](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-xj80p9.toon).
4
+
5
+ Tracker records live in the repository and are excluded from the npm package.
4
6
 
5
7
  `pm` treats project management as context management. These primitives let an
6
8
  agent learn what changed, avoid creating redundant work, and keep that work
@@ -38,10 +40,61 @@ idempotently or deduplicate replays. `--cursor-mode row` preserves the previous
38
40
  shape with one `cursor` per event and no trailer for consumers that checkpoint
39
41
  every row. Already issued version-1 cursors remain accepted by `--since`.
40
42
 
41
- Node runtimes use the rebuildable SQLite event projection. Runtimes such as Bun
42
- that do not expose `node:sqlite` transparently scan the authoritative history
43
+ Version-1 cursor ordering uses recorded timestamps, stream ids, and offsets.
44
+ A fact committed later with an older timestamp falls before an advanced cursor.
45
+ Clock-independent ordering and late-commit recovery remain tracked by
46
+ [pm-10l1vm](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-10l1vm.toon). Hosts needing complete concurrent
47
+ observation can retain a fixed lower boundary and deduplicate snapshots by
48
+ `item_id` and `version` while work is being committed.
49
+
50
+ Runtimes exposing `node:sqlite` use the rebuildable SQLite event projection.
51
+ Runtimes without it transparently scan the authoritative history
43
52
  streams with the same ordering, filters, pagination, and cursor contract; pages
44
53
  identify that path with `source: "authoritative_history"`.
54
+ Writers without SQLite use the same pending and committed invalidation protocol,
55
+ so a later Node writer cannot certify a cache that omitted their facts.
56
+ Incremental writes also verify the previous size receipt before advancing it,
57
+ so merged history cannot be hidden by a later append. Upgraded runtimes rebuild
58
+ legacy projections that could contain omitted facts with apparently current
59
+ receipts; authoritative history does not require a format migration.
60
+
61
+ Index readers take a synchronous SQLite read transaction containing both event
62
+ rows and their stream-size receipts, then close the database before checking
63
+ authoritative files. They acquire neither history-index writer lock. File
64
+ identity and write timestamps, authoritative stream sizes, and pending or
65
+ committed invalidations must still match before a snapshot is returned. A
66
+ concurrent change refuses the optional snapshot; it cannot certify older rows
67
+ using a newer size receipt.
68
+
69
+ Incremental projection writes also use a zero SQLite busy timeout. Native
70
+ reader or writer contention falls back to the authoritative append and
71
+ invalidation protocol instead of spending a separate SQLite wait budget.
72
+ An unexpired, token-owned append lease marks ordinary incremental work as
73
+ active until its commit or invalidation completes. Native contention retains
74
+ the cache file and a committed contention marker; a zero-wait native probe
75
+ distinguishes an ongoing contender from settled damage before requesting repair.
76
+
77
+ Authoritative writers fail fast when an active owner holds the projection writer
78
+ lock, including when a full repair owns it. They publish an invalidation instead.
79
+ Stale-owner recovery follows the built-in lock policy. A repair
80
+ refuses publication if those markers changed during its scan. Full projection
81
+ construction yields between batches, and marker cleanup occurs outside the
82
+ short invalidation publication lock.
83
+ After a refused full publication or failed repair, a best effort per-tracker runtime receipt
84
+ defers automatic repair for five seconds. Busy periods therefore do not restart
85
+ a complete SQLite build on every read. Pages and recency reads continue using
86
+ authoritative history; after the cooldown, a later read can repair during a
87
+ quiet interval. This backoff bounds repair frequency, not index availability
88
+ during continuous writes.
89
+
90
+ Transient generation changes and SQLite contention use authoritative fallback
91
+ directly. Missing, incompatible, or damaged projections receive one optional
92
+ repair attempt without waiting for either projection lock. Repair failure or
93
+ invalidation after rebuilding
94
+ falls back to authoritative JSONL with the same filters and cursor format.
95
+ Pages may change `source` between calls. A fallback still reports malformed or
96
+ inaccessible authoritative history as an error. A successful repair may scan
97
+ the workspace; this protocol bounds lock waiting, not total execution time.
45
98
 
46
99
  `--full` also includes the complete authoritative history entry.
47
100
  `--type`, `--author`, and `--item` accept repeatable or comma-separated values.
@@ -109,10 +162,7 @@ Package authors can query the same scorer used by create/copy and the bundled
109
162
  governance audit:
110
163
 
111
164
  ```ts
112
- import {
113
- findSimilarItems,
114
- scoreItemSimilarity,
115
- } from "@unbrained/pm-cli/sdk";
165
+ import { findSimilarItems, scoreItemSimilarity } from "@unbrained/pm-cli/sdk";
116
166
 
117
167
  const score = scoreItemSimilarity("Fix OAuth refresh", "Fix oauth refresh");
118
168
  const matches = await findSimilarItems(
@@ -155,6 +205,20 @@ accepted aliases for existing automation.
155
205
 
156
206
  ## Scale contract
157
207
 
208
+ The mixed-reader acceptance used 100 fixed-boundary snapshot observers,
209
+ five SDK writer lanes, and five CLI writer lanes, with five updates per lane.
210
+ Both separate traced and untraced cohorts passed 5,000 unique observations,
211
+ duplicate-free pages, strict history integrity, and a 2,000 ms first-observation
212
+ ceiling. These are bounded host measurements recorded in
213
+ [pm-gh1485](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1485.toon).
214
+
215
+ The native regression suspends filesystem validation and requires an
216
+ authoritative writer to finish before that reader resumes. Run it with:
217
+
218
+ ```bash
219
+ node scripts/run-tests.mjs test -- tests/unit/core/history/event-index-snapshots.spec.ts
220
+ ```
221
+
158
222
  Event catch-up reads from a persistent ordered projection and follows only new
159
223
  rows. Similarity governance is zero-cost when off and index-bounded when
160
224
  enabled on an indexed workspace. Production bundles are syntax-, whitespace-,