Repository navigation
site: Factory — a sixth design, a Defense Factory replica in SSCSB's own terms - #59
Merged
Merged
Conversation
A faithful replica of the reference's design SYSTEM — its shapes, type scale, chrome, section rhythm, diagram grammar and motion — with every word and every diagram drawn from SSCSB's own data. The pieces, and where each number came from: * The hero aperture copies the mechanism rather than the look: `timeline-scope` on the stage, `view-timeline-name` on a 100svh response panel inset to exactly one viewport, `animation-range: entry-crossing exit-crossing 0%`, two bars at `calc(50% + 1px)` translating -/+100% -> 0 and two clipped halves translating -/+50% -> 0 on `cubic-bezier(0.333333, 0, 0.666667, 1)`, plus the two `step-end` tracks that fire together at progress 1. That makes progress equal `scrollY / innerHeight` over the first viewport and nothing else — which is only true while the opening panel is exactly `100svh - header` and the header is exactly the height it subtracts. The header's 64px is therefore load-bearing and is set from the same custom property the panel reads. * Every diagram is rendered FROM the data. Nine bars are `controlsDefending(A1..A9).length`; the two the accent marks are computed — they are the groups where more than half the defending checks are ones only a maintainer's own machine can answer, which is A3 and A6 today and will follow the registry if that changes. The maze carries `PHASES.length` checkpoints on a serpentine generated from that count, with walls hashed deterministically and every edge the route crosses removed, so the route is always a legal path through it. Region count is `PHASES.length`, node chips and explorer cards are `CONTROL_REGISTRY` grouped by phase, and every question is `CHECK_QUESTIONS`. Nothing holds a hand-typed copy of the taxonomy. * Nothing fades in on scroll and nothing counts up. A whole-document sweep of the reference found exactly two animated components and 22 transitions, all of them hover/focus/state affordances; three attempts to make its figures count measured zero mutations across a 3.1s scroll-in. The restraint is the design. * Three branches, and the SETTLED state is the default: `MOTION_CSS` paints the finished frame unconditionally and only then turns motion on inside `@supports (animation-timeline: scroll())` + `prefers-reduced-motion: no-preference`. A browser without scroll-driven animation, a reader who asked for less motion and a printer all get the black response panel with its complete headline, the traces fully drawn with every checkpoint reached, and the loop standing still with its moving parts gone. * The switcher is in the colophon, in document flow. Bulletin measured a fixed one painting over body text at some scroll position on every page, twice over, and reserving clearance at the END of a document cannot protect its MIDDLE. Two deliberate departures from the reference, both because this is a directory and not a launch page: its top-right search slot ships at `opacity: 0` and ours is visible (drawn in mid-grey on no ground, so it reads on the white chapters and on the black block alike — a fixed element cannot ask what is under it), and its red is not used at all, because on this site red means fail. Two canaries bumped rather than softened, as their own comments instruct: `test/home.test.ts` and `test/layout.test.ts` each name the designs they cover. bun test 705 pass / 0 fail / 1 skip. tsc 0. build 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
The existing suite already runs against Factory, so the vocabulary ban, the honesty copy, the link integrity and the readability ceilings are covered. What it cannot see is the half of this design that is CSS and markup structure — and each of those failures is silent: * A motion branch that stops matching does not throw. `@supports not (animation-timeline: scroll())` and the reduced-motion block are the two branches almost nobody renders, and both are the ones that must paint the SETTLED state. If either quietly stopped, a reader who asked for less motion would get a blank aperture and an undrawn diagram, and no test that renders HTML would notice. * An `animation-timeline` declaration that escapes the `@supports` block is inert where it would have been honoured and invalid nowhere. It fails by doing nothing. * A diagram that stops being rendered FROM the data keeps rendering. Nine bars, six regions, six checkpoints and 54 cards are all derived; a refactor that froze any of them into a literal would still produce a page that looks right today and goes stale silently. RED FIRST, PROVEN RATHER THAN CLAIMED. The design was written before its test file, so "red first" was demonstrated by mutation instead of by order: each motion-branch and derived-diagram assertion was re-run against a source with that one property deliberately broken, and each went red on exactly the test that names it — an `animation-timeline` moved outside the branch, the reduced-motion block's trace rules deleted, an aperture keyframe renamed, the `matchMedia` check moved after the observer, the bar heights frozen to a literal, the region list sliced to five, and the loop's `[data-running]` gate removed. Seven mutations, seven reds, recorded under MEMORY/WORK/sscsb-factory-design/build/red-first-mutations.txt. Assertions are two-sided where an old form could linger and COUNTED where a partial match would pass: a `.filter` whose predicate stops matching returns an empty array, and an empty array satisfies "none of these are wrong". bun test 744 pass / 0 fail / 1 skip (39 of them new). tsc 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
… them found Self-validation at 1440x900 and 390x844 through headless Chrome with the rendering lifecycle asserted live (visibility visible, 63 rAF ticks/s). Every defect below rendered, passed the suite, and threw nothing. THE APERTURE WAS 13px OUT AT 1440. Its progress equals scrollY / innerHeight only while the opening panel is exactly one viewport minus the header, and the search control's chips wrapped to a second row — so the response panel sat at document y 913 instead of 900 and the whole range shifted down the page. The table now matches the brief to the decimal at 390 and at 0 / 50 / 100 % at 1440. Its 25 % and 75 % rows disagree by ~7px, and THE BRIEF'S ROWS ARE THE WRONG ONES: both are annotated "interpolated between samples" and were interpolated LINEARLY, while the ease is cubic-bezier(0.333333, 0, 0.666667, 1) whose y(t) is exactly 3t^2 - 2t^3. Against the brief's own 50px sample series — a real measurement — smoothstep puts scrollY 225 at -608.3 and 675 at -112.7, which is what this renders. WHAT ONLY A BROWSER COULD SAY: * "repositorycan" at 390, where the stylesheet hides the headline's break and the two text nodes closed up. * Seven tap targets under 44px, including two the FIRST probe could not see: the segmented options are label-wrapped, so they carry no [for] and the selector list never reached them. The probe was widened; the gap had survived three rounds. * The triangle's local-lane node rendered solid. fill="none" is an SVG presentation attribute and ANY CSS fill rule beats it — three branches set one. The test caught the fix and was itself pinning the inert attribute. * The loop's card type is sized in cqw with no container, so those units resolved against the VIEWPORT and every clamp pinned to its maximum: an 18px title in a 164px circle. * The resting ring was a single dot. stroke-dasharray: 0,1 renders whatever pathLength says, and at pathLength="1" the gap is the whole circumference. * The 390 rail's return packet survived BOTH fallback branches on specificity, so a reduced-motion reader got a static dot parked on the rail. * The loop's centre pulse pushed 9px of document past the right edge at 390. * An open toggletip widened the document — 6px at 1440, 17px at 390. No closed-state probe can see that; it took opening all 109 in turn and watching scrollWidth. * The taxonomy explainer rendered white-on-white inside the black chapter. The shared components take their palette from bridge tokens and followed them faithfully onto the wrong ground: headings survived, every control id and incident line went pale-grey-on-pale-grey. * Two of the eight methodology pills landed their headings under the sticky nav, because those sections are rendered by SHARED modules under their own class and a per-class scroll-margin never reached them. * The listing side-scrolled at 390 where the spec asks for the card grammar. All twelve are pinned two-sided in test/factory.test.ts. The reference's 40px pill and segmented controls are deliberately 44px here — this site's shared layer holds every other control to that floor, and the extra 4px is padding, not type. Recorded as an escalation rather than a silent divergence. Reduced motion re-measured at BOTH widths, which closes the brief's own §6 gap: getAnimations() 0, the black panel with its complete headline, traces drawn with 9 of 9 checkpoints reached, the loop static with every moving part gone, and the pill still tracking with its transition collapsed to 1e-06s. bun test 756 pass / 0 fail / 1 skip. tsc 0. build 0. 0 tap targets under 44px and scrollWidth === clientWidth on all eight pages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A1 · The opening panel now holds exactly kicker → headline → context line → ONE pill-shaped search input on the page axis → the arrow. The "already listed" chips are stripped from the shared control's output rather than the control being re-implemented, so home-shared.ts stays the single source of the ids filter.js binds; the strip throws if that block ever moves. They were measured doing real damage — wrapping to a second row at 1440 and pushing the opening panel 13px over one viewport, which moves the whole aperture range down the page, and descending as a three-step staircase at 390. The panel's container is the 1120 wrap now, not the 1376 media frame, and the display scale is cut to 8.2vw so the longest line fits inside it: line 1 was measured at 1182px hanging 29px past a 1120 container on each side. Kicker and headline both balance, and six pixels of TRAILING PADDING optically centres the display line — padding and not margin, because the element box must not move or the probe comparing the five centres measures the shim. A2 · The fixed search affordance is a plate at ≥768 — opaque white, hairline, the reference's 1px shadow — instead of a transparent disc that read as a smudge on whatever it covered. At ≤767 it is REMOVED: every route it offers is already on the page, and 44px of fixed chrome is the most expensive square on a 390px screen. A3 · The explorer's segmented control pins at 72px (12 + 48 + 12) so it and the chapter nav stack as two clean rows, which is what the reference's own frame shows; below the nav's z-index, so an overlap resolves the only way it may. It does not pin at all at ≤767. Every focusable diagram control without an id gains the same 88px scroll-margin the id rule already gives the rest, so keyboard focus can never park a control under the bar. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A4 + E2 · `nav.fy-chapters` returned null on both secondary pages when the measurement pass looked, so a reader who learned the navigation on the home page lost it the moment they opened a listing — on the longest page the site serves, where the controls table alone runs to 54 rows. The sheet gets six pills over its real sections (the record · phases · what ran · defences · who ran it · all checks) and the directory three (search · listings · the columns). Both lists are fixed rather than derived because both pages render exactly those sections unconditionally; the sheet's conditional panels (#merge, #coverage) are reachable from the section above them and would otherwise make a pill that sometimes points at nothing. Every id is on a container that already existed — nothing was invented to hang an anchor on. `fy-chapters-tight` is the secondary variant: the reference's 160px of air is right when the nav arrives after a whole black block, and a hole when it arrives two elements into a directory. Also, one line away and inside the same element: the dead `DIR_EMPTY_SCRIPT` placeholder (§B16 / Max-13) is deleted. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A5 · The fifty-four typed cards were right and orphaned — a phase picker with
nothing on the page saying where the checks come from or what they produce.
The reference draws this component as a left-to-right flow (Inputs, a dotted
working viewport, Outputs) on a dotted-grid stage, and that shape happens to be
the true one here: three evidence sources feed the checks, and the checks
produce one record.
Inputs are the three sources typed by evidence class, so a tint on an input
card means what the same tint means on a check card two columns right. The
Record column takes the reference's emphasis type — white on an ink hairline —
and deliberately carries NO data-reference-type: it is an output, not an
evidence class, and the four tints encode the class and nothing else.
The key moves above the panel and reads as dots plus one dotted-square glyph
rather than four filled swatches.
Two geometry facts found by measuring rather than by reading:
· The heads cannot live inside the bands. A band centres its content against
the tallest column on the stage, so "Inputs" and "Record" landed hundreds
of pixels below "Checks". They are the outer grid's own first row now.
· Each band is its own two-column grid with align-content: center, which is
what makes the wire's row exactly as tall as the column beside it — and
that is what lets the bracket's arms at 16/50/84 % land on the three input
cards' centres. Stretched to the grid row instead, those percentages come
from the 54-card column.
The flow takes the media frame rather than the prose wrap: at 1120 the checks
column is one card column too narrow, which doubles the middle band's height
and drags the columns that centre against it down with it. Measured after:
grid 1326, bands 851, cards 2 × 396, all three column centres on y 12003.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
… boxes A6 · The reference's grid is one tall narrow column, two stacked regions in a wide middle, two stacked narrow ones on the right and a short full-width strip across the bottom. Ours is now the same shape, and WHICH phase lands where is computed from its control count — the two largest take the wide middle, the smallest the short strip. Measured at 1440: narrow-left 310 × 1172, wide-middle 674 × 604 over 674 × 552, narrow-right 310 stacked, full-width 1326 × 264. At 390 it collapses to one column in PHASES order, which is source order, so every slot rule is dropped rather than re-pointed. Each phase now nests three deep: the region holds its plainly-answerable chips, then a stacked card whose dashed 1…n group holds the checks only a maintainer's machine can answer. That is the reference's own offset stacked-card edge, and its 6px overhang sits inside a 16px region padding so it can never reach the document edge. The regions lose their hue (§D11's first clause, landed here because A6 rebuilds the same element): four tints exist on this page and they encode the EVIDENCE CLASS. A phase is not an evidence class, so a tinted region spent the same four colours on a second meaning — and the green one spent a verdict colour on decoration. The one tint left inside a region is the class-C group's violet, which is the class encoding again. The P1…P6 badges are gone from the region corners. Chip icons carry `data-cls` and take their colour from the class, so the glyph is what says where an answer could come from — five classes, five distinct glyphs, asserted. And the region note (§D14 / Max-6): "13 checks belong to this phase", never "run here" — the scanner does not walk a phase. On the sheet, where the chips carry verdicts, it splits into "· N answered · M with no answer", because "13 checks" alone above a column of NO ANSWER chips reads as a contradiction. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A7 + D8 · It rendered the same three panels three times, word for word, with a fourth in the third lane: ninety per cent of the figure's area spent saying one thing three ways, and at a glance it read as a rendering fault. Worse for the contract, it emphasised the LOCAL lane — the weakest of the three — while drawing lanes 1 and 2 identically, which erases the only difference that matters between an outside scan and a signed CI scan. A reader left with "local sees most, and the first two are interchangeable," which is the trust ordering backwards. Now: what every lane can read is stated ONCE in a shared row above them, with a hairline under it saying it is the premise; then each lane shows only its delta — nothing more, a signature, the sixteen checks no outside scan reaches. The SIGNED CI lane takes the 2px #0285ff frame and a real `signed` marker on it (real DOM text, not a CSS ::before — generated content is exactly what a DOM-render capture drops). The local lane's one extra card takes the dashed weaker treatment the +local badge wears everywhere else. The closing line is "Two of the three can be checked by anyone. The third can only be asserted by the maintainer, and is weighted accordingly." And the arithmetic closes on the figure that invites it. 26 + 6 + 4 + 16 = 52 against a metric seven hundred pixels up that says 54; the two class-M controls were dropped with no note. The footnote now reads "+ 2 about the tool — never counted. 52 of 54 are scored", and a test adds the rendered counts and requires them to equal it, so the footnote cannot drift from the panels. The L-shaped label→group hairline brackets are restored, and drop out when the row stacks rather than pointing across a gutter that no longer exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A8 · The route serpentined over a field of random wall stubs: it never turned a corner the walls made, and the six checkpoints stacked on two edges because that is where a serpentine's legs end. Now a seeded depth-first carve makes a PERFECT maze over the reference's own 12 × 8 lattice of 40-unit cells — every cell reachable, exactly one path between any two — and the route is that path, which makes it a property of the maze rather than a line drawn on top of one. Measured: 22 straight runs, 21 turns, 6 true axis reversals, 77 interior walls plus the border, 39 cells of road. The checkpoints sit at real arc fractions (points are one per 40-unit step, so an index into them IS the fraction), first and last at the ends, minimum gap 0.21. D5 · And what the figure DEPICTS changes, which outranks how it is drawn. The scanner does not walk a route: it reads a clone and a settings API, once, and produces every verdict from that one read. So the road is the path CODE takes, from a commit to a published package, the checkpoints are where the standard set's checks sit along it, and the beat reads "One record covers the whole lifecycle." — with the T1–T7 reconciliation the home page never carried. The figure's accessible name said "a single route through 6 checkpoints, one per phase of the scan"; it now says what it draws. The metric that read "6 — phases a scan walks, in order" reads "6 — phases the 54 checks are grouped into". A test scoped to the beat fails on walks, passes, in order, or none is skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…ls that fit A9 · The root scrolls smoothly, so a click on pill 04 sent the page THROUGH 02 and 03 and the spy dutifully lit each one on the way — a 250ms cross-fade fired three times, which reads as the nav having a seizure. A click now marks its own target at once and the spy is ignored until the scroll settles: `scrollend` where the event exists, a 700ms fallback where it does not, and the flag is released either way so one click cannot stop the nav tracking forever. Over a dark section the nav inverts — #000 on a #333 border with white text — written by the spy from whether the active section is inside `.fy-dark`, the same class the black block itself is painted by. The reference never shows a white pill on black, and a 1px #e6e6e6 hairline on #000 is simply not there. The methodology's eight labels measured 1230px against the reference's 728, to within 37px of the fixed search affordance, and stopped reading as one control. They are Protocol · Threats · Scorecard · Evidence · Formula · Grades · Local · Changelog now; the section headings still carry the full titles, which is where a label belongs once it has to be read rather than recognised. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…clipped A10 · Connectors are ARCS. The reference's dotted connectors curve outward around the ring, and a straight chord between two discs on a circle reads as a different diagram. One quadratic does all five edges: the connector box is already rotated to its chord's angle, and local −y after that rotation IS the outward normal, so no per-edge sign is needed. The travelling packet rides the same path, so an active edge differs from a resting one in colour and opacity and in nothing else. The centre is a bounded 220px circle — dot pattern plus a hairline ring — which is what makes five cards read as orbiting something rather than as five cards with texture between them. Its halo is circular and stays circular: a radial gradient on a square paints a disc with four lit corners. The brief's measured values are restored where nothing forced the change: process margins −64/−112, connector base opacity 0.75, no opacity on the resting ring, and the card title/body clamps back to 20/15. Which surfaced a real defect. `padding: 7%` on a 193px card resolves against its CONTAINING BLOCK — the 840px process box — so it computed to 58.6px a side and left 75px of text width inside a 193px circle; "One commit, one snapshot" wrapped onto FOUR lines. A 26px length gives the inscribed square of the circle, and the centre's 8% padding had the same bug (84px of text in a 218px disc). Measured after: every caption 1–2 line-boxes at 1440, store title 172px. E1 · At 390 the rail inherited all of that desktop geometry and nothing reset it: the store's title rendered SIX of its twenty-eight pixels with zero dark pixels in its glyph box, card 05 was cut by 63px and every card lost 10.7px of its right edge. The stage's `overflow: clip` is what hid it. The compact block now undoes the geometry explicitly, the halo — a property of a disc — goes where the store is a card, and the clip goes with it. Measured at 390: scrollWidth === clientWidth and scrollHeight === clientHeight on the stage, all five cards and the store and its title fully inside it. There is no hardcoded `.fy-compact` any more (Max-10): the rail is a property of the viewport, so the media query is the only thing that knows about it. D9 · The centre said "the signed record" — a universal two of the four trust kinds do not have: an external scan produces an unsigned record, and so does a CI run without id-token. It says `the record` / `scan-record.json · signed when the lane can sign it` now, and the lead says the same. The caption "Shared context" named nothing a reader can point at and was stranded 25px below the stage border; it is the centre's third line, reading "One record. Every stage adds to it." Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A11 / Max M1 · `--fy-window-viewport-height` was referenced by the aperture's `view-timeline-inset` and defined by nothing. An undefined custom property is invalid at computed-value time, so the inset silently fell back to `auto` — and `auto` happens to coincide with the intended inset at exactly one viewport height, which is why it looked correct in the one place anyone measured it. It is defined on `.fy-track` now and the response panel's min-height reads the SAME property at both widths, so the panel and the timeline's inset cannot be changed apart. The guard is class-level rather than a check for that one name: every `var(--fy-…)` in the stylesheet without a fallback must be defined somewhere — in the CSS, by the script's `setProperty`, or as an inline style a renderer writes. Proven red by deleting the definition. Max M2 · The loop and the traced figures were gated on `@supports (animation-timeline: scroll())`. Only the APERTURE uses a scroll timeline. In an engine with keyframes and JS but no scroll-timeline support — every WebKit before 26, every in-app web view — the loop's rings and packets were `display: none` while its state machine kept flipping stages, and the traces drew with every checkpoint already lit because the `[data-reached="false"]` pending rules were unreachable. It fails by doing nothing, in the browsers least likely to be the ones it was tested in. The traces' pending rules and the whole loop block are in a plain `@media (prefers-reduced-motion: no-preference)` now, which is how the reference gates both. The `@supports not` branch paints the aperture's settled state and nothing else — its `display: none` on the loop's moving parts turned a missing CSS feature into a dead diagram. Reduced motion still settles all three, because all three are what a reader asking for less motion is asking about. Proven red by moving the gate back inside the supports block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…they open A12 · The sort control keeps its id and its element — filter.js binds `#dir-sort`, and a design may restyle a control but never replace one — and wears the design's chrome instead of the platform's: appearance none, a 999px pill on a hairline, 44px, a focus ring. Its chevron and the checkbox's tick are BACKGROUND IMAGES rather than generated content, because generated content is exactly what a DOM-render capture drops, and a control whose only affordance vanishes from every screenshot is a control nobody can review. The coverage checkbox is a bordered 20px square in the design's radius with 10px to its label, and the listing count has its own right-aligned cell at the end of the bar instead of crowding two controls it has nothing to do with. A13 · The repository name was ink-black with no underline: on a directory whose whole job is to be opened, the primary target was the one thing on the row that did not say it was one. It is blue and underlined now, like every other link on the site, with a `View record →` affordance under it at 96 × 44. The card's phase bars take the sheet's geometry — measured, the bar stack is now exactly the card's content width at both widths (211.1 at 1440, 316 at 390) instead of being boxed to 190px in a table cell. The MERGE pill's centre sat 27px below the top of the three-line text it marks, because the shared 44px summary rule centres a summary vertically — right for the one-line case, wrong here. Fixed on specificity rather than order, since that rule is declared later; re-measured, the pill's top and the summary's top are now the same y. E4 · Five standalone links measured 17px tall — "Install the Action →", "How that is checked →", "Search, or request one →", the repository URL and "scan run". Each is the whole content of its own block, so the WCAG 2.5.8 inline exception covers none of them and this site holds every other control to 44. Links inside running prose keep the exception and are deliberately untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
… whole voice D1 · The response panel said "— and what nobody could check." That is FALSE, and this site is the thing that disproves it: a class-C check is answerable by exactly one party, and the local lane exists so that party can answer it. It reads "— and what only its maintainer could." now, which is the same sentence shape and a true one, and the supporting line that carries the rule is unchanged. The caveat is also above the fold. The opening panel's context line is "Every listing here is a public record of one scan of one commit — what it could prove, and what it could not", so a reader who never scrolls past the first viewport has still met the claim the whole directory rests on. (One occurrence survives on the directory and the sheet: the SHARED plain gloss of `unverified` in glossary.ts reads "nobody could check this". Shared copy, out of this design's scope, recorded rather than reworded. The test is scoped to the pages Factory writes.) §B2's font half · Source Serif 4 is gone from the head and from every rule that read it — the pull-quote and the inline term glosses. A third family, with an italic axis, requested on every page of the site so that two paragraphs could be set in it. The test is two-sided: gone from the head AND gone from the CSS, because a dropped @font-face with a live `font-family` falls back to Georgia and the page still looks deliberate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…e visible D2 (which supersedes A14) · The track spanned pass + fail + gap + unverified, so a phase with five answered checks and two nobody could answer drew a green bar filled to 71.4 % — and printed 100% at the end of it. A sighted reader had no legend, no count and no label for the hatch: they either read the bar as a proportion and concluded the number was inflated, or read the number and concluded the bar meant nothing. And the hatch WAS the unanswered set, drawn as the empty tail of a pass-green progress bar — the visual grammar of shortfall, which is exactly the third state rendered as a deficit that threats.ts forbids. The track is the ANSWERED set now, its green segment is the phase's own percent and its complement is what did not pass, so the bar's width IS its number. Measured live at both widths on the fixture sheet: pass width 100% against a printed 100%, on all five rows that have answers. The sentence that explained it existed, written well, in an `aria-label` — the one place no sighted desktop reader and no touch reader will ever meet it. It is a line of its own under each bar now, in its own words: "100% of 5 answered · 2 no answer (not counted)". One three-state legend sits above the stack on the sheet, and deliberately not once per card on the directory, where the page-level key already names the same three states. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
D3 · A local-lane verdict now reads WEAKER at the row. `commit-signing` rendered a green PASS identical to `secrets`; the header said `+local 6` and the panel said beautifully that a workstation record is weaker than an authenticated scan — but the row is the only place a reader decides whether to trust an individual control, and there was no way on the page to find out WHICH six greens were the repository owner asserting his own posture on his own laptop. Every chip and every evidence-table row the local lane resolved is dashed and says `local`, and the word links to the panel that says what that signature proves. Only a COUNTABLE verdict can be marked: a "no answer" chip labelled locally-resolved would be two contradictory claims in one chip. `+local 6` was uncountable — six what, and which six — with the sentence that answered it in a `title`. It reads `+6 from a local signed record` and is an anchor to the rows it names. D4 · The contradiction badge is in the hero, before any figure. types.ts requires it "on the listing row AND on the detail page" precisely because it is the most interesting fact the directory holds about a repository, and it was on the detail page — in the seventh section, below every number a reader acts on. A visitor arriving from a shared link read A+ / 100% / not provisional and left. "The grade is not provisional" is qualified in the same breath where the sources disagreed, with its own link to #merge. The wording is words everywhere: "DIFFERENT COMMIT — the maintainer's local record describes …, this listing scans …", never MERGE and never ≠, which are a mathematician's notation standing in for the thing readers came to find out. D10 · Both figures name what they are a fraction OF. 87.1% on a page whose home had just taught "54 checks in the standard set" reads as ~47 answered; the true figure was 27 of 31 in scope, off by a factor of 1.7 in the flattering direction, and the strings 31 and 27 appeared ZERO times in the rendered page. The counts are derived from the rows the table below actually shows. D12 · `no answer` and `info` were fourteen units of grey apart, differing on one channel plus the word. `no answer` is dashed with a struck label; `info` loses its pill entirely, because it is not a verdict and a pill is what a verdict looks like here. (The three-state legend landed with D2.) The fixture for all of this is new and deliberate: the default one carries no local lane and no contradiction, so every claim above would have passed vacuously against it — the two facts this design is most obliged to surface are exactly the two it has never had. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
D6 · The accent singled out A3 and A6 — the two groups defended mostly by checks only a maintainer's machine can answer. The claim checks out against the data, and THE CHART COULD NOT SHOW IT: A8 is also 5 and grey, A7 is also 8 and grey, so the emphasis rule was underivable from anything plotted and a reader had to take the caption's word for it. Each bar is two segments now — answerable from outside, and only on a maintainer's own machine — so the fact is readable off the figure, with no bar singled out and the brand accent out of a chart about risk entirely. The hatch is a 3-of-7 duty cycle at 42% white, which averages the 0.18 the second fill wants and delivers it AS a texture, so the two segments survive greyscale. The caption describes what is drawn and carries a key for the two fills. D7 · The triangle asserted three relationships that do not exist: that lane 1 relates to lane 2 as lane 2 relates to lane 3, that the set is closed, and that there is an edge from the weakest lane back to the strongest. What this site believes is an ORDERING, and an ordering is a line. It is an open path of exactly two segments down a three-rung ladder now — the project's own signed build, a scan from outside, a maintainer's own machine — with the hollow node at the weak end and the words "strongest" and "weakest" at the edges. The headline is "Three ways a record gets made, and they do not carry equal weight.", which also retires the second-person line that addressed a maintainer on a page a consumer of someone else's record is reading (D15). Measured after moving the rank words: at x 40 "strongest" ran straight through the first node, so the ladder starts at 120 and the words sit outside it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
D11 · The green tint pair is gone entirely — it existed only to colour a phase region, which is not an evidence class, so a verdict hue was being spent on decoration. A test now walks every remaining use of the pass hue and requires its selector to be a verdict, a grade ring or a key. `meta` takes a DOTTED border instead of a fifth shade: "about the tool, never counted" is not a fifth kind of evidence, it is the absence of one, and dotted is how this page already says "not a thing that was scored". And `scored before v2` was painted amber — this page's `gap` colour, which says something went wrong, when what happened is that the rules are versioned and this record names its version. It is neutral grey and reads "scored under methodology v1 →". D13 · threats.ts is explicit that `sourced: "primary"` is a claim about THIS SITE — that someone here opened the CVE record, the government alert or the project's own write-up — and it exists because one incident once wore the mark by pattern-match rather than because anybody fetched it. The methodology page made that claim and marked its exception; the home page rendered the same citations with no tier claim and no slot for the mark, so the first time a class's lead incident was `reported` it would have cited journalism as fact, silently, on the higher-traffic page. The claim is above the A1–A9 list now, and the renderer FAILS CLOSED: an incident whose tier is missing or unrecognised renders no incident line at all. D14 · The explorer's panel note was the last "run in this phase" on the site. D16 · Local-lane evidence carries absolute workstation paths onto a public page — a real name, and the shape of a machine nobody asked to have described. `redactHome` rewrites `/Users/<name>/` and `/home/<name>/` to `~/` before display, proven through a record rather than by reading the renderer. The scanner's own output and the sweep of the other five designs stay Remaining Work in the ISA; this is the render-time floor while that is pending. D15's half that this design owns landed with D7 (the ranked figure's headline). The A3/A8 second-person lines are shared ATTACK_CLASSES data and stay out of scope, as the ISA records. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
A15 / Max-3 · The CSS comment claimed "0.2 s out the way it came — side-aware" and shipped only the enter keyframe, while the script set `hidden` synchronously: a 40 ms stroboscopic series over 0–240 ms found the panel gone at EVERY sample, delay 0 included. It vanished in one frame, which is exactly what a 0.4 s entrance makes conspicuous. There is a real `fy-tip-exit` now, it leaves by the offset it arrived on, and the script hides the panel on `animationend` — with a 400 ms belt for an engine that never fires one, and a state check so a panel re-opened while a close is pending cannot be hidden by it. Under reduced motion it closes at once. Max-4 · `role="dialog"` with focus left on the trigger behind it is a dialog a keyboard reader is standing outside of — the close button, the body and the links were all downstream of a tab order that had not moved. The panel carries `tabindex="-1"` and takes focus on open, with `preventScroll` so a panel anchored below the fold cannot jump the page; Escape still returns focus to the trigger. Measured live at 1440: on open, `document.activeElement === panel` and `scrollWidth === clientWidth`; on close, `animation-name: fy-tip-exit` at 0.2s with opacity 1 → 0.69 → 0.39 → 0.12 still in layout, then hidden. Also Max-11's phantom allowlist entry: the restraint sweep allowed `var(--popover-enter-animation-name)`, a name nothing in this tree ever animated — an allowlist entry that could only ever hide a real one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
D17 · Every `title=` and `aria-label=` in the design tree was enumerated and
classified: 34 source sites (10 titles, 24 accessible names), rendering 32
titles and 392 labels across the four fixture pages and 62 / 400 across the
built tree.
Ten carried a QUALIFYING fact — a threshold, a denominator, who could answer,
or the word "weaker" — and are surfaced or removed:
· the `provisional` chip's "Evidence coverage below 75%" title is gone; the
threshold is in the coverage note and the directory's terms note;
· the four lane chips lose their titles, and `laneKey()` prints trust.ts's own
four sentences under the listing — including the one saying the local lane
is WEAKER than the action lane, which is the single most important
qualifier the directory carries and which lived on hover;
· the phase bar's per-segment counts are gone from `title` and printed under
the bar (D2);
· the chart's aria-label clause, both traced figures' labels and the phase
row's label are each mirrored word-for-word on the visible layer.
Twenty-four are accessible names that assert nothing — Close, Read on, the nav
and region names, `grade A+`, the six phase-name labels (each also in the row's
own accessible name and on the sheet's phase bands), `Find a repository` (which
already had a visually-hidden twin) and `sscsb verify raw outcome` (glossed
visibly by the section it sits in).
One `title` on a Factory page is written by a SHARED module — the `reported`
chip's gloss in threats-shared.ts. Out of this design's file scope, and its
fact is stated in the same section by the sourcing sentence above the list, so
the title duplicates rather than hides. Asserted as such.
The test enumerates every distinct title value across the four pages, so a new
one cannot appear without this list being revisited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
The browser pass found two things no HTML test could have. The compact loop card was `position: static`, so its active and arrival rings — absolutely positioned at inset −1px — took their containing block from the whole loop. Measured at 390 they were 310 × 686 and painted a blue box round the entire rail for the 120 ms of the release animation. A still screenshot caught it; a geometry probe of the CARDS never would have, because the cards were fine. Making it `relative` then made it OBEY the desktop rule's circle percentages — `inset-block-start: 40.729%` is ignored by a static box and honoured by a relative one — which scattered all five cards and pushed the document to 575px wide at 390. Both are reset now, and both numbers are in the test's comment. And `.fy-row-lane`, the `local` link D3 added to each evidence row, measured 51.2 × 32 at 390: the card restack blockifies it out of the WCAG 2.5.8 inline exception, which is exactly why it passed at 1440 and failed at 390. It reaches the floor. Re-measured: 0 targets under 44px on all four pages at both widths. §B17 / Max-9 · One comment at the prose-margin clamp, recording that Factory sits at ~4.7 of its 5.0 for a structural reason — 54 questions rendered as cards plus 54 more in toggletips pull its home and repo means down, widening the gap from the other end — and that a red here on Factory ALONE points at the shared methodology copy, not at Factory. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
… content
R1. The mobile rules `.fy-flow-head, .fy-flow-band { grid-column: 1 }` are
(0,1,0) and lost to the desktop `.fy-flow-head[data-flow-head="in"]` family at
(0,2,0), which nothing overrides — so the three-column track survived the media
query and computed to `0px 186px 130px` at 390: "Inputs" broke to one character
per line inside a zero-width track, its cards overflowed their own column,
"Checks" landed on top of them (the site's only text overlap), and "Record" sat
2186px above the card it names. The document never widened, which is why only a
computed-style probe found it. Matching the attribute makes the mobile rules
(0,2,0) too, and the later block wins.
Also here, same figure: the stage's border is dotted like every other stroke in
it, and the three bands top-anchor at 1440 so a head sits on its own content
rather than naming a column that starts a third of a screen below it. Nothing is
capped — the figure's point is that it holds every check.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…t all R2. The sheet stated two different out-of-scope counts and attached the bigger one to the coverage claim: `21 of the 54 … out of scope` against the table's `11 out-of-scope checks are greyed`. The gap is exactly the ten registry controls the record holds no row for — binary-artifacts, webhooks, dependency-pinning, socket-firewall-ci, publish-targets, trusted-publishing, publish-tokens, publish-provenance, dist-manifests, maintainer-mfa — folded into "out of scope", which is a claim about a repository that nothing measured. It ran in the flattering direction: those ten sit outside the coverage denominator, and counting them as unanswered would put coverage under the 75% floor, so "clears the floor" and "the grade is not provisional" both rested on the guess. So `not in this record` is a state: on the chip (dotted, muted id, the words), in the key, in the phase note, as its own band in the All-controls table so "see the table" is true, and in the figures sentence as three counts that each come from the rows supporting them and sum to the registry. The phase note is a partition now — it left four of thirteen chips unaccounted — and `phaseBars` says which kind of empty a bar is: "no rows in this record" is the record saying nothing, "no checks in scope" is a decision it made. P6 asserted the second while the table said the first, for the same phase. Also: the hatch is gone (it had become a legend for itself), the key draws the real pills, and the directory card prints the denominator its percentage is of. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…se sentences R3. `info` was rendered 33 times on a sheet and named in none of the three keys on the page, while the figure above it said the same thing in plain English. The chip says `out of scope` now, every state that can render appears in every key — drawn as the page actually draws it, real pills rather than swatches that matched nothing — `gap` is amber everywhere (the table key painted it red), and the explorer's Record card promises the words the sheet actually prints. R4. Red means `did not pass` on this site; the contradiction family was painted in it, on listings with zero fails and grade A+, which is this ISA's own anti-claim. Amber is taken (it is `gap`), so the badge, the panel and the row take the neutral ink hairline the directory row already used for the same fact. `conflictBadge` returned on a stale commit BEFORE it tested contradictions, so a listing carrying both swallowed the one `types.ts` requires; it renders both. The `reported` source-tier chip stops wearing the gap amber. R5. "outside every denominator" is false under the site's own printed formula — an unanswered in-scope check is inside the coverage denominator, which is exactly why coverage reads 90.9% and not 100%. And the glossary's "nobody could answer this check" is the construction the hero was corrected away from, false on a sheet where eight of them were answered by the maintainer; Factory renders its own wording on all four pages, including inside one shared block it renders whole — by rewriting the output with a loud guard, never the shared module. R6. The re-verify links now say the signed bytes still carry the paths this page redacts; the row stops printing "vs" between two identical grades; and the home metric reconciles 16 in the standard set with the ten or eleven in scope. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…loop is a loop S1. The chapter rail was pinned to 278px inside a 344px column and inset ~34px from every other element on the page. Three costs, all at 390: one pill less of capacity on the two longest pages; a visibly indented left edge; and — because the opaque plate was NARROWER than the measure — a line passing under it stayed visible on BOTH sides, so "ar … an" and "ings" survived beside the chrome as word fragments, which reads as a rendering fault rather than as chrome. It spans the gutters now and clips at the screen edge, as the reference's own 390 rail does. S2. Five methodology tables are 560-640px inside a 344px window — including the one carrying all 54 checks, their questions and the groups each defends. Every question was cut mid-word at the viewport edge and the third column was off screen, with no fade, no shadow and no scrollbar to say so; the document never widens, which is why every overflow probe stayed green. They take the design's own edge mask, a focus ring, a tab stop and a visible cue. S3. The compact rail was five stacked cards with no connector and no return, on the chapter called "The loop" — and the 36px gutter the reference fills with its return line was reserved and empty, so the rail also read as accidentally off-centre. The cards and connectors live in two sibling containers, so both are flattened into the rail's grid and ordered from a property the renderer derives; the fifth edge is drawn as the return bracket in that gutter, the step number moves into a left gutter beside the title, and the padding is symmetric — 37px each side, measured. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…stop staircasing S4. Four centred wrapped rows — the explorer KEY, the maze legend, JUMP TO PHASE and the footer switcher — each captured their first item with the run-in label and then landed every wrapped line on a different left edge. For a key that defeats the one thing a key exists to do. The label takes its own line and the items align to one edge. S5. Every chart label was SVG text, so its RENDERED size was whatever the viewBox scaled to: 16px declared measured ~12px at 1440 and the A1-A9 row was dropped outright at 390, leaving nine unlabelled heights on a bare axis with the list that decodes them several screens away. The labels are HTML now, in real CSS pixels, positioned from the same plot geometry the bars are drawn from — bar and id centres agree within 0.4px, measured — the ids are mono like every other identifier on this site, and the chart gains the one centred axis word the reference has. The mobile stretch moves from a transform to the wrap's own aspect-ratio, so the drawing stretches and the type does not. S6. Same fix on the ranked figure, where the three names ARE the content: ~8-9px at 390 in light grey on black, and the middle label printed across the trace. They are HTML at 14px, placed off the line's own corridor — the line descends, so "above, centred" is clear for the first node and crosses it for the other two — and the weakest node finally gets the dash D7 asked for alongside its hollow. S7. A nested chip keeps its id in one piece: the class-C group gives back its indent and the pills wrap instead of the identifier. S8. Counters go 1-up at 390, the hero kicker drops the separator the break was landing on, and the 1-to-n counter gets its own nowrap cell against a two-word label — it was splitting across two lines at BOTH widths, which read as two unrelated figures. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…ure looks like one T1. The reference's single most-cited choice is that its 126.7px display line is weight 400 and nothing on the page is heavier; this tree had no rule enforcing it, so 94 of 94 strong elements rendered at 700 — five bold runs in eight lines of the honesty-rule paragraph, and at 390 a bold lead wrapping across two lines is the first thing the eye lands on. Measured after: 0 elements over 500 on any of the four pages, the shared layer's own six 600/700 weights included. T2. The pull-quote loses its left rule and indent — which took ~60px off a 344px measure at 390 — for the reference's centred sans with an em-dash attribution, and the chart beat drops its third caption-size paragraph for h2 plus one body block, with the key kept as a legend rather than a register. T3. Eighteen expandable regions looked inert. The A1-A9 lead says "Open one to see which checks defend it" directly above nine rows whose only open-state signal was a colour change, and the nine threat summaries rendered as subheadings — the shared layer sets display:inline-flex on every summary for its tap floor, and that suppresses the ::marker pseudo in this engine. A phone has no hover and no cursor to fall back on, so that was the whole affordance. Both get a marker whose transform changes with the state, and the summaries get cursor: pointer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
…ft rail T4. Round 1's E4 gave standalone links their 44px with inline-flex, which inflates a shared LINE BOX — so on the sheet's metadata line the repository URL and "scan run" rendered ~12px below the baseline of the text they sit inline with, and "scan run" dropped onto a line of its own starting mid-column. It is the first thing the eye catches in the sheet's first viewport, and it is round-1 m3's fault relocated. The hit area is an absolutely positioned pseudo now: measured 0px spread across every line of that row, at both widths. Every "·" becomes a ::before on the item that FOLLOWS it, bound to it by a non-breaking space — measured 0 stranded separators on all four pages at both widths, where there were eight. Every trailing arrow is bound to its last word. T5. The `local` marker in the verdict column reached 44px by growing into a dashed ~46px CIRCLE beside a 20px PASS pill — twice its neighbour's height, a shape that appears nowhere else on the site, and a second wrong copy of a component the phase chips already draw right. The element is the 44px target; the drawn pill is a pseudo at the neighbour's height. The cell's contents are wrapped so the 390 card restack cannot blockify the link out of the inline exception, and `raw: pass` stops breaking. T6. The grade ring was a flex sibling of the title, so the title, badges, contradiction notice, metadata and version pill sat 75px right of the rail the breadcrumb, the ring, both figures, the legend and P1-P6 share. Stacking it puts all of them on one rail at every width — a margin-hang runs out of margin below 1272px, which is a fix that only works where it was measured. T7. The headline breaks after "What each" so the two lines are closer in length. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
T8 the search field is a 999px pill on both pages — 8px is this design's DIAGRAM radius and the hero's own pill rule was losing the cascade to the override block. T9 the wordmark is Inter 500 at -0.02em rather than wide-tracked mono, which read as a terminal prompt. T10 methodology paragraphs are spaced at 1.5x their line (the gap was narrower than the leading inside them), the glosses lose the italic for the sans at a muted colour, the run-in "Checks that defend it" label hangs its wrapped list at the list's own left edge, and the `reported` chip is a pill. T11 the overview counts get a fixed right-aligned numeral cell, so "checks" stops landing at four different x positions down one column of panels. T12 the maze legend is a three-column grid (two wrapped rows, five different left edges). T13 the sheet's cards narrow to the measure they hold — every paragraph stopped at ~928px inside a frame running to 1280. T14 pass and gap take the tint/border register where they are tints, with the full-strength hue kept for the word, so contrast goes up; red stays the fail state and stays nowhere else. T16 the nav gets the plate's own shadow, so the segmented control passing under it on its way out reads as passing under something. T17 the first pill target on each page clears the nav even on the landing where the nav has not reached its sticky offset yet — it measured 0.0px. T18 the navigating guard's 700ms belt is armed only where `scrollend` does not exist: armed unconditionally it fired FIRST on any jump longer than 700ms, which is why only the longest page lit a third pill. T19/T20 land with S6 and T1. Also §B's last three: print keeps the opening panel (it carries the page's only h1), the checks count on an A1-A9 row is no longer aria-hidden, and `data-window-in-view` is written by an observer rather than hardcoded, so the aperture's `will-change` is conditional as the reference's is. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
21 new cases, and the file goes 858 -> 879. Each one pins a defect this round closed rather than the shape of the code that closed it: the three verdict keys are asserted as the SAME SET of words drawn with the real pills; the compact rail's interleave order is read off the rendered markup so a sixth stage would rail itself; the chart's id row is asserted against the plot's own column arithmetic rather than a copy of it; the navigating belt is asserted absent where `scrollend` exists. Two are written as counts on purpose. The heavy-weight check asserts SIX declarations over 500 rather than none: the concatenated sheet still contains the shared layer's own six, which this design covers with an override rather than rewriting a shared module — a seventh means the layer grew one the override does not reach, and the browser probe (0 elements over 500 on all four pages) is what actually closes the claim. The phase-name check counts the rendered key rows, because a title attribute never renders at all on a touch device and the directory is the one page that draws the bars without the names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
… numbers Self-check in real Chrome through VerifyViewport (lifecycle live), against a Bun.serve of site/dist at 1440 and 390, all four pages. 1 · The `scored under methodology v1` pill could not share a baseline with the line it sat in — a 44px pill among 21px text runs, its label centred inside it, sitting ~12px below everything beside it. That is round-1 m3 surviving T4's fix for the LINKS on the same line; §B10 already allowed the alternative, so the pill takes its own row. 2 · The explorer's Record card lost its full stop in the sepList refactor. It is in the 390 capture and invisible to every assertion that was looking for the words rather than the sentence. 3 · The first pill on EVERY page landed with 0.0px of clearance, and a 124px scroll-margin — tried first — measured 0.0px unchanged: 88px is the nav's PINNED offset, and on a page's first target the nav has not reached it, so it is still in flow directly above the section and its bottom IS the section's top, at any scroll-margin. The clearance had to be real air under the rail. 24px, and every pill of every page now clears by 23.6-28.5px. Two instrument facts are recorded in BUILD-NOTES because they produced false failures first: a tap-target probe must credit an absolutely positioned pseudo (the only way to give an inline link 44px without inflating the line box it shares), and an overlap probe must exclude the visually-hidden 1x1 idiom as well as closed <details> — overflow:hidden clips painting, not a descendant's geometry, so a hidden THEAD's cells still report real rects. Evidence under fix2/: every probe and the driver, plus captures at both widths. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
Round 3's four judges and the measurement pass converged on one sentence, and
these are its four shapes.
THE ID AWAY FROM ITS CHIP. `.fy-node-label { overflow-wrap: anywhere }` was
global while the repair that confines a break to a real hyphen — `flex-wrap:
wrap` on the chip plus `overflow-wrap: normal` on the label — lived only inside
the 767px block. A narrow region at 1440 squeezes a chip exactly the way a 390
viewport does, so the five-across Distribution & publishing band set
`publish-provenance` as `publis` / `h-` / `proven`: not a control id, and not
searchable. Both declarations are unconditional now. The squeeze itself is
round 2's new verdict word — `NOT IN THIS RECORD` is the longest in the set and
carries `flex: 0 0 auto`, so it never yields and the label absorbed all of it.
THE COMMA AWAY FROM ITS ID. T10 made the run-in checks list a two-column grid so
the label would hang it. In a grid each `<code>` is an item and each ", " between
them an ANONYMOUS item, so auto-placement dealt nine ids into column 2 and nine
bare commas into column 1 — measured at x=320 against ids at 499.4 (1440) and
x=24 against 203.4 (390), up to 81 on a fully expanded page, as the payoff of the
one interaction that section's copy advertises. The label takes its own line
instead: ordinary inline layout is back in charge of the separators, the ids get
the whole measure, and home's copy and methodology's `.tx-class-controls` — which
hung two different ways, each wrong — are one behaviour. `white-space: nowrap` on
the code then keeps `branch-protection`, `pr-template`, `maintainer-mfa` and
`publish-provenance` whole at 390.
THE MIDDOT AWAY FROM ITS ITEM. T4 moved every separator to a leading `::before`
bound by a non-breaking space, which is why no line ends on one — measured 0
across four pages. Two cases survive it and CSS can express neither: the dot
still strands at a line END when the item it introduces is an atomic inline-block
that wraps whole (the directory card's "… 30 of 33 in scope ·" with its coverage
pill below), and nothing anywhere stops a line BEGINNING on one, which is what
the fix traded into — the sheet's first viewport at 390 and the colophon both
open lines on a middot. Whether a separator sits at a line boundary is a question
only layout can answer, so the page's own script asks it after layout and again
on resize, and marks the ones that do. The mark HIDES THE GLYPH rather than
removing the box: `visibility` changes no geometry at all, so marking a separator
can never move the wrap that produced it, and the pass cannot oscillate against
its own effect. Re-run on `document.fonts.ready`, because web fonts land after
first layout and change every one of these measurements.
THE BADGE AWAY FROM ITS PILL. A 999px radius on a two-line box is an ellipse:
`DIFFERENT COMMIT` broke between its words and set a ~60px egg beside the 17px
sentence it labels, on the directory's primary row, once per listing, at both
widths — while the sheet hero draws the same fact correctly as an 8px box.
`nowrap`, and `flex: 0 0 auto` so `summary`'s inline-flex cannot squeeze it under
its own label.
Also, and each one declaration:
- 45 OF 54 DISCLOSURES SAID NOTHING ABOUT OPENING. Round 2 gave `.tx-details
summary` a rotating chevron and recorded that `.fy-merge summary` and
`.fy-table summary` already had one. Read against the built CSS they did not:
they had `cursor: pointer` and then `display: inline-flex`, which is itself
what suppresses the `::marker`. So the 41 `evidence (n)` rows on a sheet were
caption-coloured text that happened to be a button — on a page whose whole
argument is that the evidence is there to be opened, and on a phone with no
hover and no cursor to fall back on. Same glyph, same rotation, same three
declarations, so the site has one disclosure. The 44px target is untouched.
- `.fy-swipe { display: block }` is an author rule and beats the UA's `[hidden]
{ display: none }`, so the script's own `cue.hidden = max <= 1` did nothing and
three methodology tables that fit their window advertised a swipe that cannot
move. A false affordance is worse on touch than none.
- The drawn `local` pill is 18px, the height of the `.fy-oc-pass` chip it is
meant to pair with, not 22.
- Home's `reported` mark takes methodology's radius, padding and spacing, so the
two instances are the same object rather than a pill and a rectangle — and the
double word space in front of it (8px of its own on top of the 8px
`.fy-incident-when` supplies) is gone.
- `hyphens: none` on the pull-quote.
Three round-1/round-2 assertions pinned the forms this replaces and are updated
two-sided rather than deleted. The new ones are in "round 3 — a token never
breaks away from what belongs to it", including a count-based guard so a new
`<summary>` family cannot appear without the chevron rule being revisited.
888 pass / 0 fail / 1 pre-existing skip; tsc 0; build 0.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Factory — a sixth design, drawn in the Defense Factory's system with SSCSB's substance
Adds
factoryto the design registry (/_d/factory/): a direct replica of OpenAI's Defense Factory page as a system — its measured motion, its diagram grammar, its type and tint scale — with every diagram re-drawn for the problems and solutions in this project's scope. No copy, imagery or branding from the reference is used; the motion was measured from the reference frame by frame and re-implemented, not lifted.This PR ships the state after three measure-and-judge rounds plus the first group of the final targeted pass, so it can be reviewed live. The rest of that pass (diagram connectors, honesty copy, polish) is in progress on the same branch and lands as a follow-up PR.
What it is
animation-timeline(progress = scrollY / innerHeight), gated behind@supports (animation-timeline: scroll()); the no-support andprefers-reduced-motionbranches both paint the settled end state (0 animations under reduced motion at both widths — measured).pathLength = 1, dash-offset bound to a 0.30 × vh band ending at figure-centre = viewport-centre), an autoplaying loop (2.5 s per stage, offset-path packet, dotted rings), a toggletip, a radio segmented control with no sliding thumb, and a static bar chart — all data-bound toscoring.ts,reclassify.ts,checks.ts,threats.tsandtrust.ts, so the diagrams change when the registry does.Honesty additions (found by the security-reader lens, applied Factory-side)
not in this record, on chip, key, phase note, table band and figures — ten registry controls that a v1 record holds no row for were previously folded into "out of scope", which moved two counts on one sheet in the flattering direction.title.Validation so far
scrollWidth === clientWidthon all eight page/width pairs; fonts loaded, no serif face registered.mainoutside the switcher block (regression diff re-run on this exact commit).Gates on this commit
bun test888 pass / 0 fail / 1 skip ·tsc --noEmit0 ·bun run build0 · forbidden-string greps 0 (no workstation paths, no "nobody could answer/check", no reference copy).Left for follow-ups (shared copy and data, deliberately not touched in a design PR)
ATTACK_CLASSESA3/A8 address the maintainer in the second person on a page a consumer of the record reads.methodology-local.ts:55"sit outside every denominator" contradicts the printed coverage formula;glossary.ts:46"nobody could answer this check" — Factory overrides both in its own copy.🤖 Generated with Claude Code
https://claude.ai/code/session_017N6Qc2T7buVAXHZ9vYa1xm