| 1 | Reviewed `4db75572`. **The “misattribution only” claim is false.** Believing a caller’s address can change password-guessing limits and application authorization. Counting the places that read hop trust does not bound what downstream applications do with the trusted address. |
| 2 | |
| 3 | I found no separate door-only authority in the activator, cache, purge handling or sidecar marker. Reserved receiving-side handlers retain their existing authentication. The material differences are address trust and forwarded scheme. |
| 4 | |
| 5 | The residuals therefore need reassessment: |
| 6 | |
| 7 | - **Signed-record replay:** the expiry limits a replayed record to 72 hours after signing; signatures prevent arbitrary forgery. However, restored address-spoofing authority can enable access or writes. |
| 8 | - **Forged edges-file ownership:** “until the next honest publish” supplies no time bound, and ordinary publisher passes need not repair tampering. |
| 9 | - **Ownership changes:** 30 seconds is a polling interval, not a maximum authorization-staleness bound. |
| 10 | - **Database restoration:** the described credential resurrection is real and can persist through renewals indefinitely. Comparing it with other restored credentials does not establish harmlessness. |
| 11 | |
| 12 | Round-2 dispositions: |
| 13 | |
| 14 | | Finding | Disposition | |
| 15 | |---|---| |
| 16 | | R2-1: failed door-hop verification drops scope | **Partly.** Removing the protocol removes that particular downgrade, but successful ordinary hops now carry trusted addresses without receiving-side app confinement. | |
| 17 | | R2-2: unauthenticated capability and selection race | **Partly.** The capability flag is gone. Returning owner and dial target together closes the selection race. Stale or forged ownership still authorizes cross-app address assertions. | |
| 18 | | R2-3: reserved handlers precede door authentication | **Correctly superseded.** Those handlers are publicly reachable and retain their independent protections; I found no additional authority from the ordinary hop. | |
| 19 | | R2-4: unsupported unconditional `Put` | **Closed.** The specified ETag-based conditional write matches the store interface. | |
| 20 | | R2-5: renewal overwrites completed revocation | **Closed under the stated single-console assumption.** Publication is serialized, reads current database state, and rebuilds after conditional-write conflicts. | |
| 21 | | R2-6: restore reuses revisions | **Partly.** Advancing beyond a surviving, verified bucket revision addresses counter reuse. Restored revoked credentials remain authorized, with consequences stronger than the stated residual. | |
| 22 | | R2-7: persistence failure/crash contract | **Correctly superseded mechanically.** There is no persisted verifier state. Restart replay is now explicit, but its security impact is understated. | |
| 23 | |
| 24 | New findings, ranked by priority: |
| 25 | |
| 26 | 1. **P1 — Address trust can confer application authority across the removed scope boundary.** |
| 27 | |
| 28 | Task 5 deliberately sends an ordinary hop without door scope ([plan:633](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:633)). Suppose a hostname changes from app A to app B while the sending edge still reports A. A’s key passes `Owner`; the receiving edge serves B and preserves the caller-chosen XFF through the verified-hop forwarding path ([homemap.go:912](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/homemap.go:912)). If B authorizes an administrative request using that address, A can obtain access or perform a write that its public request could not. This requires neither forged bucket contents nor failed hop verification. |
| 29 | |
| 30 | There is also a concrete platform effect locally. Task 6 sets `RemoteAddr` to the chosen address ([plan:674](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:674)). The password gate keys its limiter from `RemoteAddr` ([gate.go:230](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/gate/gate.go:230)) before checking the password ([gate.go:151](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/gate/gate.go:151)). Rotating XFF therefore buys fresh guessing budgets; choosing a victim’s address consumes theirs. |
| 31 | |
| 32 | On backhaul, the receiving gate instead sees the sending edge’s actual network address, while the application still receives the claimed XFF. Thus the two serving paths have different rate-limit behavior. |
| 33 | |
| 34 | **Required:** preserve app confinement wherever forwarded-address trust is granted, including the receiving edge’s final route. Define the gate’s door-specific rate-limit contract. Add a two-edge ownership-change test with an IP-authorized application and a local gate test that rotates claimed addresses. The new security premise cannot justify dropping remote confinement. |
| 35 | |
| 36 | 2. **P2 — Ownership residuals have no claimed maximum lifetime.** |
| 37 | |
| 38 | The residual table promises one 30-second poll after ownership changes ([plan:19](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:19)). But home-map list failures retain the previous snapshot, and failed or malformed individual reads retain the previous file, without an age limit ([homemap.go:264](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/homemap.go:264), [homemap.go:305](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/homemap.go:305)). Even a successful refresh has a two-minute budget ([homemap.go:119](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/homemap.go:119)). |
| 39 | |
| 40 | Likewise, a forged owner can survive ordinary publisher passes: unchanged locally generated content skips the bucket write ([edgesfile.go:379](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/host/edgesfile.go:379)). An honest process continuing to run does not guarantee an honest replacement publication. |
| 41 | |
| 42 | **Required:** distinguish routing availability from authority freshness. Specify an enforceable ownership freshness/revalidation rule and test list failure, individual-read failure and tampering with otherwise unchanged routes. Correct both residual bounds. |
| 43 | |
| 44 | 3. **P2 — Local serving changes the forwarded scheme when an instance moves.** |
| 45 | |
| 46 | The door serves plain HTTP over Unix ([plan:703](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:703)). `setForwarded` calls `SetXForwarded`, which derives the scheme from inbound TLS; the proposed change restores only XFF ([homemap.go:912](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/homemap.go:912)). |
| 47 | |
| 48 | Consequently, a locally served application receives `X-Forwarded-Proto: http`. After backhaul, the receiving TLS edge generates `https` ([edge.go:2775](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/internal/edge/edge.go:2775)). An application enforcing HTTPS can redirect or reject locally while working remotely. Supplying `X-Forwarded-Proto` at the door does not fix this; the proxy regenerates it. |
| 49 | |
| 50 | **Required:** define the door’s application-visible scheme and keep it consistent across placement. Test local and two-edge requests against an application that enforces HTTPS. |
| 51 | |
| 52 | 4. **P3 — Revision-3 instructions contradict two required implementation checks.** |
| 53 | |
| 54 | Publication advances the revision whenever `rev <= bucketRev` ([plan:459](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:459)). An ordinary renewal therefore increments it, contradicting the required “revision unchanged” assertion ([plan:540](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:540)). Choose and test one contract; retaining the increment is consistent with the specified protocol. |
| 55 | |
| 56 | Separately, `WithEdgeDoor` takes one argument, but the agent example still passes the removed persistence path as a second argument ([plan:722](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:722), [plan:725](/home/paulca/amadan.net/carlos/platform-instance-moves-p7/docs/superpowers/plans/2026-09-28-instance-moves-p7-edge-door.md:725)). That example cannot compile; remove the obsolete argument. |
| 57 | |
| 58 | **The plan is not ready to build.** |