feat: Quick Support — one-time-code ad-hoc remote sessions (Milestone A) - #3153
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Quick Support spec Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… notes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…spec Adds review items 7-13: migration -a-/-b- split (55P04 enum trap), end-path hardening, service-side Tier 2 consent guarantee, claimed-limbo reaping, i18n mandate, Authenticode signing gate, milestone split. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…, quick_support org type Adds the Quick Support data model (spec 2026-07-06-one-off-support-session-design.md): - support_sessions (RLS Shape 1, direct org_id, four breeze_org_isolation policies in the same migration). code_hash is SHA-256; plaintext is shown once and never stored. - organizations.type += 'quick_support' — the hidden per-partner org that holds ephemeral devices, one per partner via a partial unique index. - devices.is_ephemeral, enrollment_keys.support_session_id. The migration is split -a-/-b- because Postgres rejects any USE of an enum value added in the current transaction (55P04) and autoMigrate wraps each file in one transaction; the partial index on type = 'quick_support' must therefore live in a later file. Cascade/export registration (not in the original plan — added after checking the contract tests): support_sessions goes in CORE_ORG_CASCADE_DELETE_ORDER, DEVICE_DETACH_DEVICE_ID_TABLES (device_id is ON DELETE SET NULL so the audit row outlives the purged device), CORE_DEVICE_ORG_DENORMALIZED_TABLES and CORE_TENANT_EXPORT_POLICY. The two new columns are also classified in the devices/enrollment_keys export policies, which the column-level rule requires. Migrations are dated 2026-08-13 rather than the plan's 2026-07-06 so they sort after the existing last migration (2026-08-12). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shared: SUPPORT_CODE_ALPHABET/LENGTH/PATTERN, normalizeSupportCode, formatSupportCode, and the create/redeem zod schemas. The alphabet omits I/L/O/0/1 because the code is read aloud as often as it is pasted. API: generateSupportCode (randomInt rejection sampling, not randomBytes % len, which would bias the first 16 symbols of a 30-symbol alphabet) and hashSupportCode. Only the SHA-256 hash is ever stored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
getOrCreateQuickSupportOrg lazily creates one hidden 'quick_support' org per partner (plus the default site enrollment keys require), guarded by the partial unique index. Runs inside runOutsideDbContext + withSystemDbAccessContext because a just-created org id is not yet in the caller's accessible_org_ids, so RLS would reject the INSERT and its RETURNING under the request context. The concurrent-create race is handled with onConflictDoNothing + re-select rather than catching 23505: postgres.js rethrows errors handled inside begin(), so transaction-abort recovery would surface as a 500. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
POST/GET /remote/support-sessions under the existing remote:access + MFA gate. Create is partner-scope only: the hidden Quick Support org hangs off the partner, and an org-scope token carries a partnerId but never passes breeze_has_partner_access, so it would mint sessions it could not read back. A system token with no partner context is rejected for the same reason. 'active' is derived at read time from live remote_sessions rows rather than stored, so nothing has to hook the remote-session create/end paths to keep a duplicate status in sync. The list endpoint batches the device-status and live-session lookups across the page instead of per row (~100 round trips at the default limit). codeHash is stripped from every response shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GET /support/check/:code returns nothing but a boolean, so it cannot be used to enumerate tenants. POST /support/redeem performs one atomic pending->claimed transition — the WHERE status='pending' guard is what makes a code strictly single-use under concurrent redemption — and mints a single-use child enrollment key. Deviation from the plan, resolving its own open question: the plan proposed returning AGENT_ENROLLMENT_SECRET alongside the child key, conditional on the installer flow already doing so. It does not — the global secret appears nowhere outside config validation. Instead the child key carries its OWN per-key secret, which takes precedence over the global secret in /agents/enroll. It is single-use, expires in 15 minutes, and cannot enroll anything else, so no new exposure is created. hashEnrollmentSecret moves to enrollmentKeySecurity.ts so the minting and verifying sides cannot drift apart. Unknown, expired, claimed and malformed codes all return one identical 404 body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ephemeral agent's WebSocket coming up is the only signal that the client actually installed and reached us, so onOpen is what moves a claimed session to 'ready' for the waiting technician. Guarded on devices.is_ephemeral, which is already on the row onOpen just loaded: this handler runs on every agent reconnect across a 10k-device fleet, and normal devices must pay zero extra queries. The agent's context org is the hidden Quick Support org that owns the row, so org RLS passes. Gets its own try/catch rather than sharing the enclosing one, which would file a failure under "failed to query device for online event" and misdirect anyone debugging a session stuck at 'claimed'. A failure is non-fatal — the reaper expires claimed-limbo sessions after 20 minutes. Both branches are pinned by tests, including the non-ephemeral case asserting zero support_sessions updates, so the perf guard is behaviour rather than a review convention. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A key carrying supportSessionId enrolls an ephemeral device: the session must still be 'claimed' and within its hard cap, the partner licence count is skipped, and the session is bound to the new device id inside the same transaction as the device insert. Both licence counts (enrollment + provision) now exclude ephemeral devices, so an ad-hoc support session can never consume a customer's seat. The hostname-collision lookup excludes them too, so a repeat support run on the same machine inserts a fresh row instead of taking the re-enrollment-token branch. The rejection reuses the expired-key response byte-for-byte, so a caller holding only a key cannot probe session state; the real reason (support_session_not_claimable) goes to the audit row only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GET /support/download/:platform streams the agent binary with the one-time code in the filename, so the end user never types it. The binary is proxied rather than redirected because a 302 to GitHub/S3 would name the file breeze-agent-windows-amd64.exe and lose the code entirely. Cache-Control: no-store — the code is in the filename. A nonstandard port is encoded host_PORT, not host:PORT: ':' is illegal in a Windows filename and Chromium silently rewrites it to '_' at save time, which is how #2341 shipped silently-unenrolled installs. Matches the existing windowsFilenameApiHost() convention the agent already decodes. Also fixes this branch's typecheck and lint: zValidator now comes from lib/validation (the repo's standardized wrapper) rather than @hono/zod-validator, which no-restricted-imports rejects, and the possibly-undefined destructures from Tasks 3-4 are narrowed explicitly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ephemeral devices are exempt from offline ALERTING but deliberately not from the offline status flip itself: going offline is how an ad-hoc support session ends (the end user closed the client), and the reaper watches for exactly that transition to tear the session down. Without this, every completed Quick Support session would page the on-call technician with a "device offline" alert. Both alerting paths are covered — the immediate one in processMarkOffline and the config-policy re-evaluation in processReevaluateOffline — and the re-eval sweep filters ephemeral rows so the jobs are never queued. The re-eval handler keeps its own guard because jobs queued before this deploy may still be in flight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… revocation
endSupportSession is shared by the tech-initiated route and the reaper so
both revoke identically. Ordering is load-bearing and pinned by test:
1. send support_end while the socket is still authenticated (cooperative
path — the client deletes itself immediately)
2. revoke all three token hashes and decommission the device
3. force-close the socket
Step 3 is what stops a client whose support_end was lost from sitting
connected until the 8h hard cap: it is online, so its own offline dead-man
never fires. Closing forces a reconnect, the reconnect fails re-auth, and
the dead-man converges in <=10 minutes.
The audit records the disconnect result and command delivery rather than
collapsing them into success — a 'close-failed' socket plausibly stayed live
after revocation, which is exactly what an incident review needs to know.
No new guard was needed to stop a lingering client being reconnected to:
POST /remote/sessions already rejects any device not 'online', and teardown
sets 'decommissioned'.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…elete path The permanent-delete route's cascade moves to services/deviceDeletion.ts. The Quick Support reaper purges ephemeral devices through the same function rather than hand-rolling a second delete — two cascade implementations drift the moment a table is added to one list and not the other, which is exactly how this repo has produced FK-violation and orphaned-row bugs before. The route keeps its own transaction and link-group dissolution; only the row-removal sequence is shared. Behaviour is unchanged: 450 device route tests still pass, and the ordering (transitive children, then detach targets, then device_id cascade tables, then the device row) is preserved. Also widens two hoisted test mocks whose inferred literal return types made the failed-close cases untypeable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five passes, each the safety net for a specific failed teardown: lapsed codes; claimed-limbo (client died between redeem and enroll, else the tech's panel reads "Client connecting..." for 8h); hard cap; end-user stop detected via the device going offline (there is no explicit stop API in v1); and purging ephemeral device rows 6h after the session ends. The purge re-reads the device and deletes only when is_ephemeral is true, so a corrupted or mis-linked session row can never remove a real customer device. Two tests pin that guard. Per-session failures are caught and logged individually — a reaper that dies on one bad row stops protecting every other tenant. Termination goes through endSupportSession and purging through deleteDeviceCascade, so there is exactly one revocation path and one delete path in the codebase. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`breeze-agent support` redeems a one-time code, enrolls into a TEMP workspace (never C:\ProgramData\Breeze — the machine may already run a real enrolled agent), runs in the foreground so desktop capture takes the in-process path, and tears itself down on Ctrl+C, on support_end, or via a 10-minute dead-man switch. The filename parser decodes host_PORT back to host:port, mirroring installer_filename.go — ':' is illegal in a Windows filename and Chromium rewrites it to '_' at save time. Browser duplicate-download suffixes are tolerated in both the Chrome/Edge " (1)" and Firefox "(1)" forms. support_end refuses to act unless the agent is actually in support mode. That guard is what stops a forged or misrouted command from destroying a permanently-installed agent, and its test wires in the REAL cleanup and asserts a seeded sentinel file survives — so a regression fails by deleting something rather than by a stubbed counter. The Windows self-delete sets SysProcAttr.CmdLine verbatim rather than going through exec.Command: Go's EscapeArg would emit backslash-escaped quotes that cmd.exe cannot parse, and dropping the quotes breaks on any path containing a space. Not yet verified on Windows hardware: the self-delete trampoline, console- close SIGTERM, and in-process capture under support mode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Technician page: create dialog, one-time code shown large and copyable, 3s polling that stops permanently on terminal states (pinned by a test asserting the poll count freezes), ConnectDesktopButton once the ephemeral device is online, and End via runAction. The org picker is labelled "Reporting only — this does not grant or change access to that customer's data" so attribution cannot be mistaken for a tenancy control. Public /quick page: unauthenticated, code entry with normalization, soft validity check, Windows download, macOS marked coming soon. A dropped connection renders as a distinct "check failed" state rather than "invalid code" — telling someone their code is dead because the wifi blipped sends them back to the technician for nothing. The Windows publisher line sets an honest expectation and tells the user to STOP if the publisher is unknown or unexpected, rather than coaching them past the prompt. The signer name is isolated in one interpolated key, defaulted to a neutral phrase, because the Azure Trusted Signing cert profile display name is not in the repo and must not be guessed. All 41 + 26 strings are literal-key t() across all seven locales with real translations (fr-CA distinguished from fr-FR, es-419 formal usted). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A partner user with orgAccess='selected' had no way to reach their own Quick Support sessions: the hidden 'quick_support' org is deliberately absent from every org picker, so it can never appear in the curated partnerUsers.orgIds list, and RLS then returned zero rows — silently. The session created fine (creation writes under a system context) and the technician's status panel simply stayed blank forever. Both resolution paths are updated together. auth.ts and bearerTokenAuth.ts must agree or session-JWT and OAuth/MCP callers behave differently for the same user. Chosen over the alternative of reading support sessions under a system context: that would have left the CONNECT path broken for the same users, since POST /remote/sessions authorizes the device through org scope, and special-casing remote-access authorization is a worse place to carry the exception than a single explicit org grant. Accepted trade-off, deliberately: the grant is partner-wide, so a technician can see and connect to Quick Support sessions raised by colleagues at the same partner. Per-creator scoping would need a bound connect capability and is a follow-up, not a silent default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…findings and abuse evidence countContractDevices feeds contract line quantities AND invoice line quantities, so an ephemeral device reaching it would bill a customer for a machine that existed for twenty minutes and was never theirs. Vulnerability correlation now bails at the org level for a quick_support org: correlating a stranger's software inventory would raise findings — and critical-detected alerts — against their home PC inside an org the MSP never onboarded. Checked once per entry point rather than filtered into each join, since a whole hidden org is never a legitimate correlation target. The abuse-signal invariant counting live agents per partner excludes them too; a burst of ad-hoc sessions should not read as agent sprawl. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rker These workers act ON devices. An ephemeral device is a stranger's personal machine borrowed for one ~20-minute session, so reaching them means rebooting a home PC, patching it, CIS-hardening it, backing it up, shipping its serial to a warranty vendor, or paging an on-call technician. The most serious hole was queueEventTriggers in automationWorker: events raised by an ephemeral device carry the hidden org, the legacy branch matches every automation with org_id NULL under that partner, and the config-policy branch then executes against payload.deviceId — the MSP's whole automation library running scripts on a stranger's machine, reachable from any event the device emitted. It bypasses resolveDeviceIdsForAssignment entirely, so filtering that function alone would not have closed it. Three sweeps beyond the original inventory were found and closed the same way: snmpWorker and discoveryWorker both pick "any online device in the org" to run network scans (which would scan the end user's own LAN), and userRiskJobs' org fan-out rested on an undocumented invariant rather than an explicit filter. offlineDetector is deliberately NOT filtered — ephemeral devices must keep flowing through the offline transition because the end-user-stop detection depends on it; only its alerting is suppressed. audit_chain anchoring and verification are also deliberately left covering the hidden org: excluding them would create a tamper blind spot on the most sensitive session trail in the product. The cost is that a P1 divergence incident can name the hidden org. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ing surfaces Completes the exclusion sweep. Because the hidden 'quick_support' org deliberately stays inside accessibleOrgIds so RLS lets a technician reach their own sessions, nothing filters it automatically — every enumeration, count and aggregation needs an explicit predicate. Covered here: device lists and status buckets, dashboard and SLA metrics, enrollment/OS/agent-version analytics, every device report and the executive summary, tag facets, dynamic group filter evaluation and its preview count, update-ring targeting, vulnerability and patch and policy compliance denominators, security-posture coverage, software inventory (raw-SQL aggregates, filtered via the shared conditions both interpolate), org lists and pickers, the sites list and its device counts, AI tools, MCP resources, the mobile app, the customer portal, and the public Partner API. Deliberately skipped, each verified by reading the code rather than the line number: by-id device/org resolves (group membership validation is already gated on device.orgId !== group.orgId), the slug-uniqueness read (the hidden org's slug must stay in the taken-set), and tenant offboarding/erasure (the hidden org must be drained with its partner). Also repairs a regression from the enrollment-secret extraction: a second test file mocks enrollmentKeySecurity and lacked the moved export, which silently broke four per-key-secret assertions including two that verify a mismatched secret is REJECTED. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two suites against real Postgres as the unprivileged breeze_app role — the only place the tenancy contract is actually proven, since the unit suites mock ../db wholesale and never evaluate a policy. RLS suite guards against vacuity deliberately: the cross-tenant INSERT test proves the byte-identical insert SUCCEEDS for the legitimate owner immediately before asserting 42501 for the forger, so a policy that denied everything would fail the pairing rather than pass it. Chain suite covers provisioning idempotency, redeem, double-redeem rejection (the atomic single-use claim), ephemeral enrollment and session linkage, the licence-cap exemption paired with a normal enrollment still being refused, token revocation, and the reaper purging the device while the session row survives with device_id NULL. Two fixes while getting them green: - Teardown deletes each organization in its own transaction. The org-delete trigger takes a PARTNER export lock, and the lock hierarchy forbids acquiring one after an organization lock is already held in the same transaction. - /agents/enroll answers 201, not 200 — the assertion was wrong, the route was right. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers the technician flow, the partner-scope requirement, and the partner-wide visibility of sessions. Documents what the end user's machine actually gets, since that is the question a customer will ask: user-session only, no service, self-deleting, and an ephemeral device that never counts toward licensing, never appears in lists, reports or invoices, and is never patched, rebooted, backed up or alerted on. States the Phase 1 limits plainly rather than leaving them to be discovered — Windows only, and no elevated mode yet, so the client cannot drive UAC prompts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This repo is public and the plan carried a Tailscale address for the Windows test VM. Points at the internal note instead. Pre-existing: the same address appears in five other plan docs already on main (installer-enrollment, security-auth, remote-desktop, pam). Not in scope to fix here, but they are exposed and worth a separate scrub. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deploying breeze with
|
| Latest commit: |
ccfcd04
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f5162991.breeze-9te.pages.dev |
| Branch Preview URL: | https://toddhebebrand-quick-assist-f.breeze-9te.pages.dev |
The struct-field alignment in this block was already unformatted on main, but adding IsConnected() puts the hunk inside this branch's diff, and the Lint Agent job runs golangci-lint with --new-from-rev — so it lands as a new issue and fails CI. Alignment only; no behaviour change. go vet is clean across every package this branch touches. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
staticcheck ST1005 — error strings must not be capitalized or end with punctuation. The sentinel was carrying the end-user sentence verbatim. Splits the two concerns rather than just deleting the period: the sentinel is now terse and lowercase, and the friendly wording moved to the display site in agentapp, which is the layer that actually knows its audience is a non-technical stranger. The message the end user sees is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The site-scope detector flagged both GET handlers as new offenders because they read `devices`. Exempting rather than gating, with the reasoning recorded so a future reviewer can re-derive it: - Neither route takes a device id from the caller. The ids come from support_sessions rows RLS has already authorized. - The only device datum returned is the boolean `deviceOnline`; no per-device rows are disclosed. - The devices are ephemeral rows in the hidden per-partner 'quick_support' org, which is granted to PARTNER scope only, while `allowedSiteIds` is an org-scope-only axis. A site-restricted caller cannot see these sessions at all, so there is nothing to reach a device through. Deliberately not added to SITE_SCOPE_INPUT_BASELINE — that set is frozen and only shrinks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ssist-feature # Conflicts: # apps/api/src/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Quick Support — one-time-code ad-hoc remote sessions (Milestone A)
Implements the approved spec
docs/superpowers/specs/2026-07-06-one-off-support-session-design.mdand plan
docs/superpowers/plans/2026-07-06-quick-support-phase1.md.A technician generates a short one-time code and sends it to someone whose machine
runs no Breeze agent — a customer's home PC, a prospect's laptop. The end user runs
a downloaded client (the existing Go agent in a new
supportmode) which enrolls anephemeral device into a hidden per-partner org. The entire existing remote-desktop
stack is then reused unchanged. Everything self-destructs at the end.
Milestone A only. Tier 2 (the elevated temporary service) is Task 14 and is not
in this PR.
Design decisions that deviate from the plan
1.
/support/redeemdoes not returnAGENT_ENROLLMENT_SECRET.The plan said to return it if the installer flow already did. It does not — that
value appears nowhere outside config validation. Instead the single-use child
enrollment key carries its own
key_secret_hash, which takes precedence over theglobal secret in
/agents/enroll. It is single-use, expires in 15 minutes, andcannot enroll anything else, so the flow works with no new secret exposure.
2. The hidden org is unioned into
accessibleOrgIdsfor partner-scope callers.Without this, a partner user with
orgAccess='selected'creates a session and thenreads back zero rows — the hidden org can never appear in the curated
orgIdslistbecause it is absent from every picker, so RLS denies it silently.
Chosen over reading support sessions under a system context, which would have left
the connect path broken for the same users (
POST /remote/sessionsauthorizes thedevice through org scope). Special-casing remote-access authorization is a worse
place to carry the exception than one explicit org grant.
Accepted trade-off: the grant is partner-wide, so a technician can see and connect
to a colleague's Quick Support session. Per-creator scoping needs a bound connect
capability — a follow-up, not a silent default.
3. Cascade/export registration, absent from the plan entirely.
support_sessionsis registered in
CORE_ORG_CASCADE_DELETE_ORDER,DEVICE_DETACH_DEVICE_ID_TABLES(its
device_idisON DELETE SET NULL— the audit row outlives the purged device),CORE_DEVICE_ORG_DENORMALIZED_TABLESandCORE_TENANT_EXPORT_POLICY. The two newcolumns are classified in the
devices/enrollment_keysexport policies, which thecolumn-level rule requires.
4. Migrations are dated
2026-08-13, not the plan's2026-07-06, so they sortafter the existing last migration. The
-a-/-b-split is load-bearing: Postgresrejects any use of an enum value added in the current transaction (55P04), and
autoMigrate wraps each file in one transaction.
Bugs found that the plan did not anticipate
Consequence of the union in (2): the hidden org is visible to every org-scoped query,
so ~120 call sites needed explicit exclusion. The plan scoped this at three files.
Ordered by blast radius:
org. The legacy branch of
queueEventTriggersmatches every automation withorg_id IS NULLunder that partner, and the config-policy branch then executesagainst
payload.deviceId— the MSP's entire automation library running scripts ona stranger's home PC, reachable from any event the borrowed machine emitted. It
bypasses
resolveDeviceIdsForAssignment, so filtering the assignment resolver(what the plan described) would not have closed it.
countContractDevicesfeeds contract and invoice line quantities.remediation, and warranty sync (which ships serials to third-party vendor APIs).
snmpWorker,discoveryWorkerandmonitorWorkerpick"any online device in the org" to run network probes — i.e. scan the end user's own
home LAN.
against a stranger's machine.
Deliberate non-exclusions
offlineDetectorkeeps processing ephemeral devices. Theonline → offlinetransition is the end-user-stop signal the reaper depends on; only the alerting
is suppressed.
audit_chainanchoring/verification keeps covering the hidden org. Excludingit would create a tamper blind spot on the most sensitive session trail in the
product. The cost is that a P1 divergence incident can name the hidden org —
flagging explicitly for reviewer agreement.
Security posture
plaintext returned exactly once.
WHERE status='pending'claim makes a code strictly single-use.support_endwhile thesocket is still authenticated → revoke all three token hashes and decommission →
force-close the socket. The close is what stops a client whose command was lost
from sitting connected until the hard cap.
support_endrefuses to act unless the agent is genuinely in support mode. Itstest wires in the real cleanup and asserts a seeded sentinel file survives, so a
regression fails by deleting something rather than by a stubbed counter.
fail-closed through
release-integrity-gate). The public page sets an honestexpectation and tells the user to stop on an unknown publisher rather than
coaching them past it.
Not verified
SIGTERM, in-process capture under support mode.
worktree-stack.Verification
Every gate below was run, not assumed.
--max-old-space-size; OOMs at the default)breeze_appastro check0 errors, 0 warningsgo test -race, zero failuresThe RLS suite is written so it cannot pass vacuously: the cross-tenant INSERT
test proves the byte-identical insert SUCCEEDS for the legitimate owner
immediately before asserting
42501for the forger, so a policy that deniedeverything would fail the pairing rather than sail through it.
🤖 Generated with Claude Code