ReferenceOperatorsfrontend.surface.audit

frontend.surface.audit

Generated by docs/scripts/generate-docs.mjs from operators/frontend-surface-audit/operator.md and operators/frontend-surface-audit/operator.json. Edit the source, not this page.

Binding

FieldValue
idfrontend.surface.audit
domainfrontend
resources.profilesol-reviewer
resources.requires
policy.webSearch
policy.grammarBound
policy.imageGeneration

Job

Observe the committed surface at the served route across the matrix the direction’s coverage implies, measure every node that carries a claim, and judge each measurement against the published proof rules by the owner of the node it stands on.

Readiness, capture and judgement are one job

Splitting them produced a familiar failure: a capture taken before the surface was ready, judged by a step that could no longer tell, against evidence it had not itself collected. One operator that waits, measures and judges under one receipt cannot lose that connection.

A guarded route is reached, not declared unavailable

A route that answers with a sign-in screen is serving perfectly well; what is missing is an identity, and an identity is something the runtime has. Readiness therefore includes signing in as the flow’s own account when the route requires one: the credential is resolved by name, it is typed into the form and nowhere else, and capture begins only once the redirect has landed, so no frame this operator publishes can hold it. Reporting a guarded route as an unavailable runtime is a false negative that sends a person to restart a service that was never down. The one honest stop here is that no account exists for this flow yet, which is IDENTITY_MISSING: a hand-off to the operator that provisions one, never a verdict about the surface, and never a request that a person go and make an account.

Readiness reads the entry of this route

The runtime registry holds one entry per project route, and this audit reads the entry of the route it was bound to. A registry consulted as a single block answers for whichever route happens to be recorded in it, which is how an audit comes to report that nothing is serving while the surface it needs is on screen.

The surface must contain the committed surface

The applied receipt names the commit it wrote, and the runtime serves one integration branch per product carrying the work of every session that asked for it. So the test is not equality — that would fail the moment a second session existed, and fail on arithmetic rather than on evidence — it is ancestry: the applied commit must be an ancestor of the served head, and present among the commits the bound route records as contained. A served head that fails that test is SOURCE_DRIFT with nothing captured, because a measurement of another tree proves nothing about this one. The receipt states both commits under ## Served surface, since ancestry a reader cannot see is a claim.

The endpoint is the one the bound route carries, never one this operator derived: the route names the port its entry serves, and readiness is reached there. When the served head does not contain the applied commit, or nothing is serving at all, RUNTIME_UNAVAILABLE names the commit that must be served and the operation that would serve it, and the runtime owner is the one that acts.

A served surface can also drift in the family it renders

Clean ancestry proves the source is right; it proves nothing about the family the served head renders the source through. The integration branch also merges from the mainline, so a Grammar or other dependency version the session never resolved against can already be on the served head by the time this audit runs, and a presentation verdict that flips over that has nothing to do with the source this session wrote. ## Served surface therefore always names the family version this served head actually renders and the version the delivery was resolved against, side by side; when they differ, the drift is not left implicit in the ancestry check that already passed. Wherever a verdict’s own measured evidence is the one a version drift could have flipped rather than the source, that node’s own measured text names both versions again, so a reader is never left guessing which of the two possible causes produced the verdict. This is evidence, not a new gate: it names no scope question and stops at nothing the surface’s own proof rules did not already stop at.

Two sessions on one product

The isolation law is published once, by the operator that owns the runtime, and this audit works inside it rather than restating it: one product serves one integration branch on one port, and what keeps two concurrent audits from reading each other’s state is that each drives its own browser profile. That profile is recorded under ## Served surface, so a receipt whose sign-in state came from somewhere else is visible instead of merely suspected.

Measurement beats claim, always

Each node carries the identifiers it claims to satisfy, and the audit measures what the surface actually renders. A claim is never evidence of passing: a node claiming GAP-4 while the computed gap measures 1.5rem is a failure, and no amount of claiming changes the measurement. That is the whole mechanic, and it is why the claim exists.

The owner decides where a failure goes

A failing claim on an application-owned node is a value the resolution has to publish again, so it routes back to frontend.presentation.resolve, which is the operator that caps the rounds. A failing claim on a Grammar component’s own render is a Grammar gap: it goes to a person and into the family’s own gap table, never into a resolve loop, because no application value can fix a component. The interior of an application-owned node carries no claim and is not audited at all; only that node’s own measure rules are.

The audit changes nothing

No verdict is a repair, a workaround or an instruction. A failure stays a failure in the receipt until a resolution publishes a new value and the applier writes it, and the same surface is audited again. That separation is why the receipt is worth anything: an operator that could fix what it found would always be able to report a clean surface.

Boundary

Context is read-only, and the runtime is consumed, never owned. The operator writes only response/ of its own branch: the audit receipt, its captures, its screenshots and its verdicts. It does not modify product source, the applied tree, knowledge or Grammar, repair, restyle or work around anything it observes, start, stop, deploy or reconfigure a runtime service, cite a rule identifier absent from the bound inventory, judge a node it did not measure, or accept a claim as evidence that a node passes.

Context

AliasBindRequired
@knowledge/ui/proofwhat only becomes true once rendered; the audit’s whole rule inventoryyes
@workspaces/fethe routed checkout at the commit the application wrote; the owners and identifiers observed thereyes
@worktrees/sessions/central-runtimethe shared runtime owner: the preview serving the session worktree at that commityes
@knowledge/grammars/<family>how the family the bound route names (context.grammarId) is meant to realize Common, and where its gaps are recordedno

Inputs

KindFromRequired
frontend-source-applicationfrontend.source.apply, the commit under observation and the claims it wroteyes
frontend-presentation-resolutionfrontend.presentation.resolve, the owner of every nodeyes
frontend-direction-decisionfrontend.direction.decide, the route and the coverage the matrix is derived fromyes
routeworkspace.bind, the bound route: the endpoint its entry serves and the commits the served head containsyes
uat-accountplatform.operate, the account the guarded route is reached as; absent on the first pass, which is what IDENTITY_MISSING hands overno

Requirements

FieldTypeDefaultAsk
matrixlistevery coverage entryThe matrix entries to capture; the person may only narrow what the coverage implies
readinessProbechoiceroute-servedThe floor for readiness; a state that needs data rises to route-and-data-served on its own
accountidnullThe account record the route is signed in as when it requires an identity; the value is a reference to a record of names, never a credential
enviddevThe stack whose registry entry and accounts this audit reads; a surface observed in one stack says nothing about another
resumetokennullThe blocked branch’s token when re-entering after a stop

Steps

#StepParamsReadsWritesStops with
1Validate the gate and resume, and confirm the applied commit is inside the head the route is servingresumerequest/request.json, input frontend-source-application (the commit it wrote), input route (the served branch, the served head and the commits it contains), @workspaces/fe at the frozen head, @worktrees/sessions/central-runtime, @tools/gitINVALID_INPUT, SOURCE_DRIFT, NO_PROGRESS
2Bind the authority@knowledge/ui/proof (every topic with its fingerprint and inventory), input frontend-source-application (the claims), input frontend-presentation-resolution (the owner of every node), @worktrees/sessions/central-runtime
3Select the matrix entries and read the declared surface classmatrixinput frontend-direction-decision (its response/data/coverage.json: state by viewport by colour scheme, and the surfaceClass that decision declared)SURFACE_CLASS_MISSING
4Reach readiness for each entry on the port the bound route carries, in this session’s own browser profile, signing in as the flow’s account when the route requires an identityreadinessProbe, account, envinput route for the endpoint its entry serves, @worktrees/sessions/central-runtime for the entry of this project route, input uat-account for the account of names, @tools/http, @tools/secrets, @tools/browsercontrolRUNTIME_UNAVAILABLE, IDENTITY_MISSING
5Capture and measure each entry@worktrees/sessions/central-runtime, @workspaces/fe (the observed owners and the identifiers each node carries), @tools/browsercontrolresponse/artifacts/<matrixId>.png, response/data/captures/<matrixId>.jsonEVIDENCE_MISSING
6Compare against the claims and the proof rules, judge by owner, let each topic close itself, and emit@knowledge/ui/proof, @knowledge/grammars/<family>, the capturesverdicts, frontend-surface-audit, response/response.json, hostUNKNOWN_RULE, NO_PROGRESS

Step 6 judges every claim and then lets each proof topic close itself. The canon judgement is the one above: every claim measured, judged against the published rule, routed by the owner of the node it stands on; bounded search (@tools/websearch) resolves a referent a rule names and settles nothing else. On top of it, each bound topic computes its own verdict by its own closing rule — the arithmetic lives there and is not repeated here — and the receipt publishes one row per topic under ## Verdict: presentation, composition, responsive, motion, accessibility, contrast, render-truth and taste, each with the verdict that topic’s rule produced and the route a failure carries. A topic whose evidence never arrived is blocked, which is never reported as a pass and never as a failure. The taste row is scored per matrix entry and rolled up across them, lowest score and failing verdict winning, because a surface is only as good as its worst captured viewport; a fix-first there stands even when every canon rule passed, and the checkout’s own gates wait for a ship.

The sheet is composed with @tools/visualize and served, not filed. @tools/host (the tool the registry ships) puts response/artifacts/ on the loopback interface at the first free port of the registry’s range and records the URL, the port, the folder and the pid in response/artifacts/host.json, stopping when the branch ends or is resumed; a person opens the sheet and sees every matrix entry beside its verdicts. Nothing binds 0.0.0.0.

Serving is not telling. Step 6 prints over @tools/print, into the conversation the person is reading, the sheet’s URL, the worst-scoring capture of each topic and the ## Verdict table, and the receipt lists each printed artifact under ## Printed with why it was printed. A verdict a person never saw sends nobody anywhere, and an audit that files its sheet and says nothing has audited only itself.

