@gotgenes/pi-permission-system 33.0.0 → 33.0.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [33.0.1](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v33.0.0...pi-permission-system-v33.0.1) (2026-09-19)
9
+
10
+
11
+ ### Documentation
12
+
13
+ * **pi-permission-system:** document the serving-liveness and bound-channel mechanism in the integration spec ([#942](https://github.com/gotgenes/pi-packages/issues/942)) ([2786acc](https://github.com/gotgenes/pi-packages/commit/2786accaf40136f192e6f8d187058ae60c7555b5)), closes [#942](https://github.com/gotgenes/pi-packages/issues/942)
14
+
8
15
  ## [33.0.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v32.1.0...pi-permission-system-v33.0.0) (2026-09-18)
9
16
 
10
17
 
@@ -160,7 +160,9 @@ The polling session publishes the session id it polls, and a child checks that i
160
160
 
161
161
  The announcement goes out on two channels, because a child cannot always reach the same one.
162
162
  A child running inside its parent's process reads a process-global registry.
163
+ A stale mark left in that registry by a session that died without `session_shutdown` suppresses the fast-fail and falls back to the timeout — the safe direction for that channel.
163
164
  A child running as a separate `pi` process (the `PI_SUBAGENT_PARENT_SESSION` path) shares no memory with its parent, so it reads a heartbeat record the serving session refreshes under `<agent dir>/sessions/permission-forwarding/serving/`, holding the served session id, the serving process id, and the time it was last refreshed.
165
+ That `serving/` directory is created on demand and never removed.
164
166
 
165
167
  For an out-of-process target, four things count as "not draining":
166
168
 
@@ -171,7 +173,7 @@ For an out-of-process target, four things count as "not draining":
171
173
  | A record nobody has refreshed for several seconds | The parent's process survives but has stopped polling |
172
174
  | A record for a different session id | The child is forwarding somewhere nobody is listening |
173
175
 
174
- If the target is not draining its inbox, the child gives up after a two-second grace window rather than waiting out `forwardingTimeoutMs`, and the tool is blocked with:
176
+ If the target is not draining its inbox, the child gives up after a two-second grace window (`PERMISSION_FORWARDING_SERVING_GRACE_MS`) rather than waiting out `forwardingTimeoutMs`, and the tool is blocked with:
175
177
 
176
178
  ```text
177
179
  [pi-permission-system] Running bash command 'pwd' requires approval, but no
@@ -180,6 +182,7 @@ permission requests.
180
182
  ```
181
183
 
182
184
  The grace window exists so a request that arrives while the parent is switching sessions is not abandoned in the gap.
185
+ Absence of a record is deliberately **not** read as unknown: a cleanly exited parent leaves nothing behind, so treating absence as "maybe serving" would restore the full-timeout stall that the heartbeat exists to end.
183
186
  A target that *is* draining its inbox is waited on for the full `forwardingTimeoutMs`, however long the human takes to decide.
184
187
  That includes a parent whose human is still deliberating at an earlier forwarded prompt: it keeps refreshing its heartbeat throughout, so a second child does not read it as gone.
185
188
 
@@ -188,6 +191,7 @@ None of them is reported as a user denial, because no user was ever asked.
188
191
 
189
192
  The two sides of the exchange are correlatable in the review log: the serving session writes `forwarded_permission.serving_started` with the id it polls, and the child writes `forwarded_permission.request_created` with the `targetSessionId` it forwarded to.
190
193
  When a forwarded request goes unanswered, comparing those two entries distinguishes a parent that was not polling from one polling a different session.
194
+ The child's `forwarded_permission.no_serving_session` entry also records `servingChannel` and `servingState` beside the ids observed, since "exited", "killed", and "polling a different session id" are different diagnoses the shared denial string does not distinguish.
191
195
 
192
196
  When a forwarded request *is* answered, the child's own terminal entry names both which session answered and what within it decided.
193
197
  The serving node records its decider on the response — a rule of its own (with the surface, pattern, and origin that matched), the link that ruled, or the human who answered its dialog — and the child records it nested under a `forwarded` frame:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotgenes/pi-permission-system",
3
- "version": "33.0.0",
3
+ "version": "33.0.1",
4
4
  "description": "Permission enforcement extension for the Pi coding agent.",
5
5
  "type": "module",
6
6
  "exports": {