Skip to content

Build meter: settle before drawing a new scene, choreographed changes, outcome faces - #13521

Closed
briansrls wants to merge 51 commits into
mainfrom
ui/meter-transitions
Closed

briansrls wants to merge 51 commits into
mainfrom
ui/meter-transitions

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Stacked on #13500. Its own commits are the last two; rebase onto main once #13500 lands.

What changes

  • No jitter. The meter takes its facts (accessible name, digest, ×N badge, link) on every revision at once, but draws a new scene only after it has held for 6 s. A revision back to the drawn scene cancels it. Stopped and published are drawn as soon as they're seen.
  • Changes are animated, never cut. A change plays choreography rows over the leaving and arriving server-rendered stills inside a canvas, over 800 ms: z's, marks and the old gold rule fade; the worker walks in two-unit steps with a bob (getting up first if it was sitting); the gold rule wipes in; the stop cap draws up; the arriving pose takes over and its z's drift in. A paused (stale) worker crossfades instead. Under reduced motion the dwell still applies and the drawing is replaced without animation.
  • The page hands renderings to the meter. The workflow observation keeps its revision race guard and dispatches an accepted rendering to the meter by event, instead of swapping innerHTML.
  • Poses by outcome (owner rulings 2026-10-06). Waiting for a serving seat naps on the floor; the waiting room is removed. A published worker is content: eyes closed in arcs, a small smile, antenna lit green. A failed one is sad: drooped lids, a frown, antenna lit red. A spent step budget stays deadpan. The antenna ball is six units across with cut corners, so it reads as a ball rather than a cross.
  • Specimen. The build meter's sections gain "changes of scene": one attempt rendered in every scene, with controls that hand each drawing to a live meter, and a flap control that switches faster than the dwell.
  • Adds ClipPath and GridArea to the typed CSS properties and a SlotMeterSuccess palette slot.

Evidence

  • site_build_meter_witness_test: 42/42 pass; site_element_witness_test: 69/69 pass. The most expensive claim takes 59,340 eval steps, under the new-witness ceiling.
  • New claims cover: each drawing states its scene, settle rule, stance and worker place; the cue table finishes under a second and removes every leaving part; cues run only while the canvas carries the changing class, and reduced motion stills them; the client holds a new scene for the dwell; the poller dispatches to the meter rather than swapping it in; the face follows the outcome.
  • Checked in a browser with Playwright against real server-rendered stills, which is an ad hoc check and not a CI test:
    • a scene flapping six times at 2 s intervals was never drawn;
    • a scene that held was drawn at the 6 s mark;
    • stopped and published were drawn at once;
    • under reduced motion the dwell held and the drawing changed without animation;
    • frames were captured across 0–800 ms for every pose pair, 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 21 commits October 6, 2026 17:57
The rail's rows were 19.5 to 58.5px tall: values wrapped mid-token, the status
and assignee controls were 40px, optional rows left empty divs. The new element
gunbc.site.element.field_list renders labelled facts in a fixed label column
(clamp of 23% between 80 and 120px, as measured) at a 36px pitch, each value on
one line with an ellipsis, its full text in title and in the DOM. Value arms:
text, links, action, identity, status control, identity control, work (the
build meter) and absent ("--" with its reason). Controls draw inside the pitch
with a 24px hit area; the inline avatar is a 20px circle.

The measured sidebar is recorded in extdeps.google.issue_tracker
issue_tracker_measured_field_rail and adopted in gunbc.site.element.tokens. The
rail is a plain column (leading hairline, surface, measured width) composed of
one FieldList; the superseded .issue-rail/.issue-field/.issue-assignee-*/
.issue-status-detail summary/.issue-rail-meter/.issue-rail-link/.issue-link
rules are deleted. The specimen shows a FieldList fixture with long values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gunbc.site.robot_mark now carries the #stoic-robot symbol as numbers (body,
eyes, mouth, antenna stem and ball, the body group's scale and offset) and
derives its path strings from them, byte for byte the frontend's. The build
meter's worker reads the same numbers, scaled so the body is the worker's
width: the squircle body rows from the corner radius, square 3-unit eyes, the
flat mouth and the antenna. Quantisations are named in the module: the right
eye mirrors the left, the mouth widens to an even width, and the antenna is
drawn three units tall so its ball reads above the stem. Square eyes close from
the top: the drooping lid leaves a shorter bar, sleep leaves a flat line. The
outlined (stale) worker is derived from the same body rows.

The specimen gains an actual-size strip of the worker poses (working, waiting,
stopped, stale, published). A claim checks the derived paths against the
symbol's spelling and that every pose, solid or outlined, draws the robot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every mark is the same box (measured width, chip height, 2px border on every
side, measured 2px side padding) with its label at the box's left, so the
label's left edge is identical in every row; each form's rule may change only
colours. P1 is the tracker's ring; P0, this frontend's extension, is a solid
action-coloured mark so it never reuses P1's ring; P2 is plain and P3 muted.
The measured side padding is recorded beside the measured mark. The workspace
results table's P column now renders the element (the 32x32 centred red mark
and its .issue-priority rules are deleted), and the node-row and workspace
column headings inset their "P" by the mark's border and padding. A claim
checks that every form changes colour only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cimens, failure targets at their precision

C. The producer takes, per round, the operations the tool dispatcher recorded by
HarnessTool (run, read, write, edit). A round with typed operations draws those
alone; its tool-call count and changed-path rise are proxies for the same work and
are suppressed, so no round is counted twice. Each mark's hover text names its
origin: typed, or which legacy proxy. The real ledger carries no typed operations
yet; the dispatcher stamping the kind (harness/typed-tool-event-kind) is the named
producer that will.

B. The specimen's read-heavy and write-heavy meters, which built marks directly,
are replaced by two meters built by the same producer the rail uses:
"Tool-heavy, mixed typed operations" (40 rounds, run-dominant, reads early,
periodic writes and edits) and "Single-tool stress" (40 typed runs).

D. FailureDigest's destination becomes a typed FailureTarget: ExactEvent,
RoundOperation or StageGroup. The producer emits StageGroup, the precision its
record has; the accessible name and hover digest say "open the Environment stage
failures", and only an exact event is called "the event".

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

E. NodeStatus gains Accepted (the acceptance authority lists the node; closed)
and Withheld (the plan's withheld set names it; open). observed_node_status
reads each from its authority, never from absence; Unavailable is left for a
node no authority establishes. StatusChip renders both under their own words in
the quiet forms (Accepted as Done, Withheld as Superseded).

G. A FieldList text value that is not inside a control takes keyboard focus and
unwraps on focus, so a cut value is disclosed by keyboard as well as by its
title on hover; links stay links and keep their own titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…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>
# 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
@briansrls

Copy link
Copy Markdown
Contributor Author

Folded into #13500 (its branch now carries these two commits, fb2a813) so the overhaul and the meter transitions land in one queue cycle. Closing this one.

@briansrls briansrls closed this Oct 7, 2026
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