Skip to content

I built a producer for a plane retired three weeks ago — so gate it, and close revoke server-side - #550

Merged
JasonYeYuhe merged 3 commits into
mainfrom
retire-pterm-producer
Sep 9, 2026
Merged

I built a producer for a plane retired three weeks ago — so gate it, and close revoke server-side#550
JasonYeYuhe merged 3 commits into
mainfrom
retire-pterm-producer

Conversation

@JasonYeYuhe

Copy link
Copy Markdown
Collaborator

Four items, done in the order their dependencies allowed.

1 · broadcast-terminal deployed ✅

Live at v1, verify_jwt=true. Verified against the deployed function, not the deploy log:

probe result
bogus device/secret 403 — authoritative denial, not 500
tail_snapshot_result 403 — parsed fine, so the round-2 regression is genuinely fixed on prod
bad event 400 must be one of stdout, stderr, tail_snapshot_result
GET 405

2 · "Build the consumer" — I did not, and here is why

Going to build it, I found this in the source, measured:

RemoteSessionPlane.isEnabled = false
/// `false` — the app offers no remote sessions, TERMINALS or approvals.

remote_sessions            4   all the owner's own, last 2026-07-16
remote_session_commands    0   a true never
remote_permission_requests 0

The session plane — phone-started CLI sessions, terminal streaming, remote approvals — was withdrawn across #499#514, ~12,000 lines, after measuring that no non-owner ever used it. The pterm: consumer went with it. It has no consumer by design.

So "build the consumer" is a request to un-retire that plane, and I am not doing that as a side effect of a producer task. The replacement is alive: the phone reaches the Mac over LAN/tailnet directly (LANTerminalHost).

I proposed that consumer myself last session without checking. Same mistake as the one in my own notes — count the population before building the mechanism — made while quoting it.

So the correct action was the opposite: #549's producer consulted only its ops flag. main.swift:496 already gates the cloud task on RemoteSessionPlane; the producer did not. shouldRunPrivateTerminalProducer(configEnabled:isPaired:) now ANDs the retirement — and lives in RemoteSessionPlane for the reason that file already gives: main.swift is an executable target with no test bundle, and a predicate a test cannot reach is a predicate nobody has checked.

3 · The Python producer, which was default-ON

helper/realtime_broadcast.py has had its gate defaulted ON since helper 1.24.0. Two independent reasons it delivers nothing, both measured: no consumer, and its write path is refused by Realtime because r0_broadcast holds no INSERT — invisibly, since the endpoint answers 202 either way.

New helper/remote_session_plane.py is the third copy of the flag; test_remote_session_plane.py reads both Swift sources and fails if any disagree.

4 · Parked items

v0.83 APPLIED — ledger 20260909013221. remote_helper_authorize_broadcast had no status predicate, so a session retired to status='stopped' (exactly what revocation posts) kept authorizing. Dry-run + rollback first, then verified behaviourally, not by grep:

row_status            stopped
matched BEFORE v0.83  1     <- would have authorized
matched AFTER  v0.83  0     <- raises 42501

Blast radius measured first: 3 sessions, all stopped, 0 running — authorizes strictly less, breaks nothing live.

v0.82 SUPERSEDED — do not file that support ticket. The write path was built without the grant, the feature is retired, and its own header called the ask a one-shot favour not to be spent before the design was proven. Kept, not deleted: the measurements in it are the expensive part.

Watched fail

un-retire the Swift plane   -> "the ops flag must not outvote the retirement" FAILS
Python copy set True        -> 3 tests fail, incl. both drift checks
drop the gate call          -> the wiring test FAILS

795 HelperSwift tests · 938 helper pytest · 83 migrations unique.

🤖 Generated with Claude Code

JasonYeYuhe and others added 3 commits September 9, 2026 10:25
Imgbot is free on the student pack. The only images in this repo where
compression changes what a user downloads are the 361 pet sprites under
CLIPulseCore/Sources/CLIPulseCore/Resources/Pet (4.7 MB). They are declared
via .process("Resources") in Package.swift, so they go into the app bundle --
and because that is a plain folder rather than an .xcassets catalog, actool's
compression never touches them.

Measured on a 30-file sample with zopflipng: 330.4 KB -> 283.8 KB, 14.1%,
pixel-identical when both are decoded to RGBA. Extrapolated, ~0.66 MB off the
bundle. Modest, but free and unattended.

Excluded on purpose:
  *.xcassets  - the App Store icon has hard requirements around alpha and
                dimensions; a few hundred KB is not worth debugging a rejected
                build, and actool recompresses these anyway.
  screenshots - already uploaded to App Store Connect; keep them byte-identical
                to what was submitted.

schedule=monthly and minKBReduced=50 keep this from becoming PR noise once the
one-time win is banked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Asked to "build the consumer" for `pterm:`, I went to build it and found this,
in the source, measured:

    RemoteSessionPlane.isEnabled = false
    /// `false` — the app offers no remote sessions, TERMINALS or approvals.

    remote_sessions               4   all the owner's own, last 2026-07-16
    remote_session_commands       0   pending rows are never swept — a true never
    remote_permission_requests    0
    app_push_jobs                 0   the durable zero

The remote session plane — starting CLI sessions from the phone, STREAMING THE
TERMINAL, remote approvals — was withdrawn across #499-#514, ~12,000 lines,
after measuring that no non-owner ever used it. The `pterm:` consumer was
removed with it. It has no consumer BY DESIGN, not by oversight.

So "build the consumer" is a request to un-retire that plane, and I am not
doing that as a side effect of a producer task. The replacement is alive and
shipping: the phone reaches the Mac over LAN/tailnet directly
(`LANTerminalHost` streams via `LANSessionControlClient.subscribeEvents`).

I proposed that consumer myself, last session, without checking. Same mistake
as the one in my own notes — count the population before building the
mechanism — made while quoting it.

── SO THE CORRECT ACTION IS THE OPPOSITE ─────────────────────────────

#549's producer consults only `remote_private_terminal_broadcast_enabled`.
`main.swift:496` already gates the cloud task on `RemoteSessionPlane`; the
producer did not. Flipping that ops flag would have redacted, batched and
POSTed a session's output to a topic nothing subscribes to, for a plane both
copies of that file declare retired. Not a leak — the relay authorizes and the
READ policy still scopes subscribers — but real work and real egress in
service of nothing.

`RemoteSessionPlane.shouldRunPrivateTerminalProducer(configEnabled:isPaired:)`
now ANDs the retirement. It lives there, not inline in main.swift, for the
reason that file already gives above its sibling: main.swift is an executable
target with no test bundle, and a predicate a test cannot reach is a predicate
nobody has checked — which is exactly how this one shipped unchecked.

── AND THE PYTHON PRODUCER, WHICH WAS DEFAULT-ON ─────────────────────

`helper/realtime_broadcast.py` is a complete `pterm:` producer whose gate has
DEFAULTED ON since helper 1.24.0. Two independent reasons it delivers nothing,
both measured: no consumer, and its write path (v0.65's direct mint+POST as
`r0_broadcast`) is refused by Realtime because that role holds no INSERT on
realtime.messages — invisibly, since the endpoint answers 202 either way. It
has not delivered a byte since at least 2026-08-30 while still minting a token
and issuing an HTTPS request per coalesced chunk.

New `helper/remote_session_plane.py` mirrors the flag as the third copy, and
`test_remote_session_plane.py` reads BOTH Swift sources and fails if any
disagree — the repo already runs that drift gate between the two Swift copies;
the Python one ships as a separate .pkg and is the copy most likely to be
forgotten.

── WATCHED FAIL ──────────────────────────────────────────────────────

  un-retire the Swift plane        -> "the ops flag must not outvote the
                                      retirement" FAILS
  set the Python copy True         -> 3 tests fail, incl. both drift checks
  drop the gate call from the
  producer construction            -> the wiring test FAILS

That last one matters: a predicate nothing calls gates nothing, and this file
family has shipped that mistake twice.

795 HelperSwift tests, 938 helper pytest (1 skipped).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…should never be filed

── v0.83 APPLIED: the server half of revoke ──────────────────────────

`remote_helper_authorize_broadcast` is the ENTIRE write-side boundary for the
private relay — `broadcast-terminal` runs as service_role, which is
rolbypassrls, so no RLS policy is consulted. It authorized on four predicates:
id, device, user, realtime_private. No status. No consent.

Revocation posts `status='stopped'`. The function never read it. So after a
user un-shared a session, the server kept authorizing writes to that session's
topic, and revocation was enforced entirely by a client that could be stale,
buggy, or replaced.

One predicate: `and rs.status in ('pending','running')`. An allowlist of live
states rather than `<> 'stopped'`, so a future terminal state does not keep
authorizing; 'pending' included so a helper broadcasting before its first
status post does not earn a 42501, which the Swift sink treats as an
authoritative denial and suppresses for 60 s.

Body is the LIVE definition read back with pg_get_functiondef plus the one
predicate — production function bodies drift, so it was not reconstructed from
the repo.

Dry-run first: all assertions passed inside a transaction, then rolled back,
and production was re-checked clean (predicate absent) before the real apply.
APPLIED as ledger 20260909013221, then verified BY HAND — and not only by
grepping the source, which proves nothing about behaviour:

    row_status                stopped
    matched BEFORE v0.83      1      <- would have authorized
    matched AFTER  v0.83      0      <- raises 42501

Blast radius measured first: remote_sessions = 3, all realtime_private, all
'stopped', 0 running. It authorizes strictly less and breaks nothing live.
The three rows it newly refuses are the exact class it exists to refuse.

STILL OPEN, and the edge function now says so precisely: consent.
`cloudShared` is an in-memory helper flag never mirrored to the database, so a
never-shared but running session would still authorize. Revocation is now
enforced on both sides; consent is still client-only. The note that used to say
"do not describe revocation as server-enforced anywhere" was corrected rather
than deleted — it is half right now, and which half matters.

── v0.82: SUPERSEDED, DO NOT ASK ─────────────────────────────────────

That file's whole purpose was to obtain a grant via a Supabase support ticket.
Three things killed the ask:

  1. The write path was BUILT WITHOUT IT — the relay uses service_role, which
     already holds INSERT. Proven end to end before it shipped.
  2. The feature it serves is RETIRED in three packages with a drift gate.
  3. Its own header calls the ask a one-shot favour and says not to spend it
     before knowing the design survives. It did not survive.

Marked superseded, kept not deleted: the measurements in it — the silent no-op
GRANT, the reserved membership, the NOINHERIT probe trap, the definer/bypassrls
trap — are the expensive part, and a deleted dead end gets rediscovered.

Edge function redeployed with the corrected note; boundary re-verified live
after the redeploy (bogus creds -> 403, not 500).

83 migrations, all numbers unique.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 9, 2026 01:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JasonYeYuhe
JasonYeYuhe merged commit 12ed92d into main Sep 9, 2026
56 of 57 checks passed
@JasonYeYuhe
JasonYeYuhe deleted the retire-pterm-producer branch September 9, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants