Skip to content

Connections panel — fork-side slices (credential store, routes, tab UI) - #33

Merged
kateebonner merged 52 commits into
local/amicodefrom
amico/issue-159-connections-panel
Jul 20, 2026
Merged

Connections panel — fork-side slices (credential store, routes, tab UI)#33
kateebonner merged 52 commits into
local/amicodefrom
amico/issue-159-connections-panel

Conversation

@kateebonner

@kateebonner kateebonner commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Fork-side integration branch for the Connections panel DAG (harmoniqs/amicode#159). All fork-side slices complete, every gate green (114/0 server connections+credentials suites · 270/0 ui · 388/0 app · tsgo + prettier clean). Companion amicode PR: harmoniqs/amicode#172.

Merged slices:

  • amicode#162 — CredentialStore seam + atomic 0600-at-birth writer + golden fixtures
  • amicode#165 — Connections routes: Company Compute connect path (probe-first, one round trip, loopback-guarded, redacting status parser)
  • amicode#166 — Connections tab UI (card per server-reported connection, tolerant wire parser)
  • amicode#167 — HP flip on connect (issimo grant + switching request; idempotent, one-way, value-free partial-failure warning)
  • amicode#169 — Pasqal card (minimal-env validator spawn, token-only persistence, device metadata, session-only fallback)
  • amicode#170 — resilience (mtime staleness + background revalidate, offline last-verified, submitter-drift diff, expiry→reconnect)

For the drift canary to light up live, aws-infra#185's probe response needs one string field submitter on auth-passed bodies.

🤖 Generated with Claude Code

kateebonner and others added 30 commits July 19, 2026 20:47
…n fixture (159/S1 AC1)

Read/write/clear seam in the fork server's amicode module space; the
company-compute backend writes the FROZEN cloud.json byte shape
({base_url trimmed of trailing slashes, token}, nothing else), locked by
a golden fixture the amicode-side tests can consume byte-for-byte. Path
resolution honors the same AMICO_CLOUD_FILE override the CLI's
remote-config reader uses, so the test seam is the compat seam.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Write a sibling tmp file with mode 0o600 passed at creation (never the
0666&~umask default, never a post-hoc chmod), then rename over the
target — the inode swap also corrects a pre-existing wrong-permission
file. The rename step is an injectable hook so the test asserts the TMP
file's mode before it ever becomes the target.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… writer (159/S1 AC3)

A thrown rename leaves the old credential byte-for-byte intact (or no
file at all on a first write) and never a tmp leftover. Verified the
tests bite via a mutation check: removing the writer's tmp cleanup
fails exactly these two tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t rest (159/S1 AC4)

pasqal.json fixture locks the {project_id, token, expires_at?} byte
shape. Poison tests push password/username-bearing objects through the
seam (both backends): the write throws (message never echoes a value),
the seeded credential stays byte-identical, and a whole-dir byte scan
proves the secret exists in no file. Null tokens are rejected; unknown
non-poison keys are allowlist-dropped. Mutation check: disabling the
poison guard fails exactly the poison test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(159/S1 AC5)

Missing, unparseable, and off-schema (hand-edited) credential files all
read back as undefined; the golden fixture bytes parse through the same
read path, closing the reader side of the cross-repo contract. Mutation
check: a throwing read path fails the unparseable-file test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ys (165 AC2 core)

401 → invalid, 2xx/403/404 → valid, everything else (incl. network
failure) → unreachable — the parent #159 fake-task probe contract. Token
rides the Authorization header only, asserted never-in-URL. FetchImpl is
the injectable seam; no live network in tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
….json cache (165 AC3)

GET body is built ONLY through a whitelist parser that rebuilds fresh
objects from declared, type-checked fields — poison test seeds token/
password keys into the cache file AND the in-memory overlay at every
level and asserts absence. Cache rides the sibling ops-dir env-override
idiom ($AMICODE_CONNECTIONS_FILE → ~/.amico/connections.json); the
credential file stays the truth for 'connected'; overlay entries render
'validating'; stale is computed freshness metadata (STALE_MS).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…minal status, one round trip (165 AC1+AC2)

Valid class writes via the #162 CredentialStore and answers 'connected'
in the same response; 401 answers 'invalid' and writes NOTHING (an
existing credential survives untouched); server/network trouble answers
'unreachable' with a fixed token-free message. While the probe runs the
in-flight overlay renders 'validating' for concurrent GETs. Malformed
bodies fail value-free without firing a probe. Status-cache writes ride
the same whitelist + atomic writer, so a poisoned file is scrubbed on
the next write.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…165 AC4)

Disconnect clears the credential via the #162 seam, drops the cache
entry, answers needs-key; idempotent on an absent credential.
Revalidate re-runs the probe from the STORED credential — the secret
never rides the request — and refreshes validated_at on every outcome;
invalid keeps the credential (re-entry is the user's call, only
disconnect deletes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nds with a distinct error (165 AC5)

isLoopbackHostname recognizes the mdns gate's loopback family widened
to 127/8 + the v4-mapped form; undefined (in-process webHandler, no
socket) counts as loopback. Server.listen will record the bind at
listen time; setBindHostname doubles as the test seam, and MutationDeps
takes a pure bindHostname override. Refusal code: non_loopback. The
read-only status route keeps serving.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…serve lifecycle with no extension host (165 AC6)

Route block rides the sibling raw-route idiom + the same
authOnlyRouterLayer auth wrapper (#163): GET /amicode/connections,
POST /amicode/connections/{credential,disconnect,revalidate}. The
credential rides the POST body (library idiom) — never query params.
Server.listen records its bind hostname so mutations refuse beyond
loopback; proven over live HTTP against real 0.0.0.0 and 127.0.0.1
listeners, with a node:http stub standing in for the solve service.
Route-level auth (401 before any handler), poison, and invalid-class
coverage included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ning)

Full-suite run exposed it: the mdns test's stopped 0.0.0.0 listener
left the recorded bind behind, and a later in-process mutation was
refused. Server.listen now restores the PREVIOUS bind when the listener
scope closes (or the listen fails), asserted in the real-bind route
test; the connections tests also reset bind state in beforeEach for
isolation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e in revalidate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/fields collapse safely (166 AC4)

Single consumer of the #165 status contract on the UI side (vaults.ts
idiom): GET {ok,connections} and POST {ok,connection} both parse through
one whitelisting entry parser that never throws — unknown states render
via the "unknown" fallback with the raw word preserved, unknown fields
(including a poisoned token) have no path into the view.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…imo + write the switching request (167 AC1+AC3)

A VALID save now writes BOTH shared ops-dir artifacts the amicode extension
consumes: entitlements.toml (issimo granted, existing codes + expired list
preserved, byte-compatible with applyEntitlementForMode) and solver-mode.json
({mode:"hp",status:"switching"}, the exact shape watchSolverMode re-preps
from). Paths resolve via $AMICODE_OPS_DIR → ~/.amico/amicode, the extension's
amicodeOpsDir resolution, so tests stay hermetic. Headless the artifacts are
plain durable files pending the next extension attach.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tate, safe unknown fallback (166 AC1)

stateCopy/cardModel are the pure state→props mapping the Company Compute
card projects: connected exposes actions + validated_at (+ identity when
present), the three re-key states expose the form, validating freezes it,
and unknown keeps every exit open while badging the raw wire word. The
repo has no tsx component harness, so this mapping carries the card's
behavioral contract exhaustively.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dempotent (167 AC4)

Invalid/unreachable/malformed/refused submits produce no flip artifacts;
failed revalidation and disconnect never revoke (the flip is one-way — the
user's toggle owns reverting). A repeat valid save on an already-granted,
already-hp setup writes NOTHING: the switching request only goes out when a
re-prep would change something (mode not hp yet, or the grant was missing),
so the watcher — whose re-prep restarts this very server — is never poked
for a no-op.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…it is a no-op, validating in flight, terminal from the same response (166 AC2+AC3)

submitPayload returns undefined for any empty/whitespace field, so the
card fires no request and touches no state (AC3). applyConnectionOverlay
is the pure wrapper the app layer puts around ONE POST: {validating:id}
renders the in-flight card, then {terminal} — parsed from the SAME
response — replaces it; no polling loop, base view never mutated,
sibling cards untouched (Pasqal-ready).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…+ fixed value-free warning (167 partial failure)

requestHpFlip never throws; a failed entitlement/solver-mode write surfaces
as ok:true + connected with the FIXED "hp_flip_failed: …" string in the
response error field (the module's code:detail shape, promoted to a warning
channel on renderCurrent). No token, path, or errno ever rides the message;
the credential and status cache stand exactly as saved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…AC1/AC3/AC4 at route level)

Extends the #165 route surface: a valid submit through the standalone-serve
route tree writes both ops-dir artifacts (no extension host in the process —
headless durability), disconnect leaves them untouched (one-way flip), and a
401 submit produces no flip artifacts at all. Ops dir rides $AMICODE_OPS_DIR
in both connections suites so every flip write stays hermetic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n the status popover (166 AC1)

connections-tab.tsx is a thin projection of the tested cardModel: status
dot + distinct per-state copy, key form (base_url prefills from the wire
when offered; token rides a password-masked input, cleared once a submit
lands connected, never echoed back), disconnect/revalidate when
connected, raw-word badge for unknown states. Registered as a
Tabs.Trigger/Content pair beside the vaults tab with the same
per-active-server authenticated fetch; mutations wrap ONE round trip via
applyConnectionOverlay (validating in flight → terminal from the same
response). Re-export shim rides the components/* wildcard; copy lands in
en.ts (locale fallback idiom, same as vaults).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ersistence (169 AC1+AC2)

Submit for id=pasqal-cloud spawns the #164 validator through an injectable
PasqalSpawn seam: argv is <python> <script> only (no secret ever rides argv)
and the child env is EXACTLY {PATH, PASQAL_USERNAME, PASQAL_PASSWORD,
PASQAL_PROJECT_ID} — never a process.env spread, asserted against a canary.
Interpreter resolves $AMICO_PYTHON → python3; the script resolves
$AMICO_PASQAL_VALIDATOR → the amicode-staged copy under the shared ops dir.
A valid run persists the minted token ONLY (#162 seam: project_id + token +
expiry) with identity + device metadata in the status cache, refreshed on
every submit. Pasqal never touches solver mode — the HP flip stays
company-compute-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…entitled + distinct config warning (169 AC5)

Exit 2/3/4 map to invalid / unreachable / unentitled (project-unauthorized)
with nothing written and any stored credential untouched. Exit 1, unknown
exits, off-contract stdout on exit 0, and spawn failure are the config class:
unreachable-state plus the FIXED value-free PASQAL_CONFIG_WARNING on the #167
warning channel — distinct from a plain service-unreachable verdict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…after restart (169 AC4)

A valid run that mints NO token parks its connected claim — identity,
devices, validated_at — in the new in-memory sessionOnlyOverlay: nothing
reaches the credential file or the status cache, the wire status carries a
session_only marker, and a fresh status build from disk (a restarted server)
renders needs-key. Every terminal submit outcome supersedes the claim;
disconnect ends it immediately. The session store is a whitelisted input like
the in-flight overlay — the poison test now seeds it too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… byte on disk (169 AC3)

After the full Pasqal flow through every class — valid+token, session-only,
invalid, unreachable, unentitled, config, off-contract stdout, a spawn error
whose message embeds the password — a raw-bytes scan of the whole
credential/ops tree finds the minted token artifacts but never the password
or username; responses and the in-memory stores are equally clean, and a
disconnect scrubs the token artifact too. Guard verified by mutation: a
deliberately leaky persistStatus fails the scan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kateebonner and others added 11 commits July 19, 2026 22:21
…pawn (169 AC1-AC5 at route level)

A stub validator honoring the #164 contract is staged OUTSIDE the scanned
tree and launched through the DEFAULT spawner ($AMICO_PYTHON bound to the bun
binary): the child records its env view, proving the real spawn hands over
exactly {PATH, PASQAL_USERNAME, PASQAL_PASSWORD, PASQAL_PROJECT_ID} — no
process.env spread, no argv beyond interpreter + script. Full lifecycle over
the routes: valid submit → connected + devices + token-only at rest;
revalidate never respawns (record file stays absent); disconnect scrubs the
token; exit 2/4/1 → invalid/unentitled/config-warning; null token →
session-only. Raw-byte scans of the credential/ops tree find no password.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ession-only + unentitled/expired copy (169)

The wire parser now admits expired + unentitled as first-class states
(distinct copy: token-expired and project-unauthorized), parses devices to
display names and session_only to the sessionOnly marker — all tolerant,
nothing throws. cardModel gains showDevices (connected only) and
showSessionOnly; connectionFormKind routes pasqal-cloud to a
username/password(masked)/project_id form whose payload gate
(pasqalSubmitPayload) trims identity fields, passes the password verbatim,
and yields nothing on any empty field. The password signal clears the moment
a submit lands connected. Labels wired through the status popover + en.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ate (170 AC1)

A credential file hand-edited after its last validation now renders
stale:true (credentialFileMtime seam, MTIME_STALE_SLACK_MS guard for the
connect path's own write order). Stale connected GETs render the cache
IMMEDIATELY and kick a deduped background revalidation — company-compute
probes the stored credential, pasqal reruns the local token-freshness
check — whose result lands for the NEXT read. Tests join the work via
backgroundRevalidationsSettled(); no sleeps, no live network.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… for both backends (170 AC2)

Corrupt cloud.json / pasqal.json (garbage, wrong JSON shapes, empty)
render needs-key with no stale badge, no identity, no crash — even when
the status cache still claims connected with every staleness trigger
armed; no background revalidate fires and the mutation path answers
needs-key instead of probing. Behavior existed via the #162 tolerant
read; these tests pin the honesty.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ver invalid (170 AC3)

A background revalidation that cannot REACH the service marks the cache
entry offline:true and leaves the connected state, validated_at (the
last-verified marker), identity and credential untouched — offline is a
connected-only presentation flag through the whitelist (poison-tested;
only the literal true survives). The card renders 'Offline — last
verified <at> as <identity>' via a {{slot}} label template filled with
display values (fillLabelTemplate/offlineCopy in the ui module); a
successful refresh clears the flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…0 AC4, canary for 2026-07-19)

The probe seam now surfaces an optional identity echo — a valid probe
response body carrying {submitter} (stubbed here; live endpoint is
aws-infra#185) — and a connected card shows it as its identity. A later
revalidation (manual OR background) answering a DIFFERENT submitter
persists identity_drift beside the UNTOUCHED stored record: the card
renders 'This key answered as X, was Y — historical runs may stop
authorizing'. Agreement clears the drift; no echo leaves record and
drift standing; re-submitting credentials is the human reconciliation
that resets the record. identity_drift rides the redacting whitelist +
tolerant parser (poison-tested at both ends).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…time, both backends (170 AC5)

renderStatus now maps a connected claim whose expires_at has passed to
the 'expired' wire state at READ time — company-compute behaves
identically to pasqal's #169 path, no revalidation needed to notice.
Expired is its own state: never a stale cue, never an offline marker,
never a background kick; the credential stays on disk (reconnect ≠
disconnect) and the UI's existing expired copy ('Token expired —
reconnect to mint a fresh one') is the prompt. Absent/unparseable
expiry expires nothing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r pass (170)

Route-level coverage extending #165's suite: an offline boot against a
dead loopback port (stale GET answers at once, the failed background
refresh marks offline — never invalid — and the credential survives);
the identity echo + drift diff against the stubbed identity endpoint
(stub solve service now answers a scripted JSON body, the aws-infra#185
shape); read-time expiry answering 'expired' with the credential kept.
Route afterEach drains background revalidations before the env flips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With OPENCODE_SERVER_PASSWORD set, the document authenticates via
?auth_token= but its own <script>/<link> sub-resource fetches cannot
carry a credential — the shell loaded and its bundles 401'd, blanking
the entire UI. Found live-testing the Connections panel (amicode#159):
the password was never armed before amicode#163, so the narrow
PUBLIC_UI_PATHS allowlist was unreachable dead code until now.

The content-hashed compiled shell carries no secrets; the API surface
(including all /amicode/* routes) stays fully authed. Bypass is
GET-only and prefix-exact — POST /assets/* and /assetsish/* still 401
(covered by the new regression test).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
Contributor Author

Live test-drive of the packaged build surfaced a latent auth gap, fixed in c76749a: with a server password set (first armed by amicode#163), the app document authenticated via ?auth_token= but its fingerprinted /assets/* sub-resource fetches — which cannot carry a credential — 401'd, blanking the whole UI. The narrow PUBLIC_UI_PATHS allowlist was unreachable dead code until auth became real. Fix: GET-only /assets/ prefix joins the public-UI bypass (shell carries no secrets; every API route stays authed); regression test covers the bypass + the POST//assetsish boundary.

Same constraint class as the /assets/ fix one commit back: widget
frames are iframe DOCUMENT requests (/amicode/widget-frame?id=) that
cannot carry ?auth_token= or a Basic header, so with a password armed
every widget 401'd and hit its 5s boot timeout ("widget did not boot
within 5s" across the whole home grid — found live-testing amicode#159).

The served document embeds only registry widget code + the frame
runtime (CSP default-src 'none'; config/context/data arrive via the
mediated postMessage bridge after boot), so it is public-shell class
within the same-user trust model. The widget registry route
(/amicode/widgets) and every other API route stay authed — covered by
the new regression test's boundary assertions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
Contributor Author

Second live-test find, fixed in ca69ef0: widget frames are iframe document requests (/amicode/widget-frame) — credential-less by the same constraint as the /assets/ sub-resources — so with auth armed every widget 401'd into its 5s boot timeout. The frame doc is public-shell class (registry code + runtime only, CSP default-src 'none', data via the mediated bridge post-boot); it joins the public-UI bypass. The widget registry route and all other API routes stay authed (boundary-tested). These two finds are exactly why the panel work needed a packaged test drive — no unit layer loads a document's sub-resources/iframes with auth required.

AMICODE_HIDE_STATUS_POPOVER was set 2026-07-07 to suppress the popover
when its only content was upstream MCP/LSP operator noise ("slot
reserved for a future solver-health panel"). The Vaults tab (7/15) and
the Connections tab (amicode#166) have since made it the home of
amicode-first UI — the stale flag orphaned both: the Connections panel
was compiled in but unreachable. Found live-testing amicode#159.

Follow-up (discoverability): a Connections entry on the home chrome so
"connect to cloud" doesn't require an open session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
Contributor Author

Third live-test find, fixed in a0b67cb: the status popover — the only mount point of the Vaults AND Connections tabs — was hidden fork-wide by AMICODE_HIDE_STATUS_POPOVER, set 7/7 when the popover's only content was upstream MCP/LSP noise ('slot reserved for a future solver-health panel'). Both tabs were compiled in but unreachable. Flag flipped with a dated comment; follow-up filed mentally for a home-chrome Connections entry (connect-to-cloud shouldn't require an open session — will add to #159's polish list).

kateebonner and others added 6 commits July 20, 2026 01:00
Inside the VS Code webview iframe native paste never fires and native
copy never reaches the OS clipboard, so every editable outside the
prompt input silently ignores mod+V and poisons the next paste on
mod+C. New utils/global-clipboard module: capture-phase mod+V/C/X on
editable targets (text-like inputs incl. password, textareas,
contenteditables), routed over the existing extension-host bridge,
with selection-aware insertion/extraction and bubbling InputEvents so
Solid-controlled inputs update. data-amc-clipboard="self" opts an
element's own paste handling out; copy/cut still mirror there since
nothing element-local handles them. Unframed: untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ab set (#174)

Pure, tested decisions for the popover's two mounts: the session trigger
renders unconditionally (the show-status setting scopes down to the health
dot), and the home-chrome global surface hosts exactly vaults + connections
with connections pre-selected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…heir paste (175)

entry.tsx swaps the paste-event fallback (dead in the webview — the
paste event never fires there, which is why Connections credential
fields ignored mod+V) and the copy mirror for the single tested
installGlobalClipboardFallback. The prompt input's editor roots and
home-cards' profile fields mark data-amc-clipboard="self" so their own
bridged paste handlers keep sole ownership — no double insertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… trigger (#174)

AC1 — home chrome: a Connections pill in the top-right cluster (between
Sessions and the settings gear, matching the Sessions pill idiom) opens
StatusPopoverGlobalBody — the same Vaults + Connections wiring the session
status popover hosts, extracted into createAmicodeStatusTabs (one wiring,
two mounts). The global body hosts only the global tabs (mcp/lsp/plugins are
per-directory; home mounts no directory-scoped sync context) and pre-selects
Connections via Tabs defaultValue. Manage-vaults is injected: home starts a
fresh draft session with the manage prompt (no composer exists on home).
Collapse-to-hamburger CSS covers the new pill; home's menu outside-click
handler now treats portaled popover content as inside so the dropdown cannot
display:none the popover's anchor mid-credential-entry.

AC2 — session header: the status trigger renders whenever a session is open;
settings.general.showStatus (default OFF, UI copy 'Server status') scopes
down to the health-dot overlay only, per statusTriggerVisibility in the
tested policy module. Settings description updated to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
Contributor Author

Live-test session wrap: three more slices landed on this branch since the last note — 64edf12 (#175: capture-phase clipboard bridge for every editable — the webview never dispatches paste events, the old bubble-phase fallback was dead code) and 5b0def9 (#174: global Connections pill on the home chrome, Connections pre-selected; session trigger un-gated from showStatus which defaults OFF and was orphaning the tabs; setting rescoped to the health-dot). Full tally for this PR: 6 panel slices + 5 live-test finds, all with regression tests; gates green throughout (app 393/0 · ui 270/0 · server suites 114+/0).

Connect / Revalidate / Disconnect / Retry rendered as underlined text
links; the status-popover surface already uses the ui Button component.
Connect = primary, Revalidate = secondary, Disconnect/Retry = ghost,
all size small; disabled state rides the component. Kate's live-testing
feedback (amicode#159).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner
kateebonner merged commit f0b78b6 into local/amicode Jul 20, 2026
0 of 4 checks passed
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.

1 participant