Skip to content

Cross-platform instrument motion lab: capability bindings, a synthetic impulse, and a bob that settles - #7913

Closed
gunbai-bot[bot] wants to merge 23 commits into
mainfrom
session/loyal-bat-373-motion-lab
Closed

gunbai-bot[bot] wants to merge 23 commits into
mainfrom
session/loyal-bat-373-motion-lab

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

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 PhysicalImpulse and 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 DeviceMotionEvent constructible, never called start(), 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 reclassified MotionReachabilityUnresolved.

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_chrome as 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 from dt; the two-valued oscillation became a triangle over four quarter-period legs; budget exhaustion is BobSequenceRefused; 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. TapQualified is a public constructor, so an authored qualified arm around a failing receipt reached CapabilitySupported. The stream carries the raw requirement and receipt; the verdict qualifies them itself. The negative control trusted the word Passed and now derives pass/fail from its observed idle peak. Provisional thresholds land on CapabilityQualifiedAgainstProvisionalRequirement. An unmeasured detection latency is LatencyUnobserved, 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, and witness_red_the_snapshot_decides_and_the_identity_does_not swaps the label against the numbers in both directions.

Bindings that were not bindings, receipts that were not receipts. PhysicalImpulse.source_binding pointed at a producer function → source_provider. The coverage state fused is the binding written with has anything run against it, and its CoverageImplemented { receipt: … } field carried that same producer reference — so a declaration that had never executed read as an execution receipt. It splits into BindingImplementationState × BindingProbeState; the one row claiming a probe cites instrument_bob_keystone_holds; and probe_receipt_names_a_witness makes 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_ms beside the observation's own observation_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_reachability and project_binding_stream were 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_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. frames_wire now takes frames a caller obtained by matching BobSequenceSettled, and every wire claim asserts non-emptiness first. Separately, BobSequenceRefused reported the remaining budget — always zero — under a name a reader takes for the budget allowed; the field is budget_allowed and the control pins 3 rather than the 0 it used to enshrine.

The probes misclassified readings. The event path tested acceleration.x alone, 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 disjunction acceleration_carries_any_value models, from axis-name rows each specification owns (extdeps.w3c.device_orientation_and_motion gained its three; extdeps.w3c.accelerometer already had them). The sensor reports reading events and value-bearing readings as two numbers.

Try got 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 through serialize_ts_stmt_body), and a bare-body form.

Two roster predicates had no executing consumer. coverage_targets_asserting_support and deferred_targets_all_name_a_trigger were 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 16 roadmap_serve routing claims · 3 byte-exact Try serialization 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_candidate stands at AuditionProvisional.

Release receipts, executed on the merged head

Generated-client syntax. instrument_motion_client_js_source() emitted and run through node --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:

Assertion Result
console exceptions none
firm tap crosses below rest yes (min −4px)
firm tap crosses above rest yes (max +3px)
visits intermediate positions yes
ends at the model-supplied zero yes
second tap mid-flight restarts coherently yes, settles at zero
reduced motion min 0 / max 0; receipt and controls still present
both probes replace not yet run DeviceMotionEvent · 0 events, 0 carrying values, over 2003ms and LinearAccelerationSensor · interface absent in this container

Stated rather than implied: this smoke is jsdom, not headless Chromium. Playwright's browsers downloaded but the build container lacks libglib-2.0 and 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

gunbc-ci-auto-heal and others added 2 commits August 6, 2026 05:27
…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>
@gunbai-bot gunbai-bot Bot changed the title frontend Cross-platform instrument motion lab: capability bindings, synthetic impulse, and bounded CRT bob Aug 6, 2026
gunbc-ci-auto-heal and others added 11 commits August 6, 2026 06:03
…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>
@gunbai-bot gunbai-bot Bot changed the title Cross-platform instrument motion lab: capability bindings, synthetic impulse, and bounded CRT bob Cross-platform instrument motion lab: capability bindings, a synthetic impulse, and a bob that settles Aug 7, 2026
gunbc-ci-auto-heal and others added 5 commits August 7, 2026 01:17
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>
@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Third-review sequence complete — head e1cf403418c

All five findings have code, and every claim below is green by execution on this tree.

1 · One requirement. BoundCapabilityRequirement { identity, snapshot } on the binding; TapOutcome reduced to { receipt }. The discriminating control is witness_red_the_snapshot_decides_and_the_identity_does_not — it swaps the label against the numbers in both directions, so an identity naming the signed declaration does not lift provisional thresholds into support, and an identity naming the candidate does not push a signed measurement down.

2 · Names. source_binding → source_provider; synthetic_tap_binding → synthetic_tap_provider. Coverage split into BindingImplementationState × BindingProbeState, and the one row claiming a probe now cites instrument_bob_keystone_holds rather than the producer function. probe_receipt_names_a_witness makes the rule checkable — stated at the rung it has: a naming rule, not a proof that the named witness is enrolled and green, with the witness-identity join as its next-rung trigger. Two roster predicates (coverage_targets_asserting_support, deferred_targets_all_name_a_trigger) were written to hold the roster honest and had zero executing consumers; they now run over the live roster.

3 · One window, and the third path. window_ms removed from all five stream arms across both layers. project_sensor_availability runs the coherence check first; witness_red_no_third_path_around_admission covers all three projections with a positive control, since a projection hard-wired to Unknown would satisfy every refusal and prove nothing.

4 · Two absorptions. frames_for deleted; frames_wire takes frames obtained by matching BobSequenceSettled, and every wire claim asserts non-emptiness first — the vacuous-string_contains hole is closed at the assertion as well as at the helper. budget_allowed replaces the always-zero remaining budget; the control pins 3.

5 · Probe classification and the Try receipt. Both paths emit the any-axis disjunction acceleration_carries_any_value models, from axis-name rows each specification owns. The sensor reports reading events and value-bearing readings as two numbers. witness_the_shipped_probes_count_any_axis_as_a_value pins the emitted bytes, not the AST helper, so a client still shipping the single-axis test reds. Try gained three byte-exact fixtures including the nested case that routes back through serialize_ts_stmt_body.

Executed: instrument_bob_keystone_holds · capability_binding_keystone_holds · web_motion_binding_keystone_holds · 9 motion-page claims · 5 serve claims · 3 Try fixtures.

Not done, named rather than implied. Node-level syntax validation of the emitted client and a DOM playback receipt are open — this delivers the byte-level pin on the real artifact, which is a step short of both. DESIGN.md is drifted against gunbc.design_document: it is a generated artifact and whole-tree regeneration needs the compile the GCP pool-membership defect blocks, which I was told not to touch, so CI auto-heal will regenerate it as it did last round.

The visual receipt is still the open gate. The tuning constants — 9px travel, 180ms half-life, 90ms half-period — remain audition candidates until someone can see the bob. This head is ready to hand to a session with srv1/tailnet access.

The discarded-Bool-expression lens is deliberately not here; per the review it belongs in its own language-integrity PR with a corpus census.

@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Integration-and-execution pass complete — head 61a184e9631

Merged latest main (ea1f8b2d831) with one merge commit; clean, no conflicts. Regenerated to fixed point manually via generated_artifact_gate main_wet — zero changes, so nothing is left for auto-heal to mutate after review begins. Working tree clean.

Exact-head validation — 47 claims, all green

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>
@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Parked — head d663e92bb1e

Operator called this a place to park after running the probes on the preview. Nothing further was built; the unfinished work is now roadmap rows rather than PR prose.

Three rows in gunbc.roadmap_authority

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.

gunbc-ci-auto-heal and others added 2 commits August 7, 2026 21:33
…-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>
@gunbai-bot

gunbai-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Conflict resolved — head 76dd8e11778, mergeable: MERGEABLE

Still parked and still draft; BLOCKED is the draft state, not a failing check.

Integrated main (1de8e7455ee) with a merge commit rather than a rebase, per the squash-merge policy — identical end state, no force-push.

Two textual conflicts

extdeps_scope_frontier.dag — both branches appended to one roster: this lane's four browser/W3C rows, main's two LLM rows. Unioned. No semantic choice was available; dropping either side would silently narrow a frontier whose whole purpose is to be exhaustive.

DESIGN.md — a generated projection, and the merge driver refused rather than answering, which was the right call: taking either side drops the other's authority-derived bytes and leaves the tree authority-ahead-of-artifact with nothing saying so. Regenerated from the merged authorities. 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, not 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.

One conflict git did not report, and it broke the tree

main bound a release identity to the serve process (#7909), so roadmap_serve_invoke now takes release_revision: CommitSha. 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, and all nine motion-page claims failed to resolve.

Worth naming because it is the class a merge driver structurally cannot catch: 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. I only found it because I re-ran rather than trusting the merge.

Fixed by routing through main's own deploy_witness_release_revision fixture rather than spelling a sha here; a per-file constant is 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. main had already updated the other affected call site.

Re-verified on the merged head

3 model keystones · 9 motion-page claims · generated-artifact fixed point (zero drift) · seed self-compile divergence 0. Nothing else in the lane regressed.

The three parked roadmap rows are unchanged.

@briansrls briansrls closed this Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant