Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
eece7a4
Quantize the baker grid and emit MAX_ERR_LSB.
cursoragent Aug 25, 2026
47bacba
Fold runtime X-then-Y rounding into MAX_ERR_LSB.
cursoragent Aug 25, 2026
1e6bce7
Stabilize host bilinear and cap the materialized grid.
cursoragent Aug 25, 2026
452aea5
Look up declared knots with binary search.
cursoragent Aug 25, 2026
c0473f7
Round scaled nodes without the add-half f64 bias.
cursoragent Aug 25, 2026
fd59605
Step nonzero MAX_ERR_LSB magnitudes one ULP before ceil.
cursoragent Aug 25, 2026
7c5fadb
Point runtime status docs at baker quantization.
cursoragent Aug 25, 2026
94e680e
Measure u16 host bilinear as an exact rational.
cursoragent Aug 25, 2026
0e4be21
Measure MAX_ERR_LSB as an exact rational residual.
swgiacomelli Aug 25, 2026
2e2394f
Reduce ratio operands before cross-multiplying.
cursoragent Aug 25, 2026
e73087a
Give MAX_ERR_LSB a 256-bit dyadic residual so decimal coordinates sta…
swgiacomelli Aug 25, 2026
76a5a89
Keep exponent-separated residuals finite and name bound overflow.
cursoragent Aug 25, 2026
719c615
Bump an integral residual when a same-sign tiny addend is dropped.
cursoragent Aug 25, 2026
8b83df6
Keep unaligned addends as a second bilinear term.
cursoragent Aug 25, 2026
f648b0b
Replace the baker residual kernel with host BigRational.
swgiacomelli Aug 25, 2026
614e38e
Name num-traits in the baker README and keep tiny RMS nonzero.
swgiacomelli Aug 25, 2026
532a957
Keep a 1-bit numerator when converting residuals to f64.
cursoragent Aug 25, 2026
07c0575
Convert RMS residuals with a 53-bit window and a binary exponent.
cursoragent Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ integer mappings. **The `no_std` + no-alloc runtime is the product**, not a
nice-to-have. `ph-surfaces-bake` is the host-side baker: it requires `std`
and `f64`, and must never be linked into target firmware.

Baker `MAX_ERR_LSB` is `ceil` of an **exact** rational residual, owned by
`crates/surfaces-bake/src/bound.rs`. The baker is host `std` with alloc: it
does arithmetic the embedded runtime cannot. IEEE `f64` bit-patterns are
dyadics; bilinear is an exact ratio of the `i32` grid at every coordinate,
not only exact `u16` knots. `ceil` applies only to the finished residual.
Do not implement the bound as a host `f64` lerp, `next_up` / one-ULP padding
before ceil, an 8-ULP envelope, unreduced `i128` `n/d`, a fixed-width
integer with a ceil shortcut inside add, or a stand-in dyadic.
`NonFiniteDeviation` is for a true non-finite residual.
`BoundOverflow` is a finite ceil that does not fit `i32`.

Human-facing docs describe a public Active crate published at `0.1.0`. Version,
`publish`, changelog close-out, GitHub visibility, and the crates.io upload
belong to the release process in `RELEASING.md`; do not perform those actions
Expand Down Expand Up @@ -79,7 +90,8 @@ dependency kind (including optional, path, Git, target-specific, or
dev/build). The runtime package's `Cargo.lock` entry and `cargo metadata`
graph must not resolve it. Do not add `{ name = "ph-surfaces-bake" }` to
`deny.toml` `[bans] deny`: that would deny the baker package itself. The
baker stays in the deny graph so its empty third-party tree is evidence.
baker stays in the deny graph so its host dependencies are reviewed. The
runtime package's third-party tree stays empty.

Do not add a `gen` feature, optional dependency, or `cfg` on `ph-surfaces`
that reaches the baker. That shape is used by other org crates and is
Expand Down Expand Up @@ -161,10 +173,14 @@ policy, not by a second lockfile. There is no shell script and no
PowerShell twin. `tools/consumer` and `tools/code-size` keep empty
`[workspace]` tables so they do not join the root workspace.

`crates/surfaces-bake/src` is capped at 1,500 lines of implementation,
excluding `#[cfg(test)]` tails (the same exemption as the integer-only
scanner), fixtures, and generated output directories. Exceeding the budget
is a FAIL, not a quiet raise.
`crates/surfaces-bake/src` has a declared implementation-line budget in
`xtask/config.ron` (`max_implementation_lines`), excluding `#[cfg(test)]`
tails (the same exemption as the integer-only scanner), fixtures, and
generated output directories. The first figure (1,500) was a guess before
the baker existed. The cap exists to prevent unbounded growth, not to freeze
a constant: raise the declared number in `config.ron` (and the mutation
fixture that names it) when a real kernel needs room. Exceeding the current
declared cap without that bump is a FAIL.

`cargo xtask ci --profile release --nightly nightly-YYYY-MM-DD` is the
release-evidence mode: every check must run, a would-be `SKIP` is recorded as
Expand Down Expand Up @@ -202,7 +218,8 @@ bounded hosted subset is not the complete release evidence.
| New guard in `xtask` | An `Action` variant and required-handler entry in `xtask/src/config.rs`, dispatch in `xtask/src/checks/mod.rs`, a row in `xtask/config.ron`, and a mutation case in `xtask/tests/mutation.rs` showing it fails |
| Storage or cost wording | `crates/surfaces/src/lib.rs` crate docs, `crates/surfaces/src/surface.rs` / `evaluate.rs` / `axis/` item docs, `README.md` "Resource accounting and cost" |
| New or changed axis strategy | `crates/surfaces/src/lib.rs` re-exports and § Contract, `README.md` "Per-axis lookup strategies" table, the sixteen-pairing consumer in `tools/consumer/src/lib.rs`, `docs/v0.1-traceability.md` |
| New runtime/dev/build dependency in the shipped crate | `deny.toml`, the no-`ph-curves` check, and an explicit reason in the PR. Host-only xtask dependencies stay in `[workspace.dependencies]` and must not appear on the shipped graph. |
| New runtime/dev/build dependency in the runtime crate | `deny.toml`, the no-`ph-curves` check, and an explicit reason in the PR. The runtime graph stays empty of third-party crates. |
| New baker host dependency | `crates/surfaces-bake/Cargo.toml`, root `Cargo.lock`, `deny.toml` licences/bans, baker README. Must not appear on the runtime graph. xtask host deps stay in `[workspace.dependencies]`. |
| New or changed public API item | `crates/surfaces/src/lib.rs` module docs, `README.md` status sections, `CHANGELOG.md`, `docs/v0.1-traceability.md` |
| Example map values (`ELEVATION`, `CORRECTION`) | `crates/surfaces/tests/conformance/fixtures.rs` and `examples.rs`, `README.md` "Examples", `crates/surfaces/src/lib.rs` § Examples, `tools/consumer/src/lib.rs` |
| Firmware example fixtures (quickstart, uniform, mixed, fail-safe, cost) | `crates/surfaces/examples/*.rs`, `crates/surfaces/tests/conformance/fixtures.rs` and `examples.rs`, README "Start here", `docs/usage-guide.md` / `interpolation-walkthrough.md` / `choosing-a-strategy.md`, `tools/consumer/src/lib.rs`, and `examples` in `xtask/config.ron` when the Cargo example set changes |
Expand Down
35 changes: 30 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,41 @@

### Added

- Host-side baker quantization in `ph-surfaces-bake`: fill each declared
grid node from on-knot samples, apply the caller-stated scale with
round-to-nearest (exact half-way away from zero; values just below a
half stay on the nearer integer), measure deviation of
the quantized table from every supplied sample in i32 value LSBs, and
emit the maximum as `pub const MAX_ERR_LSB: i32`. For samples whose
coordinates are exact `u16` values, the bound includes the runtime's
rounded X-then-Y path, not only unrounded host bilinear. `MAX_ERR_LSB`
is `ceil` of the exact rational residual (IEEE `f64` bit-patterns as
dyadics, bilinear as an exact ratio of the `i32` grid on the host, not a
host-`f64` lerp with ULP padding). `ceil` applies only to the finished
residual. A finite residual whose `ceil` does not fit in `i32` is
`BakeError::BoundOverflow`, not `NonFiniteDeviation`. Missing or
ambiguous nodes, a non-invertible scale, an NX×NY product above
1_048_576 cells, and `i32` overflow are closed `BakeError`s. On-knot
lookup is binary search on the ordered knot lists. The operator RMS
statistic scales before squaring so a representable tiny residual does
not underflow to 0, and converting the residual to `f64` keeps
subnormals through `2^-1074` finite. The bound is an
upper bound on deviation from the supplied samples, not a device or
accuracy claim. This is not a runtime API change.
- Reviewed host crates on `ph-surfaces-bake` (`num-bigint`, `num-rational`,
`num-traits`) for exact residual arithmetic. They stay off the runtime
graph. This is not a runtime API change.
- Host-side baker ingest in `ph-surfaces-bake`: delimited sample points
(X, Y, value as host `f64`), an explicit per-axis grid (knot list or
uniform origin/step/count), and a caller-stated output scale that is
stored and not applied. Grid validation matches the runtime constructors
in the same vocabulary; samples outside the declared domain are reported;
uniform origin/step/count), and a caller-stated output scale stored at
ingest. Grid validation matches the runtime constructors in the same
vocabulary; samples outside the declared domain are reported;
non-finite sample fields and scales are rejected; failures are a closed
`BakeError` enum. No third-party parser. This is not a runtime API change.
- Host-side baker crate floor `ph-surfaces-bake` at `crates/surfaces-bake`:
`[lib]` plus a thin CLI, zero third-party dependencies, a mechanically
checked 1,500-line implementation budget, and a packaged-file allowlist
`[lib]` plus a thin CLI, reviewed host crates for exact residual
arithmetic, a mechanically checked implementation-line budget, and a
packaged-file allowlist
checked independently of the runtime `package *` family. This is not a
runtime API change. The runtime crate cannot reach the baker through any
dependency kind, feature, or `cfg`.
Expand Down
48 changes: 48 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ Deterministic `no_std`, no-alloc integer surface mappings for embedded Rust.
> The API is intentionally narrow: one static bilinear surface, four
> compile-time lookup strategies, and an explicit Error/Clamp boundary
> policy. There is no 1.0 compatibility promise.
> Host table generation lives in the sibling crate `ph-surfaces-bake` and
> is not part of this runtime package.
> Host table generation lives in the sibling crate `ph-surfaces-bake`
> (quantize a caller-stated grid and emit `MAX_ERR_LSB` as deviation from
> supplied samples) and is not part of this runtime package.
> **Domain:** Libraries.

```toml
Expand Down
7 changes: 7 additions & 0 deletions crates/surfaces-bake/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,10 @@ path = "src/main.rs"

[dev-dependencies]
ph-surfaces = { path = "../surfaces", version = "0.1.0" }

[dependencies]
# Stay on 0.4 with `num-rational` 0.4 so cargo-deny does not see two
# `num-bigint` majors on the baker graph.
num-bigint = "0.4.8"
num-rational = { version = "0.4.2", features = ["num-bigint"] }
num-traits = "0.2.19"
Comment thread
swgiacomelli marked this conversation as resolved.
33 changes: 28 additions & 5 deletions crates/surfaces-bake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,41 @@ be linked into target firmware.

Ingest reads sample points from delimited text (X, Y, value as host `f64`)
and an **explicit** grid: a knot list per axis, or a uniform origin/step/count
matching the runtime `UniformAxis`. A caller-stated output scale is stored
and not applied. The baker does not choose knots, parse expressions, or
quantize values.
matching the runtime `UniformAxis`. Quantize fills each declared node from
on-knot samples, applies the caller-stated scale with round-to-nearest
(exact half-way away from zero), and measures deviation of the quantized
table from every supplied sample in i32 value LSBs. The maximum is the
durable `MAX_ERR_LSB` const fragment; RMS, worst-sample coordinate, and
per-knot residual print on the CLI. The baker does not choose knots or
parse expressions.

`MAX_ERR_LSB` is an i32 value LSB: `ceil` of the exact rational
`|sample*scale − reconstruct|`. IEEE `f64` bit-patterns are dyadics;
bilinear is an exact ratio of the `i32` grid, computed on the host with
allocated integers. `ceil` applies only to the finished residual. A finite
residual whose ceil does not fit in `i32` is `BakeError::BoundOverflow`.
Host `f64` lerp is not the bound oracle. For samples whose X and Y are
exact `u16` values, that includes the runtime's rounded X-then-Y path. It
is not a typical error. It is not a device, vendor, sensor, calibration,
accuracy, timing, flash, or WCET claim.

Residual arithmetic uses `num-bigint`, `num-rational`, and `num-traits`.
Those crates stay off the runtime graph.

The public host API is `BakeInput::quantize` → `QuantizedTable`, plus
`emit_max_err_lsb` for the const fragment.

**Model conformance: N/A. Physical evidence: N/A.**

```sh
ph-surfaces-bake --help
ph-surfaces-bake --samples points.txt --x-knots 0,10 --y-knots 0,5 --scale 1
ph-surfaces-bake --samples points.txt --x-uniform 0,10,3 --y-uniform 0,5,3 --scale 1
```

Quantization, Rust emission, and goldens are later issues. The crate has
zero third-party dependencies and a 1,500-line implementation budget.
Rust emission and goldens are later issues. The baker may take reviewed host
crates for exact residual arithmetic. A declared implementation-line budget
keeps it from growing without bound.

## License

Expand Down
Loading