GATE C, VISUAL. Phase 2, 28 July 2026. Instrument: tools/verify/visual-sweep. Target: https://missionmatch-staging.thatwebhostingguy.com. Supersedes the run recorded earlier the same day, which FAILED and produced the decision below. VERDICT: PASS on both surfaces, zero findings, with both positive controls proven first. THE MATRIX IS SPLIT BY SURFACE, which is a recorded product decision and not a relaxation. See docs/BUILD_STATE.md, PRODUCT DECISION RECORDED, THE SUPPORTED VIEWPORT FLOOR. authenticated 768, 1024, 1440. missionMATCH is a desk and capture tool used at a desk. The supported floor is 768 for the duration of the design partner program. Below the floor is UNSUPPORTED, which is a different statement from broken. public 320, 390, 768, 1024, 1440, with no relaxation whatsoever, because candidates arrive on phones. A single relaxed number would have quietly excused the public pages too. That is the failure the split exists to prevent. POSITIVE CONTROLS, RUN FIRST ON EACH SURFACE. Two defects are planted and BOTH must be caught, because catching one and missing the other leaves half the instrument unproven while the run reports success: {"kind":"HORIZONTAL_OVERFLOW","detail":"4000 > 1440"} {"kind":"SHELL_MIN_WIDTH_REGRESSION","detail":"route requires 4000px, ..."} positive control OK: the planted overflow AND the planted min width regression were both DETECTED COUNTED RUN, AUTHENTICATED. 2 roles, desk.admin (admin) and patriciacox6 (superuser), 9 routes, 3 viewports. captures=54 findings=0 shell guard: widest route requires 701px (/command/candidates) 2 transport findings did not reproduce and were dropped, see transient.json COUNTED RUN, PUBLIC. Anonymous, 2 routes (/ login and /accept), 5 viewports. captures=10 findings=0 shell guard: widest route requires 320px (/) 10 named expected error responses allowed, see expected.json The login page fits a 320 pixel phone with no horizontal overflow. That is the surface a candidate actually reaches, and it holds the full matrix. THE STANDING GUARD, now asserted rather than remembered. No new screen may raise the shell's minimum width past the 732px baseline plus a 24px allowance. Measured per route and written to min-widths.json, currently 320 to 706 across every authenticated route, so there is real headroom and a regression will be caught while it is one screen rather than a pattern. SIX INSTRUMENT DEFECTS, found and fixed before this run was allowed to count. The rule that produced all six is the one this build keeps relearning: A NEGATIVE RESULT IS ONLY EVIDENCE WHEN THE INSTRUMENT IS KNOWN TO WORK. 1. The shell guard computed a minimum by walking the DOM for unshrinkable elements and reported "route requires 1440px" on a 1440 viewport, because flex-shrink:0 with width:100% is not a fixed minimum, it is merely as wide as its container right now. It would have false positived on every route forever. It now measures the quantity the 732 baseline came from: render below the floor and read scrollWidth, since a page cannot compress past its true minimum. The probe asserts nothing about the probe width. 2. The guard was a brand new assertion that had never been seen to fail, which is indistinguishable from one that is silently skipped. It now has its own planted defect and the control fails unless BOTH assertions fire. 3. A tailnet blip inside an unguarded page.evaluate threw and killed the entire sweep on its first route. A crashed sweep is an unmeasured sweep. Login now retries transport failures and returns a verdict on a real 401 or 403. 4. Failed requests were recorded as a bare URL, so ERR_NETWORK_CHANGED, the sweep's own retry aborting a navigation, and a genuine refusal all looked identical. Every failure now carries its reason; every error response now carries its status, method, and path. 5. When the DOCUMENT ITSELF failed to arrive the sweep asserted on the empty page and manufactured an EMPTY_SCREEN finding, which is not transport class and so was reported as an application defect. An observation with no page is now INCONCLUSIVE and retried; three consecutive failures become UNREACHABLE, which is a real claim about a page that will not load. 6. An inconclusive first attempt returned before the screenshot, so a route that recovered on retry vanished from the contact sheet, which is the artifact a human actually reviews. Captures had quietly dropped from 54 to 40. THE TAILNET WAS THE NOISE, AND IT IS GONE. Bubbles resolves its own public hostname to its public address and hairpins back through the router, across a host with TWO active interfaces on the same LAN, wired and wireless. Chromium saw the routes flap and reported net::ERR_NETWORK_CHANGED, which the sweep reported as the application's fault. The hostname is now mapped to the loopback UNDERNEATH AN UNCHANGED URL, so the Origin, the SNI, and the certificate are identical and the server receives byte for byte the request it would receive from outside. This is not the earlier 127.0.0.1 mistake, which changed the url and had every login refused by the CSRF allowlist. Pass --no-pin to sweep over the real wire when the wire is the thing under test. Finding counts across the day, same application, better instrument: 78, then 37 with QUIC pinned, then 24, then 3, then 0. Nothing about missionMATCH changed between the 37 and the 0. That is the measure of how much of a gate result can be instrument rather than system. ONE ALLOWED ERROR RESPONSE, named exactly. An anonymous visitor triggers the session probe and the API answers 403 "no session", correctly, and Chromium logs every non 2xx fetch to the console. The allowance is keyed to role, status, and exact path together, so it cannot cover a 403 anywhere else, a different status on the same path, or the same response seen while logged in, which WOULD be a real defect. If any other error response is on the page, nothing is dropped. RECORDED, NOT FIXED: 403 is the wrong code for not authenticated, 401 is. It is docs/IMPROVEMENTS.md item P1, awaiting triage. Changing an auth status code mid gate is the drift the protocol exists to prevent. BASELINES: still none established, stated plainly rather than claimed. The protocol says new or changed screens become baselines only after Joseph approves the contact sheets. There are two now, one per surface, in this directory. Until one is approved the pixel regression half of Gate C cannot run, and saying so is more useful than a baseline nobody has looked at. CAPTURES: 64 full page PNGs, deliberately NOT committed. Binary artifacts of that size do not belong in a git history that is otherwise text, and they are regenerated by rerunning the sweep, which is the point of having an instrument rather than an archive. They live on Bubbles at /tmp/sweep-auth/ and /tmp/sweep-pub/. The contact sheets, findings.json, min-widths.json, transient.json, and expected.json ARE committed, because they are the reviewable summary.