@aefree/pi-plastic 0.7.6 → 0.8.1

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 (148) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +48 -174
  3. package/docs/2026-10-06-development.md +101 -0
  4. package/docs/2026-10-06-diffs-and-patches.md +136 -0
  5. package/docs/2026-10-06-discovery.md +135 -0
  6. package/docs/2026-10-06-integrations.md +49 -0
  7. package/docs/2026-10-06-merging.md +153 -0
  8. package/docs/2026-10-06-safety-and-receipts.md +95 -0
  9. package/docs/2026-10-06-setup.md +101 -0
  10. package/docs/2026-10-06-shelvesets-and-reviews.md +113 -0
  11. package/docs/2026-10-06-status.md +130 -0
  12. package/docs/2026-10-06-tools-and-loading.md +64 -0
  13. package/docs/2026-10-06-workspace-operations.md +142 -0
  14. package/docs/README.md +65 -0
  15. package/extensions/bash-cm-diff-guard.ts +1 -1
  16. package/index.ts +4 -687
  17. package/package.json +10 -4
  18. package/skills/using-plastic/SKILL.md +11 -5
  19. package/skills/using-plastic/references/branch-management.md +5 -1
  20. package/skills/using-plastic/references/changeset-operations.md +9 -8
  21. package/skills/using-plastic/references/code-review-creation.md +25 -18
  22. package/skills/using-plastic/references/integration.md +9 -5
  23. package/skills/using-plastic/references/quick-reference.md +4 -4
  24. package/skills/using-plastic/references/reviewing-changes.md +10 -10
  25. package/skills/using-plastic/references/shelving.md +26 -11
  26. package/skills/using-plastic/references/troubleshooting.md +4 -4
  27. package/src/diff/local-snapshot.ts +74 -0
  28. package/src/diff/text.ts +187 -0
  29. package/src/domain/add-contract.ts +24 -0
  30. package/src/domain/branch-create-contract.ts +38 -0
  31. package/src/domain/branch-delete-contract.ts +15 -0
  32. package/src/domain/branches.ts +263 -0
  33. package/src/domain/checkin-contract.ts +70 -0
  34. package/src/domain/closeout-contract.ts +30 -0
  35. package/src/domain/copied-merge.ts +42 -0
  36. package/src/domain/diff-base-xml.ts +65 -0
  37. package/src/domain/diff-pending-xml.ts +34 -0
  38. package/src/domain/merge-output.ts +327 -0
  39. package/src/domain/paths.ts +253 -0
  40. package/src/domain/pending.ts +499 -0
  41. package/src/domain/removal-contract.ts +25 -0
  42. package/src/domain/revisions.ts +301 -0
  43. package/src/domain/server-merge-contract.ts +45 -0
  44. package/src/domain/server-merge-resolutions.ts +61 -0
  45. package/src/domain/status-xml.ts +122 -0
  46. package/src/domain/switch-contract.ts +60 -0
  47. package/src/domain/switch-policy.ts +95 -0
  48. package/src/domain/undo-contract.ts +24 -0
  49. package/src/domain/update-contract.ts +16 -0
  50. package/src/domain/workspace-merge-contract.ts +41 -0
  51. package/src/execution/add-command.ts +118 -0
  52. package/src/execution/branch-create-command.ts +118 -0
  53. package/src/execution/branch-list-command.ts +75 -0
  54. package/src/execution/checkin-command.ts +116 -0
  55. package/src/execution/cli-version.ts +31 -0
  56. package/src/execution/cm.ts +59 -0
  57. package/src/execution/code-review-find-command.ts +75 -0
  58. package/src/execution/context.ts +20 -0
  59. package/src/execution/diff-revisions-command.ts +74 -0
  60. package/src/execution/process.ts +260 -0
  61. package/src/execution/removal-command.ts +118 -0
  62. package/src/execution/server-merge-command.ts +92 -0
  63. package/src/execution/shelveset-list-command.ts +75 -0
  64. package/src/execution/status-command.ts +29 -0
  65. package/src/execution/status-xml-command.ts +72 -0
  66. package/src/execution/status-xml-limits.ts +1 -0
  67. package/src/execution/switch-command.ts +118 -0
  68. package/src/execution/test-seams.ts +10 -0
  69. package/src/execution/undo-command.ts +118 -0
  70. package/src/execution/update-command.ts +118 -0
  71. package/src/execution/workspace-list-command.ts +75 -0
  72. package/src/execution/workspace-merge-command.ts +118 -0
  73. package/src/operations/add-receipt.ts +37 -0
  74. package/src/operations/arguments.ts +3 -0
  75. package/src/operations/branch-create.ts +74 -0
  76. package/src/operations/branch-delete-receipt.ts +25 -0
  77. package/src/operations/branch-list.ts +94 -0
  78. package/src/operations/branch-reads.ts +94 -0
  79. package/src/operations/branches.ts +111 -0
  80. package/src/operations/checkin-receipt.ts +140 -0
  81. package/src/operations/checkin.ts +102 -0
  82. package/src/operations/closeout-receipt.ts +74 -0
  83. package/src/operations/closeout.ts +19 -0
  84. package/src/operations/code-review-find.ts +97 -0
  85. package/src/operations/consolidated-diff.ts +144 -0
  86. package/src/operations/diff-revisions.ts +157 -0
  87. package/src/operations/diff.ts +53 -0
  88. package/src/operations/merge.ts +26 -0
  89. package/src/operations/object-delete-receipt.ts +21 -0
  90. package/src/operations/object-write-receipt.ts +105 -0
  91. package/src/operations/patch-receipt.ts +96 -0
  92. package/src/operations/patch-support.ts +375 -0
  93. package/src/operations/patch.ts +25 -0
  94. package/src/operations/removal-receipt.ts +42 -0
  95. package/src/operations/reviews.ts +90 -0
  96. package/src/operations/server-merge.ts +130 -0
  97. package/src/operations/shelveset-list.ts +90 -0
  98. package/src/operations/shelvesets.ts +90 -0
  99. package/src/operations/status.ts +129 -0
  100. package/src/operations/switch-receipt.ts +85 -0
  101. package/src/operations/switch.ts +25 -0
  102. package/src/operations/undo-receipt.ts +37 -0
  103. package/src/operations/update-receipt.ts +35 -0
  104. package/src/operations/workspace-list.ts +92 -0
  105. package/src/operations/workspace-merge-receipt.ts +50 -0
  106. package/src/operations/workspace.ts +120 -0
  107. package/src/pi/add-output.ts +52 -0
  108. package/src/pi/arguments.ts +298 -0
  109. package/src/pi/branch-create-output.ts +83 -0
  110. package/src/pi/branch-delete-output.ts +46 -0
  111. package/src/pi/branch-list-output.ts +59 -0
  112. package/src/pi/branch-output.ts +63 -0
  113. package/src/pi/capability-diagnostics.ts +23 -0
  114. package/src/pi/checkin-output.ts +68 -0
  115. package/src/pi/closeout-output.ts +87 -0
  116. package/src/pi/code-review-find-output.ts +50 -0
  117. package/src/pi/diff-output.ts +66 -0
  118. package/src/pi/diff-revisions-output.ts +55 -0
  119. package/src/pi/object-delete-output.ts +15 -0
  120. package/src/pi/object-write-output.ts +54 -0
  121. package/src/pi/patch-output.ts +69 -0
  122. package/src/pi/register.ts +188 -0
  123. package/src/pi/removal-output.ts +59 -0
  124. package/src/pi/schemas.ts +146 -0
  125. package/src/pi/server-merge-output.ts +83 -0
  126. package/src/pi/shelveset-list-output.ts +50 -0
  127. package/src/pi/status-output.ts +204 -0
  128. package/src/pi/switch-output.ts +80 -0
  129. package/src/pi/tool-registry.ts +72 -0
  130. package/src/pi/undo-output.ts +52 -0
  131. package/src/pi/update-output.ts +48 -0
  132. package/src/pi/workspace-list-output.ts +53 -0
  133. package/src/pi/workspace-merge-output.ts +46 -0
  134. package/src/plastic-core.ts +14 -5775
  135. package/src/plastic-renderers.ts +102 -22
  136. package/src/plastic-tool-loading.ts +7 -12
  137. package/src/presentation/add-results.ts +5 -0
  138. package/src/presentation/branch-create.ts +7 -0
  139. package/src/presentation/branch-delete-results.ts +7 -0
  140. package/src/presentation/checkin-results.ts +14 -0
  141. package/src/presentation/closeout-results.ts +2 -0
  142. package/src/presentation/diff-results.ts +237 -0
  143. package/src/presentation/removal-results.ts +7 -0
  144. package/src/presentation/results.ts +84 -0
  145. package/src/presentation/switch-results.ts +7 -0
  146. package/src/presentation/undo-results.ts +5 -0
  147. package/src/presentation/update-results.ts +5 -0
  148. package/src/presentation/workspace-merge-results.ts +6 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,49 @@ and this project follows semantic versioning for public package releases.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## [0.8.1] - 2026-10-12
