Piggy answered in raw markdown, threw away every tool result it streamed,
and fought the reader's scroll on every token. The three surfaces that
made it worth having — what it read, how it reasoned, what it cost — were
all on the wire and none of them reached the screen.
The transcript is now composed of five parts under components/piggy:
answers render through streamdown, the container sticks to the bottom
without pinning the reader there, tool steps say what they read and link
to the record, and each turn carries its model and token count. Three
lifecycle bugs went with them: Stop left a permanent spinner, a truncated
stream was indistinguishable from thinking, and a failed send destroyed
the message it failed to send.
Underneath, the inference path grew timeouts, jittered retries on 429 and
5xx, tolerance of the malformed frames a 30B model emits, and an
agent_runs row per turn so chat spend is observable. The system prompt now
states that a field ending in Cents is cents — without it nemotron renders
costPerGpuHourCents: 189 as "$189 per GPU-hour", which is a 100x error on
the most scrutinised number in the room.
The demo book was arithmetically incoherent: every deal's value
contradicted its own allocation revenue by up to 3.6x, nothing had ever
closed, no customer had any paper, and the marketplace was empty. Deal
value is now derived from the allocation, the book clears 5.3% across five
blocks with one deliberately underwater, and the renewal, compliance and
agent-provenance machinery finally has rows to act on. A --clear that
deleted every obligation, SLA term and capacity request in the database
regardless of origin is scoped to the demo's own ids.
Around that: accounts have a detail page, ⌘K searches the book, Settings
can mint the API keys it always claimed to, and deploy.sh actually ships
the agent instead of silently skipping its compose profile.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reframe each screen around the decisions compute brokers make: sellable capacity, full-cost margin, pipeline movement, contract deadlines, evidence review, staged imports, and controlled agent access. Group the shell by operating domain, strengthen mobile navigation and sheets, add responsive record treatments, and make loading, error, empty, readiness, and retry states explicit.
The visual audit exposed sortable table targets and an unnamed file input only after exercising the rendered app, so this commit also pins those accessibility decisions at their actual interaction boundaries. Manrope is self-hosted as a single Latin variable subset to keep the stronger hierarchy without shipping unused font payloads.
Two demo gaps, both of which made working features look like they were not
there.
**Toasts fired into nothing.** RecordSheets already called toast.success on
every save, but <Toaster /> was never mounted, so nothing appeared. It could
not be mounted, either: the shadcn original imports next-themes, which PIG does
not use — it has its own provider so a chosen theme is persisted server-side
and follows a user between devices. Rewired to PIG's useTheme, mounted inside
ThemeProvider, and offset clear of the phone tab bar and the home indicator.
Feedback added where the interface otherwise gives none: allocation and hold
report the GPU-hours actually written, because the sheet closes on success and
the only other evidence is a number moving off-screen; releasing a hold says
the capacity is sellable again; fact decisions say what the decision meant, and
that approving evidence is not the same as writing it to a record; the profile
form confirms rather than just clearing itself, which otherwise reads as the
input being discarded.
**The fact table was empty**, so the review queue and every provenance tooltip
had nothing to show — the mechanism that makes an agent-written CRM
trustworthy, invisible. Six agent-derived facts seeded with a deliberate mix:
two applied, showing what a confident agent writes unprompted, and four
proposed, including one weak claim that a reviewer should reject, so the queue
is not a row of obvious approvals. Each carries a score, a band, evidence and
where available a source. Idempotent on subject+field+value; verified over two
runs.
Verified: toast confirmed firing in a real browser on a 393px viewport, 135
unit tests and e2e green, typecheck clean, CSP hash unchanged, 0px horizontal
overflow across 12 routes at both breakpoints.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
shadcn uses `bg-accent` for its SUBTLE surfaces — dropdown item hover, command
row selection, ghost and outline button hover, the dialog close affordance. The
brand colour in shadcn is `primary`.
PIG's Tailwind config mapped `accent` to `--accent`, which is the brand. That
inverted the meaning, so every shadcn hover and selection state painted a
full-strength brand block. With the monochrome "pig" palette in dark mode the
brand is near-white, so a selected command row rendered as a white slab against
a near-black sheet. Measured before the change: selected row rgb(250,250,250)
on a rgb(9,9,11) body.
`accent` now aliases `--accent-subtle` and `accent-foreground` aliases
`--accent-fg`, which is what those tokens were created for. The eleven places
where PIG's own components wanted a solid brand fill — filled chips, selected
card borders, progress bars — move to `primary`, which still resolves to
`--accent`. A `brand` alias is added for clarity.
After: selected row rgb(39,39,42) in dark and rgb(244,244,245) in light, both a
subtle tint above the body; the pipeline's active stage chip stays a solid
rgb(250,250,250) fill, unchanged.
Found by opening overlays, which earlier screenshot sweeps never did — every
route had been checked, but a dropdown or a command palette only misbehaves
once it is open. Worth remembering: page-level sweeps do not exercise portals.
Typecheck clean, 135 unit tests and e2e green, CSP hash unchanged, 0px
horizontal overflow across 12 routes at 393px and 1440px.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The accent swatches always previewed the light-mode value, which made the
near-black "Pig" swatch effectively invisible on a dark card — the one place
the preview needed to be accurate. Each accent is tuned twice because a colour
that reads well on white is usually too dark on near-black; the swatch now
shows the value for the theme actually in effect.
Team and the placeholder routes also set document titles, so every route in
the app is now distinguishable in history and in a tab strip.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was no sign-out control anywhere. Easy to miss when you develop
permanently signed in, and a stranded feeling for anyone on a shared machine.
Clearing the identity provider's session is sufficient — PIG holds no session
of its own — and the auth listener returns to sign-in without a reload. A hard
redirect follows regardless, so a failed provider call cannot leave a
half-signed-out interface.
Every route now sets its own document title. A single static title makes
browser history and a wall of tabs useless: every entry reads "pig" and nobody
can tell the margin view from the pipeline.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
apps/web — React, Vite, Tailwind, shadcn-idiom components. Mobile Safari is a
first-class target, not an afterthought:
- Two navigation treatments rather than one compromise. A bottom tab bar on
phones, because the top of a large phone is out of thumb reach; a persistent
sidebar from lg upward, so an iPad in portrait gets it too.
- Safe-area insets throughout, so the tab bar clears the home indicator and the
last row of a list is actually reachable.
- Inputs are pinned to a 16px minimum, which is the correct fix for Safari
zooming on focus. user-scalable=no is not used: it breaks pinch-zoom for
everyone and recent iOS ignores it anyway.
- The pipeline board becomes a stage picker on phones. An eight-column board
scrolling horizontally on a 390px screen is technically responsive and
practically useless.
Theming: users pick an accent and the whole interface re-tints. Accent values
live once, in @pig/core, and are written onto the root element at runtime —
there is no CSS copy to drift from the TypeScript. Preferences are stored
server-side so they follow a person between laptop and phone, mirrored into
localStorage only so the pre-paint script can avoid a white flash. Status
colours stay fixed regardless of accent: if "at risk" re-tinted to whatever
someone picked, the signal would be gone.
Seed data is public research, every record carrying a confidence grade and a
source URL. No email addresses are seeded or inferred — none are published, and
guessing them from a name and a domain is unreliable and rude. Authorship is
not promoted to employment: contributors, residency participants and alumni are
recorded as what the evidence actually shows, and a name that could not be
sourced at all is listed as unresolved rather than invented.
Three defects found and fixed by actually running it rather than assuming:
1. The seed was not idempotent. onConflictDoNothing() with no target is a no-op
without a matching unique constraint, so a second run duplicated 27
contacts. There is deliberately no unique index on (account, name) — two
people at one company can share a name — so idempotency is enforced in the
seed instead of by bending the schema.
2. /capacity scrolled sideways on a phone. Grid items default to
min-width:auto and `truncate` sets nowrap, so a long title became
unshrinkable content and widened the track. Fixed with min-w-0 on every
truncating grid child.
3. The idle-capacity alert silently failed to fire at exactly 80% utilisation,
losing a float comparison against a 0.2 threshold. Moved to 0.15, which is
also a more sensible line for "worth attention".
The worked example is tuned to teach rather than to flatter: 70% sold at a 53%
markup lands at +6.7% margin with 20% still idle, so both the healthy number
and the alert are visible. Drop the sold share to 55% and the same block goes
underwater — that sensitivity is the argument for the product.
Verified in a real browser at 393px and 1440px, light and dark: zero horizontal
overflow on every route, zero console errors.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>