@zieglar/pi-chat-exchange 0.0.0-stage → 0.2.0

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 (94) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE +21 -0
  3. package/README.md +89 -2
  4. package/dist/bin/mcp-stdio.js +196 -0
  5. package/dist/control/debug-log.js +67 -0
  6. package/dist/control/mcp/debug-transport.js +48 -0
  7. package/dist/control/mcp/messaging-tools.js +278 -0
  8. package/dist/control/mcp/ping.js +43 -0
  9. package/dist/control/mcp/server.js +153 -0
  10. package/dist/core/authorization.js +32 -0
  11. package/dist/core/reference.js +32 -0
  12. package/dist/core/rules.js +468 -0
  13. package/dist/endpoints/pi/contract.js +2 -0
  14. package/dist/endpoints/pi/session-host.js +39 -0
  15. package/dist/host/bound-endpoint.js +176 -0
  16. package/dist/host/endpoint-host.js +839 -0
  17. package/dist/host/mcp-binding-config.js +209 -0
  18. package/dist/host/ownership-recovery.js +257 -0
  19. package/dist/index.js +11 -0
  20. package/dist/protocol/capabilities.js +46 -0
  21. package/dist/protocol/endpoint-capabilities.js +15 -0
  22. package/dist/protocol/entities.js +185 -0
  23. package/dist/protocol/formats.js +13 -0
  24. package/dist/protocol/idempotency.js +93 -0
  25. package/dist/protocol/identity.js +130 -0
  26. package/dist/protocol/index.js +8 -0
  27. package/dist/protocol/lifecycle.js +125 -0
  28. package/dist/protocol/outcomes.js +55 -0
  29. package/dist/runtime/desktop-manifest.js +65 -0
  30. package/dist/runtime/diagnostics.js +34 -0
  31. package/dist/runtime/executables.js +222 -0
  32. package/dist/storage/capability.js +221 -0
  33. package/dist/storage/connection.js +94 -0
  34. package/dist/storage/creation-request.js +176 -0
  35. package/dist/storage/creation.js +553 -0
  36. package/dist/storage/current-schema.js +397 -0
  37. package/dist/storage/delivery-ack.js +177 -0
  38. package/dist/storage/errors.js +9 -0
  39. package/dist/storage/filesystem.js +116 -0
  40. package/dist/storage/inbox-discovery.js +135 -0
  41. package/dist/storage/messaging.js +156 -0
  42. package/dist/storage/migration.js +258 -0
  43. package/dist/storage/ownership.js +789 -0
  44. package/dist/storage/participant-identity.js +127 -0
  45. package/dist/storage/participant.js +700 -0
  46. package/dist/storage/recovery.js +99 -0
  47. package/dist/storage/runtime.js +113 -0
  48. package/dist/storage/schema.js +556 -0
  49. package/dist/storage/session-state.js +75 -0
  50. package/dist/storage/store.js +450 -0
  51. package/dist/storage/transaction.js +199 -0
  52. package/dist/storage/trust-root.js +164 -0
  53. package/dist/tunnel/background-manager.js +1727 -0
  54. package/dist/tunnel/codes.js +79 -0
  55. package/dist/tunnel/health.js +75 -0
  56. package/dist/tunnel/keychain.js +526 -0
  57. package/dist/tunnel/managed-binding.js +454 -0
  58. package/dist/tunnel/manager-panel.js +249 -0
  59. package/dist/tunnel/manager-ui.js +341 -0
  60. package/dist/tunnel/manager.js +372 -0
  61. package/dist/tunnel/messaging-activation-ui.js +85 -0
  62. package/dist/tunnel/messaging-config.js +246 -0
  63. package/dist/tunnel/multi-session-admission.js +31 -0
  64. package/dist/tunnel/multi-session-policy.js +314 -0
  65. package/dist/tunnel/offline-client.js +104 -0
  66. package/dist/tunnel/profile.js +319 -0
  67. package/dist/tunnel/redact.js +9 -0
  68. package/dist/tunnel/secure-input.js +318 -0
  69. package/dist/tunnel/session-process-mutex.js +338 -0
  70. package/dist/tunnel/setup-ui.js +443 -0
  71. package/dist/tunnel/setup.js +734 -0
  72. package/dist/tunnel/state.js +127 -0
  73. package/docs/architecture.md +170 -0
  74. package/docs/chatgpt-installation.md +149 -0
  75. package/docs/delivery-ack-contract.md +86 -0
  76. package/docs/independent-install.md +156 -0
  77. package/docs/multi-session-usage.md +77 -0
  78. package/docs/ownership-contract.md +429 -0
  79. package/docs/protocol-v2.md +269 -0
  80. package/docs/releases/0.2.0.md +59 -0
  81. package/docs/storage-contract.md +1241 -0
  82. package/docs/storage-security.md +138 -0
  83. package/docs/tunnel-manager-background.md +169 -0
  84. package/docs/tunnel-setup.md +214 -0
  85. package/native/tunnel-keychain.swift +432 -0
  86. package/package.json +77 -4
  87. package/pi-extension/README.md +125 -0
  88. package/pi-extension/allowlist.example.json +11 -0
  89. package/pi-extension/index.ts +2312 -0
  90. package/pi-extension/multi-session-commands.ts +93 -0
  91. package/pi-extension/multi-session-runtime.ts +75 -0
  92. package/pi-extension/tui-keys.ts +40 -0
  93. package/scripts/reconcile-session-process-mutex.mjs +262 -0
  94. package/scripts/recover-stale-ownership.mjs +91 -0