11
+
12
+ ### Fixed
13
+
14
+ - Restored useful bounded direct status text and parseable JSON for standard, machine and XML sources, including exact admitted paths/moves, merge hints, uncertainty and presentation omissions. Native DTOs remain unchanged; opt-in raw diagnostics are separately bounded and cannot restore excluded machine identities.
15
+
16
+ ## [0.8.0] - 2026-10-08
17
+
18
+ ### Added
19
+
20
+ - Producer-owned structured output schemas for all 27 core tools, with explicit request snapshots, bounded observations, capture/read completeness, and uncertainty-aware mutation receipts. The on-demand capability loader remains schema-less.
21
+ - Agent-driven server conflict resolution through `plastic_mergeBranches`: read-only conflict analysis, validated per-file JSON resolutions, explicit source/destination fallback policy for unlisted conflicts, and conditional installed-client capability checks.
22
+ - Opt-in XML status with absolute Unicode paths and typed v2 results for supported text-file and directory records. XML capture and parsing reject malformed, unsupported, lossy, overflowing, or incomplete observations; base revisions remain unavailable.
23
+ - Structured branch reads/listing, workspace listing, shelveset listing, and code-review queries, including bounded identities, exact decimal IDs, query-scoped counts, and documented source prerequisites.
24
+ - Typed workspace merge and merge-to-branch closeout stage receipts, including narrow Windows copied-add admission, independently checked readiness, and actionable evidence gates for unsupported merge profiles.
25
+ - A task-oriented installed manual, concise README, tool/task navigation, progressive skill references, and deterministic documentation/link/packing checks.
26
+
27
+ ### Changed
28
+
29
+ - **Breaking:** replace `plastic_diffFile`, `plastic_diffRevisions`, and `plastic_workspaceDiff` registrations with `plastic_diff` and explicit `file`, `revisions`, or `workspace` modes. The old tool names have no aliases or redirects. Pending review requires selected paths or explicit `allPending=true`; raw GUI diff remains blocked.
30
+ - Consolidated diffs use qualified, hash-verified loaded bases, bounded stable local snapshots, explicit binary/unavailable results, and truthful partial workspace outcomes.
31
+ - Mutation receipts distinguish command completion, emitted identity, observed state, partial effects, and unverified outcomes. Failed core operations reject so compound callers cannot proceed from success-looking presentation text; uncertainty never authorizes blind retries or rollback.
32
+ - Review-patch receipts expose selector/backend fidelity, bounded hash/byte/excerpt observations, atomic no-overwrite publication, and owned cleanup/retention without applying patches.
33
+ - Admit bounded multiline checkin and closeout comments while retaining strict validation of paths, selectors, identities, and other control characters.
34
+ - Align active development, deterministic host/rendering checks, and tool-loading evals with stable Pi 1.1.0; host framework packages remain peers.
35
+ - Modularize execution, domain, operations, presentation, and Pi adapters while preserving canonical-root loading and core export ownership.
36
+ - Keep tests, evals, and contributor tooling repository-only while packaging the consumer manual and required runtime resources.
37
+ - Remove the post-publish registry-visibility gate while retaining fail-closed version/commit reconciliation before publishing.
38
+
39
+ ### Fixed
40
+
41
+ - Correct cross-platform deterministic tests to assert Windows-only source rejection on other platforms and use physical workspace fixture paths when the temporary root is a junction.
42
+ - Accept observed checked-out `CO` pending records with unavailable (`-1`) revisions, preserving selected paths so unrelated excluded checkouts do not block checkins.
43
+ - Resolve closeout parents through bounded installed-client leaf-name queries with emitted full-name/direct-parent validation; preserve repository/server qualifiers and stop on ambiguous or failed observations.
44
+ - Read the explicit loaded-branch status header independently of pending merge-link changeset references; reject malformed, ambiguous, lossy, or incomplete branch observations without guessing alternate identities.
45
+ - Stop compound merge/checkin continuation after failed switches, updates, readiness reads, or checkins, and retain observed created identities and earlier-effect uncertainty across later failures.
46
+ - Bound selected command collectors even when terminal or pipe closure never arrives, preserving escalation, listener cleanup, incomplete-capture facts, and no-retry behavior.
47
+ - Preserve split UTF-8 sequences across subprocess chunks; reject unsupported Windows pre-decoding path substitutions without adding an encoding fallback.
48
+ - Fail consolidated diffs closed on permission/I/O errors and unsupported workspace markers, and enforce aggregate UTF-8 response bounds without changing retained identities or completed counts.
49
+ - Preserve full cloud/server qualifiers and exact large decimal identities in server merge results; enforce one aggregate reference budget and retain contradictory-output uncertainty.
50
+ - Separate XML unsupported profiles, malformed contract data, and observation overflow without exposing source values.
51
+ - Isolate SDK rendering-test configuration before runtime imports and validate canonical package ownership in deterministic host tests.
52
+
10
53
  ## [0.7.6] - 2026-09-29