A composition or taste verdict is never closed by asking. When such a topic closes as fail or fix-first, its row routes to direction and the chain hands to frontend.direction.decide, which scores the rendered candidates against the criteria this audit failed and selects the dominant one, or, over a tie its own scores prove, asks the person from its own stop. This audit composes nothing, ranks nothing and offers nothing: the validator refuses a user route that leaves a composition or taste topic open, because the answer is computable from the direction’s rubric and a question whose answer is computable is not asked. The caller stops and NO_PROGRESS are operational here — the same head measured again with no delta — so their reason says so and carries no candidate. A topic blocked because the matrix left out a declared state is neither of those things: it is not the same head measured again, and it is not a composition or taste finding, so it never counts toward NO_PROGRESS and never closes a composition or taste topic as fix-first. A taste mean is comparable across rounds only when both covered the same state set; a round whose matrix is narrower on states than the round before it is not compared for progress and cannot close the loop or exhaust a round budget on that comparison.

A criterion that depends on data volume is measured at the flow’s representative seeded volume, the volume TASTE-9 Case 5 defines, never at whatever the served workspace happened to hold. When the served workspace is below it, the taste topic is blocked and routes to seed: the operator that owns the data brings the workspace to volume and the entry is captured again — not a direction lap, and not a yes/no for a person, because the tree already answers it by creating the data. Re-measured at volume and still failing, the criterion is recorded data-bound in its Measured cell and TASTE-13 Case 6 keeps it out of the verdict, so it blocks neither quality nor UAT.

A choice the person took from a printed sheet closes the criteria that choice was known to fail. When the direction decision this audit reads was approved by the person and its ## Scores showed a criterion failing for the selected candidate at choice time, this audit records that criterion person-accepted in its Measured cell, naming the branch of that decision, instead of failing it back to direction; TASTE-13 Case 7 keeps it out of the verdict and the topic closes on the remaining criteria. The rubric never overturns a decision the person took on its own evidence in the same session, so a taste lens whose every failing criterion is data-bound or person-accepted ships, and next names quality.verify. The validator refuses a person-accepted row that names no decision branch, names a decision the operator took by itself, or covers a criterion the chosen candidate was not shown failing.

The surface class is not this operator’s to choose or to declare. It is read from the coverage of the frontend-direction-decision this audit was given, where the direction declared it from the vocabulary COVERAGE-1 Case 7 publishes; every banded proof rule reads its threshold from that name, and the audit only carries it into ## Surface class and into the verdicts, unchanged. An input decision that carries none — one written before the class was declared — or a name outside the vocabulary, is SURFACE_CLASS_MISSING: no band, no threshold, nothing to judge, and the direction is decided again before the surface is.

The matrix is the direction’s coverage, not a new decision: matrix may only narrow it, and the orchestrator may split the entries across up to three parallel branches of the same step. Every entry produces one screenshot and one capture, and an entry that produced neither is EVIDENCE_MISSING rather than a quiet omission. Every node carrying a claim is measured; a verdict is never recorded for a node that was not.

A verdict for a topic whose rules read across states — composition and accessibility, whose STATE-*, FEEDBACK-* and FOCUS-* rules are each only ever true of one particular state, an absent branch, or a focused target, and the taste lens, which TASTE-13 already scores whole — may only be recorded pass, fail or fix-first when the matrix judged covers every state the direction’s coverage declares. A narrowed matrix may still be audited, since a resume needs exactly that, but the receipt records the covered subset under ## Matrix and names what the narrowing left out under ## Coverage gaps; the topic’s own verdict is blocked, the same value a topic with no evidence at all already carries, never a verdict computed from the states that happened to arrive.

Outputs

KindFileTypeRequired
frontend-surface-auditresponse/response.mdmdyes
captureresponse/data/captures/<matrixId>.jsondatayes
screenshotresponse/artifacts/<matrixId>.pngartifactyes
verdictsresponse/data/verdicts.jsondatayes
hostresponse/artifacts/host.jsonartifactno

Stops

CodeDisposition
INVALID_INPUTterminate
SOURCE_DRIFTterminate
RUNTIME_UNAVAILABLEterminate
IDENTITY_MISSINGterminate
EVIDENCE_MISSINGterminate
UNKNOWN_RULEterminate
SURFACE_CLASS_MISSINGterminate
NO_PROGRESSterminate

Next

WhenOperator
a claim fails on an application-owned node, so a value must be published againfrontend.presentation.resolve
a topic verdict is fix-first, or the direction declared no surface class, so the composition is decided again before any value isfrontend.direction.decide
every topic ships or passes and the checkout’s own gates must runquality.verify
a claim fails on a Grammar component’s own render, so a person records the family gap and publishesfrontend.surface.audit
a state-reading topic is blocked because the matrix leaves out a state the direction’s coverage declares, so the surface is audited again once the matrix covers itfrontend.surface.audit
a density criterion was measured below the flow’s representative seeded volume, so the data is seeded before the surface is judged againplatform.operate
the route requires an identity and this flow has no account yet, so one is provisioned before the surface is observedplatform.operate

Source: operators/frontend-surface-audit/operator.md.