Skip to content

Handle grayscale images in expand2square - #97

Merged
Ying1123 merged 2 commits into
sgl-project:mainfrom
isaac-vidas:iv-grayscale-expand2square
Jan 25, 2024
Merged

Ying1123 merged 2 commits into
sgl-project:mainfrom
isaac-vidas:iv-grayscale-expand2square

Conversation

@isaac-vidas

Copy link
Copy Markdown
Contributor

Fix error when handling grayscale images in expand2square:

Exception in TokenizerManager:
Traceback (most recent call last):
  File "/home/gcpuser/sglang/python/sglang/srt/managers/tokenizer_manager.py", line 61, in get_pixel_values
    image = expand2square(
  File "/home/gcpuser/sglang/python/sglang/srt/mm_utils.py", line 167, in expand2square
    result = Image.new(pil_img.mode, (width, width), background_color)
  File "/opt/conda/envs/sglang_flashinfer/lib/python3.9/site-packages/PIL/Image.py", line 2941, in new
    return im._new(core.fill(mode, size, color))
TypeError: color must be int or single-element tuple

Fix handling grayscale images in expand2square

@haotian-liu haotian-liu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. It makes sense not to assume that they are in RGB.

Comment thread python/sglang/srt/mm_utils.py Outdated
if width == height:
return pil_img
elif width > height:
if pil_img.mode == "L":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just move this if pil_img.mode to the outer block, in case there's something else broken when width==height. Anyway we will need RGB.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!
I moved the conversion to her as we only need to convert it if the width and height are not the same + changed elif to if condition to support the change.

@haotian-liu haotian-liu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

@Ying1123
Ying1123 merged commit 0c457ba into sgl-project:main Jan 25, 2024
@isaac-vidas
isaac-vidas deleted the iv-grayscale-expand2square branch January 25, 2024 00:23
timethink pushed a commit to timethink/sglang that referenced this pull request Mar 9, 2025
pi314ever pushed a commit to pi314ever/sglang that referenced this pull request Aug 1, 2025
* [LLama3.1-70b][2x] resolve functional failure

* Syntax fix
zhuyijie88 pushed a commit to zhuyijie88/sglang that referenced this pull request Sep 4, 2025
<!-- Thank you for your contribution! Please follow these guidelines to
enhance your pull request. If anything is unclear, submit your PR and
reach out to maintainers for assistance. Join our Slack community at
https://slack.sglang.ai to discuss further. -->

## Motivation

<!-- Describe the purpose and goals of this pull request. -->

## Modifications

<!-- Detail the changes made in this pull request. -->

## Accuracy Tests

<!-- If this pull request affects model outputs (e.g., changes to the
kernel or model forward code), provide accuracy test results. -->

## Benchmarking and Profiling

<!-- If this pull request impacts inference speed, provide benchmarking
and profiling results. -->

## Checklist

- [ ] Format your code according to the [Format code with
pre-commit](https://docs.sglang.ai/developer_guide/contribution_guide.html#format-code-with-pre-commit).
- [ ] Add unit tests according to the [Run and add unit
tests](https://docs.sglang.ai/developer_guide/contribution_guide.html#run-and-add-unit-tests).
- [ ] Update documentation according to [Write
documentations](https://docs.sglang.ai/developer_guide/contribution_guide.html#write-documentations).
- [ ] Provide accuracy and speed benchmark results according to [Test
the
accuracy](https://docs.sglang.ai/developer_guide/contribution_guide.html#test-the-accuracy)
and [Benchmark the
speed](https://docs.sglang.ai/developer_guide/contribution_guide.html#benchmark-the-speed).
sammysun0711 pushed a commit to sammysun0711/sglang that referenced this pull request Dec 16, 2025
vschandramourya pushed a commit to vschandramourya/sglang that referenced this pull request Feb 3, 2026
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jue WANG <zjuwangjue@gmail.com>
efschu added a commit to efschu/htsglang that referenced this pull request Jul 20, 2026
…TS + BUG, no backend

Two zero-backend generators that turn the S1 PlanResult (or a parsed boot
log) into copy-paste markdown AND a prefilled GitHub-issue URL, so
crowdsourcing "what runs how on what hardware" needs no DB. Nothing is ever
sent -- the functions only RETURN text/URL the user submits.

* scrub.py (design §4.5): paths -> basename, secrets (HF_TOKEN / hf_* /
  ghp_* / API keys / Authorization) dropped, GPU UUIDs / non-loopback IPs /
  $USER / home dropped; error-window log excerpt (±30 lines, scrubbed,
  length-capped). A rig is a hardware CLASS (card model + count), never a
  machine identity.
* issue_text.py:
  - results_issue / results_from_plan  -- the RESULTS submission (§4.2):
    verdict + anonymous fingerprint + config block + per-rank GB + max-KV.
    Numbers labelled "planner estimate" (from S1) or "measured" (from a
    boot log via results_from_boot_log, reusing the rig-dashboard
    parse_plan_file).
  - bug_issue / bug_from_plan  -- the BUG report (§4.3): the planner
    verdict becomes the "expected" side of a divergence line; scrubbed
    log excerpt.
  - both emit copy-paste markdown + a prefilled efschu/htsglang issue URL,
    with a ~6 KB URL budget flag (copy-paste fallback above it, §4.4).
  - HardwareFingerprint doubles as a hardware-profile seed (§2.7 later).
* CLI: --emit-results / --emit-bug SYMPTOM [--bug-log FILE] [--quant ...].

Honesty (structural, mirrors §3.4 / §5A.5): the benchmark/energy fields
(§5B.2) are MEASURED-ONLY. The energy module (S2.5) does not exist yet, so
BenchmarkFields/EnergyFields are all-Optional, default None, render nothing
when omitted -- there is NO code path that fabricates a tok/s or a Joule.
Tests assert results_issue exposes no estimated-perf parameter and the
measured dataclasses carry no non-None numeric default.

Tests: test/registered/unit/planner/test_issue_text.py -- 23 passed
(scrub, fingerprint anonymity, RESULTS/BUG rendering + URL round-trip,
PlanResult bridges, measured-only honesty). Full planner suite 56 passed
(CPU-only). Manual CLI runs: RESULTS for Qwen3.6-27B-AWQ on 5090+2x3080
(stock-cannot-shard verdict, no fabricated capacity %); BUG with a seeded
log verifying path/HF_TOKEN/IP/UUID scrubbing + the planner-vs-actual line.
efschu added a commit to efschu/htsglang that referenced this pull request Jul 20, 2026
…§6): thin client over the planner

A self-contained stdlib HTTP server (same no-CDN style as
tools/rig_dashboard/server.py) serving one inline-CSS/JS page + a narrow
planner API. The page is a THIN CLIENT: every edit re-POSTs the whole form to
/api/plan, which runs the SAME feasibility.plan() the CLI runs -- the UI can
never diverge from the engine. No GPU, no server boot; pure offline math.

* webui.py:
  - GET /              -> the single HTML page (no external deps).
  - GET /api/knobs     -> the editable-knob list, FEATURE-DETECTED from the
                          deployed ServerArgs schema (§2.6†): a curated
                          catalog intersected with the live dataclass fields,
                          so the UI never offers a knob the running build
                          cannot honor. rank_kv_ratio / weightless-KV (other
                          branches) are correctly absent here; rank_gpu_id/
                          -gpu_memory_mib/-tp_ratio/-mlp_ratio/-moe_ratio/
                          -vocab_ratio + dcp_size are detected & offered, plus
                          the planner-only per-card free-reserve (§2.5). The
                          "not expressible" cases (per-layer scatter,
                          non-proportional expert/head sets, off-grid widths)
                          are surfaced as explanatory notes, not silently
                          omitted.
  - POST /api/plan     -> fit / infeasible-reasons / split / per-card VRAM
                          breakdown / max-KV / capacity-% / launch flags /
                          honest advantage. Live re-validation of every manual
                          edit through the same feasibility path (§2.6).
  - POST /api/issue    -> the S2 RESULTS/BUG issue text + prefilled GitHub URL
                          ("Submit config" / "Report bug" buttons).
* cli.py: --serve [--host --port] starts the UI (--model then optional).

Honesty (design §3.4): the API returns only capacity/feasibility/split; the
JSON carries no throughput field, and the page has no widget that renders an
estimated rate. Measured card scores appear only when a cached hardware
profile exists (surfaced by S1's advantage module), else labelled absent --
never guessed. A test asserts the plan response contains no tok/s-shaped key.

Tests: test/registered/unit/planner/test_webui.py -- 11 passed (knob
feature-detection, auto plan, manual-edit rejection-with-reason, free-reserve
monotonicity, RESULTS/BUG issue gen, and one real in-process HTTP round-trip
on an ephemeral loopback port). Full planner suite 67 passed (CPU-only).
Manual: served on an isolated port, curled GET / + /api/knobs + POST
/api/plan + /api/issue against the 5090+2x3080 rig, server torn down by own
pgid.
efschu added a commit to efschu/htsglang that referenced this pull request Jul 20, 2026
…2.7 / §8): model x rig matrix

The planner-core is a pure function of (model, HardwareSpec) (S1), so varying
the HARDWARE side is free -- the explorer is a new HardwareSpec SOURCE + a
matrix view over the SAME plan(), not a second engine.

* profiles.py -- hardware-profile library (§2.7):
  - GpuProfile (hardware-only, non-sensitive: name/VRAM/sm-arch/PCIe/NVLink/
    TDP; optional measured gemm/membw only if a submission carried a probe).
  - SEED_PROFILES: the memory rig (RTX 5090 32GB + RTX 3080 20GB) + common
    consumer/datacenter cards (4090/3090/A6000/L40S/A100/H100/H200/MI300X...).
  - ProfileLibrary: JSON load/save, add (measured fields fill but never
    downgrade), and populate_from_fingerprint -- seeded from S2's anonymous
    RESULTS fingerprints (card model + count), closing submissions -> library.
  - compose_rig -> HardwareSpec(source="library-composition").
* explorer.py -- model x rig matrix over plan(): each cell = fit / capacity-% /
  split / stock-even-TP feasibility, plus a text renderer for the CLI.
* CLI: --matrix (--matrix-model LABEL=PATH, --rig NAME=prof,prof,... | live),
  --list-profiles.
* webui.py: an "Explore rigs (matrix)" tab + /api/profiles + /api/matrix; the
  rig composer picks library profiles into a heterogeneous pile and renders
  the model x rig grid.

HONESTY (design §8, structural): a composed rig has NO measured free-VRAM and
NO measured interconnect -> an ESTIMATE. provenance_of() derives the label
from HardwareSpec.source ALONE ("composed" -> estimate=True + the mandatory
"assumes pcie/nvlink topology, not measured" note), so a composed cell can
never be passed off as measured; live-NVML/declared real rigs are visibly
distinct (no star, no note). Capacity/feasibility is VRAM math
(interconnect-independent), so the composed number is honest as capacity --
never as throughput (the matrix cell carries no tok/s field; a test asserts
it).

Tests: test/registered/unit/planner/test_explorer.py -- 18 passed (seed,
populate-from-fingerprint incl. skip-unknown-VRAM + no-downgrade, save/load
keeps seed, composition, provenance composed!=measured, matrix over
models x rigs, every composed cell carries the estimate note, real-rig cell
does not, text renderer stars composed, no-throughput-field, and the webui
/api/profiles + /api/matrix endpoints). Full planner suite 85 passed
(CPU-only). Manual: --list-profiles, a 2x2 CLI matrix, and the served
/api/profiles + /api/matrix on an isolated port (torn down by own pgid).
efschu added a commit to efschu/htsglang that referenced this pull request Jul 20, 2026
…B): measured-only store + Mode-A/B matrix

Turns the crowdsourced results into a comparable, anonymous reference DB +
landscape. The schema is built NOW; the measured perf/energy columns come
from the energy module (S2.5, GPU) and stay structurally ABSENT until then --
never fabricated.

* results_store.py -- local results.jsonl (§5B.1), append-only, no server:
  - QuantDescriptor(nominal_bits, scheme, group_size), canonical parse of
    4b/AWQ/g128 / Q4_K_M / fp8 / GPTQ-Int4 / compressed-tensors g32; exact_key
    (default) vs similar_key (nominal bits only, approximate).
  - Band(lo, hi[, central]) -- saved kWh/seconds are BANDS; a bare scalar is
    rejected (false precision treated as dishonesty, §5A.4/§5A.5).
  - ResultEntry -- full schema: feasibility (available now) + MEASURED perf
    (per-batch-bucket tok/s curves, peaks) + MEASURED energy (per-bucket
    J/token curves, coverage, per-card efficiency, kWh/seconds bands) all
    Optional; the reproduce_flags "reproduce this" block; anonymous hardware
    class (card model + count).
  - INGEST GUARD (§5B.3a): the store holds only MEASURED runs. An entry with
    perf/energy but non-measured provenance is REJECTED (IngestRejected), not
    stored-with-a-caveat; a measured-tagged entry with no measured field is
    rejected; a pure feasibility record is not stored here (the landscape
    computes it live). The guard re-runs on jsonl load so a hand-edited file
    cannot smuggle an unmeasured number in.
* landscape.py -- (model, quant) cross-rig matrix:
  - Mode A (§5B.3): rows = rigs; measured store rows (preferred) + planner/
    composed FEASIBILITY rows for the rest; efficiency compared ONLY at a
    selected batch bucket (blank, never extrapolated, when absent); every max
    carries its operating point; each rig shows its reproduce config.
  - Mode B (§5B.3): strict same-key (model, quant, tp/dcp, batch, concurrency,
    kv_dtype) -- only identical-key runs share the axis.
* CLI: --landscape (--quant, --rig, --results-store, --bucket, --similar-quant),
  reusing the S4 profile library. UI: a "Landscape (benchmark DB)" tab +
  /api/landscape.

HONESTY (structural): measured-vs-estimate is derived, not supplied -- a cell
is_measured only from a measured-provenance store entry; planner/composed cells
carry the S4 estimate provenance and their perf/energy columns are absent (no
tok/s without a measurement). Tests assert: unmeasured perf rejected at ingest,
measured accepted; Mode-A measured/estimate separation + measured-preferred;
efficiency only at a matched bucket; similar-quant labelled approximate; bands
not scalars; a composed cell can never be flagged measured; the LandscapeCell
carries no bare kwh scalar.

Tests: test/registered/unit/planner/test_landscape.py -- 20 passed. Full
planner suite 105 passed (CPU-only). Manual: CLI --landscape over the
5090+2x3080 + 3x4090 rigs (perf columns empty, feasibility from the planner),
and the served /api/landscape on an isolated port (torn down by own pgid).
efschu added a commit to efschu/htsglang that referenced this pull request Jul 22, 2026
…city/feasibility/split, never tok/s

Pure-library planner over the fork's EXISTING parse-time sizing math -- no
formula is re-implemented:

* PlanInputs (uneven_perf.py): the small boot-free input contract of
  PerfCostModel (design sgl-project#97 §2.1), incl. per-card effective_vram_mib
  budgets (§2.5) and manual-edit override fields (§2.6).
  PerfCostModel now takes PlanInputs; the boot path builds it via
  PlanInputs.from_server_args at its single call site, so server and
  offline planner run identical sizing code (the §5 sync guarantee).
* sglang/srt/planner/: hardware.py (HardwareSpec; NVML via the
  rig-dashboard sample_nvml -> nvidia-smi -> MANUAL spec fallback -- fully
  offline-capable), model.py (HF config.json / .gguf / hub-config-only
  resolution, never weights), plan.py (derive_auto_plan: pure lift of
  _resolve_auto_rank_tp_ratio; reserve formulas called UNBOUND from the
  real ServerArgs methods), capacity.py (predict_capacity wrapper),
  feasibility.py (auto + manual-edit validation mirroring
  _handle_uneven_tp; fail-loud naming card/ranks/limit), advantage.py
  (stock-even-TP contrast: feasibility reasons + capacity-% RANGE;
  measured scores cache-only, gated to live-NVML specs).
* python -m sglang.planner CLI: fit verdict, split + launch flags,
  per-rank VRAM breakdown, max-KV estimate, advantage vs stock.
* Honesty is structural (§3.4): no planner dataclass carries a
  throughput-shaped field; a CPU test enforces it.

Tests: test/registered/unit/planner/test_planner_core.py -- 33 passed
(CPU-only; manual 5090+2x3080 rig, synthetic sparse checkpoints).
Regression: test_uneven_tp_args / _mlp_solver / _partition / _memory
identical pass/fail sets before and after the refactor (the 8 failures
are pre-existing on integration/r1, the sgl-project#95 testfix lives on other
branches); mlp_solver+partition (direct PerfCostModel consumers) fully
green. Manual CLI runs: Qwen3.6-27B-AWQ TP=3 (fits, stock cannot shard
4 KV heads / 544-unit FFN across 3), TP=4 co-location 0,0,1,2 with
--plan-free-reserve-gb, dense GGUF Q3_K_M (68-unit grid), physical
impossibility rejection 2x20000 MiB on the 32607-MiB card.
efschu added a commit to efschu/htsglang that referenced this pull request Jul 22, 2026
…TS + BUG, no backend

Two zero-backend generators that turn the S1 PlanResult (or a parsed boot
log) into copy-paste markdown AND a prefilled GitHub-issue URL, so
crowdsourcing "what runs how on what hardware" needs no DB. Nothing is ever
sent -- the functions only RETURN text/URL the user submits.

* scrub.py (design §4.5): paths -> basename, secrets (HF_TOKEN / hf_* /
  ghp_* / API keys / Authorization) dropped, GPU UUIDs / non-loopback IPs /
  $USER / home dropped; error-window log excerpt (±30 lines, scrubbed,
  length-capped). A rig is a hardware CLASS (card model + count), never a
  machine identity.
* issue_text.py:
  - results_issue / results_from_plan  -- the RESULTS submission (§4.2):
    verdict + anonymous fingerprint + config block + per-rank GB + max-KV.
    Numbers labelled "planner estimate" (from S1) or "measured" (from a
    boot log via results_from_boot_log, reusing the rig-dashboard
    parse_plan_file).
  - bug_issue / bug_from_plan  -- the BUG report (§4.3): the planner
    verdict becomes the "expected" side of a divergence line; scrubbed
    log excerpt.
  - both emit copy-paste markdown + a prefilled efschu/htsglang issue URL,
    with a ~6 KB URL budget flag (copy-paste fallback above it, §4.4).
  - HardwareFingerprint doubles as a hardware-profile seed (§2.7 later).
* CLI: --emit-results / --emit-bug SYMPTOM [--bug-log FILE] [--quant ...].

Honesty (structural, mirrors §3.4 / §5A.5): the benchmark/energy fields
(§5B.2) are MEASURED-ONLY. The energy module (S2.5) does not exist yet, so
BenchmarkFields/EnergyFields are all-Optional, default None, render nothing
when omitted -- there is NO code path that fabricates a tok/s or a Joule.
Tests assert results_issue exposes no estimated-perf parameter and the
measured dataclasses carry no non-None numeric default.

Tests: test/registered/unit/planner/test_issue_text.py -- 23 passed
(scrub, fingerprint anonymity, RESULTS/BUG rendering + URL round-trip,
PlanResult bridges, measured-only honesty). Full planner suite 56 passed
(CPU-only). Manual CLI runs: RESULTS for Qwen3.6-27B-AWQ on 5090+2x3080
(stock-cannot-shard verdict, no fabricated capacity %); BUG with a seeded
log verifying path/HF_TOKEN/IP/UUID scrubbing + the planner-vs-actual line.
efschu added a commit to efschu/htsglang that referenced this pull request Jul 22, 2026
…§6): thin client over the planner

A self-contained stdlib HTTP server (same no-CDN style as
tools/rig_dashboard/server.py) serving one inline-CSS/JS page + a narrow
planner API. The page is a THIN CLIENT: every edit re-POSTs the whole form to
/api/plan, which runs the SAME feasibility.plan() the CLI runs -- the UI can
never diverge from the engine. No GPU, no server boot; pure offline math.

* webui.py:
  - GET /              -> the single HTML page (no external deps).
  - GET /api/knobs     -> the editable-knob list, FEATURE-DETECTED from the
                          deployed ServerArgs schema (§2.6†): a curated
                          catalog intersected with the live dataclass fields,
                          so the UI never offers a knob the running build
                          cannot honor. rank_kv_ratio / weightless-KV (other
                          branches) are correctly absent here; rank_gpu_id/
                          -gpu_memory_mib/-tp_ratio/-mlp_ratio/-moe_ratio/
                          -vocab_ratio + dcp_size are detected & offered, plus
                          the planner-only per-card free-reserve (§2.5). The
                          "not expressible" cases (per-layer scatter,
                          non-proportional expert/head sets, off-grid widths)
                          are surfaced as explanatory notes, not silently
                          omitted.
  - POST /api/plan     -> fit / infeasible-reasons / split / per-card VRAM
                          breakdown / max-KV / capacity-% / launch flags /
                          honest advantage. Live re-validation of every manual
                          edit through the same feasibility path (§2.6).
  - POST /api/issue    -> the S2 RESULTS/BUG issue text + prefilled GitHub URL
                          ("Submit config" / "Report bug" buttons).
* cli.py: --serve [--host --port] starts the UI (--model then optional).

Honesty (design §3.4): the API returns only capacity/feasibility/split; the
JSON carries no throughput field, and the page has no widget that renders an
estimated rate. Measured card scores appear only when a cached hardware
profile exists (surfaced by S1's advantage module), else labelled absent --
never guessed. A test asserts the plan response contains no tok/s-shaped key.

Tests: test/registered/unit/planner/test_webui.py -- 11 passed (knob
feature-detection, auto plan, manual-edit rejection-with-reason, free-reserve
monotonicity, RESULTS/BUG issue gen, and one real in-process HTTP round-trip
on an ephemeral loopback port). Full planner suite 67 passed (CPU-only).
Manual: served on an isolated port, curled GET / + /api/knobs + POST
/api/plan + /api/issue against the 5090+2x3080 rig, server torn down by own
pgid.
efschu added a commit to efschu/htsglang that referenced this pull request Jul 22, 2026
…2.7 / §8): model x rig matrix

The planner-core is a pure function of (model, HardwareSpec) (S1), so varying
the HARDWARE side is free -- the explorer is a new HardwareSpec SOURCE + a
matrix view over the SAME plan(), not a second engine.

* profiles.py -- hardware-profile library (§2.7):
  - GpuProfile (hardware-only, non-sensitive: name/VRAM/sm-arch/PCIe/NVLink/
    TDP; optional measured gemm/membw only if a submission carried a probe).
  - SEED_PROFILES: the memory rig (RTX 5090 32GB + RTX 3080 20GB) + common
    consumer/datacenter cards (4090/3090/A6000/L40S/A100/H100/H200/MI300X...).
  - ProfileLibrary: JSON load/save, add (measured fields fill but never
    downgrade), and populate_from_fingerprint -- seeded from S2's anonymous
    RESULTS fingerprints (card model + count), closing submissions -> library.
  - compose_rig -> HardwareSpec(source="library-composition").
* explorer.py -- model x rig matrix over plan(): each cell = fit / capacity-% /
  split / stock-even-TP feasibility, plus a text renderer for the CLI.
* CLI: --matrix (--matrix-model LABEL=PATH, --rig NAME=prof,prof,... | live),
  --list-profiles.
* webui.py: an "Explore rigs (matrix)" tab + /api/profiles + /api/matrix; the
  rig composer picks library profiles into a heterogeneous pile and renders
  the model x rig grid.

HONESTY (design §8, structural): a composed rig has NO measured free-VRAM and
NO measured interconnect -> an ESTIMATE. provenance_of() derives the label
from HardwareSpec.source ALONE ("composed" -> estimate=True + the mandatory
"assumes pcie/nvlink topology, not measured" note), so a composed cell can
never be passed off as measured; live-NVML/declared real rigs are visibly
distinct (no star, no note). Capacity/feasibility is VRAM math
(interconnect-independent), so the composed number is honest as capacity --
never as throughput (the matrix cell carries no tok/s field; a test asserts
it).

Tests: test/registered/unit/planner/test_explorer.py -- 18 passed (seed,
populate-from-fingerprint incl. skip-unknown-VRAM + no-downgrade, save/load
keeps seed, composition, provenance composed!=measured, matrix over
models x rigs, every composed cell carries the estimate note, real-rig cell
does not, text renderer stars composed, no-throughput-field, and the webui
/api/profiles + /api/matrix endpoints). Full planner suite 85 passed
(CPU-only). Manual: --list-profiles, a 2x2 CLI matrix, and the served
/api/profiles + /api/matrix on an isolated port (torn down by own pgid).
efschu added a commit to efschu/htsglang that referenced this pull request Jul 22, 2026
…B): measured-only store + Mode-A/B matrix

Turns the crowdsourced results into a comparable, anonymous reference DB +
landscape. The schema is built NOW; the measured perf/energy columns come
from the energy module (S2.5, GPU) and stay structurally ABSENT until then --
never fabricated.

* results_store.py -- local results.jsonl (§5B.1), append-only, no server:
  - QuantDescriptor(nominal_bits, scheme, group_size), canonical parse of
    4b/AWQ/g128 / Q4_K_M / fp8 / GPTQ-Int4 / compressed-tensors g32; exact_key
    (default) vs similar_key (nominal bits only, approximate).
  - Band(lo, hi[, central]) -- saved kWh/seconds are BANDS; a bare scalar is
    rejected (false precision treated as dishonesty, §5A.4/§5A.5).
  - ResultEntry -- full schema: feasibility (available now) + MEASURED perf
    (per-batch-bucket tok/s curves, peaks) + MEASURED energy (per-bucket
    J/token curves, coverage, per-card efficiency, kWh/seconds bands) all
    Optional; the reproduce_flags "reproduce this" block; anonymous hardware
    class (card model + count).
  - INGEST GUARD (§5B.3a): the store holds only MEASURED runs. An entry with
    perf/energy but non-measured provenance is REJECTED (IngestRejected), not
    stored-with-a-caveat; a measured-tagged entry with no measured field is
    rejected; a pure feasibility record is not stored here (the landscape
    computes it live). The guard re-runs on jsonl load so a hand-edited file
    cannot smuggle an unmeasured number in.
* landscape.py -- (model, quant) cross-rig matrix:
  - Mode A (§5B.3): rows = rigs; measured store rows (preferred) + planner/
    composed FEASIBILITY rows for the rest; efficiency compared ONLY at a
    selected batch bucket (blank, never extrapolated, when absent); every max
    carries its operating point; each rig shows its reproduce config.
  - Mode B (§5B.3): strict same-key (model, quant, tp/dcp, batch, concurrency,
    kv_dtype) -- only identical-key runs share the axis.
* CLI: --landscape (--quant, --rig, --results-store, --bucket, --similar-quant),
  reusing the S4 profile library. UI: a "Landscape (benchmark DB)" tab +
  /api/landscape.

HONESTY (structural): measured-vs-estimate is derived, not supplied -- a cell
is_measured only from a measured-provenance store entry; planner/composed cells
carry the S4 estimate provenance and their perf/energy columns are absent (no
tok/s without a measurement). Tests assert: unmeasured perf rejected at ingest,
measured accepted; Mode-A measured/estimate separation + measured-preferred;
efficiency only at a matched bucket; similar-quant labelled approximate; bands
not scalars; a composed cell can never be flagged measured; the LandscapeCell
carries no bare kwh scalar.

Tests: test/registered/unit/planner/test_landscape.py -- 20 passed. Full
planner suite 105 passed (CPU-only). Manual: CLI --landscape over the
5090+2x3080 + 3x4090 rigs (perf columns empty, feasibility from the planner),
and the served /api/landscape on an isolated port (torn down by own pgid).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants