Skip to content

amicode: solver toggle does the real switch — solver-mode contract + switch wizard - #14

Closed
Rchari1 wants to merge 26 commits into
local/amicodefrom
rchari/solver-wire
Closed

Rchari1 wants to merge 26 commits into
local/amicodefrom
rchari/solver-wire

Conversation

@Rchari1

@Rchari1 Rchari1 commented Jul 9, 2026

Copy link
Copy Markdown
Member

The solver toggle becomes a REAL switch (fork half; pairs with harmoniqs/amicode rchari/solver-wire).

  • File-backed GET/POST /amicode/solver-mode: POST writes {mode, status:switching}; "ready" is only ever written by the extension AFTER the actual switch (entitlement + config re-prep + server restart). Idempotent on the settled mode.
  • Toggle is server-truth controlled (localStorage = boot hint only); selecting a mode opens a staged switch wizard that polls THROUGH the server restart (connection failures = the restarting stage, not errors) with a 90s never-trap valve.
  • Verified live: flip → issimo entitlement granted → restart → ready → authoring allowlist gains Piccolissimo → AGENTS carries the Solver-mode section. 5 endpoint tests + typechecks green (one PRE-EXISTING flaky harness preload hook noted, unrelated).

🤖 Generated with Claude Code

Rchari1 and others added 26 commits July 8, 2026 12:31
…ion-lookup.ts — shared by the About-You card and the onboarding wizard; card keeps debounce/sequencing/race guards

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… about-you with live institution/logo lookup → profile preview + open chat); saves through POST /amicode/profile so the home page autofills affiliation + logo; shows exactly once (fresh profile, dismiss remembered) + tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… the starter chips (Open chat owns 'start something'); PDFs upload via POST /amicode/library into ~/.amico/library (sanitized basename, %PDF- magic check, 30MB cap), GET lists newest-first; 'Discuss latest →' hands the agent the paper path + tests

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

On a fresh browser profile against a bare `opencode serve`, the home
page's primary CTA (Meet-Amico card / "Open chat") did nothing: the
persisted client-side project list is empty, so startWithPrompt fell
through to openNewSession(), which needs the same newSessionProject()
that just came back empty and silently returns.

Fall back to the focused server's own working directory, synced from
GET /path (.directory; "" until loaded, so the guard holds). Open and
touch it as a project — self-healing: the home page tracks it from then
on — and start the draft with the prompt preserved. Deliberately not
sync.data.project: the server's "global" record has worktree "/".

Regression spec drives the real UI against a mocked server with no
localStorage seed; verified failing on the unfixed code and passing
with the fix. tsgo -b clean; bun test:unit 376 pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
amicode(home): fix silent dead-end on 'Open chat' with no tracked projects
…' (upload PDFs between about-you and the finish; ✓-list of uploads, continue-without-papers path; step skipped when upload isn't wired); home Library card stays; shared fileToBase64 util

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mo udd hit exactly this) + trunk

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… demoted to the quiet secondary — the autofilled home is the payoff shot

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
amicode: first-run onboarding wizard — welcome UI that autofills home-page affiliation + logo
…99

The fork rendered the old "digi" pixel-H mark in four independent copies
while amicode redesigned its mark (PR #99). This unifies them to a single
MARK_PATH and syncs the geometry to #99's FINAL square mark (viewBox
0 0 3600 3600) — not the intermediate "hackathon" geometry an earlier
draft of this branch had copied, which #99 itself later abandoned.

- logo.tsx: MARK_PATH = amico_reduced.svg's outer-bracket path (fill-rule
  evenodd). Mark/Splash render it; viewBox 64x56 → 3600 square.
  MarkDetailed = amico.svg's full mark (bracket + internal accents),
  viewBox 116 287 3377 3035 → 3600 square, for the Meet Amico card only.
- spinner.tsx (AmicoSpinner) + run-card.tsx (share-card SVG) both now
  import MARK_PATH instead of carrying their own copies — run-card was a
  fourth private copy of the old glyph; its transform is recalibrated
  (scale 0.55 → 0.011) for the 3600-unit space.
- favicon/amico.svg: reduced bracket on the yellow chip, viewBox 3600,
  path kept byte-identical to MARK_PATH.
- logo.css: aspect-ratio 8/7 → 1/1 (mark is square now).
- Small contexts use the reduced mark, the Meet Amico card uses the
  detailed one — matching amicode's own small/large split.

Rebased onto local/amicode (picks up PR #8; AMICODE-PATCHES.md conflict
resolved, entry 15 rewritten for the final geometry).

Checks: bun turbo typecheck (ui+app) green; ui bun test src 95 pass;
app vite build clean — new mark path in the bundle, old geometry and the
64x56 viewBox gone (0 chunks), favicon carries the new path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reduced bracket is right for small chrome (titlebar, footer, tiny
fallbacks), but the large brand-hero contexts should show the full mark.
Switch to MarkDetailed at:
- the new-session / main chat landing hero (both the v2 design view,
  144px, and the classic view, 112px)
- the onboarding wizard welcome step (56px)
The wizard's tiny 36px affiliation-logo fallback stays on the reduced
Mark (below where the internal accents resolve).

Checks: typecheck (ui+app) green; ui bun test src 99 pass; app build
clean with the detailed-mark accents present in the bundle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consolidate brand mark to one geometry; fix drift from amicode's redesign
Adds an "Inspect Run" button on the amicode problem-header rail, beside
the live run chip, that opens the VS Code Run Inspector on demand instead
of relying on auto-launch. It fires the existing host bridge —
postAmicode("amicode.openInspector") — which chat_panel.ts relays to the
already-allowlisted vscode command; no new bridge, allowlist, or route.

- entity-rail.tsx: new optional onInspectRun prop + button, gated on a run
  existing (hasRun) so it shows alongside the run chip, not before any
  solve. packages/ui stays bridge-agnostic (fires a callback only).
- message-timeline.tsx: wires onInspectRun to the bridge, passed only when
  framed in Amicode (inAmicode()), so the public web/share build shows
  nothing.
- use-amicode-commands.tsx: export postAmicode + inAmicode for reuse.

Pairs with harmoniqs/amicode#116 (stops the inspector auto-launching);
reaches amicode users after this is re-vendored into the extension binary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The message timeline had three independent systems writing scrollTop to
the bottom on the same content update, reading scroll geometry at slightly
different instants from a virtualizer whose item heights are estimates.
When virtua corrected a measured height a frame later, the writers had
already landed on slightly different positions -> visible bounce.

- session.tsx: gate createAutoScroll on the session's real working state
  instead of a hard-coded `true`. The auto-scroller's ResizeObserver was
  force-following the bottom on *any* reflow (image load, accordion expand,
  font swap), which read as the chat jumping on its own. Send-to-bottom and
  the jump button are unaffected (they use the force path).

- message-timeline.tsx: only realign via virtua's estimate-based
  scrollToIndex(align:"end") when the row set changes or status flips, not
  on every streamed token. Pure intra-row growth is left to the
  measured-bottom rAF lock, which pins against the real DOM height, so the
  two mechanisms stop disagreeing frame-to-frame. Safe because
  timelineRowKeys is memoized with `equals: sameKeys`.

- message-part.tsx: honor prefers-reduced-motion in the imperative
  ShellSubmessage reveal (the CSS already does; this JS animate() did not,
  and its initial render collapses width to 0 / blurs the value).

Verified: app + ui typecheck clean; message-part, scroll-view,
layout-scroll, file-tab-scroll, use-session-hash-scroll unit tests pass
(16/16). Perceptual smoothness during live streaming still wants a visual
pass against a real model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 3px accent-colored border-left (and the onboarding wizard's 4px accent border-top) read as a heavy yellow outline on every amicode card. Drop the rail from the home dashboard hero cards, the in-chat receipt/entity/ask/run cards, the problem rail, and the onboarding wizard — each keeps its neutral 1px hairline. The H-mark, live dots, hover tints, and focus outlines (keyboard a11y) are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Locks the contract the entity-rail "Inspect Run" button depends on:
postAmicode posts exactly {source:"amicode", kind:"command",
command:"amicode.openInspector"} (the command chat_panel.ts allowlists),
never throws if the parent frame rejects the post, and inAmicode()
reports false when unframed so the button stays hidden on the public web
build. Solid components can't be DOM-rendered under this repo's bun test
harness, so this covers the button's observable contract at the bridge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fold the full AMICO receipt redesign into the rail removal: instead of just
dropping the accent bar, give the whole family one visual language.

- receipt card (card.tsx): the H-mark doubles as the working spinner, diffs
  render structured (dimmed old -> new) instead of a run-on string, a green
  check settles the done state, failure tints the card red, and it is a real
  <button> with a focus ring (was a click-only <div>, invisible to keyboard)
- entity view (entity-view.tsx): raw keys lead with a human label and keep the
  technical name beneath (params.drive_max -> "Drive max"), nested fields get a
  subhead, the arrived-from change is highlighted, the edit-in-chat affordance
  is always visible, and a footer states the read-only / edit-in-chat contract
- rail / ask-card / run-window share the surface + H-mark signature
- identity via an accent-tinted wash + gold hairline, no side rail
- new pure helpers receiptParts / humanizeKey / fieldGroup (receiptText output
  unchanged); interaction/animation styles in new amicode.css

Typecheck clean; 66/66 amicode tests pass; app build succeeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(amicode): "Inspect Run" button on the entity rail
Fix chat scroll jitter during streaming; respect reduced motion
… Piccolissimo + Altissimo PRO] segmented control on home (spec-20260709-093000); selection persists in localStorage, changes nothing about solves (future wiring: executor cloud-altissimo seam + issimo entitlement as the subscription gate) + tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… restore the <Logo> component and its Racing Sans One face (straight-sans experiment reverted per review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iew: keep trunk's MarkDetailed (redesign) + this branch's Logo typeface wordmark (Racing Sans One restore)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
amicode: show-only High-Performance Solver toggle (Piccolissimo + Altissimo PRO) + brand typeface restore
… /amicode/solver-mode (POST writes status:switching; 'ready' is the extension's word after the actual switch), toggle becomes server-truth controlled, and a staged switch wizard polls THROUGH the server restart (connection failures = the restarting stage) with a 90s never-trap valve + tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e reads 'Unlocking Piccolissimo' (same rule as the SCORE naming guard)

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

Copy link
Copy Markdown
Member

Closing as stale — 278 commits behind, and packages/app/src/pages/home.tsx has been rewritten underneath it.

Not superseded: only the UI half of this reached the default branch. solver-toggle.tsx is there, but solver-mode.ts and solver-switch-wizard.tsx are not — so today the toggle renders without a backend contract behind it. This PR was the half that made it do the real switch.

Tracked in #78. Branch rchari/solver-wire is preserved.

cc @rchari — worth a fresh implementation rather than untangling the rebase.

kateebonner added a commit that referenced this pull request Aug 21, 2026
…ract

#167 gave the tier a durable way IN: a validated Company Compute credential
grants `issimo` and writes {mode:"hp",status:"switching"} for the extension's
watcher to re-prep from. Nothing ever wrote the other direction, so
connections.ts carried exactly one `switching` writer and it was hardcoded
to hp.

The toggle's Piccolo button called saveSolverMode() — localStorage — and left
the ops dir on hp, so amico-run went on refusing every local launch while the
UI read "Piccolo". Disconnect was the same story: pick(modeAfterDisconnect())
never reached the server, so the "disconnecting Company Compute can never
leave HP selected" invariant was not enforced anywhere.

- requestPiccoloFlip() mirrors requestHpFlip: revoke the entitlement AND
  request the switch in one operation. Both, or the setup is split-brained —
  a piccolo mode file beside a granted `issimo` is exactly what amicode#259's
  reconcileSolverMode heals straight back to hp.
- POST /amicode/solver-mode serves piccolo ONLY. hp still arrives exclusively
  with a validated credential; a second hp writer is the duplicate flip
  ADR 0001 forbids.
- releaseRequestForPick() names that rule on the client and pick() routes
  through it, so disconnect gets the durable release for free.

revokeIssimo deliberately rethrows anything that is not ENOENT: readSolverMode
falls back to piccolo on the same broken ops dir, so swallowing an IO fault
would short-circuit the flip and report success having written nothing. A test
covers that path.

Not included: the staged switch wizard from the stale #14. It polls the UI
through the server restart and is separable from making the switch work.

Refs #78
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.

3 participants