Repository navigation
Cross-platform instrument motion lab: capability bindings, a synthetic impulse, and a bob that settles - #7913
gunbai-bot[bot] wants to merge 23 commits into
Conversation
…conclude Three modules and a witness, landing the model layer the motion lab consumes. No page, no route, no bob yet. extdeps.w3c.device_orientation_and_motion (CRD 12 February 2025) and extdeps.w3c.generic_sensor (CRD 14 May 2026) are separate authorities for separate standards, and neither contains any browser or platform behavior. Both were read from the specs rather than recalled, which mattered: the hollow-event sentence is SHOULD, not MUST, and devicemotion dispatch requires BOTH the accelerometer and gyroscope permissions. Either fact alone is enough to make "zero events" uninterpretable, and an earlier draft of this work asserted the opposite of the first one. The Generic Sensor spec warns against the exact inference that produced this lane: feature detection "do not tell you anything, however, about whether that API is actually connected to a real hardware sensor, whether that sensor works, if it's still connected, or even whether the user is going to allow you to access it." Constructor presence is exposure. The lifecycle is what interrogates the platform, and each of its five failures names itself. gunbc.design.motion_binding carries what an execution actually observed, with the axes independent because they fail independently. Its central claim is negative: an observation that did not look cannot conclude. StreamNoEventsObserved projects to SensorAvailabilityUnknown and never to SensorAbsent; a refused hardware connection likewise stays unknown, since NotReadableError describes one attempt rather than a machine. Only an unexposed interface reaches absent. The witness reconstructs the 2026-08-05 capability probe field by field — embedded context unread, both feature policies unread, visibility and focus unread, no observation window — and asserts it resolves nothing. It counts five unread axes rather than asserting them, so the claim reds if an axis is quietly dropped. Green by execution: motion_binding_keystone_holds, 14 claims, cpu=1ms. Two substrate facts found the hard way: leading-operator line continuation is a parse error where trailing is the corpus idiom, and a variant name colliding across two coproducts is refused rather than shadowed, which is why the Generic Sensor error arm is SensorAccessNotAllowed after its upstream NotAllowedError instead of a second SensorPermissionDenied. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The observation carrier landed in the previous commit was browser-shaped. It declared BrowserProductRef and MotionExecutionSubject as top-level types of a supposedly neutral motion observation, which quietly asserted that the product is a website and that every other container is a variant of one. It is the other way round. Four axes that were fused now separate, because container is not renderer is not operating system is not capability provider. A native desktop application can render the same DOM surface a website renders; a website can render through DOM or WebGPU; a native shell can host today's instrument unchanged while adding typed platform bindings underneath it. gunbc.host_realization carries container kind and renderer kind as independent structural axes, with platform, device and build as symbolic references to their own authorities — so a pairing like native-desktop process rendering DOM/CSS is constructible, which is the first native architecture worth building and would have been unspellable under a fused enum. gunbc.capability_binding makes support a derived projection rather than an authored table. There is no WindowsSupported = true here and there cannot be: a verdict is per host, per requirement, per provider, and it comes from an executed observation. PhysicalImpulse is the one fact every binding produces — web DeviceMotion, web Generic Sensor, a Windows sensor, Core Motion, SensorManager, Linux IIO, and the deterministic synthetic source all converge on it — so the bobber physics never learns where motion came from and a new platform is a new producer, not a physics edit. The distinction that table would have lost is fitness. A readable sensor is not a fit sensor: PhysicalImpulseRequirement declares axes, sample rate, detection latency, gravity handling and a discriminating magnitude, and a stream that delivers clean samples without ever separating a knock from typing DEGRADES rather than supporting. Every degradation must name what is missing and what is offered instead, and the alternative names itself as synthetic — so a screen that bobbed can always say what moved it, and a synthetic impulse never masquerades as a hardware reading. gunbc.design.motion_binding becomes gunbc.web_motion_binding and keeps exactly what is genuinely web: browsing context, secure context, Permissions Policy admission, the permission route, and the event-versus- value distinction the WebIDL's nullability creates. It projects outward into the neutral BindingStreamState. Its ObservedIdentity carrier is deleted as a second spelling of ResolvedRef one file away. The seam carries a rule as an unreachable arm rather than a promise: no web stream projects to TapDiscriminatorQualified, so a web binding cannot reach CapabilitySupported by projection alone. Qualification is a judgement over samples against a declared requirement, never a state a browser reports. Green by execution: capability_binding_keystone_holds 11 claims cpu=1ms web_motion_binding_keystone_holds 15 claims cpu=2ms Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…hardware The two pieces of the motion lab that do not need a served route. gunbc.design.instrument_bob is the fishing-bobber response: the inner display takes a knock, rides, and settles. Three properties make it a modelled behaviour rather than an animation, and each is checked rather than asserted. BOUNDED. Impulse magnitude maps into the envelope and is then CLAMPED at nine pixels, so the strongest possible knock and an absurd one produce the same travel and the plate cannot be thrown off screen. Nine is derived rather than picked: it sits strictly under the register's existing attraction travel, and that relationship is asserted between the two authorities so a later retune of either reds. SETTLING, and this is why the envelope is geometric rather than an integrated spring. A discrete spring in integer arithmetic has to be argued into stability, and the argument holds only until someone retunes a constant. A geometric envelope makes decay structural: the amplitude halves every half-life, so it cannot grow for any choice of constants. The claim is carried as std.termination DescentEvidence over the advance function — Strict past a half-life, NonIncreasing below one, never Unknown — so a model whose envelope could grow fails a termination claim rather than merely looking wrong. Settle time is derived from the bound, the floor and the half-life rather than declared: 1080ms for the largest admissible knock, which is about what a bobber on water actually takes. INERT. The bob rides the existing impulse-glitch channel and inherits its law by citing it, not by restating it: no instrument channel may carry a domain fact. Reduced motion removes the travel and KEEPS the receipt — suppressing the impulse alongside the movement would turn a preference about animation into a loss of information, and would make an arriving impulse indistinguishable from a sensor that never fired. The physics is blind to which binding produced the impulse: two impulses of equal magnitude, one synthetic and one a hardware reading, produce identical states. That is what makes a new platform a new producer rather than a physics edit. The binding identity survives on the impulse for the receipt to render and has no influence on travel. The synthetic tap is the one provider that is ours, so it lives in the product layer beside the verdict it serves as an alternative to. It is a SOURCE, not a simulation and not a fallback: deterministic, chosen rather than selected-on-failure, and self-labelling. impulse_is_synthetic derives from the producing binding rather than from a flag, so a hardware reading wearing a synthetic label — or the reverse — is not expressible. Three strengths rather than a slider, because the control exists to demonstrate the bound and a continuous input lets a viewer miss both ends: light (900) falls BELOW the discriminating floor, firm (2600) clears it, knock (6000) reaches the clamp. Green by execution: instrument_bob_keystone_holds 11 claims cpu=1ms capability_binding_keystone_holds 13 claims cpu=2ms Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review repair across all eight findings, plus the deterministic frame sequence and the coverage frontier. Also restores the branch: the preceding WIP commit was an auto-snapshot of 2 of 8 files taken mid- rename, so it referenced symbols it had deleted and imported two modules it did not contain. THE CENTRAL DEFECT WAS MINE AND IT WAS THE ONE THIS LANE EXISTS TO PREVENT. derive_capability_verdict mapped a freely authored TapDiscriminatorQualified arm straight to CapabilitySupported, while stream_meets_requirement — which checked two of the requirement's five declared dimensions — was never called by the verdict at all. So "qualified" was a caller's assertion and "supported" was reachable by writing the word, in a module whose whole subject is refusing unearned claims. Three of the five dimensions had no enforcement path in either direction. TapQualified now has exactly one minter. qualify_tap is total over magnitude, latency, axes, sample rate and gravity handling, plus a negative control, and cannot produce the qualified arm while any cause stands; CapabilitySupported consumes that receipt. Each dimension has its own RED. The negative control is a rejection cause rather than a neutral state, because a magnitude floor with nobody having typed underneath it establishes sensitivity, not discrimination. AN UNOBSERVED QUANTITY IS NOT ZERO. The web projection filled frequency and noise floor with zeros the observation never supplied — and a zero noise floor is not an absence, it is a claim of a perfect signal. Each measured axis now carries its own observed-or-not coproduct, frequency is derived from the interval actually present, and a qualification needing a dimension nobody measured refuses on it. NO EVENTS IS NOT AN ACTIVATION. The projection rendered the web's no-events-at-all into an arm literally named ActivatedNoSamples, asserting a lifecycle state that never occurred — and a witness pinned it, which made the invention load-bearing. The neutral arm carries the lifecycle, so the merge widens a remedy instead of claiming a fact. Three self-contradictions closed, where the note was right and the code was not: a refused backend connection now leaves hardware reachability unresolved, as its own note always said; permission-method exposure splits from permission state, so the discredited probe's unread-axis count moves from five to six — the sixth being the permission the old carrier scored as read; and a contradictory observation (readings under an insecure context, a blocked policy, or a denied permission) refuses with located causes rather than deriving reachable from the stream arm alone. Four more: extdeps.w3c.accelerometer lands as its own authority with the three concrete interfaces the Generic Sensor base explicitly delegates, so a provider is an exact interface rather than a family — and gravity handling now selects one, since only LinearAccelerationSensor removes it. extdeps.browser.google_chrome separates product from engine, restoring a boundary this repository already ruled on and that the fixture had reopened. CompanionDevice moves to a HostRole axis and the process-lifetime Boolean is deleted in favour of InstrumentContinuity. Verdict rows retain their binding, causes and obstacles are typed, and the degradation's alternative is a reference rather than a sentence. The bob thresholds are marked AuditionProvisional and renamed _candidate: their justifications read as derivations and were hypotheses. PhysicalImpulse magnitude becomes Nat, repeating a fix the corpus already made once for the same reason. Added: the deterministic frame sequence, so the whole response is a finite list computed with no clock and no host and a physics regression is a diff over a list. It carries the oscillation the envelope lacked — first excursion downward, because a knock pushes the plate away from the hand — and terminates by counting settled frames rather than checking the last one. And the coverage frontier, seeded only with targets that have a real near-term reason. CoverageProvider splits modelled from not-yet-modelled because a deferred target cannot cite a module that does not exist, and pointing at one would be the fabricated symbol DESIGN warns about. Two substrate refusals worth recording. A frame count is not a duration: dividing settle time by frame interval propagates the Milliseconds brand into a quotient that is dimensionless. Reaching for a cast was refused in turn, and that was the better answer — Milliseconds is a refinement of Int, so 'as Int' converts nothing. A brand is not carried by a value and shed on request; it is required by a position. The budget therefore falls away at a boundary that asks for plain magnitudes. Green by execution: capability_binding_keystone_holds 25 claims cpu=4ms web_motion_binding_keystone_holds 18 claims cpu=3ms instrument_bob_keystone_holds 16 claims cpu=8ms Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixes the compile-clean gate failure on 252d00c, and closes the verification hole that let it reach CI past three green witnesses. The defect itself is one character. A single-variant coproduct needs its leading pipe — `= | GoogleChromeDistribution` — or the parser reads the declaration as a type ALIAS, so the variant is a dangling type reference and the value constructor is undefined. extdeps.browser.chromium already had the right form one directory away. It was the only single-arm type in this change; everything else is multi-arm and unaffected. WHY THREE GREEN WITNESSES DID NOT SEE IT, which is the part worth fixing. extdeps.browser.google_chrome was referenced only through DeclarationRef strings. That is the correct way to carry symbolic identity, and it is exactly what §3 asks for — but it proves a NAME, not a module. No closure I ran ever loaded the file, so nothing typechecked it, and the whole-tree compile-clean gate was the only consumer that would ever look. Green witnesses over a closure that excludes a module say nothing about that module. Closed structurally rather than by remembering: the web witness now IMPORTS google_chrome and asserts that the discredited probe's reduced values are the cited frozen User-Agent tokens rather than a coincidence. That claim earns its place independently — Chrome reports "Mac OS X 10_15_7" and "MacIntel" as constants regardless of the machine, so pinning the fixture to the cited tokens means a later edit swapping in a real-looking version string reds instead of quietly promoting a constant back into a fake measurement. Its side effect is that the module is now inside a closure that compiles. Every module in this change now has at least one importer, so each sits in a witness closure that typechecks it. That is the property that was missing, and it is checkable rather than a resolution to be more careful. The gate cannot be run standalone to verify this: it refuses without the executor's whole-tree compile receipt, which is correct behaviour — it declines to answer without the evidence it exists to consume — so the importer coverage is the local substitute. Green by execution: web_motion_binding_keystone_holds, 19 claims, cpu=3ms. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lent Fixes the batch-3 failure on f2f3c79 — v2.lens.non_fold_residue caught 13 wildcard `_ =>` arms I had written across six files. The lens is right and the cost is not stylistic. A wildcard makes a coproduct's growth SILENT: a new variant lands, falls into the catch-all, and is read as a legitimate answer rather than as a missing arm. extdeps.languages.rust.emit's rust_pair_completion_op_key_totality_note records the same lesson from an earlier incident, caught by the same lens on its first unsuperseded floor run. Two of mine would have done real damage, both re-opening a hole this very lane had just closed: stream_unread swept every unlisted MotionStreamState to zero — meaning a newly added arm would have counted as an OBSERVED axis, inflating an observation's decisiveness on something nobody read. That is precisely the defect the permission-method split was landed to fix, reintroduced one function away through a catch-all. stream_carries_readings swept unlisted arms to false, so a future readings-bearing arm would have been invisible to the coherence admission and its contradictions would have stopped being detected. The rest were less dangerous and are gone on the same principle: nine verdict, contradiction, phase and coverage-state matches now write every arm. Where expanding a nested match inline would have been unreadable the inner match became its own named function — permission_state_contradiction and state_names_a_trigger_if_it_needs_one — which is the fold the residue lens is asking for rather than a wildcard wearing a different shape. Adding a variant now forces an edit at each site instead of defaulting, and that is enforced by non-exhaustiveness at compile time rather than hoped for. Green by execution: capability_binding_keystone_holds 25 claims cpu=4ms web_motion_binding_keystone_holds 19 claims cpu=3ms instrument_bob_keystone_holds 16 claims cpu=8ms Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One conflict, purely additive: both sides appended to scope_carrier_paths in gunbc.extdeps_scope_frontier — main adding the rusage, sysctl and procfs authorities, this branch adding the two W3C motion specifications, the Accelerometer extension and the Google Chrome distribution. The union is the resolution; the rosters do not overlap and no row was dropped. Verified rather than assumed: all nine rows resolve to files on disk, which is the property roster_paths_resolve_on_disk enforces and the one a careless union resolution would break. Merge commit rather than rebase, per the repository's integration policy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s that report only what happened The synthetic tap is the first-class input, not a fallback. Press it and the inner plate rides and settles on any machine, with no sensor involved and nothing to grant — so the response is judgeable before any hardware question is answered, and a viewer can tell whether the bob feels right independently of whether their laptop can produce one. The three magnitudes straddle the discriminating floor and say so on the button, which is what stops the control from reading as a volume knob. THE PHYSICS DOES NOT MOVE INTO THE RENDERER. gunbc.design.instrument_bob decides the displacement sequence and the page ships it as data; the client replays it. Both preferences travel with the button — the full ride and the at-rest frame the model decides for MotionReduced — and the client selects by matchMedia, so reduced motion is a model answer rather than a renderer opting out. A witness asserts the client contains no arithmetic call at all, which is the RED that catches physics migrating outward. The probes report exactly what happened: how many events arrived, how many carried values, over what measured window, which lifecycle state was reached, and which named error refused it. An unanswered question renders as unanswered, and an absent interface is reported as absent rather than as silence — different observations, never rendered the same way. TypeScript grew a try/catch arm to make that possible. A Generic Sensor constructor raises SecurityError outside a secure context or under a blocking permissions policy, with no property to ask first; without a catch the probe would fault mid-handler and the page would keep displaying "not yet run" — an unanswered question standing where a refusal was observed, at the one seam this lane exists to keep honest. The grammar grows one arm rather than the probe pretending the throw cannot happen. The three instrument paths now have one path authority. The router builds its route specs from the same declarations the shared header renders its nav from, and a witness requires every rendered link to select a route — so a header link to a 404 is caught by execution rather than by noticing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tness ran it The rule construction read class_name where the cited Selectors Level 4 carrier declares name. Nothing caught it earlier because the page had no executing consumer: the route existed, the model was green, and the module typechecked nowhere. The witness is what made it a red instead of a page that 500s on first request. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s not conjoined THE PRODUCT DEFECT. The envelope decayed by each STEP's duration, so at the production sixteen-millisecond frame against a one-hundred-and-eighty- millisecond half-life it computed zero half-lives and fell by nothing. The frame budget then truncated the sequence to an empty tail and the client set translateY(0) on its own. Between them, a model that never settled rendered as one that had — the fabricated plausible output aimed at the one thing a person was supposed to judge by looking. Amplitude is now a function of CUMULATIVE elapsed time rather than an accumulator, so no choice of frame interval can lose decay, with linear interpolation inside each half-life so the fall is a curve rather than a staircase. Descent evidence is measured by comparing two amplitudes instead of inferred from dt, and returns DescentUnknown if the envelope ever grows. The two-valued oscillation became a triangle over four named quarter-period legs, because a square wave satisfies "appears on both sides of rest" while never occupying a position between them. Budget exhaustion is BobSequenceRefused, so a truncated sequence is not a shorter success, and the client's manufactured final zero is deleted. THE FAILURE WORTH REMEMBERING is not the physics. Five frame claims sat in a discarded expression above the keystone's returned conjunction — evaluated, thrown away, and reported green. The same shape was then found in the web witness. A claim that is called but not joined looks exactly like a claim that is enforced, so both files now carry one returned expression and a note saying why. THE SUPPORT WALL WAS A CONVENTION. Naming qualify_tap the sole minter does not make it one: TapQualified is a public constructor, and while the stream carried an already-qualified value a caller could author it around a failing receipt and reach CapabilitySupported. The stream now carries the raw requirement and receipt; the verdict qualifies them itself. Two neighbours fell to the same reading — the negative control trusted the word Passed rather than comparing its observed idle peak with the floor, and a measurement clearing thresholds the model calls unsigned reached supported. Detection latency of zero was the worst available answer for an unmeasured dimension, zero being the best possible latency. WEB ADMISSION WAS BESIDE THE PATH. A witness proved the checker notices a contradiction; nothing proved a contradicted observation had no route to a verdict. Both consumers run the check first — deliberately rather than routing an admitted-observation wrapper, which in a substrate without opaque construction would be the same forgery one level up. Coherence now reads the gyroscope policy DeviceMotion actually requires, treats an unanswered prompt as contradicting readings, and derives required axes from the provider rather than demanding a requestPermission exposure from sensors that have none. Continuity's fourth field was named for the failure and required to be true. Renamed rather than flipped: a field whose name says one thing and whose required value says the opposite reads correctly at every call site and is wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
I hand-edited a generated artifact. CI's auto-heal regenerated DESIGN.md from gunbc.design_document and deleted all sixteen lines, correctly — the file is a projection, and an edit to a projection is a second representation the next regeneration silently discards. The heal then failed the run and the floor refused downstream with FloorUpstreamAlreadyRed rather than spending its budget on a branch already known red. Build and regen themselves passed; the drift was the only real failure in that run. The row now lives in gunbc.design_document as one li(text: ...), condensed to the single-paragraph shape every other open-threads row uses, and verified by rendering expected_design_md and finding it in the output. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…dict
Five seams from the third review, four of them the same shape — a name
standing where a fact was owed.
ONE REQUIREMENT. The observation carried a requirement identity on the
binding and an independently writable requirement value on the tap
outcome, with nothing making them the same requirement; the witness
demonstrated the hazard by binding every row to the provisional
candidate and passing the signed twin through the stream. They are
BoundCapabilityRequirement { identity, snapshot } now, the tap outcome
carries only the receipt, and the snapshot is what qualification reads
— asserted in both directions by a control that swaps the label against
the numbers.
NAMES. PhysicalImpulse.source_binding pointed at a producer function.
The coverage state fused "is the binding written" with "has anything
run against it", and its receipt field carried that same producer
reference, so a declaration that had never executed read as an
execution receipt. It splits into BindingImplementationState and
BindingProbeState; the one row claiming a probe cites an executing
witness; probe_receipt_names_a_witness makes the rule checkable, and it
is honestly a naming rule rather than a proof.
ONE WINDOW. Three web stream arms and two binding stream arms each
carried a window_ms beside the observation's own observation_window_ms.
A record reporting four seconds of quiet inside a window of zero was
constructible and had no defined reading.
THE THIRD PATH. project_sensor_availability — the projection feeding
the sandbox's admission input, the one a consumer acts on — was still
matching the stream arm alone after the other two consumers were moved
onto the coherence check. Same bypass, still open, at the exit that
mattered most.
TWO ABSORPTIONS AT THE PAGE. frames_for/frames_wire answered a refused
sequence with [] and "", which made every string_contains(html, wire)
control vacuously true — the control meant to pin the shipped sequence
would have passed on a page shipping nothing. And BobSequenceRefused
reported the remaining budget, always zero, under a name a reader takes
for the budget allowed.
THE PROBES MISCLASSIFIED READINGS. The event path tested acceleration.x
alone, so a knock landing on y or z read as hollow; the sensor path
counted reading events and tested no axis at all, on a route whose axes
the specification declares nullable. Both emit the disjunction
acceleration_carries_any_value models, from axis-name rows each
specification owns.
The Try arm gained three byte-exact serialization fixtures, because a
substring check proves an arm was reached and nothing about what it
emitted. Two roster predicates that had no executing consumer now run
over the live roster.
Green by execution: instrument_bob_keystone_holds ·
capability_binding_keystone_holds · web_motion_binding_keystone_holds ·
9 motion-page claims including the emitted probe bytes ·
5 serve claims · 3 Try fixtures.
Still open: node-level syntax validation of the emitted client, a DOM
playback receipt, and the visual receipt — the tuning constants remain
audition candidates until someone can see the bob.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Third-review sequence complete — head
|
Integration-and-execution pass complete — head
|
| Group | Result |
|---|---|
instrument_bob_keystone_holds · capability_binding_keystone_holds · web_motion_binding_keystone_holds |
3/3 |
instrument_motion_page_witness |
9/9 |
roadmap_serve_witness (all, not just touched) |
16/16 |
Try serializer fixtures |
3/3 |
| all-seven stage0 partition compile gate | 7/7 |
claim_batch was rebuilt at the merged head first — the prior binary was two days stale, and a stale binary answers about a tree that no longer exists.
Release receipt 1 — generated-client syntax
instrument_motion_client_js_source() emitted and run through node --check: PASS. The complete assembled program, not three isolated fixtures.
Release receipt 2 — playback smoke
The emitted page and emitted client executed together in a DOM. Full motion: no console exceptions; firm tap reaches −4px and +3px, so it crosses both sides of rest; visits intermediate positions; ends at the model-supplied zero; a second tap mid-flight restarts and settles. Reduced motion: min 0 / max 0, receipt panel and controls still present. Both probes replace not yet run — DeviceMotionEvent · 0 events, 0 carrying values, over 2003ms (a bounded silence claim carrying its window, not a verdict) and LinearAccelerationSensor · interface absent in this container.
This smoke is jsdom, not headless Chromium, and I am not going to let that pass unstated. Playwright's browsers downloaded but the build container has no libglib-2.0 and no root to install it. jsdom executed the real shipped client against the real emitted DOM, so the assertions are genuine executions — but it is not a rendering engine. A Chromium run stays a named follow-up.
Visual receipt — ready for the operator
No tailnet here, so the preview is the exact emitted bytes with the client inlined, published for direct viewing:
https://claude.ai/code/artifact/4973d581-15a8-4874-920e-9597511121b8
Shipped wires at 16ms/frame — light peaks at −1px, firm at −4px, knock at −7px. One property worth judging deliberately: every wire ends in a long run of zeros, because the model keeps emitting frames while the envelope sits above its floor but the displacement has rounded sub-pixel. Light is the extreme case, roughly 26 still frames after about 0.15s of movement. Honest, and possibly a dead pause.
Not flipping ready yet — the visual ruling is a human gate and it has not happened. At most one constants-only tuning commit will follow from it.
Two Class B sightings, neither in this diff and neither touched
The scoped-entry GCP failure reproduces exactly as documented: the whole-tree run resolves 640 sources, the narrow closure refuses on GcpProjectId. Separately, a scratch emit probe bound the wrong fn cell — there are two in the corpus, gunbc.roadmap_instrument_sandbox taking s: and gunbc.plans.md_helpers taking text: — and the resolver picked by pool membership, producing a call-contract mismatch. The shipped page is unaffected; its route witness passes. Recorded because it is a second live specimen of the same class, not a request to fix it here.
The operator ran the probes on the published preview and called this a place to park. Nothing more is being built here; what was not finished is recorded where the roadmap can dispatch it, not left in a PR body. THREE ROWS. instrument-motion-physical-qualification: a real tap on a real machine reaching the bob. Executed Chrome and Safari receipts with the host named exactly, an idle-and-typing negative control that must NOT qualify, the calibration that either signs bob_impulse_requirement_ candidate or finds it cannot be signed, and the rendering-engine playback receipt that the jsdom run substituted for. Native macOS is reached for only if the web routes produce no usable values. instrument-rendered-control-coverage: derive the interaction-coverage denominator from the rendered control contracts. The present one omits the theme, clear and activity controls, so it reads green while naming fewer controls than the page ships. Explicitly out of scope: repairing it by adding three remembered enum variants, which reproduces the hand-listed denominator one edit later. discarded-bool-result-wall: census then refuse a Boolean expression in non-terminal position inside a function returning Bool. Two keystones in this lane reported green with claims sitting above the returned expression, discarded; one of them was a bob that could not settle. Census first, because the population decides whether the wall lands in one step or behind a frozen roster. THE DESIGN ROW RECORDS THE PARK STATE. Two release receipts were executed before parking: node --check on the complete emitted client, and a playback run over the emitted page and client together. That playback ran in a DOM implementation, NOT a rendering engine, and the row says so — calling the substitute a browser receipt would be the fabricated-plausible-output failure aimed at the one claim a reader cannot check. The probes run on the preview returned zero DeviceMotion events over 2002ms and a SecurityError refusing sensor construction. That is the Permissions Policy path this lane opened on, observed live rather than reasoned about, and it says nothing about the host's hardware. It is recorded as a fact about the harness. No feel verdict was given, so the tuning constants stay AuditionProvisional and no constants commit was made. ROADMAP.md and DESIGN.md regenerated to their fixed point. Roadmap authority witnesses green: ids unique, rows complete, graph acyclic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Parked — head
|
| id | what it owes |
|---|---|
instrument-motion-physical-qualification |
executed Chrome and Safari receipts with the host named exactly · idle-and-typing negative control that must NOT qualify · the calibration that signs bob_impulse_requirement_candidate or finds it cannot be · the rendering-engine playback receipt the jsdom run substituted for. Native macOS only if the web routes produce no usable values. |
instrument-rendered-control-coverage |
derive the coverage denominator from rendered control contracts. The present one omits theme, clear and activity, so it reads green while naming fewer controls than the page ships. Explicitly out of scope: adding three remembered enum variants, which reproduces the hand-listed denominator one edit later. |
discarded-bool-result-wall |
census then refuse a Boolean in non-terminal position inside a -> Bool function. Two keystones in this lane reported green with claims sitting above the returned expression; one was a bob that could not settle. Census first — the population decides one-step wall vs. frozen roster. |
Roadmap authority witnesses green: ids unique, every row a complete unsigned ticket, graph acyclic, edge endpoints exist. ROADMAP.md and DESIGN.md regenerated to fixed point.
What the probe run on the preview actually established
DeviceMotionEvent · 0 events, 0 carrying values, over 2002ms
LinearAccelerationSensor · construction refused · SecurityError
That SecurityError is the Permissions Policy path this lane opened on — observed live rather than reasoned about, and it is the first executed instance of it. It says nothing about the host's hardware: the preview is an embedded document whose default feature allowlist is 'self', which is the same context that produced the original discredited probe. It is recorded in the DESIGN row as a fact about the harness, not as a capability observation. Zero DeviceMotion events over a recorded window is likewise a bounded silence that names no cause.
State at park
Green by execution on this head: 3 model keystones · 9 motion-page claims · 16 serve routing claims · 3 Try fixtures · 7 stage0 partition compile-gate claims · 8 roadmap authority witnesses. node --check passes on the complete emitted client. The playback smoke passes in a DOM implementation — not a rendering engine, stated in the DESIGN row rather than left to be inferred, and owed to the first row above.
No feel verdict was given, so the tuning constants stay AuditionProvisional and no constants-only commit was made. PR stays draft.
…-motion-lab Two conflicts, both resolved without picking a side. extdeps_scope_frontier: both branches appended to one roster — this lane's four browser/W3C rows, main's two LLM rows. Unioned. There is no semantic choice here; dropping either side would have silently narrowed a frontier that exists to be exhaustive. DESIGN.md: a generated projection, and the merge driver refused rather than answering. Taking either side would have dropped the other's authority-derived bytes and left the tree authority-ahead-of-artifact with nothing saying so. Regenerated from the merged authorities instead; design_document.dag itself auto-merged clean, so the projection carries both this lane's park record and main's changes. Seed emitter verified on the two-pass protocol rather than one: the first pass runs a binary predating the change it emits and can self-verify at divergence 0 for the wrong reason. Rebuilt, re-ran, regen_divergence_count=0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main bound a release identity to the serve process, so roadmap_serve_invoke takes release_revision. Git merged both files without a conflict and the result did not typecheck: three call sites in this lane's page witness supplied three of four required arguments. Worth naming because the merge driver cannot see it. A textual merge that touches neither side of a call can still break the call, so a clean merge is not evidence the tree holds — re-running the witnesses is. These nine were the only failures across the lane. The revision comes from main's own deploy_witness_release_revision fixture rather than a constant spelled here. A per-file sha would be the dual representation that fixture's own note forbids, and it lives under dag/test/ precisely so witnesses can share one without it reaching production. Green by execution after the fix: all nine motion-page claims, plus the three model keystones which never broke. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Conflict resolved — head
|
What this closes
A cross-platform capability vocabulary, a deterministic synthetic impulse, a bounded bob that actually settles, reduced motion as a decided answer, raw top-level DeviceMotion / LinearAccelerationSensor probes, and a discoverable motion lab at
/sandbox/instrument/motion.What it does NOT close, named rather than implied
An executed Chrome receipt · an executed Safari receipt · a qualified physical tap · a physical sensor reaching
PhysicalImpulseand driving the bob · native macOS access · Windows / mobile / Linux bindings · the false-green dead-hover law · node-level syntax validation of the emitted client · a DOM playback receipt.The client counts events and readings and prints prose lines. It does not construct a typed
WebMotionObservation, emit a copyable receipt, qualify an impulse, or feed a real reading into the bob. This is the synthetic bob plus raw capability probes.The lane opened on a mistake
A browser probe found
DeviceMotionEventconstructible, never calledstart(), and a verdict of sensor absent was asserted from it. Three facts refuted it: the specification's hollow-event allowance is a SHOULD; constructor presence is not sensor presence; and the probe ran inside an artifact whose Permissions Policy default allowlist is'self', so the decisive question was never asked. Receipt kept, verdict withdrawn, observation reclassifiedMotionReachabilityUnresolved.Four layers, kept apart
Product semantics · application container · renderer realization · platform capability bindings are independent axes on
HostRealization. A browser is ONE realization. OS support is not one Boolean — each provider is its own extdeps authority (extdeps.w3c.device_orientation_and_motion,extdeps.w3c.generic_sensor,extdeps.w3c.accelerometer,extdeps.browser.google_chromeas a distribution distinct from the Chromium engine), so adding a platform adds a row and never widens a product enum.Second-review repairs
The bob did not settle. The envelope decayed by each STEP's duration, so at 16ms against a 180ms half-life it computed zero half-lives and fell by nothing; the budget truncated the sequence and the client supplied
translateY(0). Amplitude is now a function of cumulative elapsed time with interpolation inside each half-life; descent evidence is measured by comparing amplitudes, not inferred fromdt; the two-valued oscillation became a triangle over four quarter-period legs; budget exhaustion isBobSequenceRefused; the client's manufactured final zero is gone.The keystone was not conjoined. Five frame claims sat in a discarded expression above the returned one — which is how all of the above reported green. The same shape was found in the web witness. Both files now carry one returned expression.
The support wall was a convention.
TapQualifiedis a public constructor, so an authored qualified arm around a failing receipt reachedCapabilitySupported. The stream carries the raw requirement and receipt; the verdict qualifies them itself. The negative control trusted the wordPassedand now derives pass/fail from its observed idle peak. Provisional thresholds land onCapabilityQualifiedAgainstProvisionalRequirement. An unmeasured detection latency isLatencyUnobserved, not zero.Web admission is on the decision path, not beside it — both consumers run the contradiction check first. Coherence reads the gyroscope policy DeviceMotion requires, treats an unanswered prompt as contradicting readings, and derives required axes per provider.
Continuity polarity corrected by renaming to
avoid_cold_start_replay.Third-review repairs
Four of the five were one shape: a name standing where a fact was owed.
One requirement, not two. The observation carried a requirement identity on the binding and an independently writable requirement value on the tap outcome, with nothing making them the same requirement — a row could name signed thresholds while measuring against provisional ones, and the witness itself demonstrated the hazard by doing exactly that. They are now
BoundCapabilityRequirement { identity, snapshot }; the tap outcome carries only the receipt. The snapshot is what qualification reads, andwitness_red_the_snapshot_decides_and_the_identity_does_notswaps the label against the numbers in both directions.Bindings that were not bindings, receipts that were not receipts.
PhysicalImpulse.source_bindingpointed at a producer function →source_provider. The coverage state fused is the binding written with has anything run against it, and itsCoverageImplemented { receipt: … }field carried that same producer reference — so a declaration that had never executed read as an execution receipt. It splits intoBindingImplementationState×BindingProbeState; the one row claiming a probe citesinstrument_bob_keystone_holds; andprobe_receipt_names_a_witnessmakes the rule checkable. Honest rung: it is a naming rule, not a proof that the named witness is enrolled and green — next-rung trigger is the witness-identity join the enforcement-intent lane owns.One observation window. Three web stream arms and two binding stream arms each carried a
window_msbeside the observation's ownobservation_window_ms— one duration, two writable homes, and a record reporting four seconds of quiet inside a window of zero was constructible. The arms keep only what is theirs.The third path around admission.
derive_reachabilityandproject_binding_streamwere moved onto the coherence check last round;project_sensor_availability— the projection feeding the sandbox's admission input, the one a consumer acts on — was left reading the stream arm alone. Same bypass, still open, at the exit that mattered most. All three now refuse, and the RED covers all three.Two absorbing fallbacks at the page.
frames_for/frames_wireanswered a refused sequence with[]and"", which made everystring_contains(html, wire)control vacuously true — the control meant to pin the shipped sequence would have passed on a page shipping nothing.frames_wirenow takes frames a caller obtained by matchingBobSequenceSettled, and every wire claim asserts non-emptiness first. Separately,BobSequenceRefusedreported the remaining budget — always zero — under a name a reader takes for the budget allowed; the field isbudget_allowedand the control pins 3 rather than the 0 it used to enshrine.The probes misclassified readings. The event path tested
acceleration.xalone, so a knock landing on y or z read as a hollow event; the sensor path counted reading events and tested no axis at all, on a route whose axes the spec declares nullable. Both now emit the disjunctionacceleration_carries_any_valuemodels, from axis-name rows each specification owns (extdeps.w3c.device_orientation_and_motiongained its three;extdeps.w3c.accelerometeralready had them). The sensor reports reading events and value-bearing readings as two numbers.Trygot its own execution receipt. A substring check proves an arm was reached and nothing about what it emitted. Three byte-exact fixtures: a try/catch, a try nested inside a handler (which routes back throughserialize_ts_stmt_body), and a bare-body form.Two roster predicates had no executing consumer.
coverage_targets_asserting_supportanddeferred_targets_all_name_a_triggerwere written to hold the roster honest and nothing ran them. They now execute over the live roster.Green by execution
instrument_bob_keystone_holds·capability_binding_keystone_holds·web_motion_binding_keystone_holds· 9 motion-page claims including a route-level control that the shipped 16ms sequence starts at rest, moves downward first, visits intermediate positions, crosses rest, loses reach, contains exactly one settled frame, and ends at zero without the renderer manufacturing it · all 16roadmap_serverouting claims · 3 byte-exactTryserialization fixtures · all 7 stage0 partition compile-gate claims.The tuning constants — 9px travel, 180ms half-life, 90ms half-period — remain audition candidates until the visual receipt below exists.
bob_impulse_requirement_candidatestands atAuditionProvisional.Release receipts, executed on the merged head
Generated-client syntax.
instrument_motion_client_js_source()emitted and run throughnode --check— PASS. This is the complete assembled 4.9KB program, not three isolated serializer fixtures.Playback smoke. The emitted page and the emitted client, executed together in a DOM:
DeviceMotionEvent · 0 events, 0 carrying values, over 2003msandLinearAccelerationSensor · interface absent in this containerStated rather than implied: this smoke is jsdom, not headless Chromium. Playwright's browsers downloaded but the build container lacks
libglib-2.0and root to install it. jsdom executed the real shipped client against the real emitted DOM, so the assertions are genuine executions — but it is not a rendering engine and is not offered as one. A Chromium run remains a named follow-up.Visual receipt
Preview of the exact emitted bytes at this head, with the client inlined so it runs without a server: https://claude.ai/code/artifact/4973d581-15a8-4874-920e-9597511121b8
Shipped wires, at 16ms/frame: light peaks at −1px, firm at −4px, knock at −7px. One property to judge deliberately — every wire ends in a long run of zeros, because the model keeps emitting frames while the envelope is above its floor but the displacement has rounded sub-pixel. Light is the extreme: roughly 26 still frames after about 0.15s of movement. Honest, possibly a dead pause.
Awaiting the operator's ruling on light, firm, knock, repeated tap, and reduced motion. The tuning constants stay audition candidates until then.
🤖 Generated with Claude Code