@@ -188,3 +188,26 @@ upgrade still closes `4401`. One found-in-production fix: the shell's
188188Dockerfile never declared the three new build args, so the first bake
189189silently kept localhost fallbacks — Docker only passes ARGs a Dockerfile
190190names.
191+
192+ ### The human gate caught a zombie (#73 , filed and fixed same hour)
193+
194+ The operator's walk-through hit a wall that looked exactly like a dead
195+ database — empty roster, searches dying with * "the workspace did not
196+ reply"* — while the backend answered a freshly-minted session perfectly
197+ (441-org roster, instant search). Root cause: id-didi-sh's JWT lives
198+ ~ 12h inside a 30-day cookie with a ` /api/session/refresh ` contract, and
199+ ** nothing ever called it** . On expiry the UI stayed rendered from
200+ localStorage, the transport reconnect-looped on 4401 at ~ 2/sec (a
201+ literal reject storm in the production logs), and queued invokes
202+ blamed the server at their 120s deadline.
203+
204+ The fix landed both halves in ` packages/workspace ` : every surface now
205+ refreshes the token hourly and on tab-focus (the endpoint re-mints even
206+ an expired JWT while the session row lives), and the transport treats
207+ close 4401/4403 as auth-death — failing all pending work instantly with
208+ an honest * "session expired — sign in again"* , emitting a new
209+ ` auth_required ` status that clears ` user ` so the SignInWall reappears
210+ over the stale UI, trying one silent refresh-then-reconnect (mid-flight
211+ expiry heals invisibly), and retrying at a glacial 30s instead of
212+ storming. Operator findings on the header chrome landed as a second
213+ issue (#72 ) for the polish pass.
0 commit comments