@@ -0,0 +1,269 @@
1
+ # pi-chat-exchange Protocol v2 (frozen)
2
+
3
+ Frozen 2026-10-06 by PH-0002 (the approved architecture correction of
4
+ PH-0001). Changes require an explicit contract revision. Machine-readable
5
+ forms live in `src/protocol/` (schemas, lifecycle requirement table) and
6
+ `src/core/rules.ts` (pure enforcement). See [architecture.md](architecture.md)
7
+ for layering; the superseded v1 is recorded in `docs/protocol-v1.md` (repo-only,
8
+ not distributed).
9
+
10
+ **Authorized PH-0003 amendment:** the owner-abandonment cancellation exception
11
+ is superseded by the amendment recorded in `docs/quarantine-hotfix-ph0003.md`
12
+ (repo-only, not distributed). The amended rule itself is stated in this contract.
13
+ No identity format, outcome vocabulary or normal close precondition changes.
14
+
15
+ **Approved PH-0003 convergence:** Client/Agent labels become scoped action grants;
16
+ MCP is a control surface, not conversation delivery. Peer endpoint support is
17
+ independent of authorization and factual evidence. Entity/identity schemas and
18
+ the corrected lifecycle edges remain unchanged. The underlying audit is recorded
19
+ in `docs/chat-bridge-audit-ph0003.md` (repo-only, not distributed).
20
+
21
+ ## 1. Identity (compatibility preserved)
22
+
23
+ | Entity | Prefix | Status |
24
+ | --- | --- | --- |
25
+ | Exchange | `ho_<ULID>` | legacy v1 prefix retained (v1 "handoff" → Exchange aggregate); no id migration |
26
+ | Result | `hr_<ULID>` | unchanged from v1 |
27
+ | Message | `msg_<ULID>` | additive v2 |
28
+ | DeliveryAttempt | `att_<ULID>` | additive v2 |
29
+ | Receipt | `rcpt_<ULID>` | additive v2 |
30
+ | Event | `evt_<ULID>` | additive v2 |
31
+
32
+ All ids: Crockford Base32 ULID (48-bit ms timestamp + 80-bit CSPRNG
33
+ randomness, losslessly encoded — derivation recorded in
34
+ `docs/identity-hotfix-ph0002.md`, repo-only, not distributed), opaque, unique,
35
+ immutable, non-secret, independent of payload contents. Display suffixes are
36
+ never authoritative.
37
+
38
+ ## 2. Message lifecycle
39
+
40
+ ```text
41
+ CREATED → QUEUED → CLAIMED → DISPATCHING → ACCEPTED → RUNNING → SETTLED
42
+ → RESULT_AVAILABLE
43
+ ```
44
+
45
+ Auxiliary states: `DELIVERY_UNKNOWN` (quarantined), `CANCEL_REQUESTED`, and
46
+ finished `CANCELLED` / `FAILED` (with `RESULT_AVAILABLE`). There is no
47
+ `CONSUMED`: reads never mutate lifecycle state.
48
+
49
+ Transition legality is a two-tier table (`TRANSITION_REQUIREMENTS` in
50
+ `src/protocol/lifecycle.ts`): shape-only helpers (`canTransition`,
51
+ `isLegalTransition`) answer structural legality, never authorize mutations.
52
+ Every actual transition checks scoped grants; evidence-bearing moves additionally
53
+ check their correlated factual evidence. Highlights:
54
+
55
+ - `CLAIMED → QUEUED` / `CLAIMED → CANCELLED`: scoped release/confirm grant + recorded
56
+ lease + a consistent `not_attempted` / `pending` attempt (the only safe
57
+ requeue). Contradictory transport facts cannot be laundered by the marker.
58
+ - `CLAIMED → DISPATCHING`: scoped dispatch-start grant + **current** lease + durable
59
+ `started` dispatch marker (marked BEFORE any adapter effect).
60
+ - `DISPATCHING → ACCEPTED`: current authoritative fenced lease + transport
61
+ `delivered` **and independently correlated runtime `accepted` evidence**.
62
+ Transport delivery alone is never runtime acceptance.
63
+ - `DISPATCHING / CLAIMED / CANCEL_REQUESTED → DELIVERY_UNKNOWN`: recorded
64
+ attempt + potentially attempted/ambiguous transport evidence; lease expiry
65
+ does not prevent recovery into quarantine. These recovery records do not
66
+ grant live dispatch authority.
67
+ - `DISPATCHING → FAILED`: current lease + transport `failed`, reported only
68
+ when the adapter proves no side effect occurred; otherwise `ambiguous`.
69
+ A crash after the start marker quarantines via `CLAIMED → DELIVERY_UNKNOWN`.
70
+ - Runtime progress requires current fencing and independently correlated
71
+ `RuntimeEvidence` (`exchangeId`, `messageId`, `attemptId`, endpoint, outcome,
72
+ observation time): `RUNNING` needs `running`; `SETTLED` needs settlement-grade
73
+ `settled|runtime_error|cancelled|interrupted`. A dispatch marker is not proof
74
+ of execution. `SETTLED → RESULT_AVAILABLE` additionally requires a validated
75
+ correlated immutable Result loaded from successful publication.
76
+ - `DELIVERY_UNKNOWN → ACCEPTED/FAILED`: scoped reconciliation grant + recorded lease +
77
+ correlated transport evidence + **explicit reconciliation evidence**. Acceptance
78
+ additionally requires an independent scoped runtime-progress grant and evidence.
79
+ `DELIVERY_UNKNOWN → CANCELLED` is prohibited (PH-0003 authorized hotfix):
80
+ owner intent/reconciliation text is not execution evidence. Administrative
81
+ abandonment is a separate disposition, never an execution-state transition.
82
+ No exit to retryable states; no automatic retry anywhere.
83
+ - Cancellation: `QUEUED → CANCELLED` (cancellation-request grant; nothing dispatched)
84
+ is evidence-free but NOT permission-free. From `CLAIMED/DISPATCHING/ACCEPTED/RUNNING`
85
+ the requester may only `→ CANCEL_REQUESTED`; confirmation requires a separately
86
+ scoped cancellation-confirmation grant.
87
+ (`CANCEL_REQUESTED → CANCELLED`) needs either provably not-attempted
88
+ dispatch (`not_attempted` plus `pending`) or a started/delivered attempt with
89
+ correlated runtime `cancelled` confirmation; ambiguity remains quarantined.
90
+ Started runtime cancellation ALSO requires settlement-report authority;
91
+ no-attempt cancellation does not synthesize a runtime event.
92
+ Failure/settlement requires its own evidence, not the request. Queued
93
+ cancellation also rejects contradictory presented dispatch evidence.
94
+
95
+ Guards must correlate the exact message, attempt, endpoint and recorded lease.
96
+ For live progress and safe release/requeue, `currentLease` must ALSO match the
97
+ authoritative latest claim read by the host transaction (token, consumer,
98
+ instance and expiry). An old attempt's matching lease is not enough. Invalid
99
+ timestamps fail closed. Quarantine/reconciliation may cite historical leases
100
+ but never authorize retry or dispatch.
101
+
102
+ These helpers validate supplied snapshots, not persistence/authentication.
103
+ The future host must authenticate the principal, load the current message,
104
+ attempt, latest claim, complete exchange message set and published result itself,
105
+ then check-and-commit atomically. Never accept `authorization`, `currentLease`, or
106
+ published-result proof directly from an external adapter as authoritative.
107
+ Concurrent revision/CAS and durable fencing allocation remain unimplemented.
108
+ Request-only moves need no synthetic lease input. Attempt-backed moves still
109
+ require validated recorded/current lease evidence according to the unchanged
110
+ transition table.
111
+
112
+ ## 3. Entities (src/protocol/entities.ts)
113
+
114
+ - `Exchange { exchangeId, state OPEN|CLOSED, createdAt, closedAt? }`
115
+ - `Message { messageId, exchangeId, from, to, state, payloadDigest,
116
+ payloadLength, createdAt, idempotencyKey? }` — either direction; no
117
+ product fields survive schema validation.
118
+ - `EndpointRef { adapter, endpointId, instanceId? }` — opaque non-secret
119
+ routing identity; durable endpoint vs ephemeral instance; no free routing
120
+ metadata, no credentials (`additionalProperties: false`).
121
+ - `Lease { consumerId, instanceId, fencingToken ≥ 1, expiresAt }`
122
+ - `DeliveryAttempt { attemptId, messageId, endpoint, lease, dispatch
123
+ not_attempted|started, transport pending|delivered|ambiguous|failed,
124
+ createdAt }`
125
+ - `RuntimeEvidence { exchangeId, messageId, attemptId, endpoint, outcome,
126
+ observedAt }` — independent runtime observation, never inferred from transport.
127
+ - `Result { resultId, exchangeId, messageId, attemptId, source, transport,
128
+ runtime, body, resultDigest, settledAt, applicationEvidence? }` —
129
+ transport trichotomy `delivered|ambiguous|failed`; runtime ladder
130
+ `accepted|running|settled|runtime_error|cancelled|interrupted`;
131
+ `applicationEvidence` is opaque JSON the protocol never interprets.
132
+ - `Receipt { receiptId, exchangeId, messageId, endpoint, kind
133
+ read|delivery_ack|duplicate_suppressed, createdAt }`
134
+ - `Consumer { consumerId, label?, createdAt, lastSeenAt? }`
135
+ - `Event { eventId, exchangeId, sequence ≥ 1, kind, subjectId, createdAt,
136
+ digest?, length?, outcome? }` — diagnostics carry IDs/digests/lengths/typed
137
+ outcomes only; raw payload bodies are structurally rejected.
138
+
139
+ ### Administrative termination without execution resolution
140
+
141
+ Normal `Exchange.state = CLOSED` still requires every Message to be finished.
142
+ It is not broadened to mean an unresolved Exchange was cancelled or succeeded.
143
+ Instead an immutable `ExchangeDisposition` records administrative termination:
144
+
145
+ ```text
146
+ status = ABANDONED_UNRESOLVED
147
+ exchangeId, ownerId, recordedAt, reason, reconciliation intent
148
+ unresolved[] = { messageId, originalState: DELIVERY_UNKNOWN,
149
+ transport: ambiguous, unresolvedSideEffects: true,
150
+ attempt: original started/ambiguous DeliveryAttempt snapshot }
151
+ ```
152
+
153
+ The Exchange snapshot remains OPEN and Messages remain DELIVERY_UNKNOWN; the
154
+ independent disposition makes the aggregate administratively inactive, not
155
+ execution-resolved. A future view/API must expose BOTH execution facts and the
156
+ disposition, never translate this marker into CANCELLED, FAILED_NO_EFFECT, a
157
+ Result or success. The marker itself is the immutable administrative audit
158
+ record. Its owner/time/reason and investigation metadata are not execution proof.
159
+ `reconciliation.resolvedAt` retains the existing metadata field name, but here
160
+ timestamps the investigation/intent record, not resolution of side effects.
161
+
162
+ `archiveUnresolvedExchange` requires owner authority, at least one unresolved
163
+ Message, exactly one correlated started/ambiguous active attempt per unresolved
164
+ Message, and no remaining in-flight activity. Other Messages may already be
165
+ finished. It preserves snapshots and permits exact replay, never replacement.
166
+ No transport outcome is altered, no retry/requeue is authorized, no Result is
167
+ manufactured. Unknown→ACCEPTED/FAILED still requires actual correlated evidence
168
+ and explicit reconciliation BEFORE administrative termination.
169
+
170
+ `assertExchangeActive` is the host admission precondition for creation, claims
171
+ and every subsequent protocol mutation. Transition, publication and normal
172
+ close helpers also reject a supplied authoritative disposition. The future
173
+ host MUST load that record atomically; external callers cannot select/omit it.
174
+ Administrative termination does not stop an already-delivered external runtime
175
+ or prevent its side effects; it only stops protocol activity. Later external
176
+ facts may be retained as separate audit observations, never revive the archived
177
+ protocol or rewrite the original uncertainty snapshot. Historical reads remain
178
+ non-mutating and allowed. Persistence, ACLs, audit append and APIs are not
179
+ implemented in this phase.
180
+
181
+ ## 4. Idempotency (create)
182
+
183
+ Keyed by **(namespace, key)** with a canonical-request digest (SHA-256 over
184
+ recursively key-sorted JSON; unsupported values and cyclic structures are
185
+ rejected with `DigestInputError`). Equivalent repeats replay the same
186
+ immutable record; same key with a different digest fails closed with
187
+ `IDEMPOTENCY_KEY_CONFLICT`. The in-memory reference store
188
+ (`src/core/reference.ts`) is a semantics reference only, not durable.
189
+ Namespace/key storage uses an unambiguous JSON tuple, not concatenation with
190
+ a caller-allowed separator. Opaque application evidence must be finite, acyclic
191
+ plain JSON; Maps/Sets/Dates, sparse arrays, symbols and unsupported values are
192
+ rejected at core publication/read boundaries. Publication requires a
193
+ settlement-grade runtime outcome; reading returns immutable snapshots without
194
+ recording semantic completion.
195
+
196
+ ## 5. Action grants and endpoint support
197
+
198
+ Closed `CONTROL_OPERATIONS`: `exchange_send/get/list/cancel/result`. Optional
199
+ `exchange_close` and `exchange_archive` remain separate grants and unimplemented
200
+ control APIs. `ENDPOINT_OPERATIONS`: claim, dispatch-start, delivery report,
201
+ runtime activity/settlement, publication, lease release, factual reconciliation
202
+ and cancellation confirmation. Catalog separation is checked by
203
+ `assertOperationSeparation`; it does NOT impose protocol roles.
204
+
205
+ `AuthorizationContext { principalId, grants[] }`; each grant has
206
+ `{ action, principalId, scope }`. Actions and scopes are a closed discriminated
207
+ union, validated at typecheck and runtime. Send/get/result require Exchange
208
+ scope; cancel requires Message scope; claim requires Message+destination scope;
209
+ endpoint mutations require Message+Attempt+recipient scope (all include Exchange).
210
+ Close/archive require owner scope and bind ownerId to the context principal.
211
+ Listing declares collection permission; future host filtering is still required.
212
+ Different principal/Exchange/Message/Attempt/endpoint incarnation cannot reuse
213
+ a grant. Delivery authority alone cannot assert runtime acceptance.
214
+
215
+ **Contexts are not credentials.** The future host authenticates identities,
216
+ maps sender/destination/owner/consumer bindings, loads current grants and
217
+ authoritative snapshots and supplies contexts to pure core rules transactionally.
218
+ Caller-provided grants, adapter kind, implemented interface or support claims
219
+ cannot establish any of those facts. No host/authentication service exists here.
220
+
221
+ `EndpointDeclaration { kind, capabilities }` advertises independent delivery,
222
+ observation, cancellation, follow-up and result-production support.
223
+ Support is `supported|unsupported|unknown`; optional/missing means unknown.
224
+ No method or advertisement creates evidence or grants. Pi declares only a
225
+ binding shape; no implemented capabilities are advertised. No ChatGPT endpoint
226
+ is implemented. Known delivery with unknown execution cannot be mislabeled
227
+ DELIVERY_UNKNOWN or manufacture runtime acceptance/settlement. Unsupported
228
+ workflows may be rejected by future admission policy before effects.
229
+
230
+ ## 5a. Result versus conversational reply
231
+
232
+ Result remains processing evidence/output for one Message/Attempt. Publication
233
+ requires its scoped grant, settlement-grade outcome and immutable replay/conflict
234
+ validation. The future host must check publication and RESULT_AVAILABLE transition
235
+ together against authoritative settled Message/Attempt/runtime facts; the helper
236
+ alone is not proof of execution.
237
+
238
+ Reply/follow-up communication is another Message in the same Exchange, with
239
+ its own ID, reversed or otherwise explicit from/to and independent evidence.
240
+ No automatic Result-to-Message conversion, reply send, read-consumption or close
241
+ exists. This needs no change to Message/Result/EndpointRef wire schemas.
242
+
243
+ ## 6. Superseded v1 semantics (documented)
244
+
245
+ | v1 (PH-0001) | v2 (PH-0002) | Why |
246
+ | --- | --- | --- |
247
+ | Handoff entity `ho_` | Exchange aggregate `ho_` (same prefix) | aggregate root correction |
248
+ | `CONSUMED` terminal state | removed | reads must never be semantic consumption |
249
+ | `DELIVERED` state, `CLAIMED→QUEUED` shape-legal | `DISPATCHING` + evidence-gated requeue | durable dispatch-start before effect; validated no-attempt proof |
250
+ | `piSessionRef` source field | generic `EndpointRef` | opaque, product-neutral routing identity |
251
+ | `CHATGPT_TOOLS` / consumer surfaces | `CLIENT_OPERATIONS` / `AGENT_OPERATIONS` ports | no product names; disjoint literal authority |
252
+ | transport `delivered\|delivery_unknown`; runtime `succeeded\|failed\|…` | transport `delivered\|ambiguous\|failed`; runtime `accepted\|running\|settled\|runtime_error\|…` | generic vocabularies, layers never borrow terms |
253
+ | (proposed) loopback HTTP + bearer token broker | deferred with the durable host | out of v2 scope |
254
+
255
+ Superseded v1 tests: `schemas.test.ts` and `surfaces.test.ts` (removed; their
256
+ invariants survive as `entities.test.ts` and `capabilities.test.ts`);
257
+ `lifecycle.test.ts` was rewritten for the v2 machine; `idempotency.test.ts`
258
+ was extended (namespace scoping, immutable records, strict digest input).
259
+ Retained unchanged: the 11 identity/encoder tests
260
+ (`identity.test.ts`, hotfix-regression included) and the MCP smoke tests
261
+ (`test/control/mcp/`, moved by PH-0003 without smoke behavior changes).
262
+
263
+ ## 7. Security rules (frozen, carried from v1)
264
+
265
+ Never persist or expose credentials, API keys, auth files, environment
266
+ secrets, or hidden model reasoning. Payload/result bodies are sensitive:
267
+ correlate via digests in diagnostics; events carry IDs, digests, lengths, and
268
+ typed outcomes only. The MCP surface performs no `process.env` access
269
+ (enforced by the package check). Endpoint identity is non-secret by contract.
@@ -0,0 +1,59 @@
1
+ # 0.2.0
2
+
3
+ **MIT authorized and third-party evidence complete.** The owner authorized MIT for CE's own code, Copyright (c) 2026 zieglar; see the package LICENSE. The full 101-item dependency closure is audited in the repo-only license audit record `docs/license-audit.md` (retained in the repository, not distributed in this tarball): 100 已验证兼容 plus the Host peer — the two former evidence gaps (`@earendil-works/pi-tui@1.3.0`, Host peer `@earendil-works/pi-coding-agent@1.3.0`) closed via three-layer exact-version evidence (registry tarball declarations + upstream tag `v1.3.0` root LICENSE: MIT, (c) 2025 Mario Zechner; upstream artifacts omit license text — packaging omission, not incompatibility). `private: true` is removed per the owner's conditional rule. Owner authorization covers CE's own code only — it is not a grant to relicense dependencies.
4
+
5
+ ## 0.2.0 scope
6
+
7
+ Prebuilt Pi extension for explicit message exchange, durable SQLite storage and Secure MCP Tunnel management. No new cleanup authority, lifecycle hooks, automatic transport start, Recovery or unknown-result retry. All direct dependency pins remain unchanged.
8
+
9
+ The user-visible feature delta carried by 0.2.0 — opt-in Session-authorized `ce_ack`, `/ce-tunnel doctor` and `/ce-tunnel deactivate`, independent Sessions on a shared Tunnel, and trusted portable runtime installs — is enumerated in [CHANGELOG.md](../../CHANGELOG.md). Version 0.1.1 was internal only and never published. Changesets remains the repository's version authority: the queued `.changeset/ce-e2b-ack-mcp.md` entry is described, not consumed, and a future version PR must reconcile it with this hand-written 0.2.0 entry.
10
+
11
+ Certification target: **Node 24.21.0 + Pi 1.3.0 + macOS arm64**. Existing approved Node 24.22.1 is not part of 0.2.0's certification; Linux is experimental/unverified. **CLOUD_TRANSPORT: NOT_VERIFIED.** Loopback registry and synthetic client evidence must not be represented as public npm or cloud evidence.
12
+
13
+ ## Installation routes
14
+
15
+ Where this exact version is available from a registry you trust, the native managed npm route is:
16
+
17
+ ```sh
18
+ "$CE_APPROVED_NODE" "$CE_PI_CLI" install npm:@zieglar/pi-chat-exchange@0.2.0
19
+ "$CE_APPROVED_NODE" "$CE_PI_CLI" list
20
+ ```
21
+
22
+ Use approved absolute Node and Pi 1.3.0 CLI paths, and npm supplied by that Node with private config/cache and ignore-scripts. Pi suppresses peer auto-installation; its independent Host supplies Pi peers. The install-command evidence for 0.2.0 was produced against an owned loopback registry, not public npm; registry availability itself is not certified by this document. Always confirm the exact version actually resolves before relying on it.
23
+
24
+ [Independent installation](../independent-install.md) describes the separate prebuilt tarball asset fallback and the mandatory safe uninstall/upgrade/rollback procedure. GitHub assets are downloaded/hashed before physical prefix installation, not passed as Pi URLs; monorepo source loading is a development route, not managed npm. Do not load two copies.
25
+
26
+ ## Producer record and artifact integrity
27
+
28
+ Author uses frozen pnpm 12.9.1 dependencies with ignore-scripts and approved Node. Run `pnpm run package:pi-extension` in the package: build → validate disk closure → validate native pack inventory → pack without hooks. Retain the exact `.tgz`, SHA256/SRI, inventory, fixed commit, lockfile hash, tool versions, argv/private environment and test evidence. Never rebuild on consumer machines or substitute an old archive for the tested artifact.
29
+
30
+ Where 0.2.0 is distributed as a GitHub Release asset, it is the exact tested `zieglar-pi-chat-exchange-0.2.0.tgz` plus `SHA256SUMS` generated with `shasum -a 256 zieglar-pi-chat-exchange-0.2.0.tgz > SHA256SUMS`. Consumers download both assets and run `shasum -a 256 -c SHA256SUMS` before installation. The archive is never rebuilt between validation and upload.
31
+
32
+ **Integrity claim limits.** The harness computes the artifact's SRI/SHA256 metadata, serves exactly those bytes over the owned loopback registry, and compares every installed payload file byte-for-byte against the tested archive. That is metadata plus installed-payload byte identity. There is no corrupted-metadata/corrupted-payload **integrity-rejection negative**, so no claim is made that a consumer npm would refuse a tampered artifact.
33
+
34
+ The third-party LICENSE evidence gates are closed: the per-version evidence is retained in the author's private evidence store and summarized in `docs/license-audit.md`, which is repo-only and not distributed in this tarball. Whenever the shipped pins change, the retained evidence must be re-confirmed against them. Cloud transport validation is a separate, still-undecided scope and no cloud claim is made by 0.2.0.
35
+
36
+ ## Isolated author regression (explicit opt-in, repo-only)
37
+
38
+ These release notes ship in the tarball, but the instructions in this section
39
+ are **repo-only and NOT consumer-executable**: they describe author harness
40
+ scripts that exist in the monorepo and never ship in the package.
41
+
42
+ In a fresh private archive stage with physically installed frozen dependencies,
43
+ set `CE_DISTRIBUTION_ARCHIVE` to the newly validated 0.2.0 `.tgz` and
44
+ `CE_DISTRIBUTION_NPM_CLI` to the approved Node distribution's `npm-cli.js`.
45
+ Run `pnpm run test:distribution-npm` for actual native Pi install/remove/reinstall,
46
+ and `pnpm run test:distribution-host` for the separate physical tarball route.
47
+ Both require exact Node 24.21.0 and macOS sandbox-exec; missing prerequisites
48
+ fail loudly. They retain private evidence and use the existing guardian for
49
+ Host/native npm descendants. Never run against real profiles or credentials.
50
+ The four existing heavy default exclusions remain unchanged.
51
+
52
+ These lanes use real Pi/PTY and real managed package installation, but an owned
53
+ loopback registry and synthetic configuration/Store/key. The package's own
54
+ bytes come from that loopback registry; only its ordinary third-party
55
+ dependencies are downloaded from npmjs, and solely during the install stage.
56
+ Runtime is offline and Seatbelt-denied. No real Tunnel client
57
+ is executed. The packaged simulator's real-process owned stop and background
58
+ manager external-owner/UNKNOWN/refusal cases are separate targeted tests; they
59
+ are not evidence of cloud transport or automatic proof of other-user absence.