| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / jouleclaw-rs (pull_request) Has been cancelled
standards workspaces build + test / aac-rs (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
Everything this gateway does was **private convention**. It gates, meters, debits and seals every `tools/call`, `resources/read` and `prompts/get` — and a client had no way to discover that and no way to insist on it. A client that dropped the `_meta` block got served anyway, and a client talking to a gateway that enforced *nothing* could not tell the difference. Enforcement nobody can require is a courtesy, not a control. `initialize` is now the one discovery method not relayed verbatim: the gateway adds its own entry to `result.capabilities.extensions`, under the same reverse-domain key it already uses for per-call side data — one name for one thing. MCP's 2026-07-28 revision formalised `capabilities.extensions` for exactly this, with reverse-domain third-party keys and a 12-month deprecation policy behind it, so the advertisement has a defined place to live rather than an invented one. It names the profile it seals with and the methods it enforces, so a client can require the parts it needs instead of the bundle. `require_jcp(initialize_response, required)` is the half that makes the advertisement worth making. A client calls it before sending anything and **fails closed**: an endpoint advertising nothing is refused, and so is one that enforces `tools/call` but not `resources/read` — which is the case that matters, since the resource read is the egress door that was open until 971ef435. Garbage is refused rather than interpreted. Three tests. The advertisement round-trips through `require_jcp` with the right profile and method list; a client refuses a bare endpoint, refuses a partially enforcing one for the method it does not enforce, and refuses non-JSON; and advertising preserves everything else — an upstream's `protocolVersion`, `serverInfo`, its own `capabilities.tools`, and a third party's existing `extensions` entry are all untouched, while a response that is not a JSON-RPC result comes back byte-identical. That last property is the same one `attach_receipt` has to have: never mangle a payload you do not understand. `RequireError`'s `Display` is written out rather than derived, because this crate carries no `thiserror` dependency and three variants are not worth adding one for. 396 tests pass across the jcp workspace, 0 clippy findings in the crate. Also records a measurement in `jcp/tools/counter-resolution/`: the Apple `GPU Energy` rail's republish gaps, now over 90 s rather than 6. The short run gave a max of 992.2 ms, which sits just inside a one-second timeout and invites the conclusion that one second is enough. Over 90 s the same host produced **three gaps past 1000 ms — 1446, 1919 and 2033 ms** (n=2936) — so about 1 idle gap in 1000 exceeds a one-second wait and the worst was 2× it. It also pins the condition the right way round: under sustained load the rail is tight (max 42 ms, n=435); the long tail belongs to **idle**. Anything waiting a bounded time for this rail to republish should bound above ~2.5 s, or count the timeout rather than be surprised by it. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
| .. | ||
| counter_resolution.py | ||
| gpu_rail_idle_tail.py | ||
| gpu_rail_period.py | ||
| ioreport_rails.py | ||
| README.md | ||
What a counter can actually resolve
Two harnesses behind the numbers jcp-energy declares. Both are the evidence
for a constant in the crate; neither is a test of the crate.
counter_resolution.py — the per-process CPU counter's update period
ri_energy_nj is the only source in the survey that attributes energy to a
principal rather than to silicon, so whether it may grade a span decides
whether Apple silicon has any process-attributed reading at all.
Burns this thread's CPU for a fixed interval, samples the counter 60 times per interval, and reports the fraction of intervals in which it advanced — the crate's own liveness criterion is 80%.
Measured on an M5 Max, macOS 27:
| interval | advanced | median step | clears 80% |
|---|---|---|---|
| 10 µs | 0% | — | no |
| 50 µs | 0% | — | no |
| 100 µs | 2% | 20.4 mJ | no |
| 500 µs | 5% | 21.1 mJ | no |
| 1 ms | 35% | 2.8 mJ | no |
| 2 ms | 63% | 4.9 mJ | no |
| 5 ms | 87% | 9.6 mJ | yes |
| 10 ms | 100% | 19.0 mJ | yes |
| 50 ms | 100% | 92.9 mJ | yes |
The crate declares 10 ms, not the 5 ms where it first clears the criterion: over-declaring a period refuses spans that would have been fine, while under-declaring grades spans that were not, and at a ceiling only the second error is dangerous.
Note the shape below 1 ms. The counter does not lag smoothly — on the few intervals where it advanced at all, the median step was ~20 mJ, two orders above the 1 ms step. It accrues in lumps, which is the same batched-refresh pathology the crate already refuses on IOReport's CPU rails. A sampler that read it every 500 µs would see nothing most of the time and a 20 mJ jump occasionally, and would report both as measurements.
This is also why a per-operation figure for an 11.85 ms decision is taken as the mean of 200 decisions over a 2.6 s span rather than as 200 counter reads.
ioreport_rails.py — which Apple rails exist and advance
Enumerates the IOReport Energy Model group unprivileged (364 rails on an
M5 Max) and prints each channel's name, unit and delta. What it establishes:
GPU Energy is live in nJ, every CPU Energy / MCPU* / PACC* /
*_SRAM rail is frozen for an unprivileged reader, and ANE0 is the only ANE
channel — no ANE Energy aggregate, no sub-rails. Units differ within one
sample, so a summer that assumes one unit is wrong.
gpu_rail_period.py / gpu_rail_idle_tail.py — when the GPU rail republishes
The GPU Energy rail has no fixed period. It republishes when there is
activity to report and holds its value when there is not, so the number you
measure depends entirely on which condition you measure in.
Sampling every 2 ms on an M5 Max, macOS 27, the gap between actual changes:
| condition | p50 | p90 | p95 | p99 | max | n |
|---|---|---|---|---|---|---|
| sustained MLX matmul | 13.1 ms | 15.0 ms | — | — | 42.0 ms | 435 |
| idle, 6 s | 12.7 ms | 91.0 ms | — | — | 992.2 ms | 112 |
| idle, 90 s | 13.1 ms | 30.6 ms | 86.2 ms | 436.2 ms | 2032.8 ms | 2936 |
Three things follow, and the third is why the long run exists.
Under sustained load the rail is tight; the long tail is an idle property. That is the opposite of the intuitive reading, and it reconciles an earlier fleet observation that put the hold at "300–600 ms under load": the GGUF decode it came from is dispatch-latency-bound with idle gaps between tokens, so it was sampling idle behaviour. 300–600 ms is about the idle p98–p99 here, consistent with having seen that region and not past it.
A declared period has to be the idle worst case. A measurer cannot
guarantee the fabric stays busy, and a span landing entirely inside one hold
reads zero — which a naive grader would report as a measurement of zero.
jcp-energy declares 1 s for this rail on that basis.
The sample max is not a bound. The 6 s run gave a max of 992.2 ms, which sits just inside a 1 s timeout and invites the conclusion that 1 s is enough. Over 90 s the same host produced three gaps past 1000 ms — 1446, 1919 and 2033 ms — so roughly 1 idle gap in 1000 exceeds a one-second wait, and the worst was 2× it. Any code that waits a bounded time for this rail to republish should bound above ~2.5 s, or treat the timeout as a counted outcome rather than a rare surprise.