open-standards/wai/extensions/haptics.md
Transaction Science d009db9087
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m48s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m17s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m16s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m29s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 22s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 2m7s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 22s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 42s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 39s
wai formal verification (integer core) / kani (pull_request) Successful in 4m59s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 52s
WAI neural decoders end-to-end / synthetic fixtures → Rust decode → reference (±4) (pull_request) Failing after 1m7s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 6m49s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 24s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 2m28s
standards workspaces build + test / aac-rs (pull_request) Successful in 3m25s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 3m46s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 1m22s
standards workspaces build + test / map-rs (pull_request) Successful in 2m16s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m3s
standards workspaces build + test / openpay (pull_request) Successful in 18m29s
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Successful in 1m58s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Failing after 7s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Failing after 7s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Failing after 8s
standards workspaces build + test / arl-rs (pull_request) Successful in 3m49s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 3m19s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 3m45s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 3m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 4m0s
standards workspaces build + test / macOS energy backend (jcp-energy) (pull_request) Successful in 3m42s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 27s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 2m43s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 28s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 1m14s
wai cross-architecture byte-equality / windows-x86_64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · windows (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · windows (pull_request) Has been cancelled
wai: on-chip counters and calibrated instruments are separate energy classes, and every joule-carrying receipt can say which
The single `HwShunt` acquisition class covered both an on-chip vendor
counter (RAPL, NVML, SMC, IOReport) and an external calibrated shunt. They
are different evidence: a calibrated instrument's uncertainty is traceable to
a calibration, while a counter is a vendor's reading whose error the vendor
states (RAPL readings are deliberately noised when SGX or TDX is enabled,
per security advisory INTEL-SA-00389).

- extensions/energy-measurement.md §2 splits hardware evidence into
  `OnChipCounter` and `CalibratedInstrument`, each with a required declared
  uncertainty (relative error and integration window). IOReport is an
  on-chip counter, like RAPL and NVML. `HwShunt` stays readable as the legacy
  class, ranked below both, and is not sealed into a new WAI receipt.
- Every receipt family that carries joules — video, world, film, reel,
  haptic, score, splat4d, audio scene, ternary, provenance and the wai-quantum
  receipts — can carry its class. The label is additive: every committed
  signed vector still verifies, and the signed bytes of unlabelled and
  legacy-labelled receipts are pinned by tests. A sealed figure declares its
  1 µJ resolution, and the floor is stated as the rule verified (0.5/√3 µJ).
- The acquisition rules are scoped to the receipt profiles WAI defines, and
  the text says what enforces each one.
- Meters open their window from rest, report an all-zero power reader as
  unusable rather than clean, and state the running-window count model as
  conservative.
- oer-receipts.md maps OER's evidential grade onto the refined classes. The
  rule that a producer must not grade `measured` a figure whose class is
  `Estimator` is kept as settled on main.
- wai-quantum verifies a receipt in either form on every in-tree verify
  path, including wai-quantum-serve's POST /verify.
- CI: wai-energy-receipts.yml runs the energy-class, label and legacy-pin
  tests for wai-rs, wai-quantum and wai-quantum-serve, which no workflow
  enabled before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 01:27:37 -04:00

104 lines
4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WAI Extension: Haptics
> Status: Draft. Phase 2 of the cargo roadmap. Touch as instructions:
> ship a keyframed intensity/sharpness envelope, the sink reconstructs an
> actuator signal. Conformance is **sample-equivalence**. Reference impl:
> the `haptic` feature of `wai-rs`; corpus: `haptic-conformance/`; live
> sink: wai.transaction.science/haptics.
Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
## 1. Scope and model
A `wai.haptic.signal` object is a per-channel keyframed envelope of
**intensity** and **sharpness** (the Core-Haptics-shaped pair every
modern actuator API maps to) that the sink reconstructs to a per-sample
buffer and plays on whatever actuators it has. It is lever 3
(instructions-at-the-sink) for touch — an effect is a few hundred bytes,
not a recorded waveform.
In scope: the container, the deterministic reconstruct contract, the
**sample-equivalence** conformance criterion, the fallback floor, the
receipt profile.
Out of scope: a transport; actuator hardware specifics (the
channel→actuator binding is the sink's); carrier synthesis (the signal
is an amplitude/sharpness envelope, not a modulated waveform — the
deterministic floor stays trig-free).
Relationship to the core spec: mirrors interactive-worlds / spatial
audio. The reconstruct runs in the `wai.det.fixed64` floor; `media`
takes the informational value `"haptic"`; `wai.haptic.signal` is
authoritative.
## 2. Container (`WHAP`)
```
"WHAP" | u16 n_sections | section table (u8 kind, u32 off, u32 len) | sections
```
| kind | section | required |
|---|---|---|
| `0x01` | contract (canonical JSON) | REQUIRED |
| `0x02` | channel signals | REQUIRED |
### 2.1 Contract
```json
{ "sample_rate": 1000, "numeric": "wai.det.fixed64",
"channels": 1, "duration": 1500 }
```
Haptic rates are low (≈1 kHz); `duration` is in samples.
### 2.2 Channel signals
`n_channels u32`, then per channel: `n_keys u16`, then
`n × ( pos_sample u64 | intensity i64 Fx | sharpness i64 Fx )`.
Both fields are in `[0, 1]`. Between keyframes they linear-interpolate
in `Fx`; before the first / after the last key they hold.
## 3. Reconstruct contract
For each channel, for each sample `t ∈ [0, duration)`:
`intensity(t)`, `sharpness(t)` = the `Fx` linear interpolation of the
channel's keyframes at `t`, each clamped to `[0,1]` and quantized to a
`u8` (`round(v · 255)`, half away from zero, in integer space). The
canonical reconstruction is, per channel, the interleaved
`[intensity, sharpness]` `u8` pairs.
## 4. Conformance — sample-equivalence
> Given the same `wai.haptic.signal`, a conforming sink MUST reconstruct
> the identical canonical `u8` buffer, hence the identical BLAKE3 — on
> every machine, no tolerance parameter.
```
signal_hash = BLAKE3("wai:haptic-signal\x01" || per-channel u8 pairs)
```
## 5. Fallback floor
A sink with no actuators ignores the signal (haptics are
supplementary); there is no perceptual substitute to fall back *to*, so
`fallback` is typically `null`. A sink MAY surface the envelope visually
(a waveform) — presentation, not conformance.
## 6. Receipt (JWP profile)
`signal_hash` is the identity; the group's objects are per-channel
reconstruction blocks, Merkle-bound; one Ed25519 signature over
signal_hash + root + `work` (= duration × channels) + carried
`joules_micro`; `parent_receipt_hash` chains — the worlds/audio receipt
shape reused. The figure's acquisition class rides beside it as an optional signed label
([energy-measurement](energy-measurement.md) §2.8): absent, the receipt keeps
its legacy bytes and the figure is unlabelled; present, it is inside the
signature. The reference meter labels every figure it measures
`OnChipCounter`, with its declared uncertainty.
## Appendix
Sample-equivalence is replay/mixdown-equivalence with the tick replaced
by the haptic sample. The envelope is trig-free by construction
(amplitude + sharpness, not a modulated carrier), so the `Fx` floor
reconstructs it exactly with `+,−,×,÷` alone — the simplest cargo class
to make bit-exact, which is why it's the fast Phase-2 win.