Skip to content

Metal: platform-aware expert-cache defaults via honest storage probe (#379) - #386

Merged
JustVugg merged 14 commits into
JustVugg:devfrom
monotophic:defaults/metal-cache
Jul 31, 2026
Merged

Metal: platform-aware expert-cache defaults via honest storage probe (#379)#386
JustVugg merged 14 commits into
JustVugg:devfrom
monotophic:defaults/metal-cache

Conversation

@monotophic

Copy link
Copy Markdown
Contributor

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic

Problem

On Apple Silicon (Metal backend, unified memory, fast NVMe), colibri's stock
defaults leave a large performance win on the table. Measured campaign
(issue #379, M5 Max 128 GB):

config tok/s
stock defaults 0.4
tuned (MTP=0 CAP_RAISE=0 --ram 90 --cap 1) ~2.0

Scope caveat, to prevent over-reading: the tuned row is a four-knob
configuration. This PR changes the defaults of exactly two of those knobs
(cap, CAP_RAISE); MTP and RAM sizing remain manual and out of scope. Stock
Metal runs with these defaults should therefore land somewhere between 0.4
and 2.0 tok/s
, not at 2.0 β€” this PR is a partial capture of the measured
configuration, and how much of the 5x the two cache knobs alone recover is
exactly what the on-box validation run (below) will measure.

Issues #180 (M3 Ultra) and #107 (M4 Pro) corroborate the same shape on other
Apple Silicon boxes. As the maintainer noted in #379: no one maintaining this
repo has Metal hardware, and this PR was explicitly invited from the field.

Mechanism (#379)

Metal's per-buffer residency cost makes the engine's own expert LRU cache
anti-productive on fast NVMe. The OS page cache already streams cold
experts back in cheaper than Metal can re-pin them into GPU-visible buffers,
so a large expert cache just adds residency churn on top of I/O that was
already going to happen. On this class of hardware, a minimal cache (so the
engine gets out of the page cache's way) beats a large one.

Whether a volume is "fast" has to be measured, not assumed: buffered
reads lie (page-cache hits read 23-97 GB/s on the reference box; a real
F_NOCACHE read measured 14 GB/s on the same file). That's why this PR adds
an honest storage probe rather than just flipping the default unconditionally
on every Metal build.

Design

S1 -- honest storage probe (glm.c, coli_ssd_probe_raw/coli_ssd_probe_cached)
C-side, in the engine's own startup path, so it covers glm direct users and
the coli wrapper alike -- Python-only logic would miss direct users.
Mirrors compat_open_direct()/iobench.c's existing __APPLE__ branch: open
a real model shard (readdir order -- any shard is representative for a
bandwidth probe), fcntl(F_NOCACHE,1), disable readahead, random 16K-aligned
pread, single thread, ~0.35s wall-clock budget. The result is cached in
<model>/.coli_ssd (plain-text GB/s) so every startup after the first reads
a file instead of re-probing; a missing or unparsable cache file just
re-probes. The cache write is atomic (tmp+rename, the same model-dir
convention as stats_dump_q); if two engines race on a virgin dir (e.g. a
concurrent serve + run pair), both probe under mutual contention and may
cache a low reading -- the safe direction (defaults simply stay historic);
delete .coli_ssd to re-measure, and an unparsable file re-probes
automatically on the next start.

S2 -- platform-aware cache defaults (glm.c, coli, openai_server.py)
When g_metal_enabled && darwin && probe-fast:

  • expert LRU cap defaults to 1/layer.
  • CAP_RAISE defaults to 0 (previously 1) -- raising the cache back up
    under a generous RAM budget is the same anti-pattern the cap default exists
    to avoid.

MTP, RAM sizing, and autopin are untouched -- out of scope for this PR.

Precedence (coli_resolve_cap(), pure function, unit-tested in isolation):

tier cap CAP_RAISE
1 (highest) explicit --cap N CLI --
2 explicit CAP env explicit CAP_RAISE env
3 platform default (Metal + darwin + fast SSD) -> 1 platform default (same condition) -> 0, independently of how cap was set -- see note
4 (lowest) historic default: 8 via the coli wrapper ("0 = auto" sentinel), 64 for a bare ./glm with no positional argument historic default -> 1

An explicit setting is never overridden by the probe, at any tier.

Note on the cap/CAP_RAISE coupling (deliberate): on a qualifying box, an
explicit --cap 16 does not re-enable auto-raise -- CAP_RAISE still
defaults to 0 there. Rationale: the Metal residency cost scales with cache
growth, so auto-raise is the same mechanism the minimal-cache default avoids;
a user who explicitly sizes the cache gets exactly that size. Explicit
CAP_RAISE=1 re-enables auto-raise.

S3 -- the one-line notice (glm.c, stderr, alongside the existing config banner)
Printed only when the platform cap default actually engages:

METAL: fast SSD (X.X GB/s) β€” page cache favored, expert cache minimal (cap 1); override with --cap

Silent when the probe ran but storage was slow -- defaults stay at their
historic values with no extra output.

S4 -- doctor/plan surfacing (doctor.py, resource_plan.py)
coli doctor and coli plan read <model>/.coli_ssd if present and display
it. Read-and-display only: neither command re-measures or guesses. A new
storage.ssd_probe doctor check reports "pass" with the cached GB/s, or
"skip" before the first Metal+darwin startup.

What's explicitly out of scope

  • MTP, RAM sizing (--ram), autopin -- their defaults are untouched (and are
    the other half of the measured 5x; see the scope caveat at the top).
  • Routing, CACHE_ROUTE, sampling -- nothing here can change a generated
    token. Cache sizing is a pure performance knob: it changes how often an
    expert is re-read from disk, never which expert gets computed for a given
    token.
  • Non-Metal, non-darwin, or slow-storage runs: the probe never engages
    (g_metal_enabled stays 0, or the measured GB/s is under the threshold,
    default 4.0 GB/s, COLI_SSD_FAST_GBS to override), and every invocation
    resolves byte-identically to today -- including the bare ./glm fallback
    of 64.

Behavioral disclosures (small, but stated plainly)

  1. --cap 0 / CAP=0 now mean "auto" on every platform, not just Metal.
    This is the sentinel that lets the wrapper say "not explicitly set."
    Previously a literal cap=0 was accepted and produced a working zero-slot,
    always-cold-load cache mode; that mode was undocumented and unused
    repo-wide (no test, tool, doc, or wrapper passes 0). Anyone who somehow
    relied on it can get the nearest supported equivalent with --cap 1.
  2. coli's --cap argparse default changed from 8 to 0 (auto).
    Without this, coli always forced an explicit 8 onto the engine command
    line, which (per the precedence table) would have permanently shadowed the
    platform default for every wrapped invocation. openai_server.py's
    --cap flag and its internal Engine/serve() defaults got the same
    sentinel so programmatic callers don't silently bypass auto.
  3. The benchmark harness (tools/eval_glm.py) keeps its fixed --cap 64
    deliberately -- benchmarks need a reproducible cache size, not a
    platform-dependent auto (commented in the source).

Durable vs. current-state (a review map)

Two kinds of change ship here, and they age differently:

Durable machinery -- the F_NOCACHE probe and .coli_ssd cache, the
coli_resolve_cap() precedence chain and cap sentinel, the notice
mechanism, and the doctor/plan surfacing. None of these encode an opinion
about how big the cache should be; they survive any change in residency
economics.

Current-state calibration -- the qualifying-platform values: cap 1
and CAP_RAISE 0. These encode today's measured economics (per-buffer
Metal residency cost makes a growing expert cache anti-productive, #379)
and are deliberately concentrated so that revisiting them is a two-constant
edit. "Today" is a checkable coordinate, not rhetoric: measured 2026-07 on
macOS 26.5 (M5 Max, 128 GB) against engine base caa49f7 (dev)
-- the
in-code marker comments carry the same stamp. A reader far from those
coordinates (newer macOS Metal runtime, or an engine that has absorbed the
#379 residency work) should treat the constants as suspect and re-run the
#379 A/B (cap 1 vs cap 16, hit rate vs tok/s) before trusting them. Two
foreseeable developments would flip them:

  1. The residency-mechanism work in Metal β€” growing the expert cache makes decode SLOWERΒ #379 itself. The MTLHeap experiment
    already flips the sign of caching on the reference box (cap16 ~ +5% over
    cap1 with heap-backed slabs); a follow-up PR is planned from the same
    investigation. If it lands, the right qualifying default likely becomes a
    larger, RAM-scaled cap -- not 1.
  2. Metal's move toward first-class tensor objects (MTLTensor and
    runtime-managed residency in current and upcoming macOS releases). If
    expert storage migrates there, the per-buffer registration cost -- the
    entire reason cap 1 wins today -- changes wholesale.

In both cases the edit is confined to the platform-default branch of
coli_resolve_cap() and the single CAP_RAISE default expression (both
carry a marker comment in the code); probe, precedence, notice, and
surfacing are unaffected. The COLI_SSD_FAST_GBS threshold (4.0) is
likewise a current-economics number, with the env override as escape hatch.

Testing

Author-side testing was parse-level and unit-level only -- no model was
loaded and no inference was run
:

  • tests/test_cap_precedence.c -- exhaustive precedence-table coverage of
    coli_resolve_cap(), including bare-invocation vs wrapper-sentinel vs
    explicit CLI/env on fast and slow platforms. Portable (no Metal/Apple
    hardware required), part of the default make test-c gate.
  • tests/test_resource_plan.py / tests/test_doctor.py -- cache-file
    parsing (read_ssd_probe: missing, empty, malformed, negative, valid) and
    the doctor/plan surfacing contract.
  • make glm METAL=1 and plain make glm both compile clean
    (-Wall -Wextra); full make test-c + python unittest suites pass.
  • Startup-path smoke tests against a scratch directory containing only a
    dummy *.safetensors file (no config.json, so every run exits before
    model_init -- deliberately): notice printed + cap=1 on a fast volume;
    .coli_ssd written once (atomically) and reused on the next start;
    --cap 16 / CAP=4 override silently; forced-slow threshold and
    non-Metal builds stay silent at historic defaults; corrupted .coli_ssd
    re-probes; bare ./glm still resolves cap 64.

On-box validation (performed 2026-07-18): M5 Max 128 GB, macOS 26.5.2,
real GLM-5.2 int4 model, engine at this branch's HEAD (base caa49f7,
dev).
Three-run block, fixed prompt,
temp 0, 32 decoded tokens each:

  1. Stock defaults (no cache flags, no env): notice printed
    (METAL: fast SSD (9.7 GB/s) -- page cache favored, expert cache minimal (cap 1); override with --cap), cap resolved to 1, .coli_ssd written
    once. Decode 1.48 tok/s vs 0.4 at the old defaults -- the two cache
    knobs alone recover roughly 3.7x of the measured 5x (MTP and RAM sizing
    remain manual, as scoped above).
  2. Explicit --cap 16: silent (no notice), cap honored at 16/layer,
    .coli_ssd untouched. Decode 0.86 tok/s despite the hit rate rising
    24% -> 50% -- a same-session replication of the Metal β€” growing the expert cache makes decode SLOWERΒ #379 mechanism this PR
    encodes: growing the Metal-registered cache makes decode slower even as
    it hits more.
  3. Restart, stock again: cached probe reused (.coli_ssd mtime unchanged,
    same 9.7 GB/s in the notice), cap=1 again, decode 1.49 tok/s
    replicating run 1; temp-0 output text identical across the two stock runs.

@JustVugg

Copy link
Copy Markdown
Owner

Heads-up: c/glm.c was just split into c/colibri.c + header modules (#391, now merged into dev). This PR touches the old glm.c, so it will need a rebase onto current dev with its changes moved into colibri.c (or the relevant extracted header: quant.h, sample.h, kv_persist.h, telemetry.h, grammar.h). The make glm target still works (alias of make colibri), so no build scripts break. Apologies for the churn β€” ping me if the rebase gets thorny and I can help place the hunks.

@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic

Rebase after #391

This PR was rebased (relocation-only, no behavior change) from engine base
caa49f7 onto dev @ 61004dc, after upstream PR #391 split c/glm.c into
c/colibri.c + four extracted header modules (quant.h, sample.h,
kv_persist.h, telemetry.h). Everything this PR touches -- the F_NOCACHE
probe, coli_resolve_cap(), the cap/CAP_RAISE wiring in main(), and
cap_for_ram()'s conditional auto-raise -- lives in code that #391 kept in
colibri.c itself; none of it landed in an extracted header. git range-diff caa49f7..f3a7fb9 61004dc..HEAD confirms the only tree-level changes are the
file rename (glm.c β†’ colibri.c in diff hunk headers) and updating this
PR's own stray glm.c filename references to colibri.c: a Makefile
prerequisite list (which also gained the four split-out headers --
quant.h sample.h kv_persist.h telemetry.h -- mirroring the sibling
test_dsa_select target's own convention post-#391, not just a filename
swap), a test's #include, and doc-comment mentions of "where this lives".
The two commit titles had the same stray reference (glm.c: honest F_NOCACHE... and glm.c/coli/openai_server.py: platform-aware...) and have
likewise been reworded to colibri.c: ... / colibri.c/coli/openai_server.py: ... -- message-only, trees unchanged. make glm is still a working alias
for make colibri (unaffected by this PR either way). Below, every glm.c
reference in the Design section has been updated to colibri.c to match;
the on-box validation numbers in Testing predate the rebase (measured
against caa49f7) and will be re-verified against 61004dc by the
orchestrator separately -- no model was run as part of this rebase.

Problem

On Apple Silicon (Metal backend, unified memory, fast NVMe), colibri's stock
defaults leave a large performance win on the table. Measured campaign
(issue #379, M5 Max 128 GB):

config tok/s
stock defaults 0.4
tuned (MTP=0 CAP_RAISE=0 --ram 90 --cap 1) ~2.0

Scope caveat, to prevent over-reading: the tuned row is a four-knob
configuration. This PR changes the defaults of exactly two of those knobs
(cap, CAP_RAISE); MTP and RAM sizing remain manual and out of scope. Stock
Metal runs with these defaults should therefore land somewhere between 0.4
and 2.0 tok/s
, not at 2.0 β€” this PR is a partial capture of the measured
configuration, and how much of the 5x the two cache knobs alone recover is
exactly what the on-box validation run (below) will measure.

Issues #180 (M3 Ultra) and #107 (M4 Pro) corroborate the same shape on other
Apple Silicon boxes. As the maintainer noted in #379: no one maintaining this
repo has Metal hardware, and this PR was explicitly invited from the field.

Mechanism (#379)

Metal's per-buffer residency cost makes the engine's own expert LRU cache
anti-productive on fast NVMe. The OS page cache already streams cold
experts back in cheaper than Metal can re-pin them into GPU-visible buffers,
so a large expert cache just adds residency churn on top of I/O that was
already going to happen. On this class of hardware, a minimal cache (so the
engine gets out of the page cache's way) beats a large one.

Whether a volume is "fast" has to be measured, not assumed: buffered
reads lie (page-cache hits read 23-97 GB/s on the reference box; a real
F_NOCACHE read measured 14 GB/s on the same file). That's why this PR adds
an honest storage probe rather than just flipping the default unconditionally
on every Metal build.

Design

S1 -- honest storage probe (colibri.c, coli_ssd_probe_raw/coli_ssd_probe_cached)
C-side, in the engine's own startup path, so it covers glm direct users and
the coli wrapper alike -- Python-only logic would miss direct users.
Mirrors compat_open_direct()/iobench.c's existing __APPLE__ branch: open
a real model shard (readdir order -- any shard is representative for a
bandwidth probe), fcntl(F_NOCACHE,1), disable readahead, random 16K-aligned
pread, single thread, ~0.35s wall-clock budget. The result is cached in
<model>/.coli_ssd (plain-text GB/s) so every startup after the first reads
a file instead of re-probing; a missing or unparsable cache file just
re-probes. The cache write is atomic (tmp+rename, the same model-dir
convention as stats_dump_q); if two engines race on a virgin dir (e.g. a
concurrent serve + run pair), both probe under mutual contention and may
cache a low reading -- the safe direction (defaults simply stay historic);
delete .coli_ssd to re-measure, and an unparsable file re-probes
automatically on the next start.

S2 -- platform-aware cache defaults (colibri.c, coli, openai_server.py)
When g_metal_enabled && darwin && probe-fast:

  • expert LRU cap defaults to 1/layer.
  • CAP_RAISE defaults to 0 (previously 1) -- raising the cache back up
    under a generous RAM budget is the same anti-pattern the cap default exists
    to avoid.

MTP, RAM sizing, and autopin are untouched -- out of scope for this PR.

Precedence (coli_resolve_cap(), pure function, unit-tested in isolation):

tier cap CAP_RAISE
1 (highest) explicit --cap N CLI --
2 explicit CAP env explicit CAP_RAISE env
3 platform default (Metal + darwin + fast SSD) -> 1 platform default (same condition) -> 0, independently of how cap was set -- see note
4 (lowest) historic default: 8 via the coli wrapper ("0 = auto" sentinel), 64 for a bare ./glm with no positional argument historic default -> 1

An explicit setting is never overridden by the probe, at any tier.

Note on the cap/CAP_RAISE coupling (deliberate): on a qualifying box, an
explicit --cap 16 does not re-enable auto-raise -- CAP_RAISE still
defaults to 0 there. Rationale: the Metal residency cost scales with cache
growth, so auto-raise is the same mechanism the minimal-cache default avoids;
a user who explicitly sizes the cache gets exactly that size. Explicit
CAP_RAISE=1 re-enables auto-raise.

S3 -- the one-line notice (colibri.c, stderr, alongside the existing config banner)
Printed only when the platform cap default actually engages:

METAL: fast SSD (X.X GB/s) β€” page cache favored, expert cache minimal (cap 1); override with --cap

Silent when the probe ran but storage was slow -- defaults stay at their
historic values with no extra output.

S4 -- doctor/plan surfacing (doctor.py, resource_plan.py)
coli doctor and coli plan read <model>/.coli_ssd if present and display
it. Read-and-display only: neither command re-measures or guesses. A new
storage.ssd_probe doctor check reports "pass" with the cached GB/s, or
"skip" before the first Metal+darwin startup.

What's explicitly out of scope

  • MTP, RAM sizing (--ram), autopin -- their defaults are untouched (and are
    the other half of the measured 5x; see the scope caveat at the top).
  • Routing, CACHE_ROUTE, sampling -- nothing here can change a generated
    token. Cache sizing is a pure performance knob: it changes how often an
    expert is re-read from disk, never which expert gets computed for a given
    token.
  • Non-Metal, non-darwin, or slow-storage runs: the probe never engages
    (g_metal_enabled stays 0, or the measured GB/s is under the threshold,
    default 4.0 GB/s, COLI_SSD_FAST_GBS to override), and every invocation
    resolves byte-identically to today -- including the bare ./glm fallback
    of 64.

Behavioral disclosures (small, but stated plainly)

  1. --cap 0 / CAP=0 now mean "auto" on every platform, not just Metal.
    This is the sentinel that lets the wrapper say "not explicitly set."
    Previously a literal cap=0 was accepted and produced a working zero-slot,
    always-cold-load cache mode; that mode was undocumented and unused
    repo-wide (no test, tool, doc, or wrapper passes 0). Anyone who somehow
    relied on it can get the nearest supported equivalent with --cap 1.
  2. coli's --cap argparse default changed from 8 to 0 (auto).
    Without this, coli always forced an explicit 8 onto the engine command
    line, which (per the precedence table) would have permanently shadowed the
    platform default for every wrapped invocation. openai_server.py's
    --cap flag and its internal Engine/serve() defaults got the same
    sentinel so programmatic callers don't silently bypass auto.
  3. The benchmark harness (tools/eval_glm.py) keeps its fixed --cap 64
    deliberately -- benchmarks need a reproducible cache size, not a
    platform-dependent auto (commented in the source).

Durable vs. current-state (a review map)

Two kinds of change ship here, and they age differently:

Durable machinery -- the F_NOCACHE probe and .coli_ssd cache, the
coli_resolve_cap() precedence chain and cap sentinel, the notice
mechanism, and the doctor/plan surfacing. None of these encode an opinion
about how big the cache should be; they survive any change in residency
economics.

Current-state calibration -- the qualifying-platform values: cap 1
and CAP_RAISE 0. These encode today's measured economics (per-buffer
Metal residency cost makes a growing expert cache anti-productive, #379)
and are deliberately concentrated so that revisiting them is a two-constant
edit. "Today" is a checkable coordinate, not rhetoric: current engine-base
coordinate: 61004dc (dev); the underlying cap-1-vs-cap-16 measurement
itself is unchanged -- taken 2026-07 on macOS 26.5, M5 Max, 128 GB, engine
base caa49f7 -- not redone as part of this rebase.
The in-code marker
comments still carry that original caa49f7 stamp, untouched (per the
relocation-only rebase: only this document's coordinate label moves to the
new base). A reader far from those coordinates (newer macOS Metal runtime,
or an engine that has
absorbed the #379 residency work) should treat the constants as suspect and
re-run the #379 A/B (cap 1 vs cap 16, hit rate vs tok/s) before trusting
them. Two foreseeable developments would flip them:

  1. The residency-mechanism work in Metal β€” growing the expert cache makes decode SLOWERΒ #379 itself. The MTLHeap experiment
    already flips the sign of caching on the reference box (cap16 ~ +5% over
    cap1 with heap-backed slabs); a follow-up PR is planned from the same
    investigation. If it lands, the right qualifying default likely becomes a
    larger, RAM-scaled cap -- not 1.
  2. Metal's move toward first-class tensor objects (MTLTensor and
    runtime-managed residency in current and upcoming macOS releases). If
    expert storage migrates there, the per-buffer registration cost -- the
    entire reason cap 1 wins today -- changes wholesale.

In both cases the edit is confined to the platform-default branch of
coli_resolve_cap() and the single CAP_RAISE default expression (both
carry a marker comment in the code); probe, precedence, notice, and
surfacing are unaffected. The COLI_SSD_FAST_GBS threshold (4.0) is
likewise a current-economics number, with the env override as escape hatch.

Testing

Author-side testing was parse-level and unit-level only -- no model was
loaded and no inference was run
:

  • tests/test_cap_precedence.c -- exhaustive precedence-table coverage of
    coli_resolve_cap(), including bare-invocation vs wrapper-sentinel vs
    explicit CLI/env on fast and slow platforms. Portable (no Metal/Apple
    hardware required), part of the default make test-c gate.
  • tests/test_resource_plan.py / tests/test_doctor.py -- cache-file
    parsing (read_ssd_probe: missing, empty, malformed, negative, valid) and
    the doctor/plan surfacing contract.
  • make glm METAL=1 and plain make glm both compile clean
    (-Wall -Wextra); full make test-c + python unittest suites pass.
  • Startup-path smoke tests against a scratch directory containing only a
    dummy *.safetensors file (no config.json, so every run exits before
    model_init -- deliberately): notice printed + cap=1 on a fast volume;
    .coli_ssd written once (atomically) and reused on the next start;
    --cap 16 / CAP=4 override silently; forced-slow threshold and
    non-Metal builds stay silent at historic defaults; corrupted .coli_ssd
    re-probes; bare ./glm still resolves cap 64.

Post-rebase gates (performed against dev @ 61004dc, this branch's HEAD):
make glm METAL=1 and make glm METAL=0 both build clean, zero warnings
(-Wall -Wextra, matched against a zero-warning stock 61004dc build --
zero new warnings either way); make check (portable build + full C test
suite, 18 binaries including test_cap_precedence + full Python
unittest discover, 86 tests) passes, exit 0. test_cap_precedence was
spot-checked for vacuous-pass risk by temporarily neutering the
platform_fast branch in coli_resolve_cap(): the mutation produced 3 real
test failures (reverted immediately after). No model was run (no coli run/
coli serve) as part of this rebase, per the rebase task's constraints.

On-box validation (performed 2026-07-18, predates this rebase): M5 Max 128
GB, macOS 26.5.2, real GLM-5.2 int4 model, engine at this branch's
pre-rebase HEAD (base caa49f7, dev).
Three-run block, fixed prompt,
temp 0, 32 decoded tokens each:

  1. Stock defaults (no cache flags, no env): notice printed
    (METAL: fast SSD (9.7 GB/s) -- page cache favored, expert cache minimal (cap 1); override with --cap), cap resolved to 1, .coli_ssd written
    once. Decode 1.48 tok/s vs 0.4 at the old defaults -- the two cache
    knobs alone recover roughly 3.7x of the measured 5x (MTP and RAM sizing
    remain manual, as scoped above).
  2. Explicit --cap 16: silent (no notice), cap honored at 16/layer,
    .coli_ssd untouched. Decode 0.86 tok/s despite the hit rate rising
    24% -> 50% -- a same-session replication of the Metal β€” growing the expert cache makes decode SLOWERΒ #379 mechanism this PR
    encodes: growing the Metal-registered cache makes decode slower even as
    it hits more.
  3. Restart, stock again: cached probe reused (.coli_ssd mtime unchanged,
    same 9.7 GB/s in the notice), cap=1 again, decode 1.49 tok/s
    replicating run 1; temp-0 output text identical across the two stock runs.

These numbers predate the rebase onto 61004dc and will be re-verified
on-box against the rebased branch by the orchestrator separately -- this
rebase performed no model runs.

Post-rebase on-box verification (2026-07-19, M5 Max 128 GB, macOS 26.5, base 61004dc)

Smoke on the rebased branch (0822b18), METAL=1, GLM-5.2 int4, run via this
branch's own coli wrapper:

  • Stock (no cap given): F_NOCACHE probe ran and cached to <model>/.coli_ssd
    (9.98 GB/s), notice fired verbatim: METAL: fast SSD (10.0 GB/s) β€” page cache favored, expert cache minimal (cap 1); override with --cap; cap resolved to 1
    ([RAM_GB=90.0] cap=1 ok).
  • --cap 16: silent (no notice), honored (cap=16 ok).
  • Explicit-wrapper tier (incidental but real): driving this branch's engine
    through a pre-Metal: platform-aware expert-cache defaults via honest storage probe (#379)Β #386 coli wrapper β€” which injects its historic explicit --cap 8 β€”
    yields silent cap=8: tier-1 explicit-wins precedence verified end-to-end.
  • Usage-file snapshot/restore md5-verified around every run.

@monotophic monotophic changed the title Metal: platform-aware expert-cache defaults via honest storage probe (#379) Metal: platform-aware expert-cache defaults via honest storage probe (#379) now based to dev @ 61004dc Jul 19, 2026
@JustVugg

Copy link
Copy Markdown
Owner

Rebase needed: this went stale against dev after today's merges (#298 reworked scale plumbing; #192 touched the engine). Your Metal storage-probe logic itself shouldn't need changes β€” likely just contextual conflicts in colibri.c. If you'd rather I do the mechanical rebase, say so and I'll push it to your branch (maintainer edits are enabled); otherwise all yours.

@monotophic
monotophic force-pushed the defaults/metal-cache branch from 0822b18 to 57b0b76 Compare July 20, 2026 20:36
@monotophic monotophic changed the title Metal: platform-aware expert-cache defaults via honest storage probe (#379) now based to dev @ 61004dc Metal: platform-aware expert-cache defaults via honest storage probe (#379) now based to dev @ 68ac9ff Jul 20, 2026
@monotophic

Copy link
Copy Markdown
Contributor Author

Re-based to dev 68ac9ff and verified clean at my end.

@JustVugg

Copy link
Copy Markdown
Owner

Rebase heads-up: dev is green and moved (Metal PRs #426/#447 among others landed). Please rebase on current dev, then β€” since this changes the storage-probe cache defaults β€” a quick before/after tok/s on Apple Silicon confirming the new defaults don't regress the small-cache case (the #379 symptom). CI green + that measurement and I merge. Thanks @monotophic.

@monotophic
monotophic force-pushed the defaults/metal-cache branch from 57b0b76 to 758ceb2 Compare July 22, 2026 02:35
@monotophic

Copy link
Copy Markdown
Contributor Author

Rebased, requested verification in my queue. Should be available and posted tonight or tomorrow AM. Machine is pretty tied up and hot at the moment.

@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic.

Rebase: head 758ceb2 on dev @ 008ecc3. One conflict (both sides appended a
test binary to TEST_BINS β€” resolved as the superset), everything else
patch-identical to the previously-reviewed content (git range-diff clean; the
CURRENT-STATE CALIBRATION markers and their measurement coordinates untouched).
Gates on the new base: build zero warnings, 22/22 C test binaries, 137 Python tests
OK, metal-test green with COLI_METAL_RESSET both off and on.

The before/after measurement (M5 Max 128 GB, macOS 26.5, plugged; interleaved
A/B/A/B with 100 s gaps, temp-0 fixed prompt, ngen 64, both arms at FULL STOCK
defaults β€” no env overrides, each arm using its own coli wrapper):

arm binary defaults chosen tok/s
A1 dev @ 008ecc3 stock 0.78
B1 this PR @ 758ceb2 platform tier β†’ cap=1 (notice fired, projected peak 60.3 GB) 1.73
A2 dev @ 008ecc3 stock 0.40
B2 this PR @ 758ceb2 platform tier β†’ cap=1 (projected peak 67.7 GB) 1.82

Two observations:

  1. No small-cache regression β€” the small-cache case IS the new default, and it wins
    2.2–4.5Γ—.
    The PR's platform tier selects cap=1 on this hardware; both branch
    arms sit stable within Β±2.5% of each other.
  2. The stock arms' own instability (0.78 β†’ 0.40 across two interleaved runs on a
    quiet machine) is the Metal β€” growing the expert cache makes decode SLOWERΒ #379 symptom class showing up live: with the historic cache
    defaults, Metal decode both underperforms and drifts as the run history warms the
    engine cache. The branch arms don't exhibit it.

Let me know if you have questions or if there is anything else I can do.

@monotophic monotophic changed the title Metal: platform-aware expert-cache defaults via honest storage probe (#379) now based to dev @ 68ac9ff Metal: platform-aware expert-cache defaults via honest storage probe (#379) Jul 22, 2026
@monotophic
monotophic force-pushed the defaults/metal-cache branch from 758ceb2 to 12c8209 Compare July 22, 2026 13:59
@monotophic

Copy link
Copy Markdown
Contributor Author

Rebased onto dev dce7012 to absorb the #509 test_temp_env TEST_BINS addition; range-diff patch-identical; gates re-run green both RESSET states.

@JustVugg

Copy link
Copy Markdown
Owner

This conflicts with dev now, and part of that is my doing β€” several PRs landed today that touch the same files (openai_server.py gained an Anthropic /v1/messages endpoint in #525 and an engine-path fix in #526; colibri.c changed in #532). Sorry for the churn.

The substance of this one β€” platform-aware Metal cache defaults driven by an honest storage probe rather than a guess β€” is something I want, and it's the same discipline as your fmt=7 proposal: measure, then decide, and refuse to pretend when the measurement isn't available. Rebase onto current dev and I'll review it properly.

One thing worth confirming while you're in there: #457 (your grouped-int4 Metal GEMV) and this PR both touch Metal defaults. If they interact β€” e.g. if fmt=4 support changes what a sensible default cache size is β€” say which should land first and I'll sequence them that way rather than discovering it at merge time.

@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic
(we/our = the joint work; me/my = @monotophic alone).

Rebased: r6, head 3e6c086 on dev @ f1b0f7e.

Same discipline as r4/r5: git range-diff shows commits 1 and 3
patch-identical to what you've already seen; commit 2 differs in exactly
one line β€” the serve() signature conflict you predicted, where our
cap=8 β†’ cap=0 change met #526's engine=None fix. The resolution keeps
both (cap=0, … engine=None); the cap=0 "engine resolves it" handling
below the signature is untouched. The CURRENT-STATE CALIBRATION markers
and their measurement coordinates (2026-07, macOS 26.5, M5 Max, base
commit stamp) are untouched β€” they date the measurement, not the rebase.

Gates on the new base (M5 Max, macOS 26.5):

  • METAL=1 build zero warnings; per-commit builds clean
  • make check: all C test binaries + 151 Python tests OK (10 platform
    skips; count includes this branch's own probe/cap-precedence tests)
  • metal-test ok under both COLI_METAL_RESSET states
  • behavior evidence (notice fires, probe caches to .coli_ssd, explicit
    --cap stays silent and honored, cached-probe reuse on restart) carries
    from the r4/r5 validation runs β€” the rebase is patch-identical at those
    code paths; happy to re-run the smoke on request

Sequencing: full four-PR order + reasoning is on #457 (short version:
#457 first, this second, #528 revised third, #529 stacked last). Your
interaction question is answered there in full β€” the one-line version:
no interaction; the cap-1 default is #379 residency economics,
format-independent, and its revisit trigger is the residency-set default
flip, not fmt=4 support.

@JustVugg

Copy link
Copy Markdown
Owner

This conflicts with dev now β€” several PRs landed today touching colibri.c/coli/openai_server.py. The substance (platform-aware Metal cache defaults from an honest storage probe) is something I want, same discipline as your fmt=7 work: measure, then decide. Rebase onto current dev and I'll review it. If it interacts with #457 (both touch Metal defaults), say which should land first and I'll sequence them.

@monotophic
monotophic force-pushed the defaults/metal-cache branch from 3e6c086 to b68cdf7 Compare July 23, 2026 19:09
@monotophic

Copy link
Copy Markdown
Contributor Author

Rebased and ready for review. Verification on b68cdf7: git range-diff against r6 shows commits 1 and 3 patch-identical; commit 2 differs only in the Makefile TEST_BINS line (the disclosed superset β€” dev's test_router_nan + this PR's test_cap_precedence). All three CURRENT-STATE CALIBRATION markers are present with their measurement coordinates intact (2026-07, macOS 26.5, M5 Max). Gates on this head: make check (full C suite including this PR's own test_cap_precedence, plus the Python suite with its probe/cap tests β€” 13 platform skips), METAL=1 build with zero warnings, and metal-test under both COLI_METAL_RESSET states. Behavior evidence (notice fires, probe caches to .coli_ssd, explicit --cap honored, cached-probe reuse) carries from the r4–r6 validation runs β€” the rebase is patch-identical at those code paths, and we'll re-run the smoke on request.

monotophic and others added 10 commits July 29, 2026 20:35
… S4)

`coli doctor` and `coli plan` now read <model>/.coli_ssd, if the
engine has already written it, and display the measured GB/s. Purely
read-and-display: never re-measures, never guesses, and shows nothing
before the first Metal+darwin engine startup.

resource_plan.read_ssd_probe() is the shared reader; build_plan()
threads it into plan["ssd_probe_gbs"] (None if not yet cached),
format_plan() adds one line when present, and doctor.run_doctor() adds
a storage.ssd_probe check ("pass" with the cached value, or "skip"
before the first probe / when the model itself is invalid).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… cache (JustVugg#379)

F_NOCACHE bypasses the page cache only for pages that are not already
resident: probing a warm shard measured 22.1 GB/s of RAM and cached it as
disk bandwidth, permanently latching the fast-SSD cap default on hardware
that never earned it. The probe now snapshots residency with mincore and
reads only 4 MB windows whose every page is cold; when the file offers
fewer than 64 MB of such windows the measurement is vetoed as contaminated
-- nothing is cached, one stderr line says why, and the probe retries on
the next (colder) startup.

The .coli_ssd cache gains a v2 format, "v2 <gbs> <st_dev>", under a strict
grammar (digits[.digits], 0 < gbs < 1000, no strtod permissiveness): a
cache is trusted only when it parses AND its st_dev matches the model
dir's current volume, so a dir rsync'd to another drive re-probes instead
of carrying the old hardware's number. Legacy bare-number caches (possibly
warm-contaminated) re-probe once and upgrade. The cache write goes through
mkstemp+rename: unique name, so a pre-planted symlink at a predictable
temp path can no longer redirect it.

The decision layer (grammar parser, cold-tile steering, veto) is pure C,
pinned by tests/test_ssd_probe.c over injected residency vectors and the
shared grammar-vector file (tests/fixtures/ssd_cache_vectors.txt, chewed
by the Python reader's tests too). The probe block now compiles only for
its consumer (COLI_METAL on __APPLE__, or the test define), removing the
default build's coli_ssd_probe_cached orphan.
…ustVugg#379)

The Python reader mirrors the engine's new strict .coli_ssd contract
byte-for-byte: parse_ssd_cache() classifies raw bytes under exactly the
grammar colibri.c's coli_ssd_cache_parse() accepts (both suites consume
the same vector file, tests/fixtures/ssd_cache_vectors.txt, so the two
readers cannot drift), and read_ssd_probe() surfaces a value only when a
v2 cache's recorded st_dev still matches the model dir's volume. A legacy
bare number (possibly measured through a warm page cache) or a cache
rsync'd to another drive is one the engine will re-measure -- showing it
in doctor/plan would report a number the engine no longer believes.

float() permissiveness is gone with it: "inf" used to sail through and
reach doctor's JSON as the bare literal Infinity, which json.loads
rejects; the new doctor test pins that a corrupt cache can never break
machine consumers of --json again.
…nes (JustVugg#379)

The 0=auto cap sentinel is a colibri.c contract: coli_resolve_cap resolves
it platform-aware. inkling.c reads the same argv as "fit the expert LRU to
all available RAM" (cap <= 0), so forwarding the wrapper's 0 default to a
non-glm engine silently changed its memory behavior from the 8 slots coli
always forced before. cap_for_engine() now translates at the one funnel
every launch passes through -- Engine's argv -- keyed on the engine
binary's identity (COLI_ENGINE can route any arch to the glm binary, and
it is the binary that interprets the argv): a non-glm engine receives the
legacy 8 when the user gave no explicit cap, an explicit --cap N passes
through to any engine, and glm keeps the 0 sentinel.

This shim is CURRENT-STATE CALIBRATION, not durable core: it internalizes
an inconsistency that lives across the engines (0 = platform-auto in
colibri.c, RAM-auto in inkling.c, historically forced 8 in coli). If cap
sentinel semantics are ever unified across engines, remove it and
re-derive.

coli chat's local-server path now also forwards --cap, which it previously
dropped on the floor for non-glm models.
…ustVugg#379)

Document what a user meets when the F_NOCACHE storage probe leaves its
cache in the model dir: the cold-range steering and the contamination
veto (why a warm start can print a deferred-probe line), the strict
one-line v2 format both readers share, the st_dev volume-identity rule
(rsync the dir to another drive and the engine re-probes instead of
inheriting the old number), the one-time legacy upgrade, and that the
probe measures the primary model dir only under split/mirror layouts.
…st shard (JustVugg#379)

A sparse or still-downloading shard defeats the cold-range steering from
the other side: its never-resident pages are HOLES, and pread of a hole is
VFS zero-fill at RAM speed -- a 10 GB shard with 100 MB of real data
measured 73 GB/s through the whole probe path and latched it as disk
bandwidth, a fast-lie that survives the download completing. st_blocks*512
must now cover st_size within 12.5% slack before anything is read; an
under-allocated shard is contaminated-class -- nothing cached, honest
stderr, re-checked next start. Same conservative polarity as the
residency veto.

The deferral line names the condition that actually fired: not-fully-
allocated (finish the download), under-64MB-of-windows (this shard can
never host a trustworthy probe -- previously a fully-cold 30 MB shard was
told it was "page-cache resident" forever), or genuinely resident (wait
for a cold start). The shard picker takes the LARGEST .safetensors
instead of readdir-first, so a stray small shard cannot starve the probe
below the floor while a full-size neighbor sits untouched.

Also: an implausible measurement (0, >=1000 GB/s, non-finite -- numbers
the cache grammar itself refuses) no longer counts as fast for the
current run; a cache-write failure (read-only model dir) gets one stderr
diagnostic instead of silence; the cache file honors the umask instead of
forcing 0644; and the tile modulo is explicitly guarded against
ntiles==0 rather than relying on the floor to imply it.

test_ssd_probe.c grows the matching arms, including a pread recorder
that pins the steering INTO probe_raw: a probe that computes tiles[] and
then reads random offsets anyway now fails 113 assertions instead of
zero.
…eans absent (JustVugg#379)

Basename keying broke both ways. COLI_ENGINE users package the glm engine
under arbitrary names (glm52, colibri-1.2, glm-metal) -- every one of them
was handed the legacy 8 as if explicit, silently disabling the JustVugg#379
platform-auto for exactly the custom-packaging users COLI_ENGINE exists
for; and an inkling binary someone names glm got the 0 sentinel back, the
leak the shim exists to stop. cap_for_arch() now keys on the MODEL's
config.json model_type, end-to-end the same rule coli's model_arch uses
(openai_server's main() now shares the helper instead of duplicating it).

The sentinel itself becomes honest: --cap defaults to None (flag absent)
in both coli and openai_server, and Engine's cap parameter follows.
Absent -> glm arch gets the 0 sentinel to resolve platform-aware, non-glm
gets the legacy 8. An EXPLICIT --cap N passes through verbatim to any
engine for ALL N -- including --cap 0, which for inkling means upstream's
RAM-auto again: people who ask for upstream semantics get them. The glm
direct-spawn paths (run, chat) translate None to the 0 sentinel at the
argv.

CapSentinelShimTest now walks the full matrix (arch x arbitrary engine
name x cap absent/5/0) against real temp model dirs, and coli chat's
--cap ride-along -- kept deliberately; the historical silent eating was
the bug, and this is a disclosed behavior change -- gets its own test
driving the real cmd_chat with the process boundary faked.
… yet" (JustVugg#379)

"no cached probe yet" was a lie whenever a .coli_ssd file sat right
there: a legacy cache now reads "legacy cache pending engine upgrade",
a v2 from another volume "cache from another volume; the engine will
re-probe here", an unparsable file "unreadable cache". ssd_probe_state()
classifies (ok / legacy / foreign / garbage / absent), read_ssd_probe()
stays the trusted-value view on top of it, the plan carries the state
alongside the gbs, and doctor + format_plan share one wording table.

The reader is also bounded now: 65 bytes read instead of the whole file
-- the strict grammar caps a well-formed cache at 64 bytes, so byte 65
alone already convicts an impostor file of any size.
…asons (JustVugg#379)

st_dev can be recycled across sequentially attached external volumes
(demonstrated on macOS), so a carried cache can be wrongly trusted on a
different drive that inherits the old device id -- say so plainly, with
the delete-the-file remedy, and name volume-UUID identity as the
follow-up. The veto bullet gains the two new refusal conditions
(under-allocated shard, shard too small for 64 MB of windows) and the
largest-shard selection.
…'s precondition (JustVugg#379)

Two validator-reported gaps, tests only. The picker had no pin: reverting
it to readdir-first-match slipped the whole suite. A dir with a below-
floor shard alongside a full-size one now asserts pick_shard returns the
largest AND that the probe measures where a first-match picker vetoes
SMALL. And the sparse e2e arm's skip-precondition called the very gate
function under test, so mutating the gate self-disabled the arm; the
precondition now reads st_blocks raw from stat (fixture-specific bound:
under half allocated), independent of the code it guards -- a neutered
gate now fails all four e2e assertions plus the new sparse-beats-small
precedence pin (allocation is checked first: "finish the download" is
the actionable advice when both conditions hold).
@monotophic
monotophic force-pushed the defaults/metal-cache branch from 211cdf5 to 543a8e6 Compare July 30, 2026 04:12
…d vectors (JustVugg#379)

The new python tests wrote their .coli_ssd fixtures through
Path.write_text, and on Windows text mode translates \n to \r\n -- the
strict reader then (correctly) classified every fixture as garbage: six
MinGW CI failures, zero on macOS/Linux. The reader and the grammar are
right; the fixtures were lying about their bytes. Every fixture write in
test_resource_plan.py and test_doctor.py is now write_bytes.

Today's lesson is pinned as explicit intent: the shared C/Python vector
file gains "v2 14.322 123\r\n" -> garbage, so both parsers stay honest
about \r forever (a reader loosened to strip it fails its vector suite
on every platform). For the same definitional cleanliness the C cache
read and the C-test fixture writers open in binary mode -- Apple-gated
today, but the format is exact bytes and a text-mode file API is a
latent CRLF source if the gate ever widens.
@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic

@JustVugg, this is rebased onto current dev (c9ab660) β€” and then our own review of the rebased code found real problems, so this push carries the rebase plus fixes. New head 0d15ba2 (10 commits: the 3 you reviewed, replayed, + 7 new). The delta is bigger than "rebase and notify" promised β€” here is exactly what changed and why, worst news first.

(If you saw a brief red Windows check on an earlier head 543a8e6: our new
python tests wrote .coli_ssd fixtures in text mode, and Windows CRLF
translation corrupted them β€” the strict parser rejected its own fixtures,
exactly as designed. Fixtures are byte-exact now and CRLF-rejection is pinned
as a shared C/Python grammar vector. Product code unchanged by that fix.)

What our review found (measured on the shipped binaries, not inferred)

  1. The F_NOCACHE probe measured RAM, not disk, whenever the shard was already
    page-cache resident
    β€” and a just-downloaded/converted model always is.
    Measured: a 100%-resident shard probed at 22.1 GB/s through F_NOCACHE
    (which stops cache population, not service from resident pages), latched
    .coli_ssd, and engaged the cap-1 default β€” permanently, on any media,
    because the cache had no invalidation. Verified-cold same-machine truth:
    8.9 GB/s.
  2. Sparse/partially-downloaded shards were worse: reading a hole is VFS
    zero-fill; a 10 GB shard with 100 MB of real data probed at 73 GB/s and
    latched it as disk bandwidth (this one we introduced ourselves in round 1 β€”
    cold-page steering prefers holes; caught by our own audit).
  3. The --cap default change leaked into the other engines. coli serve
    on an inkling-arch model passed the new 0 sentinel where it previously
    passed the forced default 8 β€” and inkling.c reads cap <= 0 as "auto:
    fit the LRU in available RAM". Measured at the launcher level (old coli β†’
    8, previous head β†’ 0). The PR's earlier claim that cap=0 was "unused
    repo-wide" was true for colibri.c and false for inkling.c; that was our
    error.

What the fixes do (commits 4–9)

  • Probe trust model (colibri.c): reads are steered to verified-cold
    ranges (mincore); a measurement is REFUSED β€” nothing cached, one honest
    stderr line naming the actual reason, retry next start β€” when the shard is
    page-cache resident (<64 MB cold), under-allocated (st_blocks vs size:
    partial download), or too small. Untrustworthy β‡’ behave as slow: the
    conservative default, consistent with the existing race comment's polarity.
  • .coli_ssd v2: v2 <gbs> <st_dev> β€” re-probes on volume change, legacy
    bare numbers are re-measured and upgraded (this also flushes any contaminated
    caches already in the wild), and the C and Python readers accept exactly the
    same strict grammar (shared test vectors run in both suites; inf/hex/
    garbage can no longer reach doctor's JSON). Symlink-safe unique-temp
    writes; umask respected. st_dev identity is best-effort and documented as
    such (BSD device slots recycle across sequentially-attached externals;
    volume-UUID identity is a named follow-up).
  • Cap sentinel containment (coli/openai_server.py): the --cap default
    is now absent (None). Absent β†’ glm gets 0 (resolved platform-aware in
    colibri.c), non-glm engines get the historical 8 β€” keyed on model arch,
    so COLI_ENGINE custom binaries keep the right behavior regardless of
    filename. An explicit --cap N passes through verbatim to any engine for
    every N, including --cap 0 (which for inkling is upstream's own RAM-auto).

⚠ Engine-default inconsistency, internalized β€” please read

cap = 0 currently means three different things in this repo: platform-
aware auto in colibri.c (this PR), RAM-auto in inkling.c (pre-existing),
and "never happens, the launcher forces 8" (the historical de-facto contract
for non-glm engines). This PR preserves the historical behavior for non-glm
engines via a launcher shim
rather than silently switching inkling to
RAM-auto in a PR about GLM cache defaults.

That shim is a current-state calibration, not durable design (marked as
such in the code). Mooting trigger: if/when cap-sentinel semantics are
unified across engines, the shim must be removed and the translation
re-derived.
We would prefer that unification to exist; until it does, this
PR does not expand its own scope to impose one.

Disclosed behavior changes beyond the rebase

  • coli chat --cap N is now honored (it was silently ignored before β€” on
    dev as well as in earlier revisions of this PR). Anyone whose ignored
    --cap 32 becomes live may see different memory use; we think honoring the
    user's flag is correct, and it is disclosed here rather than discovered.
  • doctor/plan now say why a probe cache is pending ("legacy cache
    pending engine upgrade" / "cache from another volume") instead of a false
    "no cached probe yet".
  • Small-shard model dirs (largest shard < 64 MB) never latch a probe verdict
    (they get the conservative default with an honest message). Read-only model
    dirs re-probe each start (~0.35 s) and now say so once on stderr.

Verification (all on 0d15ba2, macOS 26.x / Apple M5 Max, 2026-07-30)

gate result
make check OK β€” 255 python tests (242 at base: +13 net), 13 skipped; all C bins incl. the new test_ssd_probe
behavioral battery (real binary, synthetic shards, mincore-verified states) resident β†’ refused+no-latch Β· cold β†’ measures (n=5: 8.88–8.98) + v2 + trusted on rerun Β· sparse β†’ refused before any read Β· volume move β†’ re-probe Β· legacy/inf/hex/negative/garbage β†’ never trusted, re-measured
launcher matrix (real coli serve, 18 cells) arch {glm,inkling,kimi} Γ— COLI_ENGINE variants Γ— {absent, --cap 5, --cap 0} β€” every cell as specified above
mutation coverage 25 distinct mutations across three independent reviews, 24 caught by the suite (the 25th was an equivalent mutant); includes reverting each fix to reproduce its measured failure (resident-latch 22.1, sparse-latch 65.9–75.9, sentinel leak)
builds METAL=1 zero warnings; per-commit builds clean across all 10; -Wunused-function census identical to c9ab660 baseline (the round-1 orphan we introduced was fixed in round 2)
metal-test ok under both COLI_METAL_RESSET states

Capstones, one per load-bearing claim: contamination (resident 22.1 vs cold
8.9, same file, same machine) Β· sparse (73 GB/s on 99%-holes) Β· sentinel leak
(launcher argv 8β†’0 A/B across the base commits) Β· fix efficacy (each
reverted fix fails its test loudly and reproduces the measured lie).

Notes and current-state calibrations (coordinates: 543a8e6, APFS/M5 Max)
  • The 4.0 GB/s threshold is UNCHANGED β€” we tested the hypothesis that cold
    M5 Max readings fall below it and REFUTED it (five verified-cold runs,
    8.88–8.98).
  • st_dev recycling and the 12.5 % allocation slack are measured on macOS/
    APFS; eagerly-allocating filesystems skip the sparse arm by construction.
  • Explicit --cap 0 passes to glm as positional 0, which remains glm's own
    auto sentinel (argv-level verbatim; pre-existing glm semantics).
  • A model dir with a broken/missing config.json defaults to arch=glm
    (pre-existing routing); the sentinel could then reach a manually-specified
    non-glm binary via COLI_ENGINE. Unreachable through coli's own routing.
  • Probe cost when no valid cache exists: one mincore pass (~17 ms/GB of
    shard) + ≀0.35 s of reads, first start only on healthy setups.

If the added scope is unwelcome in this PR, we can split commits 4–10 into a
follow-up PR and land the pure rebase first β€” but we did not want to hand over
a head containing defects we had already measured.

@monotophic

Copy link
Copy Markdown
Contributor Author

@JustVugg dude, that "needs rebase" tag is hurting my feelings ;) Thanks for all you are putting into this project! Yesterday's merges were huge. As of my circle back this PR is unconflicted and all green checks, ready to merge.

This package moved a little because we took a full pass at our (accumulating) validation process and found some issues that are now fixed. As stated in the rebase comment --cap=n behavior is not consistent across the engines and this is not sane/durable behavior. The engine-forks approach makes sense, but you need some infrastructure for enforcing interface-layer conformance so this doesn't just turn into goo (#700 gets this right for usage records; flag semantics need the same treatment).

I am ready to move forward with the MacOS CI and also have ideas for how to implement the engine interface-layer conformance verification (it would generalize the same mechanism as the test battery in this PR). Confirm and I will move forward with both or either.

Regards,
Chris

…the wildcard

Resolved by a maintainer rather than asking for an eleventh rebase, because the
conflict was caused by a merge made minutes earlier and the resolution deletes
work rather than adding any.

The only conflicting hunk was TEST_BINS. This branch appended
test_cap_precedence and test_ssd_probe to the hand-written list; dev (JustVugg#731) now
derives that list with a wildcard, specifically so that adding a test stops
conflicting with every other PR that adds a test. So the branch's append is
dropped: both tests are discovered automatically, and their build rules β€” which
merged cleanly, in a different part of the file β€” are untouched.

Verified: TEST_BINS goes from 29 to 31 entries, both new gates included;
`make test-c` passes; test_cap_precedence and test_ssd_probe both report ok.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
JustVugg added a commit to monotophic/colibri that referenced this pull request Jul 31, 2026
…nflicts

TEST_BINS was one long shared line listing 28 gates. Every PR that adds a test
appended to that same line, so any two such PRs conflicted in the Makefile by
construction β€” even when they touched entirely unrelated parts of the engine.

That is not a hypothetical. c/Makefile appears in 26 of the 40 currently open
PRs, and JustVugg#386 hit this specific conflict twice across its rebases:

    "One conflict (both sides appended a test binary to TEST_BINS)"

Adding a gate now means adding your tests/test_*.c and its own build rule, which
land in different places in the file. Nobody edits a line somebody else is also
editing.

TEST_EXCLUDE keeps the four test_*.c that were never default gates, plus
test_uring which is appended conditionally on Linux just below β€” a bare wildcard
would have promoted it to every platform.

Verified the derived set is byte-identical to the hand-written one (29 entries
including test_uring on Linux, same names), `make test-c` passes, and a freshly
created tests/test_*.c is picked up without touching this line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JustVugg
JustVugg merged commit 3bce2f0 into JustVugg:dev Jul 31, 2026
10 checks passed
@JustVugg

Copy link
Copy Markdown
Owner

Merged. Thirteen days and eleven rebases after you opened it β€” the last one being my fault twice over, so let me put on the record what happened rather than just thanking you.

I merged #731 an hour ago: it replaces the hand-written TEST_BINS line with a wildcard, precisely so that two PRs adding tests stop conflicting by construction. You are the contributor who hit that conflict twice while rebasing, and your comment is what sent me looking for it:

"One conflict (both sides appended a test binary to TEST_BINS)"

Then I merged that fix before this PR instead of after, and conflicted you an eleventh time β€” in the very file I had just changed to stop doing that. So I resolved it myself rather than asking you again. maintainerCanModify was on; I merged dev into your branch, dropped your TEST_BINS append (unnecessary now β€” test_cap_precedence and test_ssd_probe are discovered automatically), and left your two build rules alone, since they merged cleanly. Verified before pushing: 29 β†’ 31 gates with both of yours included, make test-c green, and both new tests reporting ok on their own.

Nothing of yours was rewritten. Your commits are intact; the only thing I removed is a line that no longer needs to exist.

On the needs-rebase label β€” you were right and the joke landed:

"dude, that 'needs rebase' tag is hurting my feelings ;)"

It was measuring our merge order, not your work. Two things change from here:

  1. Oldest-clean-first. A PR that is green and unconflicted merges before anything opened after it. The reason you rebased eleven times is that new small PRs kept jumping the queue and resetting you β€” that is a starvation loop we built, not bad luck on your part.
  2. The label comes off when the PR is clean, instead of lingering as a verdict. Yours had been stale on a green PR.

You have three more open here β€” #528 (fp8-e4m3-b128), #529 (the container stamp), and #379/#387 on the issue side. #528 and #529 are both CLEAN right now and are next in the queue under the new rule, ahead of anything filed since. You should not have to touch either of them again before they land.

Thank you for the patience, and for the discipline in every one of those rebases β€” git range-diff showing patch-identical commits, gates re-run in both RESSET states, the disclosed Makefile superset. That is what made it safe for me to finish this one for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

metal Backend Metal/Apple needs-rebase Confligge, serve rebase dell'autore

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants