Skip to content

Frontend visual overhaul: one design language from measured Issue Tracker facts - #13500

Merged
briansrls merged 53 commits into
mainfrom
ui/visual-overhaul
Oct 8, 2026
Merged

briansrls merged 53 commits into
mainfrom
ui/visual-overhaul

Conversation

@briansrls

@briansrls briansrls commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The owner's directive for the internal tools frontend is to anchor on Google's Issue Tracker, with no homegrown UX (docs/plans/buganizer-visual-contract.md). The pages did not do that. Each page hand-built its own markup and styles, and nothing was shared between them:

  • two text-colour sets and two hairline colours;
  • a 12px radius on nearly everything;
  • every control 40px tall, even on desktop;
  • issue rail rows anywhere from 19.5px to 58.5px tall, with values wrapping mid-token;
  • a breadcrumb, a link panel and a status word, each derived separately on the issue page;
  • fonts named in the CSS but never shipped.

The element spec measured Issue Tracker and our preview side by side, element by element, and the owner ruled on the differences (§5 R1–R6 and the revisions in §5c–§5m). This PR replaces the hand-built pieces with one design language derived from those measured facts.

What lands

  • Measured upstream facts, then one palette and one token set. extdeps.google.issue_tracker carries the 2026-10-04 capture as cited facts: palette in both schemes, type scale, metrics, and the anatomy of the card, status chip, button, header chip, priority mark, relation table and field rail. gunbc.site.element.palette is the frontend's one palette; local adoptions are spelled out with their reasons. gunbc.site.element.tokens builds the radii, heights and geometry from those measurements.
  • Nine text roles (gunbc.site.element.text): Body, Label, CardLabel, SectionHeading, Control, Title, ProseHeading, Identifier and Code. Each role adopts one measured row. Title and Control set Google Sans, Code sets monospace, and the rest set Roboto, all through the family tokens.
  • Elements, one module each under gunbc.site.element.*: Card, SectionHeading, StatusChip, Button, Chip, PriorityMark, NodeRow, RelationTable, NodeChain, FieldList and BuildMeter. Each has a typed input, one markup function, its own rules and its own class. Pages compose the elements and do not style their insides.
  • One typed display status. gunbc.roadmap_issue_status IssueDisplayStatus is the one closed set. Accepted and Withheld come from their own authorities, and "Status unavailable" appears only where no authority establishes a status.
  • The hierarchy view. gunbc.roadmap.roadmap_hierarchy_view answers once where an issue sits and what relates to it: a NodePresentation, a NodeChain that keeps its refusal arms, and four typed relations (Parent, Sub-issues, Blocked by, Blocking) whose counts are functions of their rows.
  • FieldList rail. The issue rail is one FieldList at a 36px pitch with a fixed 120px label column. Each value sits on one line with its full text in title and in the DOM.
  • PriorityMark. One priority renderer at one geometry, left-aligned. P0 is this frontend's solid extension; P1 is the tracker's ring.
  • Compact build meter. It sits in the rail under the Fabric assignee as a quiet visual link: a strip of rounds with per-kind lanes, the robot-mark worker, state marks and at most a ×N badge. All facts are in its accessible name and a hover digest; a failure opens the Work tab at the failure event. A content-hash view revision keeps a late poll response from replacing a newer one.
  • Specimen at /specimen: every element in every variant, built from the production element functions, plus the actual-size worker poses.

Rulings implemented

From the owner's element spec, sections cited by name (the spec lives with the reference captures, outside the repository; docs/plans/buganizer-visual-contract.md is the in-repo summary and names it):

  • §5 Rulings: R1 (the chain shows slugs), R2 (Roboto and Google Sans, self-hosted; the faces arrive with the infrastructure PR), R3 (the product's density on desktop, 40px targets under a coarse pointer), and R6 (no status-tinted header band, so nothing is drawn). R4 (prose capped at the card) and R5 (dependency graph removed) are not in this PR.
  • §5c Revisions after review: relations and routes (one canonical node presentation, typed relation rows, counts from the same result as the rows), and behaviour (keyboard and touch reach a title, "--" means absent only, visual height and pointer target are separate).
  • §5d BuildMeter and §5h–§5k (the worker scene): the compact meter is the shipped form, as a visual status link. The cast is the robot mark played deadpan. Each non-working state has its own mark, there is a typed failure digest, coverage is kept apart from outcome, and a view revision covers the whole projection.
  • §5f One authority through the stack, §5e No legacy accommodation, §5l Closing the overhaul (Accepted and Withheld from their own authorities, P0 as a local solid mark, FieldList values keep their full text, typed media conditions, real font delivery), and §5m Waiting pose.

Added in this PR beyond the reviewed stack

  • Adapted to main: ts_if's parameter is now then_stmt (v2 grammar: a keyword is not a value name; module and data are contextual value names (ROOT E) #13168), and WorkflowAttemptEvidence carries a typed modeled_state instead of a Bool (roadmap: convert Filesystem.Read sites to the read-outcome and file-observation folds #13281). The round ledger matches all three standings.
  • Fonts through the tokens: font_sans and font_heading name families from the same source rows the served @font-face rules name.
  • Touch targets: gunbc.site.element.touch_target. Under (pointer: coarse), every interactive element gets at least 40px: buttons, the NodeRow, NodeChain and FieldList links, disclosure summaries, and the meter link. Desktop heights are unchanged and chips get nothing. No element has tabs (the issue page's tabs are page markup).
  • The waiting room: the robot sleeps on a side-view chair beside an empty one, under a wall clock, with drifting z's. The published worker naps too, beside the gold finish rule. One shared z drawing, seeded per attempt, still under reduced motion. The hourglass is gone.

Dependencies

This branch contains the commits of #13324 (prune) and #13499 (typed media conditions and self-hosted fonts) until they land. It will be rebased onto main then, keeping only its own commits.

Rebase and verification (in progress)

  • Rebase. The 33 frontend commits were replayed onto main + Delete unused frontend pages: sandbox, instrument labs, repo atlas, project page, served roadmap #13324 + Typed media conditions and self-hosted fonts (Roboto, Google Sans) for the frontend #13499 with git rebase --rebase-merges, so the hierarchy-view merge stays a merge. Every replayed commit's added and removed lines are identical to the original's; the merge was compared against its first parent. Conflicts:
    • The merge's original resolution (one typed status) was replayed file by file onto the new first parent, three-way and without conflicts.
    • gunbc.roadmap_belt_actuate had two import-block conflicts. Main's gunbc.roadmap_workflow_command import was kept beside the meter's imports.
  • Adaptation to main (its own commit). Found by compiling the rebased stack: ts_if's then_stmt, and the typed modeled_state.
  • Witnesses on the adapted stack (a03510b5cd), with binaries freshly built from it (no Rust differs from main):
    • site_element_witness_test: 46/46.
    • site_build_meter_witness_test: 19/19.
    • roadmap/roadmap_hierarchy_view_witness_test: 12/12.
    • roadmap/roadmap_serve_witness_test: 43/46. The 3 approval-route claims fail identically on unmodified origin/main.
    • A first batch of 12 importer modules: 274 pass, 8 fail. Seven are roadmap_belt_actuate_witness_test exec claims that stop at a hermetic route gap. One is floor_unimported_bare_provider_debt_test standing_refuses_stale_debt_and_an_unrostered_pair. Both still need a control run on main.
  • Pending. The three consumption and art commits on top (fonts, touch targets, waiting room) have not been compiled locally yet. Also pending: the full run over the ~115 witness modules that import a changed module, control runs on main for every failure, and the preview screenshots. This body will be updated.
  • Known CI risk. The frontend's specimen_content_is_built_from_every_registered_element renders the whole specimen. It measured 621 ms CPU raw on srv2, so the floor's new-witness enrolment margin (391 ms calibrated) will likely refuse it unless it moves to the long home.

Screenshots

Pending: the preview restart, plus light/dark captures of the issue rail and the specimen at 1440 and 390, and the two napping poses at real size and 6x.

Verification update (final head f557022)

  • Specimen claim: the whole-page claim is gone. Specimen sections are a total match over the SiteElement identity; the per-section and per-fixture claims stay under 60k eval steps. The heavy build-meter claims are split into single cases.
  • Full importer run: 113 modules. The 48 failing claims all fail identically on main. Two live-tree census modules exceed 24G locally and were not run to completion.
  • Preview (127.0.0.1:18098, restarted from this head): routes 200/404 as expected, the font stylesheet is served, rail rows are 36px, Google Sans renders on titles. Under pointer: coarse every interactive element measures ≥40px while chips stay 22px; on a fine pointer heights are unchanged.
  • Screenshots (issue-tracker-shots/ours/final-*.png): the waiting worker naps on a chair beside an empty one under a clock with z's; the published worker naps beside the gold rule; robot worker in every pose; the rail is intact in both themes.

🤖 Generated with Claude Code

briansrls and others added 30 commits October 6, 2026 17:53
… project suite

Owner ruling: unused frontend pages are deleted, with everything that exists
only to serve them, and no legacy accommodation (the site has no users). The
allocations page is KEPT: it works (live client over the real workspace
contract, #13272), so its page, client, style, routes, nav link, witnesses and
handoff note are exactly as upstream.

Routes removed from gunbc.roadmap_serve: /sandbox, /sandbox/echo,
/sandbox/instrument, /sandbox/instrument/tuner, /sandbox/instrument/motion,
/sandbox/repo-atlas and their JS assets; /project/{node_id} (no redirect). The
issue breadcrumb now links ancestors to /issue/<id>.

Page modules, their client programs in gunbc.roadmap_component, the project
suite functions and the sandbox-only forest renderer in gunbc.roadmap_page,
and the witness modules that existed only for those pages are deleted.

Rosters updated with the deletions: v2.workflow.floor_cost_debt (two rows left
with their witness), v2.workflow.floor_unimported_bare_provider_debt_roster
(two rows retired as FileDeleted), gunbc.ci_layer_roots (long-lane exclusion
and substrate long-lane rows), gunbc.deleted_cadence_reference_census and the
deleted_cadence_reference rung drop population (one row, recorded as a
gunbc.rung_drop_amendment; docs/design-rung-drops.md regenerated).

/roadmap and /ROADMAP.md are NOT cut: the surface-observation bundle, healthz
digests and the deploy readback consume both surfaces.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ce contract

Owner ruling: the old full roadmap page and the served markdown go, in this
branch, with no redirect or shim.

gunbc.roadmap_serve drops RoadmapFullPageHandler and RoadmapMdHandler and their
routes. The two surfaces leave the whole observation/deploy chain in one
motion: the bundle type loses roadmap_md and full_html
(gunbc.roadmap_site_surface_types), the bundle identity fold and the healthz
artifact members lose both (gunbc.roadmap_site_surface_observe / _render /
_expect), gunbc.roadmap_static_site loses the markdown artifact, its static
route and its arm of both readback scripts, and gunbc.live_deploy.readiness
and gunbc.roadmap_site_surface_witness build the served document from the
three remaining surfaces. The stale-artifact control now stales the dispatch
JSON digest instead of the markdown one.

The deploy digest readback still verifies a real served body: it curls
/target/roadmap-dispatch.json, compares its FNV-1a digest to the deploying
tree's and parses it, exactly as before; only the /ROADMAP.md arm is gone. The
healthz document still fingerprints /, the dispatch JSON and the dispatch
asset for the readiness poll.

Not touched: gunbc.roadmap_document, gunbc.roadmap_emit, the committed
ROADMAP.md and its drift gate (gunbc.generated_artifact RoadmapArtifact over
gunbc.roadmap_authority expected_roadmap_md), and the full-page renderer in
gunbc.roadmap_page, which roadmap_page_for_authority and the page witnesses
still consume. The bundle's subject identity still folds the markdown
projection's digest: it identifies the roadmap snapshot, not a served route.

One v2.workflow.floor_cost_debt row left with its witness
(witness_roadmap_route_is_plain_text).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…diaCondition

The typed CSS model could not say "this rule holds only under pointer: coarse",
which ruling R3 (dense desktop heights, 40px targets on touch) needs.

- extdeps.languages.css.media_queries: cites Media Queries 4 (pointer,
  max-width), Media Queries 5 (prefers-reduced-motion) and CSS Conditional
  Rules 3 (@media). MediaCondition is one parenthesized media feature with
  spec-closed values (pointer none|coarse|fine, prefers-reduced-motion
  no-preference|reduce) or a typed CssLength (max-width); css_media_rule_wire
  is the one @media serializer. No raw query-text arm.
- gunbc.design.material: BuildRule gains MediaRule { condition, selector,
  decls }, serialized in place through serialize_rule, so authored order is
  cascade order. It carries declarations only: a conditioned transition or
  keyframe cycle is unwritable, because those are emitted by passes outside
  any rule and would lose the condition.
- reduced_motion_block and theme_transition reframe_css now serialize their
  prefers-reduced-motion block through the same authority (bytes unchanged).
- theme_transition rule_selector/rule_decls see a media rule's declarations,
  so the colour and length censuses cover them.
- Witnesses: test.claim.css_media_condition_witness_test (wire per condition;
  a coarse-pointer rule appears once inside its @media block, after the rule
  it overrides; tokened positive control; RED: a raw px and literal colour
  inside a media rule are each caught once). Ownership witness counts a
  selector once per condition.

No production row constructs a MediaRule yet: the tracker frontend branch is
its first consumer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and Google Sans

- extdeps.languages.css.font_face: the CSS Fonts 4 @font-face at-rule as a
  typed row (family, numeric weight, font-style and font-display keyword
  sets, one url() source with its format() hint) and its one serializer.
  Bounded grain: woff2 is the only format keyword; local(), unicode-range
  and weight ranges are the named next grammar.
- extdeps.fonts.google_fonts: the google/fonts repository pinned at
  7085eb89a950e85db5b166b7a58d414544b4140c, with each family's variable
  source path, its OFL.txt path and the SIL OFL 1.1 citation. Upstream
  facts only; the faces derived from these files are this repository's
  receipts and live with their consumer.
- LICENSES/OFL-1.1-Roboto.txt and LICENSES/OFL-1.1-GoogleSans.txt: the two
  OFL.txt files verbatim from that commit. Neither declares a Reserved
  Font Name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…font/woff2 media types

ServeResponseHeaderCacheImmutable { max_age_seconds } renders through the
existing WireHeaderCacheControl wire name as
"public, max-age=<n>, immutable" (RFC 9111 max-age, RFC 8246 immutable), so
the seed's header reader needs no change. text_css_utf8 and font_woff2 join
the media-type rows. The account-controls witness's exhaustive header match
gains the arm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t (ruling R2, option B)

No seed change: `gunbc serve` carries text bodies only, so the faces reach
the browser as data: URLs inside one text/css stylesheet.

- gunbc.site.web_fonts: five derived faces (Roboto 400/500/700, Google Sans
  400/500), each a row carrying its google/fonts source, weight, the axis
  pins it was instanced at, and its WOFF2's SHA-256, byte size and base64.
  The derivation (fontTools 4.66.1, SOURCE_DATE_EPOCH at the pinned commit's
  time, unicode ranges, pyftsubset flags) is a typed row; two independent
  runs gave identical digests. The bytes live as .dag data rather than a
  file read at serve time so a face has one authority, and the stylesheet
  and its path are pure functions of the rows that every page head can
  derive with no read.
- The stylesheet is the faces' typed FontFaceRule rows (font-display: swap),
  served at /assets/fonts-<fnv1a64 content hash of the stylesheet>.css as
  text/css with Cache-Control: public, max-age=31536000, immutable.
- gunbc.site.document links it once in the application shell's head, by its
  content-addressed path, ahead of the inline styles. The approval shell does
  not: its server (the approval broker) has no such route.
- Witnesses: test.claim.web_fonts_witness_test (each face once with its
  family and weight; served weight equals instanced weight; the URL moves
  when a face row changes; the real route table selects the handler only at
  the current address; the response's type and cache header; the head links
  it once and every head URL is same-origin; the approval head links
  nothing), each under the new-witness step ceiling.
  test.claim.long.web_fonts_bytes_witness_test (long home: each face's
  base64 decodes through std.encoding to the recorded size and hashes,
  through extdeps.crypto.sha2, to the recorded SHA-256, about 51M eval steps
  per face; RED with a size off by one; the end-to-end GET through the
  served entry).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… values

The issue page derived a node's place several times over: a breadcrumb from the
alignment resolution with a Project/Task crumb split the model denies, a link
panel carrying a lifecycle key string as a status, and "child" naming blocking
edges. gunbc.roadmap.roadmap_hierarchy_view is now the one projection: a
NodePresentation (slug, title, typed status, priority, canonical route), a
NodeChain from the one parent walk that keeps its refusal arms, and four typed
relations -- Parent and Sub-issues from membership, Blocked by and Blocking from
the dependency edges -- whose counts are a function of their rows.

The status is a closed DerivedStatus, spelled once; a related node's status
comes from the same row producer as its own page, or says it is unavailable.
The /issue/<id> route family is declared once in gunbc.roadmap_issue_location.
IssueLinkView, IssueLinkPanel, the crumb types and scheduling_blockers are gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…end palette from it

extdeps.google.issue_tracker gains the 2026-10-04 capture as cited facts
(issues.chromium.org, signed out, 1440x1100; local folder and shared folder
as authorities): the measured palette in both schemes, the type scale, the
metrics, card, status chip and button anatomy, and the outlined button
idiom. The owner-directed dark token row is replaced by the measured dark
palette, which holds only what the dark capture shows. The interface
version row is bumped to 2026-10-04.

gunbc.site.element.palette is the one palette of the internal tools
frontend: one custom property per slot, both schemes answering every slot
through a total match. Adopted values read the upstream rows by reference;
local adoptions (the link ink for the grey ground, the dark values the
capture did not reach, the three status inks) are spelled there with their
reason. gunbc.roadmap_style emits the --issue-* block from it, and the
status inks move into it from gunbc.site.status.

Existing pages change in the dark scheme only, where the measured values
replace the directed ones (text, subtle ground).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gunbc.roadmap_issue_status IssueDisplayStatus is the closed set of statuses
an issue is shown with; the word and the sort rank are total matches over
it. gunbc.roadmap_presentation issue_display_status derives the value, and
issue_status_label and issue_status_sort_rank read it, so existing callers
are unchanged. The former catch-all word "Open" is gone: the last arm now
matches the scheduling position directly, and the only position that used
to reach it (superseded scheduling on a row whose lifecycle is not
superseded) reads Superseded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gunbc.site.element.tokens builds the frontend's length and font tokens
from the upstream measurements with the shared scale's constructors:
radius 4 and 2, the chip, button, tab, row and bar heights, card, status
chip and button geometry, line heights, the heading stack and the card
label's tracking. They are scoped to this frontend; the block it emits is
its tokens minus the ones the shared scale already emits, by name, so the
shared :root block is untouched.

gunbc.site.element.text is the typed role set (Body, Label, CardLabel,
SectionHeading, Control, Title, ProseHeading, Identifier, Code); each role
adopts one measured row and produces its declarations from tokens.

Card, SectionHeading, StatusChip and Button are one module each under
gunbc.site.element: a typed input, a markup function, its own rules and a
class used only there. StatusChip takes IssueDisplayStatus; Button takes
the upstream idiom and availability. gunbc.site.element.styles registers
each element's class with its rules and assembles the :root blocks a page
needs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The tree fold prepended ancestors onto the current node, which drew the current
node outermost with the root inside it. The live page showed it; no witness
did, because every one checked link order and none the current node's place.
The breadcrumb witness now pins that each level's text precedes the next
level's inside the tree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gunbc.site.specimen renders every element in every variant from the
production element functions, the nine text roles, the adopted heights
beside their measurements, and one composite card; gunbc.roadmap_serve
serves it at /specimen. It is the first consumer of the measured upstream
facts, the palette, the tokens and the roles.

test.claim.site_element_witness_test asserts each element's markup and
rules for a supplied fixture, the token block, both palette schemes, the
text roles and the link pairing; that the route selects the specimen
handler and the specimen content carries every registered element; and,
as guards, that each element class is declared by one element module,
that the specimen styles no element internals, and that element rules
carry no literal colour or raw length.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The two branches each typed the displayed status. The merged tree keeps
gunbc.roadmap_issue_status IssueDisplayStatus (nine arms) as the one closed
type, issue_display_status as the one derivation from a row view, and one
label, one sort rank and one is-closed predicate beside the type.
DerivedStatus and its derivation, text and predicate are deleted;
NodePresentation.status, the issue page and the witnesses read the kept type.

The tenth arm (Open) is not carried: it was the fall-through for a
scheduling position that is neither ready nor not-ready, and the only such
positions are done (already Review) and superseded (already Superseded by
the lifecycle arm; the kept derivation names it as Superseded).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…as values

relation_count is the typed count a heading formats (closed over total only
when every status is derived); relation_count_text prints the same value.
node_status_is_closed, relation_empty_text, relation_undeclared_text and
node_chain_refusal_text move the page's local spellings to the view, and the
issue page reads them from there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three measured rows in extdeps.google.issue_tracker, the tokens adopted from
them, and one palette slot for the ground of a closed relation row (measured
in the light scheme; the dark value is local until a capture shows it).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e, NodeChain

NodeRow renders one NodePresentation as a table row (title link, priority
mark, slug chip, status chip or an explicit unavailable status) and builds
the header row from the same column roster; its closed treatment follows
node_status_is_closed. RelationTable renders one NodeRelation: heading words
and count, rows, empty sentence and undeclared ids all from that one value.
NodeChain renders the membership lineage as one chip of slugs, folding the
middle of a chain longer than four levels behind a counted details control,
and renders a refused lineage as its reason. All five are rows of the
element style registry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The specimen gains an issue-head composite (chain chip over the title), a
Dependencies card of three relation tables, the chain in its three states,
an empty relation, a nested table and the row at grid density, all over a
planted fixture. The witness gains per-element fixture claims, the ownership
guard over the new classes, the chain-overflow claim and the claim that a
row's closed state follows the status predicate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The nesting conjuncts sat inside a claim whose other conjuncts all hold when
the current node is drawn outermost, so that claim's red could not say which
defect it saw. They are now one claim, with two more conjuncts on the relation
itself: the current node does not precede the root, and it sits inside the
nearest ancestor's list item. Executed red: with issue_breadcrumb_tree folding
root-first (current outermost), the names-and-links claim passes and this one
fails; with the fix restored both pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…authorities

Closure. NodeStatusDerived carries whether the node is closed beside the
status it is shown with. The page's producer states it from the lifecycle
(work_lifecycle_is_closed), relation_summary counts closed from it, and
NodeRow draws its closed state from it, so a done node shown as Unknown is
still counted and drawn closed. Unavailable is left for a node whose state
the producer cannot establish.

Omitted nodes. A declared node the plan omits is given its lifecycle by the
shared producer (omitted_node_lifecycle: its own line and signoff, or the
acceptance authority's accepted set) and the status a closed plan row gets
(closed_lifecycle_display_status, which issue_display_status now reads too).
An accepted or superseded omitted node is Done or Superseded; an open one
stays unavailable with the reason the plan omits it.

Rail. The rail's prerequisite row counts the row's unmet prerequisites from
its readiness (row_unmet_prerequisites over GapDependencies blockers) under
the label Unmet prerequisites, shows nothing when none is unmet, and falls
back to a neutral Prerequisites count where readiness was not assessed (done
and superseded positions). The Blocked by relation still lists every
declared prerequisite.

Sub-issue count. A tree row states its sub-issue count as a plain link to
the node's page instead of a chevron with nothing behind it; the disclosure
slot, its tokens and the measured slot width are removed with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One attempt's recorded rounds as marks in per-kind lanes on a token base, a
pixel gunbai worker posed by observed activity, and the same facts in text.
Seven kind and five worker palette slots, light and dark. Idle life (blink,
glance, nap, one beat on a landed round) through the typed motion model, all
stilled under reduced motion; the pointer eggs are a site client binding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…flow wire

build_meter_view reads WorkflowAttemptProgress through the owning authorities:
the write rule is the strip's own files-rise rule, hoisted out of
round_segment_kind so both consumers share it; the outcome is a new label on
CandidateHandoffState. The belt's attempt object carries only the view key;
a page whose drawn key differs re-reads its issue page for the rendering.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n the specimen

The rail renders the latest attempt's meter as a link to the Work tab only
when Fabric holds the issue and an attempt exists; otherwise nothing. The
issue page adopts the element's rules and tokens. The workflow poll refreshes
the meter from the wire key, one page re-read per distinct key, one beat
when the round count rose. The specimen plants seven states.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ownership

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…acy attempt is unobserved

The ledger reader answered RoundsUnobserved for a readable stream with no round
row, which made a new attempt look like one whose rounds were never captured.
It now reports an observation of zero rounds; the progress projection states
unobserved rounds itself for an attempt that predates round capture or whose
stream is unreadable. round_files_rise is renamed round_changed_path_count_rise:
it observes the tree, it does not count writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Fabric test to the event log

Withdraws candidate_handoff_state_label from the submission module: the words
live once, in the BuildMeter element. event_principal_is_fabric moves beside
EventPrincipal so the compact work producer can decide visibility.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…coverage apart from outcome

Visible content is the strip, the worker, a state mark and a ×N badge. Every
fact moves to a visually hidden accessible name and a hover/focus digest line.
Distinct marks: stop cap, verification seal, neutral budget bracket, broken
round mark, hollow unrecorded frame, dotted no-round start, outlined paused
worker for a stale attempt, gold finish rule. Marks carry their evidence
(typed operation, tool call count, changed-path rise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sh view revision

compact_work_summary decides visibility (Fabric-held, with an attempt).
attempt_failure_events lists failed stages by their workflow obligation key;
the digest names the first and links its Work tab anchor. The revision hashes
the whole view through std.content_hash; the workflow wire carries it as
attempt_view_revision, given the same staleness the pages compute (the tick
now reads the launch standing once and hands it to the three surfaces).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the refresh against stale reads

The rail only places compact_work_summary. Each attempt on the Work tab lists
its failure events with ids from the shared anchor helper. The poll refresh
swaps a fetched rendering only when its revision equals the latest wanted
one. Specimen: a captured real run, typed read-heavy and write/edit-heavy
runs, legacy, refusal before the first round, verification failure, stale,
waiting and published.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t marks, revision coverage, link target

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
briansrls and others added 14 commits October 6, 2026 17:57
…the field list's assistive text

The meter's hover digest grew to name the failure target and ran 144px past a
1440px page as an invisible box, adding a horizontal scroll; it now wraps at a
32ch measure. A field value's visually hidden full text was positioned against
the page rather than its line; the line is now its containing block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he longest label

Each row is a subgrid of the list, whose label column is minmax(80px,
max-content); a label is nowrap and capped at the measured 120px, so the
longest label sets one column for every row and values still start at one x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ide a wider label column

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… at one x on every page

The column followed each list's longest label (80px on one issue, 115px on
another). It is now var(--w-field-label-max), 120px, shared by every row through
the subgrid; labels stay one line and uncut. The rail claim asserts the fixed
column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tanding

Two interfaces the frontend commits were written against moved on main while
they were in review, so the rebased stack no longer resolved:

- #13168 (ROOT E) renamed ts_if's `then` parameter to `then_stmt`, because a
  keyword is not a value name. The build meter client and the workflow
  meter's refresh program call ts_if with the new name.
- #13281 replaced WorkflowAttemptEvidence.modeled_state_present (a Bool) with
  modeled_state: WorkflowModeledStateStanding. The round ledger now matches
  it: an Absent standing is a legacy attempt whose rounds were not recorded
  (the Bool's false arm, unchanged), an Unreadable standing says its rounds
  were not read and why, and only an Observed standing reads the stream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…her role Roboto

Ruling R2 assigns Google Sans 400/500 to the Title and Control roles and
Roboto 400/500/700 to Body, Label, CardLabel, SectionHeading, ProseHeading
and Identifier; Code stays the generic monospace family. The roles already
pick their face from the measured row (gunbc.site.element.text); what was
missing is a family token that names the faces this frontend now serves.

- gunbc.design.scale font_sans takes its first family from
  extdeps.fonts.google_fonts roboto_source, the row the served @font-face rule
  names, so the token and the stylesheet name one family. Bytes unchanged.
- gunbc.site.element.tokens font_heading is a typed ScaleToken: Google Sans
  (google_sans_source) ahead of the same body stack, which is the product's
  measured heading stack. It replaces the raw string token copied from the
  upstream measurement; no element module spells a family.
- Witness: text_roles_set_the_served_faces_through_the_family_tokens checks
  the nine roles' families, that each stack opens with a face the stylesheet
  serves (with a red: a stack naming an unserved face), and that each stack,
  quotes aside, equals the measured upstream stack. The token block now reads
  --font-heading: 'Google Sans', 'Roboto', 'Arial', sans-serif.

The shared head links the font stylesheet once (gunbc.site.document, from the
infrastructure commits; web_fonts_witness_test).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inter

Ruling R3 keeps the product's density on desktop and asks for 40px targets on
touch; element spec 5c separates the drawn height from the pointer target. The
typed MediaRule from the infrastructure commits is the only mechanism: each
rule is conditioned on extdeps.languages.css.media_queries coarse_pointer, so
no rule a fine pointer reads changes.

- gunbc.site.element.touch_target: the shared minimum (gunbc.design.scale
  height_control in both directions) in three shapes, because how a control
  reaches the target depends on its layout: a box takes the minimum as its
  size; a link laid out as a flex item or a block also centres its text; a
  link inside an ellipsised line becomes an inline block one target tall and
  keeps its ellipsis.
- Buttons (both sizes), NodeRow's title and sub-issue links, NodeChain's links
  and its fold summary, the build meter's link, and FieldList's summary,
  action button and links take the rule. The field list keeps one row pitch
  on touch by taking the target as its pitch, and its summary drops the
  fine-pointer margins under the same rule (one owner per condition).
- Chips, status chips and priority marks are not interactive and take
  nothing. No element has tabs (the issue page's tabs are page markup).
- Witness: interactive_controls_take_the_touch_target_under_a_coarse_pointer
  reads the registered element rules, joins the conditioned selectors against
  the expected roster (each exactly once, nothing else), checks the
  serialized @media blocks, that no chip, status or priority is conditioned,
  and that the fine-pointer button rule precedes its override.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aps too

Owner art direction (2026-10-06, element spec 5m). The hourglass beside a
standing worker read as a dumbbell at the real 22px size and is removed.

- Waiting for a serving seat: the worker sits asleep on a side-view chair
  (post as backrest and back leg, a two-unit seat, a front leg), beside an
  empty chair, under a five-unit wall clock with two hands. All props are in
  the prop paint; the room has no ticket or number, because the view carries
  no place in a queue. The worker sits at its standing height on the seat.
- Published: the worker keeps its floor-sitting pose beside the gold finish
  rule, and now naps as well.
- The nap is one drawing shared by both: two z glyphs beside the head, placed
  from the worker's own top. A seeded ambient cycle (build_meter_drift_cycle,
  whole-unit steps, the attempt's own period and offset, the second glyph half
  a period behind) drifts each up and away; the shared reduced-motion rule
  stills it and both glyphs then show where they rest.
- Where the worker rests is a typed fact (BuildMeterRest: on its feet, on the
  floor, on a chair); sitting means no feet and both lid rows shut. A paused
  (stale) worker has neither the room nor the nap.
- The two napping poses stand side by side in the specimen's actual-size
  pose strip.
- Witness: the_nap_and_the_waiting_room_belong_to_their_poses (z glyphs in
  waiting and published only; chair, empty chair and clock in waiting only;
  the finish rule in published only; none in working, stopped, idle or stale;
  the z cycle stilled by the reduced-motion block). The robot-mark claim now
  also expects the waiting worker's eyes shut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ledger-Repair-Judged: docs/design-rung-drops.md
Ledger-Rows-Repaired: docs/design-rung-drops.md identity_cast_route_new_witness_eval_step_cost
Heal-Candidate-Run: 37517952043
… per claim

The specimen was a hand-built list of sections, and one claim rendered the
whole page (621-671 ms CPU) to string-match each registered class against
it: two hand-kept lists cross-checked after the fact, and eleven
independent cases forced through one budget.

- gunbc.site.element.styles: SiteElement is the closed element identity.
  element_style is a total match over it and element_styles reads it
  through site_elements, the one enumeration. Rows, order and CSS are
  unchanged.
- gunbc.site.specimen: specimen_element_sections is a total match from an
  element to the names of its sections (SpecimenSection), and
  specimen_section_node draws each name. So an element registered without
  sections does not compile. The language's red for that state is
  test.claim.match_exhaustiveness_coproduct_witness
  w_cross_module_provider_growth_reports_one_non_exhaustive. The page lists
  the element sections in registry order, after the composites and before
  the text roles and heights. The chip and the priority mark get a section
  each.
- The BuildMeter section no longer repeats the five meters the pose strip
  shows, and each section derives only its own fixtures (the pose strip
  derived all nine views to pick five).
- Witnesses: the whole-page claim is deleted. Its replacements are:
  - every_registered_element_names_a_specimen_section, a join over the
    registry with a red for an element mapped to no section;
  - one claim per section (twelve), each rendering only that section and
    requiring the element's class, the heaviest at about 220 ms;
  - a red for a section that is not the element's and for hand-built
    markup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the floor's ceiling

The floor refuses a newly enrolled witness above about 72,300 eval steps.
Several of the frontend's claims were conjunctions of independent cases paid
through one budget (DESIGN section 3).

- site_build_meter_witness_test:
  - each_state_is_drawn_by_its_own_mark (73k) becomes six claims, one per
    state.
  - the_failure_target_is_stated_at_its_precision becomes three, one per
    target.
  - the_accessible_name_carries_every_fact becomes two.
  - the robot-mark claim becomes the symbol-spelling claim plus one claim
    per pose.
  - the nap claim becomes four.
- site_element_witness_test:
  - The build meter's specimen sections are checked as the element's and
    non-empty. Each named fixture (gunbc.site.specimen SpecimenMeterFixture,
    a total match) is drawn on its own claim through build_meter_art.
  - The field-list coverage claim reads the fixture's rows by the element's
    own key instead of rendering the fixture a second time.
- gunbc.site.specimen: the meter fixtures are named. The field list's Work row
  shows the verification-failed meter (the longest hover digest the rail must
  hold) instead of the forty-round typed run.

The largest new claim is now about 58k steps (the field list section), and
every meter fixture claim is at most about 41k.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…refix

The per-face decode and pure SHA-256 fold took millions of eval steps per face
and never reached a verdict inside the floor (CI job 112527986443). Each face's
recorded size is now read from the base64 length and padding. The off-by-one red
stays. One inhabitance claim decodes a real face's first quadruples to the WOFF2
signature. The digest remains the derivation's receipt; a floor-reachable octet
digest waits on a host-realized SHA-256 over octets in std.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…choreography

Facts (accessible name, digest, badge, link) update on every revision at once. A new
scene is drawn only after it has held for the dwell (6 s); a revision back to the drawn
scene cancels it, so flapping activity is never drawn. Stopped and published settle at
once. Each change plays rows of cues over the two server-rendered stills in a canvas
(800 ms: rouse, walk, arrival); under reduced motion the drawing is replaced without them.
The page's workflow observation now hands an accepted rendering to the meter by event
instead of swapping its innerHTML.

Poses follow the outcome: waiting for a serving seat naps on the floor (the waiting room
is removed); a published worker is content with its antenna lit green; a failed one is
sad with its antenna lit red; a spent step budget stays deadpan. The antenna ball is six
units across so it reads as a ball rather than a cross. Adds clip-path and grid-area to
the typed CSS properties and a meter-success palette slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One attempt drawn by the server in every scene, with controls that hand each drawing to a
live meter through the same event the workflow observation uses, plus a flap control that
changes scene faster than the dwell. A section of the build meter element.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 7, 2026
gunbc-ci-auto-heal and others added 4 commits October 7, 2026 22:43
# Conflicts:
#	dag/gunbc/roadmap/roadmap_page.dag
#	dag/gunbc/roadmap/roadmap_serve.dag
#	dag/test/claim/roadmap/roadmap_presentation_witness_test.dag
#	docs/design-rung-drops.md
The event carrier checked the roadmap-events branch out under the instance
root with `git worktree add`, but the provision plan never ensured that path.
On srv1 the instance root (/opt/gunbc) is root-owned, so the worktree could
not be created and every issue page answered 503. The path is now declared
once in gunbc.roadmap_dashboard_instance, the carrier reads it from there, and
the plan ensures it; the_plan_provisions_the_roadmap_event_worktree checks the
plan against the carrier's own layout for both srv1 instances.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
served_observation_issue_query_surface takes a launch standing on this
branch; the claim landed on main against the three-argument form. The claim
is about the standings read through the snapshot close, so it supplies the
existing fixture launch_host_unobserved_static_render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@briansrls
briansrls added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 5ee25af Oct 8, 2026
6 checks passed
@briansrls
briansrls deleted the ui/visual-overhaul branch October 8, 2026 15:32
gunbai-bot Bot pushed a commit that referenced this pull request Oct 9, 2026
…ndency in unused_parameters and structural_resolution

#13500 added a second DependencyView declarer (gunbc.roadmap.roadmap_hierarchy_view). These two
modules have no imports and used the bare name, which stopped resolving once both declarers were
in one closure. Reproduced on pristine main c6ef9d1 with a probe module importing
v2.lens.unused_parameters and roadmap_hierarchy_view; resolves with these imports.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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