Summary
Gateway readiness switches from the Gateway's high backend ports to public ports 80/443 when either active PF redirects match or merely the prepared anchor file matches. If macOS has removed PV's system pf.conf reference, the prepared file still matches even though no redirect is active.
Reconciliation then probes unreachable public ports for 60 seconds, marks a healthy Gateway process failed, and holds the global mutation lock for the duration.
This compounded the live incident described in #300's follow-up investigation.
Current behavior
The relevant selection is in gateway_readiness_ports:
if active_gateway_redirects_match_plan(plan)
|| prepared_gateway_redirects_match_plan(paths, plan)
{
return GatewayReadinessPorts {
http: PUBLIC_HTTP_PORT,
https: PUBLIC_HTTPS_PORT,
};
}
The reconciliation queue acquires the shared lock when mutating work is enqueued (reconciliation.rs) and releases it only when the queue becomes idle.
Observed sequence:
- Prepared anchor correctly mapped 80 → 48080 and 443 → 48443.
- The system anchor file also existed, but the system
pf.conf reference was missing.
- Gateway and Project worker processes were listening and direct high-port HTTPS returned 200.
- Reconciliation selected ports 80/443 solely because the prepared file matched.
- The public probe timed out after 60 seconds with connection refused.
- During that minute,
pv update --check reported that the update lock was held.
This also conflicts with the documented readiness example that the Gateway responds on its high HTTP/HTTPS ports (DESIGN.md).
Expected behavior
Prepared configuration alone must not be treated as proof that privileged redirects are loaded. Gateway process readiness and low-port system-integration health should remain distinguishable.
Acceptance criteria
- A current prepared anchor with a missing/stale system reference does not select a doomed public-port readiness probe.
- A live Gateway on its assigned high ports is not marked failed solely because privileged PF routing is stale.
- PF drift is recorded/reported as a system-integration repair requirement.
- Reconciliation does not hold the global mutation lock for the full public-port timeout in this state.
- Preserve safe handling for the macOS behavior noted in the code comment where direct target-port connections can hang while matching redirects are genuinely active.
- Add integration coverage for:
- prepared current + system reference missing + backend healthy;
- active redirects current;
- backend genuinely unhealthy.
- Do not change the foreground privilege boundary for
pv ports:install.
Related
Summary
Gateway readiness switches from the Gateway's high backend ports to public ports 80/443 when either active PF redirects match or merely the prepared anchor file matches. If macOS has removed PV's system
pf.confreference, the prepared file still matches even though no redirect is active.Reconciliation then probes unreachable public ports for 60 seconds, marks a healthy Gateway process failed, and holds the global mutation lock for the duration.
This compounded the live incident described in #300's follow-up investigation.
Current behavior
The relevant selection is in
gateway_readiness_ports:The reconciliation queue acquires the shared lock when mutating work is enqueued (
reconciliation.rs) and releases it only when the queue becomes idle.Observed sequence:
pf.confreference was missing.pv update --checkreported that the update lock was held.This also conflicts with the documented readiness example that the Gateway responds on its high HTTP/HTTPS ports (DESIGN.md).
Expected behavior
Prepared configuration alone must not be treated as proof that privileged redirects are loaded. Gateway process readiness and low-port system-integration health should remain distinguishable.
Acceptance criteria
pv ports:install.Related
pv updateincurs a 10-second launchd throttle after switching app binary #300