11
54
 
12
55
  ### Changed
package/README.md CHANGED
@@ -1,209 +1,83 @@
1
1
  # Pi Plastic
2
2
 
3
- Pi tools, footer status, and skill guidance for Plastic SCM / Unity Version Control workflows.
3
+ Plastic SCM / Unity Version Control tools and workflow guidance for [Pi](https://pi.dev).
4
4
 
5
- ## Tool presentation
5
+ Use it to inspect a workspace, review changes without opening a GUI, and perform explicitly scoped branch, checkin, merge, shelveset, and code-review operations.
6
6
 
7
- Plastic tools use compact action headers inside Pi's standard tool boxes. Headers show the workspace name and the branch, file, revision pair, or query being acted on; command previews are labeled explicitly. Collapsed results summarize structured status counts, diff availability, patch output, and server-merge outcomes. Blocked checkins, unresolved effects, omitted results, and unavailable comparisons remain visible without expansion. Plain CLI output stays neutral rather than implying a verified mutation.
7
+ ## What you get
8
8
 
9
- Expand a result using your configured tool-expansion shortcut to see the workspace, request, colored diff hunks, and complete original returned evidence. The display preserves JSON identifiers and numeric text, masks common credential assignments, and removes terminal control sequences. Rendering does not change tool execution or model-facing output; it is not a general source-code secret scanner.
10
-
11
- Run `npm run preview:tools` from a repository checkout for offline examples. The preview uses plain colors and a test expansion binding; Pi supplies the live theme, box, and configured shortcut.
12
-
13
- ## Plastic branch footer status
14
-
15
- When Pi starts inside a Plastic workspace, this package adds a themed `Plastic <branch>` status to Pi's built-in footer. It discovers the nearest enclosing `.plastic/plastic.workspace` and reads either the selector's `smartbranch` or `br` form as the credential-free branch source. A bounded `cm status` call is used only when the selector has no valid branch. Selector changes and successful same-workspace `plastic_*` tools refresh the status; sibling workspaces are ignored.
16
-
17
- The extension owns only the `plastic-branch` status key. It does not replace Pi's footer or suppress Pi's Git branch display, so Git and Plastic information can appear together in nested workspaces. If the Plastic marker exists but neither the selector nor `cm` yields a branch, the footer shows `Plastic branch unavailable`. Non-Plastic directories show no Plastic status.
18
-
19
- ## File-discovery filter
20
-
21
- When `@aefree/pi-file-discovery` is also loaded, Pi session startup registers the independent advisory `plastic.ignore-files` file-discovery filter through the package-qualified capability-registry rendezvous key. The packages may have separate module roots; Plastic does not import file-discovery from its own root. It discovers readable `ignore.conf` and `cloaked.conf` only from the nearest Plastic workspace to each requested root, then supplies them as ripgrep ignore files without replacing native ripgrep/Git-ignore behavior. A root is emitted only when it has at least one readable ignore/cloak file; each emitted root declares `filterDecision: "applied"`, decision code `plastic_ignore_files_applied`, and that workspace as its `filterBoundary`. No-op Plastic roots are omitted from mixed requests, and a request with no effective ignore/cloak records is `not_applicable`. The integration is optional: without `pi-file-discovery`, all Plastic tools and skills still load and no filter registry is created. Missing, malformed, or unavailable Plastic filter data degrades to generic discovery; `pi-file-discovery` owns that execution hygiene and disclosure behavior. It does not register workflow guidance or perform Plastic CLI readiness checks; owning `plastic_*` tools validate their own workspace and CLI requirements.
22
-
23
-
24
- ## Mutation execution
25
-
26
- Directly invoked mutating `plastic_*` tools do not require approval tokens or package-owned UI confirmation. After the tool's existing argument, command, workspace-readiness, exact-target, and path-containment checks pass, each command attempt proceeds to its intended `cm` spawn. The process layer makes one attempt and does not retry implicitly; inspect Plastic status before manually retrying an ambiguous side-effecting failure.
27
-
28
- Removing the approval layer does not relax Plastic safety guards. Command allowlists, exact mutation targets, workspace/path containment, non-interactive process selection, blocked `cm diff`, safe merge flags, and operation-specific preflight behavior remain authoritative. Compound tools may intentionally execute multiple validated command steps.
29
-
30
- ## Tools
31
-
32
- - `plastic_tool_search` (dynamic capability search and loader)
33
- - `plastic_status`
34
- - `plastic_update`
35
- - `plastic_add`
36
- - `plastic_checkin`
37
- - `plastic_undo`
38
- - `plastic_resolveDeleteChangeConflict`
39
- - `plastic_diff`
40
- - `plastic_patch`
41
- - `plastic_diffRevisions`
42
- - `plastic_diffFile`
43
- - `plastic_workspaceDiff`
44
- - `plastic_branchCreate`
45
- - `plastic_switchBranch`
46
- - `plastic_merge`
47
- - `plastic_mergeBranches`
48
- - `plastic_mergeToBranch`
49
- - `plastic_finalizeMerge`
50
- - `plastic_currentBranch`
51
- - `plastic_branchList`
52
- - `plastic_branchExists`
53
- - `plastic_branchDelete`
54
- - `plastic_shelvesetCreate`
55
- - `plastic_shelvesetApply`
56
- - `plastic_shelvesetDelete`
57
- - `plastic_shelvesetList`
58
- - `plastic_codeReviewCreate`
59
- - `plastic_codeReviewUpdate`
60
- - `plastic_codeReviewDelete`
61
- - `plastic_codeReviewFind`
62
- - `plastic_workspaceList`
63
-
64
- ## Dynamic tool loading
65
-
66
- The package exposes 30 public `plastic_*` tools. `plastic_workspaceCreate` is intentionally not registered or discoverable until the package provides a paired, safe workspace-cleanup capability. `plastic_tool_search` is a package-owned loader that searches the explicit Plastic capability catalog, reports bounded matches and safety guidance, and additively enables selected tools for the next model request.
67
-
68
- The default **balanced** session set keeps `plastic_tool_search`, `plastic_status`, and `plastic_currentBranch` active. The other Plastic tools remain registered but inactive until selected; built-in and other-extension tools are not removed. Previous loader additions on the active session branch are restored on startup, resume, fork, and reload.
69
-
70
- For controlled comparisons, set `PI_PLASTIC_TOOL_LOADING_MODE` before starting Pi:
71
-
72
- ```bash
73
- PI_PLASTIC_TOOL_LOADING_MODE=balanced # default production candidate
74
- PI_PLASTIC_TOOL_LOADING_MODE=loader-only # maximum initial schema reduction
75
- PI_PLASTIC_TOOL_LOADING_MODE=all-active # all 30 currently exposed tools; loader omitted
76
- ```
77
-
78
- Pi uses canonical `sourceInfo` provenance to identify this package's effective tools before deferring, restoring, or activating them. If canonical provenance or ownership of the effective loader cannot be proven, `pi-plastic` fails safe: it preserves the complete current active set exactly, does not defer, remove, or activate any `plastic_*` name, and an effective package loader can only report known tools that are already active rather than activating inactive names. On sourceInfo-capable Pi instances, providers without native deferred definitions still receive the complete current active set after a loader call. Reload or restart Pi after source edits; source files are not watched automatically.
79
-
80
- ## Safety behavior
81
-
82
- The Bash guards run only in Pi processes that actually load this package. A project-local install does not protect a delegated child process whose working directory resolves different project settings. Install `pi-plastic` at user scope (the default `pi install`, without `-l`) when subagents and sessions in arbitrary workspaces must inherit the guards. Restart existing Pi processes after installation or source changes.
83
-
84
- - `plastic_branchCreate` supports an explicit parent branch independent of the loaded workspace branch, defaults relative names to the current branch when no parent is supplied, and rejects top-level paths unless `allowRootBranch=true` is explicit.
85
- - `plastic_diff` remains a disabled alias by design. Use `plastic_status` for changed-path listing; do not diff as routine post-edit validation or checkin preflight. When change-boundary evidence is needed, use `plastic_diffFile` for one exact file, `plastic_workspaceDiff` with selected paths or explicit `allPending=true`, or `plastic_diffRevisions` for an explicit historical pair. Diff responses use small defaults and caller-controlled `maxChars` bounds. Automatic pending-file bases bind each status revision ID to its owning workspace or Xlink repository/server, including mixed-Xlink reviews. If ownership cannot be resolved, that comparison is reported unavailable rather than retrieving a bare revision from the caller repository. Historical and workspace bytes are copied to ASCII-safe package-owned paths before the backend runs, while normalized headers retain the logical Unicode labels.
86
- - `plastic_status(machineReadable=true, format="json")` returns parsed `items`, aggregate `summary`, and `itemCount` (`total`, `returned`, `omitted`) rather than requiring agents to parse Plastic rows. It returns at most 100 items by default; set `maxItems` (up to 500) when more are intentional. `includeRaw=true` adds the original unbounded Plastic output for diagnostics, so omit it for normal agent use to conserve context tokens.
87
- - Pending-diff ownership containment uses filesystem identity, so a workspace reached through a symlink, junction, or platform filesystem alias still resolves its workspace and nested Xlink bases safely. Plastic commands and returned labels retain the caller's original lexical path; missing deleted or moved ownership ancestors remain unavailable rather than falling back to a parent repository.
88
- - Preflight is not routine confirmation. Use it for ambiguous or broad mutation scope, moved/deleted path rewriting, compound operations, or explicit preview requests; otherwise rely on exact targets and the tools' runtime guards.
89
- - `plastic_patch` generates review patches with `cm patch`, including `clean` and `integration` filters for branch review workflows. It does not expose patch apply. Unqualified `br:/...` selectors are qualified only with the current workspace selector's exact repository; otherwise pass `br:/<branch>@<repository>@<server>`.
90
- - Bash safety rails block `cm diff` and unsafe interactive `cm merge --merge` usage.
91
- - Merge tooling surfaces Plastic `FILE_CONFLICT` records and merge-state metadata from `cm status`.
92
- - `plastic_mergeBranches` is a separate workspace-free server-side route. It requires fully repository/server-qualified source and target branches in the same exact repository/server and a nonempty message. Its optional preflight only renders the command; it does not analyze remote conflicts. A completed result proves one emitted root-mount target changeset for this dispatch, not source merge-link identity, exclusive target-head ownership, server capability beyond the dispatch, rollback, or xlink effects. No-op and conflict records do not independently prove that no server effect occurred. The route has no workspace fallback, retries, target-head unification, xlink policy, shelve mode, or conflict-policy override; undetected server-side xlink effects remain possible.
93
- - `plastic_mergeToBranch` performs the common safe closeout flow: resolve the source branch's parent as the default target, switch to the target branch, optionally update, merge a source branch non-interactively, verify merge state, and check in the merge result. It verifies the loaded target before merge/checkin and rejects final-branch mismatches; Plastic checkins stay on the branch where they were created, so switching afterward is not a Git-style integration.
94
- - `plastic_finalizeMerge` supports reviewed/manual-resolution flows where Plastic still needs merge metadata finalized before checkin.
95
-
96
- ## Patch generation examples
97
-
98
- ```text
99
- plastic_patch(source="<branch-spec>", integration=true)
100
- plastic_patch(source="<branch-spec>", clean=true, integration=true, output="<patch-file>")
101
- plastic_patch(source="<left-spec>", destination="<right-spec>")
102
- plastic_patch(source="<branch-spec>", toolPath="<path-to-diff-tool>")
103
- ```
104
-
105
- If `output` is omitted, the package returns patch content. If `output` is provided, it must be a new path: the package generates into a package-owned sibling staging file, validates it, and atomically publishes it without overwriting an existing path. Plastic/server patch output may encode a moved item either as a move or as delete/add records; `pi-plastic` does not claim a representation without a live backend fixture. Inspect patches before sharing them because they can contain source code, binary content, local paths, or secrets that were present in the changed files.
106
-
107
- ## Included skill
108
-
109
- - `using-plastic` - PlasticSCM branch, workspace, merge, shelveset, checkin, and code-review workflow guidance
9
+ - **27 core tools** with producer-owned structured results, plus an on-demand capability loader.
10
+ - **Text-only diffs and generated review patches**, with explicit scope and bounded output.
11
+ - **Agent-driven server conflict resolution:** inspect conflicts, validate merged files, and submit per-file JSON decisions without a merge UI.
12
+ - **Truthful mutation receipts:** command completion, observed identities, partial effects, and uncertainty stay separate.
13
+ - **Pi integration:** compact tool displays, a Plastic branch footer, Bash guards, and optional Plastic ignore/cloak filtering for file discovery.
14
+ - **The `using-plastic` skill**, with task-specific references loaded only when needed.
110
15
 
111
16
  ## Install
112
17
 
113
- Install the latest stable npm release at user scope so the safety guards also load for delegated child processes in other workspaces:
18
+ Install the npm release at user scope:
114
19
 
115
20
  ```bash
116
21
  pi install npm:@aefree/pi-plastic
117
22
  ```
118
23
 
119
- Install a pinned GitHub release over HTTPS:
120
-
121
- ```bash
122
- pi install git:github.com/aefreedman/pi-plastic@v0.7.6
123
- ```
124
-
125
- Equivalent SSH install:
126
-
127
- ```bash
128
- pi install git:git@github.com/aefreedman/pi-plastic@v0.7.6
129
- ```
130
-
131
- To intentionally track the moving default branch instead of a release tag:
24
+ To test the current Git version instead:
132
25
 
133
26
  ```bash
134
27
  pi install https://github.com/aefreedman/pi-plastic
135
28
  ```
136
29
 
137
- Local development install:
138
-
139
- ```bash
140
- pi install <path-to-pi-plastic>
141
- ```
142
-
143
- Project-local install:
144
-
145
- ```bash
146
- pi install -l <path-to-pi-plastic>
147
- ```
148
-
149
- Project-local installation protects only Pi processes that load those project settings. It is insufficient as a global Bash safety rail when a subagent launches with another working directory.
150
-
151
- ## Requirements
152
-
153
- - Node.js 22.19.0 or newer
154
- - Latest stable Pi; the current development and eval baseline is Pi 0.99.1
155
- - Plastic SCM / Unity Version Control CLI (`cm`) available on `PATH`, or `PI_PLASTIC_CM_EXECUTABLE` set to its full executable path
156
- - A GNU/POSIX-compatible text `diff` available on `PATH`, or `PI_PLASTIC_DIFF_EXECUTABLE` set to its full executable path (including paths containing spaces), for text-only diff tools. Pi invokes that resolved executable as-is and does not discover Git Bash paths automatically. On macOS, bare `diff` is PATH-dependent: it may be GNU Diffutils (often installed as `diff` ahead of system paths) or Apple’s BSD `/usr/bin/diff`; the package does not substitute one for the other. Configure the intended text executable explicitly when that distinction matters.
157
- - Patch generation has a separate executable policy: `toolPath` is the one-call highest-priority override, followed by `PI_PLASTIC_PATCH_EXECUTABLE`. On Windows, set one to a verified patch-capable non-GUI executable such as Git's `diff.exe`; the package deliberately does not reuse `PI_PLASTIC_DIFF_EXECUTABLE`/GnuWin32 as a patch default. macOS validation with Plastic 11 found that Apple BSD `/usr/bin/diff` supports text-only diffs but rejects the `--binary` argument supplied by `cm patch`; configure a verified GNU Diffutils-compatible executable explicitly for `plastic_patch`. The non-Windows fallback to `PI_PLASTIC_DIFF_EXECUTABLE` or bare `diff` remains only for environments whose resolved executable satisfies that patch contract. In an interactive Pi session, an invalid configured patch override or missing Windows patch setting produces one package capability warning per Pi runtime; the warning omits configured paths, and `plastic_patch` retains its tool-time validation.
158
- - A configured Plastic workspace for workspace-scoped operations. Text diffs require an ASCII-safe temporary directory; if the configured backend cannot accept Unicode paths, set `TEMP` and `TMP` to a writable ASCII-only location.
159
- - `pi-file-discovery` is an optional independently loaded integration. When its `discover_candidate_files` tool is active, it receives the advisory Plastic ignore/cloak filter through the shared global capability protocol; when absent, `pi-plastic` loads without file-discovery filtering. The tarball does not embed linked sibling workspaces or `node_modules` paths.
160
-
161
- ## Testing
162
-
163
- ```bash
164
- npm test
165
- ```
166
-
167
- `npm test` first runs `npm run typecheck` with pinned TypeScript and Node 22 types. The strict, no-emit check covers `index.ts`, `src/`, every extension, and compile-only schema-inference contracts under `tests/types/`. Runtime tests and eval harnesses execute through `tsx`.
30
+ Git main can contain unreleased changes; npm installs the published release. See [setup](docs/2026-10-06-setup.md) for pinned releases, local checkouts, configuration, and updating an existing installation.
168
31
 
169
- The default suite is credential-free and covers tool validation, schema conversion, path-resolution regressions, extension registration, rendering, OpenAI strict-schema compatibility classification, and bash guard behavior.
32
+ ### Requirements
170
33
 
171
- Run the opt-in read-only live smoke test against a dedicated clean sandbox workspace:
34
+ - Node.js **22.19.0 or newer** and the latest stable Pi.
35
+ - An authenticated Plastic CLI (`cm`) on `PATH`, or an explicit executable override.
36
+ - A configured Plastic workspace for workspace-scoped tools.
37
+ - A compatible non-GUI `diff` for text comparisons. Patch generation has a **separate backend policy**, particularly on Windows and macOS; see [diff and patch setup](docs/2026-10-06-setup.md#diff-and-patch-backends).
172
38
 
173
- ```bash
174
- PI_PLASTIC_TEST_WORKSPACE=/absolute/path/to/sandbox npm run test:live
175
- ```
39
+ Restart existing Pi processes after installation or source changes. User-scope installation makes the guards available across workspaces; project-local settings alone do not protect child processes launched elsewhere.
176
40
 
177
- The live test requires `/main`, no pending changes, and no merge in progress. It does not mutate the repository. Mutation tools should still be rehearsed manually in a disposable sandbox before relying on them in a new environment.
41
+ ## Start with inspection
178
42
 
179
- ### Dynamic tool-loading eval
43
+ Open Pi in the intended Plastic workspace and ask it to inspect pending changes. The default balanced mode starts with `plastic_status`, `plastic_currentBranch`, and `plastic_tool_search` active.
180
44
 
181
- The package-local behavioral eval uses fresh Pi 0.99.1 JSON subprocesses against an explicitly attested dedicated Plastic sandbox and is not a skill eval. It compares all-active, balanced, and loader-only mode behavior, checks exact smallest-sufficient loader activations, blocks destructive calls unless they are supported `preflight: true` previews, captures tool calls and sanitized provider-schema measurements, and deletes raw provider payload captures by default.
45
+ These are tool calls inside Pi, not shell commands:
182
46
 
183
- ```bash
184
- npm run eval:tool-loading -- --dry-run
185
- PI_PLASTIC_EVAL_SANDBOX=/absolute/path/to/sandbox PI_PLASTIC_EVAL_ALLOW=dedicated-sandbox npm run eval:tool-loading -- --model openai-codex/gpt-5.6-luna --condition balanced
47
+ ```text
48
+ plastic_status(source="xml", maxItems=20)
49
+ plastic_tool_search(query="text diff")
50
+ plastic_diff(mode="workspace", paths=["Assets/Example.txt"])
186
51
  ```
187
52
 
188
- See [`evals/tool-loading/README.md`](evals/tool-loading/README.md) for approved model restrictions, cases, measurements, and result hygiene.
53
+ XML status is opt-in and has Windows CM11 source validation. Pick the status source appropriate to your client using the [status guide](docs/2026-10-06-status.md). Load other capabilities as needed; don't enable all tools or run every preflight as routine ceremony.
189
54
 
190
- ## Constrained sampling compatibility
55
+ ## Find the right documentation
191
56
 
192
- Pi supports provider-side constrained sampling for tools. `pi-plastic` does not currently opt in: every public Plastic schema includes optional fields (at minimum `workdir`), while OpenAI strict function schemas require closed objects and all declared properties to be required. Pi forwards the registered schema without converting those optional fields.
57
+ | Need | Start here |
58
+ |---|---|
59
+ | Install, update, or configure executables | [Setup](docs/2026-10-06-setup.md) |
60
+ | Find a tool or understand on-demand loading | [Tool catalog and loading](docs/2026-10-06-tools-and-loading.md) |
61
+ | Interpret success, partial results, and failures | [Safety and receipts](docs/2026-10-06-safety-and-receipts.md) |
62
+ | Inspect status, branches, workspaces, or object IDs | [Status](docs/2026-10-06-status.md) · [Discovery](docs/2026-10-06-discovery.md) |
63
+ | Add, undo, switch, check in, or manage branches | [Workspace operations](docs/2026-10-06-workspace-operations.md) |
64
+ | Merge or close out a branch | [Merging](docs/2026-10-06-merging.md) |
65
+ | Compare changes or generate a patch | [Diffs and patches](docs/2026-10-06-diffs-and-patches.md) |
66
+ | Save/apply a shelf or create/update a review | [Shelvesets and reviews](docs/2026-10-06-shelvesets-and-reviews.md) |
67
+ | Understand the footer, displays, or file-discovery integration | [Integrations](docs/2026-10-06-integrations.md) |
68
+ | Work on the package or consume its structured API | [Development](docs/2026-10-06-development.md) |
193
69
 
194
- Enabling `strict: "prefer"` now would therefore either produce invalid strict OpenAI requests or require a breaking redesign of the ordinary tool arguments. The test suite audits all registered tools and prevents accidental opt-in until a schema is genuinely strict-compatible. Existing TypeBox validation and Plastic runtime safety checks remain authoritative.
70
+ The [documentation index](docs/README.md) routes by task and by tool. Agents should read the relevant page or section, not the whole manual. For operational workflows, start with [the skill](skills/using-plastic/SKILL.md).
195
71
 
196
- OpenAI Codex models may advertise grammar tools without advertising strict JSON-schema tools. Grammar sampling is not used here because Plastic operations have structured multi-field arguments rather than a single bounded string language.
72
+ ## Important safety behavior
197
73
 
198
- ## Implementation notes
74
+ - Prefer `plastic_*` tools. Raw `cm diff` / `cm differences` and unsafe interactive merge commands are blocked by the loaded Bash guards.
75
+ - Mutations do **not** require package-owned approval tokens or UI confirmation. The agent must still have user authorization and inspect the intended scope.
76
+ - A completed command is not automatically a verified effect. Read the receipt before chaining calls; after an uncertain mutation, inspect state rather than blindly retrying.
77
+ - The tool reports supported facts and unknowns; the agent chooses further investigation or resolution within the user's authorization. No universal rollback, conflict-resolution, or cross-platform guarantee is implied.
199
78
 
200
- - The core implementation lives in `src/plastic-core.ts`.
201
- - Shared workspace discovery and branch parsing live in `src/plastic-workspace.ts`.
202
- - `extensions/plastic-branch-status.ts` owns the additive footer status and its session-scoped refresh lifecycle.
203
- - `index.ts` is the Pi tool registration layer.
204
- - `src/plastic-renderers.ts` owns compact calls, result summaries, and expanded evidence.
205
- - Output shapes are intentionally stable for prompt and workflow compatibility.
79
+ ## Contributing and license
206
80
 
207
- ## License
81
+ For a checkout, run `npm ci --ignore-scripts --no-audit --no-fund` and `npm test`. See [development](docs/2026-10-06-development.md), [contributing](https://github.com/aefreedman/pi-plastic/blob/main/CONTRIBUTING.md), and [security reporting](https://github.com/aefreedman/pi-plastic/blob/main/SECURITY.md).
208
82
 
209
- MIT. See `LICENSE`.
83
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,101 @@
1
+ # Development and structured API
2
+
3
+ [Documentation index](README.md) · [Receipt semantics](2026-10-06-safety-and-receipts.md)
4
+
5
+ For contributor policy, see [CONTRIBUTING](https://github.com/aefreedman/pi-plastic/blob/main/CONTRIBUTING.md). This page explains current source ownership, validation, and consumer limitations—not a one-time release procedure.
6
+
7
+ ## Checkout setup
8
+
9
+ ```bash
10
+ npm ci --ignore-scripts --no-audit --no-fund
11
+ npm test
12
+ npm run test:host:status
13
+ npm run eval:tool-loading -- --dry-run
14
+ npm pack --dry-run
15
+ ```
16
+
17
+ Run commands from the manifest root. `npm test` starts with `npm run typecheck`: strict no-emit coverage includes index/src/extensions and compile-only schema-inference contracts. Runtime tests/evals use tsx.
18
+
19
+ The current pinned development/eval SDK and TUI baseline is **1.1.0**, as declared in package.json; older Pi releases are not a supported matrix. Historical fixture/evidence version strings are not alternate runtime targets. Host-provided framework packages remain peers, not bundled runtime dependencies.
20
+
21
+ Default tests are credential-free. They cover schemas/semantic guards, registration/loading, aliases, paths/snapshots, lifecycles/retirement, rendering, Bash guards, documentation/navigation, ownership and constrained-sampling classification. The SDK-host harness uses real file loading/finalization/direct/codemode/nested consumers and JSON execution events, with a deterministic local provider and synthetic CLI—no network/backend-effect acceptance.
22
+
23
+ ## Structured API and transport
24
+
25
+ All 27 core tools have closed output schemas and direct native producer execution. The capability loader is deliberately schema-less. Core exports remain string-returning views; selected failures reject so compound callers cannot proceed on presentation text.
26
+
27
+ Producers own request snapshots, source admission, bounded projection and same-observation presentation. Native details vary by route: legacy read presentation can remain in rawResult, while mutation/diff receipts use empty details. Don't parse strings to reconstruct canonical facts.
28
+
29
+ ### Consumer caveats
30
+
31
+ - Host policy/preabort can reject before a producer DTO exists; handle host-native rejection as well as DTO ok.
32
+ - Optional null may be normalized to omission before delivery, and invalid enums may be rejected by the SDK before the producer. No universal raw-submitted-value fidelity is promised.
33
+ - Foreign result hooks own replacements; content-only changes can remove structured output and cause text fallback. The producer doesn't restore it or enforce post-hook bounds.
34
+ - Ordinary transcript messages don't automatically persist the full DTO; general RPC/provider fidelity is not claimed.
35
+ - Identity, capture, request/argv/outcome/effect consistency matters beyond closed JSON shape. Keep adversarial semantic tests when changing schemas.
36
+
37
+ The [family references](README.md#look-up-a-tool) describe the canonical fields/bounds; [receipt semantics](2026-10-06-safety-and-receipts.md) explains chaining decisions.
38
+
39
+ ## Source map
40
+
41
+ | Area | Owner |
42
+ |---|---|
43
+ | Explicit core exports | src/plastic-core.ts; operation modules under src/operations |
44
+ | Shared workspace discovery/branch parsing | src/plastic-workspace.ts |
45
+ | CLI execution/capture/context | src/execution |
46
+ | Source parsing/admission and domain contracts | src/domain |
47
+ | Pi registry/parameters/structured adapters | src/pi; index.ts is the entry shim |
48
+ | Text/JSON presentation | src/presentation |
49
+ | Compact/expanded tool rendering | src/plastic-renderers.ts |
50
+ | Footer lifecycle | extensions/plastic-branch-status.ts |
51
+ | Bash safety guards | Declared extensions and their focused tests |
52
+ | Task workflow guidance | skills/using-plastic and its on-demand references |
53
+ | Public consumer manual | docs/README.md and dated topic pages |
54
+
55
+ Keep stable public tool names/output shapes unless a deliberate breaking change is documented. Do not weaken guards, mutate dependencies/versions incidentally, or centralize another package's policy here.
56
+
57
+ ## Live validation
58
+
59
+ Live CM runs require an authorized, dedicated disposable sandbox and the contributor's own authentication. Never add credentials, organization/server coordinates, original private files or raw provider payloads to public fixtures/docs.
60
+
61
+ Read-only smoke, from an intentionally clean sandbox with /main and no merge in progress:
62
+
63
+ ```bash
64
+ PI_PLASTIC_TEST_WORKSPACE=/absolute/path/to/dedicated/sandbox npm run test:live
65
+ ```
66
+
67
+ For explicit branch-creation mutation validation:
68
+
69
+ ```bash
70
+ PI_PLASTIC_TEST_WORKSPACE=/absolute/path/to/dedicated/sandbox \
71
+ PI_PLASTIC_ALLOW_MUTATION_TESTS=true \
72
+ npm run test:live:branch-create
73
+ ```
74
+
75
+ The branch test creates uniquely named hierarchical branches, checks explicit-parent/root guards, does not switch the workspace and removes its temporary branches under its cleanup contract. Do not run broad mutation suites merely to add evidence; inspect exact scope first.
76
+
77
+ For behavior changes, report the narrow actual live test and resulting-state/cleanup evidence without private coordinates. If unavailable, mark live validation pending. Documentation-only/internal changes can mark live validation not applicable with a reason. Source-backed platform/client limits remain in the family references.
78
+
79
+ ## Tool-loading eval
80
+
81
+ The package-owned behavioral eval is not a skill eval. Fresh SDK 1.1.0 JSON subprocesses compare all-active/balanced/loader-only mode, smallest-sufficient activations and sanitized provider-schema measurements.
82
+
83
+ Dry-run validates configuration without live provider trials. Actual trials require an explicitly attested dedicated Plastic sandbox and an approved model. Destructive calls are blocked unless supported preflight previews; raw payload captures are deleted by default.
84
+
85
+ Read the repository [eval guide](https://github.com/aefreedman/pi-plastic/blob/main/evals/tool-loading/README.md) for model restrictions, cases, metrics and result hygiene. Tests/eval harness files are intentionally repository-only rather than packed consumer dependencies.
86
+
87
+ ## Constrained sampling
88
+
89
+ The package does not opt in to provider-side strict sampling. Public schemas include optional fields (at least workdir); OpenAI strict function schemas require closed objects and every declared property required. Pi forwards schemas without converting optional fields.
90
+
91
+ `strict="prefer"` would therefore need either invalid requests or a breaking argument redesign. Tests prevent accidental opt-in until schemas are genuinely compatible. Runtime/TypeBox admission remains authoritative.
92
+
93
+ Codex grammar capability does not imply strict JSON-schema capability. Grammar sampling is not used because these operations have structured multi-field arguments, not one bounded string language.
94
+
95
+ ## Documentation and packaging checks
96
+
97
+ Keep README as a landing page, docs as the consumer reference, skill files as progressive workflow guidance, and workspace plans/private evidence outside the package. New topic pages retain date-prefixed filenames; update navigation and links when adding/moving content.
98
+
99
+ Documentation tests verify relative links/anchors, every core tool route, schema-bearing coverage, concise README, current baseline claims and packed-document closure. Review `npm pack --dry-run` content as well as its file list: no tests/evals/private coordination material is added by splitting the manual.
100
+
101
+ These are structural and execution checks, not a browser accessibility audit or proof that every agent will choose the right page. No provider-backed doc-reading eval is implied.
@@ -0,0 +1,136 @@
1
+ # Diffs and patches
2
+
3
+ [Documentation index](README.md) · [Backend setup](2026-10-06-setup.md#diff-and-patch-backends) · [Safety and receipts](2026-10-06-safety-and-receipts.md)
4
+
5
+ Use `plastic_diff` for bounded comparison evidence. Use `plastic_patch` to generate a review artifact. Neither opens the GUI diff; patch application is not exposed.
6
+
7
+ ## Choose the output you need
8
+
9
+ | Need | Tool |
10
+ |---|---|
11
+ | Loaded/historical base against one local file | diff, file mode |
12
+ | Two explicit historical selectors | diff, revisions mode |
13
+ | Selected pending paths or a bounded all-pending set | diff, workspace mode |
14
+ | A generated branch/spec review patch or an intentional new output file | patch |
15
+
16
+ Status is the changed-path listing tool; diff only when content evidence is needed. Inspect artifacts before sharing: changed content can contain secrets, local paths, code or binary data. Display masking is not a source-code secret scanner.
17
+
18
+ ## Diff modes
19
+
20
+ `plastic_diff` requires one explicit closed mode. The former specialized names are removed, not aliases.
21
+
22
+ | Mode | Required scope | Behavior |
23
+ |---|---|---|
24
+ | file | path; optional revision | Omitted revision uses a verified loaded base; explicit revision skips status/base queries |
25
+ | revisions | leftRevision and rightRevision | Two sequential owned exports; selectors retain unresolved identity unless observed independently |
26
+ | workspace | Nonempty paths or allPending=true | Match pending scopes; includePrivate only with allPending |
27
+
28
+ ```text
29
+ plastic_diff(mode="file", path="Assets/Example.txt", maxChars=3000)
30
+ plastic_diff(mode="revisions", leftRevision="<left file-revision selector>", rightRevision="<right file-revision selector>")
31
+ plastic_diff(mode="workspace", paths=["Assets/Example.txt"])
32
+ ```
33
+
34
+ Workspace paths cap 20. maxFiles is 1–20, default 3 for all-pending/20 for scoped paths. Directories select pending descendants, while directory rows themselves are skipped. A moved source or destination selects the same observation.
35
+
36
+ All modes return a closed versioned action diff envelope independent of text/JSON format. Comparison data records pending/comparison kind, origins/selectors/paths, observed loaded identity when available, bytes/binary flags, backend/capture evidence, excerpts and counts.
37
+
38
+ ## Loaded bases and snapshots
39
+
40
+ Loaded ownership comes from strict UTF-8 status/fileinfo/ls observations: a genuine qualified file revision ID, repository/server agreement, and exported bytes matching loaded metadata's MD5/SHA1 hash.
41
+
42
+ - Deleted files use the frozen loaded root tree deliberately.
43
+ - Local moves use observed OldPath metadata.
44
+ - Added and explicitly selected private files use an intentional empty base; added-empty is distinct from unchanged.
45
+ - Unavailable/nodata/unsupported ownership fails, never becomes an empty side.
46
+ - No changeset number becomes a file revision, bare-ID ownership guess, or failed-query fallback.
47
+ - Mixed-Xlink ownership remains unverified.
48
+
49
+ Historical exports use new owned temporary destinations outside the workspace. `cm cat --file=` writes that destination; it is not an input selector. The tools own their exports/cleanup.
50
+
51
+ Local snapshots require physical workspace containment, regular non-symlink files, bounded descriptor reads, and stable observable identity/size/timestamps/namespace. Retained bytes are independent of later edits, not an atomic filesystem/repository snapshot. Cleanup completes before success.
52
+
53
+ ## Diff result and failure interpretation
54
+
55
+ Text comparison requires one configured GNU/POSIX `diff -u`:
56
+
57
+ - Exit 0 with empty output, or exit 1 with complete fatal-UTF-8 structurally consistent unified hunks, is admitted.
58
+ - NUL/invalid-UTF-8 content uses exact internal byte equality.
59
+ - Signal/null terminal, stderr, timeout, malformed/partial streams, failed/oversized exports or cleanup failures return sanitized errors.
60
+ - English GNU no-final-newline markers are supported; unverified variants fail closed.
61
+ - No retry or backend substitution.
62
+
63
+ Workspace results preserve per-file failures plus parsed/eligible/selected/attempted/completed/failed/skipped/unattempted/limited/returned/omitted counts, private exclusions and unmatched paths. Overall ok can be false while earlier comparisons remain recorded. Inspect read/projection completeness before declaring a review complete.
64
+
65
+ ```js
66
+ const dto = await tools.plastic_diff({mode: "workspace", paths: ["Assets/Example.txt"]});
67
+ text({ok: dto.ok, completeness: dto.completeness, data: dto.data});
68
+ ```
69
+
70
+ This deliberately keeps partial evidence rather than turning failure into an empty comparison.
71
+
72
+ ### Diff bounds
73
+
74
+ | Bound | Value |
75
+ |---|---|
76
+ | Each retained/export-read side | 4 MiB; not a hard cat disk-transfer quota |
77
+ | Command capture | 1 MiB stdout /64 KiB stderr |
78
+ | Process timeout initiation | 30 seconds plus collector escalation |
79
+ | File/revisions excerpt | 8,000 characters default; 500–20,000 |
80
+ | Workspace excerpt | 3,000 default; 500–8,000 |
81
+ | Compact DTO | 131,072 UTF-8 bytes |
82
+ | Presentation | 24,000 characters |
83
+
84
+ Excerpts use surrogate-safe UTF-16 source/marker/omission counts and are not guaranteed applyable patches. Workspace aggregate projection may omit whole outcomes with explicit counts, never clip IDs. JSON remains valid and may direct callers to structuredContent instead of duplicating it.
85
+
86
+ ## Patch generation
87
+
88
+ `plastic_patch` uses `cm patch` for generation only. Defaults: JSON presentation, clean=false, integration=false; current backend precedence and local-selector qualification remain.
89
+
90
+ ```text
91
+ plastic_patch(source="br:/main/owned-feature", integration=true)
92
+ plastic_patch(source="br:/main/owned-feature", clean=true, integration=true, output="new-review.patch")
93
+ plastic_patch(source="<left spec>", destination="<right spec>")
94
+ plastic_patch(source="<branch spec>", toolPath="<verified patch-capable executable>", format="text")
95
+ ```
96
+
97
+ `output` is a new artifact path, not the text/JSON presentation selector. `format="text"` is additive presentation. `toolPath` is the highest-priority one-call backend override; consult [setup](2026-10-06-setup.md#diff-and-patch-backends) before selecting a backend.
98
+
99
+ Unqualified branch selectors are qualified only from the current workspace selector's exact repository/server. Otherwise supply a complete qualified branch. No alias equivalence, immutable/head selection, move encoding, workspace-effect, custom-backend-effect or rollback proof is invented.
100
+
101
+ The receipt separates:
102
+
103
+ 1. Requested/effective selectors and backend, with a redacted command projection.
104
+ 2. One generation attempt and capture.
105
+ 3. Bounded observed artifact bytes, SHA256, UTF-8/character/excerpt evidence where admitted.
106
+ 4. Atomic no-overwrite publication, separate from observation.
107
+ 5. Owned cleanup/retention and recovery directory information.
108
+
109
+ No `--apply`, backend/strategy retry, probe fallback or workspace mutation follows. Server output may represent moves as moves or delete/add; don't assume representation without inspecting the generated artifact.
110
+
111
+ ## Publication and cleanup
112
+
113
+ With no output path, admitted patch content is returned and owned temp cleanup follows the supported route. An empty omitted-output artifact is legitimate.
114
+
115
+ Explicit output requires nonempty admitted bytes, then atomic exclusive hard-link publication from owned sibling staging. Existing destinations are never replaced. Failed/incomplete/warning captures cannot publish.
116
+
117
+ Already observed artifacts/publication remain recorded after later failure. Possibly running/timed-out/aborted processes cause staging/recovery retention when cleanup cannot be justified; retirement does not prove the child stopped. Destination content, aliases and concurrent/global scope are not independently verified by publication alone.
118
+
119
+ ### Patch bounds and preflight
120
+
121
+ | Bound | Value |
122
+ |---|---|
123
+ | Stable regular artifact read | 4 MiB |
124
+ | Local selector read | 64 KiB |
125
+ | Request / controls | 32 KiB UTF-8 /4096 UTF-16 code units |
126
+ | DTO | 512 KiB UTF-8 |
127
+ | Excerpt | 60,000 characters |
128
+ | CM capture | 64 KiB stdout /16 KiB stderr |
129
+
130
+ UTF-8 character/byte metrics are correlated, including truncated/opaque projections. Input/capture/observation/publication/outcome relationships are validated, not merely JSON shape.
131
+
132
+ Preflight renders command intent; it may read local selector metadata, but does not stage, probe the backend, or generate a patch. It is not conflict analysis or artifact existence proof.
133
+
134
+ ## Validation scope
135
+
136
+ Comparison source evidence is bounded to Windows CM 11.0.16.10371 and the tested GNU diff backends; macOS text-only/backend incompatibility evidence is documented in setup. Other client/platform/backends, mixed-Xlink/nodata ownership, foreign post-hooks and RPC remain unverified. Those limits are not permission to silently switch routes.