instar 1.3.627 → 1.3.628

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.
@@ -0,0 +1,151 @@
1
+ # Side-Effects Review — matrix-cell-operator-cancel
2
+
3
+ **Change:** Adds operator-cancel for an in-flight account×machine matrix cell — a
4
+ target-local route `POST /subscription-pool/follow-me/enroll/:id/cancel`, a fronting
5
+ relay `POST /subscription-pool/follow-me/cancel`, two `PendingLoginStore` hardening
6
+ tweaks, two `EnrollmentWizard` pass-throughs, a dashboard Cancel button, and a one-clause
7
+ CLAUDE.md awareness addition. Dark behind `multiMachine.accountFollowMe`.
8
+
9
+ **Spec:** `docs/specs/matrix-cell-operator-cancel.md` (converged iter 2, approved).
10
+
11
+ ## 1. Over-block — what legitimate inputs does this reject that it shouldn't?
12
+
13
+ - A cancel against a `completed`/`abandoned` login returns a calm idempotent `200`
14
+ (`cancelled:false, alreadyTerminal:true`) — it does NOT reject; correct.
15
+ - A cancel while a `submit-code` is in flight returns `409` ("try again in a moment").
16
+ This is intentional and momentary (the ~2s credential-poll window) — the operator can
17
+ re-tap. It is the right call: cancelling mid-credential-write would strand a partial
18
+ credential. Not an over-block.
19
+ - Malformed id (`^[a-z0-9-]+$` fail) → `404`. The store's own `ID_RE` is identical, so a
20
+ malformed id could never name a real login anyway — no legitimate input rejected.
21
+
22
+ ## 2. Under-block — what failure modes does this still miss?
23
+
24
+ - **Peer cancel when the peer is offline** → honest `502` (the relay can't reach it); the
25
+ peer's pane keeps running until that machine's next enroll pre-cleans it. Surfaced to the
26
+ operator, not silently swallowed.
27
+ - **Crash between abandon and pane-kill** → orphaned pane. Self-heals on the next enroll
28
+ (enroll-start pre-cleans the slot's pane before re-spawning). Accepted (D2).
29
+ - **Mandate not revoked** on cancel (D4) — a bounded, re-mint-only, 1h-expiring mandate
30
+ lingers. Grants no standing authority; accepted residual.
31
+ - **configHome slot not wiped** (D3) — a deliberate decision (wiping could clobber a valid
32
+ prior credential for the same account); stale-slot hygiene is the existing
33
+ credential-coherence path's job.
34
+
35
+ ## 3. Level-of-abstraction fit
36
+
37
+ Correct layer. The route family already exists (`start-cell` mints; `submit-code` operates
38
+ on an in-flight login). Cancel is a peer of `submit-code` ("operate on an existing login")
39
+ and is placed in the same route closure, sharing the `followMeSubmitInFlight` guard. The
40
+ store-level terminal guard + `issue()` replace push correctness DOWN to the store (defense
41
+ in depth) rather than relying on route logic alone. The pane teardown uses the SAME raw
42
+ `tmux kill-session` the spawn (`server.ts:10713`) uses — not a higher-level helper that
43
+ turned out to be a no-op for these unregistered panes.
44
+
45
+ ## 4. Signal vs authority compliance
46
+
47
+ The route holds de-escalating authority (kills a pane, abandons a record) gated by Bearer
48
+ auth + the dark flag. It is NOT a brittle detector with blocking teeth — it reuses the
49
+ existing structural API-edge gates (auth, `^[a-z0-9-]+$` validation, terminal-state
50
+ idempotent read, the in-flight 409). No content/intent judgment is made; the "should I
51
+ cancel?" decision is the operator's tap, not an inferred classifier. The `transition()`
52
+ terminal guard is pure mechanics (refuse a terminal→terminal flip), not a judgment gate.
53
+ Compliant with `docs/signal-vs-authority.md` (the exempted "structural guard at the edge /
54
+ idempotency mechanics" class).
55
+
56
+ ## 5. Interactions
57
+
58
+ - **Shares `followMeSubmitInFlight` with submit-code** — cancel reads it (409 if held). It
59
+ never writes it, so it can't deadlock submit-code. Verified the cancel route is colocated
60
+ in submit-code's closure (it references the same `Set`).
61
+ - **`issue()` change touches ALL callers** — but the only production caller is
62
+ `EnrollmentWizard.start()` (verified: the other `.issue(` hits are the unrelated mandate
63
+ store). start-cell only reaches `issue()` after its reuse pre-check fails on a live-pending
64
+ record, so any same-id record at `issue()` is non-pending → safe to replace.
65
+ - **`transition()` terminal guard** affects `complete()` + `abandon()` (both route through
66
+ it). It only blocks terminal→terminal; normal `pending→completed`/`pending→abandoned`
67
+ unaffected. `reissue()` does not call `transition()` and already guards terminal states.
68
+ - **Cancel vs start-cell reuse** — abandon-first makes the record non-reusable before the
69
+ cell clears, so start-cell's reuse path can never hand out a cancelled login's URL.
70
+ - No double-fire / shadow: the relay and target-local route have distinct paths
71
+ (`/follow-me/cancel` vs `/follow-me/enroll/:id/cancel`); `:id` cannot match the literal
72
+ `start`/`cancel` segments.
73
+
74
+ ## 6. External surfaces
75
+
76
+ - **Dashboard Cancel button** — a new operator-visible affordance on the in-progress (◷)
77
+ matrix cell, behind the dark dev-agent gate. Mobile-first (full-tap-target button,
78
+ optional native confirm that degrades to proceed under headless). Ships with the npm
79
+ package (no migration).
80
+ - **Two new HTTP routes** — dark behind `multiMachine.accountFollowMe` (503 when off). No
81
+ new config key.
82
+ - **No new external network egress** beyond the existing same-mesh relay hop (Bearer-authed,
83
+ to this agent's own paired machines only — `resolvePeerUrls`). No credential ever crosses.
84
+ - Timing/runtime dependence: only the momentary submit-in-flight 409 (a real, transient
85
+ condition the operator retries through).
86
+
87
+ ## 6b. Operator-surface quality (Operator-Surface Quality standard)
88
+
89
+ This change touches an operator surface (`dashboard/subscriptions.js` — the Cancel
90
+ button on the in-progress matrix cell).
91
+
92
+ 1. **Leads with the primary action?** Yes. The Cancel button is the single,
93
+ visible action on an in-progress (◷) cell — a full-tap-target `<button>Cancel</button>`
94
+ rendered inline beside the status glyph on every poll re-render (not collapsed,
95
+ not below the fold, no explanatory prose in front of it).
96
+ 2. **Zero raw internals as primary content?** Yes. The cell shows the glyph + the
97
+ word "Signing in…" + the "Cancel" button; on tap, a plain status line
98
+ ("Cancelling…" → "Cancelled — you can set this up again.") or the route's
99
+ plain-English error. No JSON, no fingerprints, no config paths, no slugs. The
100
+ `loginId`/`machineId` ride as `data-*` attributes (support metadata), never shown.
101
+ 3. **Destructive actions de-emphasized?** N/A in the harmful sense — Cancel is
102
+ itself the *reversing* (de-escalating) action, fully reversible (re-tap "Set up"
103
+ to redo). It is a small single button, optionally guarded by a native confirm
104
+ ("Cancel this in-progress setup?"). There is no separate destructive control to
105
+ demote; the constructive "Set up" path reappears after a cancel.
106
+ 4. **Plain language + phone width?** Yes. "Cancel" / "Signing in…" / "Cancelled —
107
+ you can set this up again." read the way a non-engineer would say them; the
108
+ button is a real tap target in the existing mobile-responsive matrix grid (same
109
+ cell layout as the shipped "Set up"/"Submit" buttons), no horizontal scroll, no
110
+ truncated table hiding the action.
111
+
112
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
113
+
114
+ **Proxied-on-write (relay).** A `PendingLogin` + pane live on the machine running the login
115
+ subprocess; the target-local route is machine-local by necessity. Cross-machine reach is the
116
+ fronting relay `follow-me/cancel`, dispatching by `machineId` to self-loopback or the owning
117
+ peer over the authed mesh hop — the SAME proven pattern as `follow-me/submit-code`. The
118
+ dashboard always calls the relay, so a peer cell cancels correctly; an offline peer yields an
119
+ honest 502. No durable state strands on topic transfer (a PendingLogin is not topic-scoped);
120
+ no generated URL crosses a machine boundary. The earlier self-only draft (which would have
121
+ silently 404'd peer cells) was rejected in convergence — this is the corrected posture.
122
+
123
+ ## 8. Rollback cost
124
+
125
+ Single `git revert`. Pure additive surface behind an existing dark flag. The two store
126
+ changes are backward-compatible (the terminal guard only PREVENTS a clobber that should
127
+ never happen; the `issue()` replace only RELAXES a throw). No data migration — `abandoned`
128
+ is already a valid terminal state the store + sweeps handle today. No agent-state repair. The
129
+ auto-merger handles the merge; a bad merge is one revert.
130
+
131
+ ---
132
+
133
+ ## Second-pass review
134
+
135
+ _(High-risk: touches a block/allow decision surface — a kill path + a dark gate + the word
136
+ "gate". Reviewer appended below.)_
137
+
138
+ An independent second-pass reviewer audited the actual implementation code (not just the
139
+ spec) against the artifact, line by line. Findings: **all [OK]** — kill targets the correct
140
+ pane with no injection (derived from the stored record, not `req.params.id`; `id` regex-gated
141
+ `^[a-z0-9-]+$`; no shell); gate order exactly as specified with abandon-before-kill; the
142
+ `@silent-fallback-ok` tag is correct and both catch ratchets pass; the `transition()` terminal
143
+ guard cannot break `complete()`/`reissue()`/normal flows; `issue()` replace has a single
144
+ production caller (`EnrollmentWizard.start`) and still throws on a live-pending dup; the
145
+ dashboard Cancel is on the durable cell, no PIN, confirm degrades under jsdom; template↔migrator
146
+ parity + idempotency hold; the relay adds no SSRF surface beyond submit-code (own paired
147
+ machines only, `encodeURIComponent`'d id, no `code` body); no new CI ratchet trips. One
148
+ **[MINOR]**: the submit-in-flight 409 is a momentary retry-through window (documented in §1) —
149
+ not a defect. No blockers, no material issues, no signal-vs-authority violation.
150
+
151
+ **Verdict: Concur with the review.**