Skip to content

unsloth: prove each shipped feature actually runs, not just that it merged - #178

Merged
danielhanchen merged 9 commits into
masterfrom
feature-matrix/prove-each-feature-runs
Sep 4, 2026
Merged

unsloth: prove each shipped feature actually runs, not just that it merged#178
danielhanchen merged 9 commits into
masterfrom
feature-matrix/prove-each-feature-runs

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Stacked on #175. That PR proves the merge did not lose a pin's code; this one proves the features still work, which is a different question and neither implies the other.

The case that makes the difference concrete: the Inkling banded-attention kernel merged against upstream's sparse attention is thirteen hunks of CUDA template parameter threading. Get one wrong and you get wrong attention output, a clean merge, a clean pin_contract.py, a clean merge_checks.py and a clean compile.

feature-checks.json

Says per feature what proves it. Keyed by feature with the pin as a binding, and not the other way round: when upstream absorbs a feature the pin is deleted, and deleting the check with it would put the blind spot back somewhere else. The feature is still in the release, it just arrives through the base tag now. So an entry outlives its owner.

Every pin in pr-set.json must appear in features or in unchecked, and the lint fails otherwise. unchecked is a recorded reason, not a hole; it is exactly how DiffusionGemma went five weeks with no coverage and no record of it. The lint earned its keep on the first run by catching that the manifest still named unslothai#107 after the pin had moved to #177.

The one thing this has to get right

A pass has to be positive evidence. Both harnesses exit 0 having done nothing:

test-llama-archs -a diffusion-gemma   # excluded -> prints SKIP, exits 0
test-backend-ops test -o TYPO         # matches nothing, exits 0

So every probe rejects skip markers and requires a non-zero count of cases it actually ran. Without that this whole layer is decoration, and the tests are mostly about that rather than about the happy path: an all-SKIP arch run, an arch with no row at all, an op filter that matched nothing, an mtmd run with zero assertions. Fifteen checks, each fed the verbatim output shape of a real run.

No GPU in CI, said out loud

Every runner in the prebuild pipeline is ubuntu-24.04 / windows-2022 / macos-*. test-backend-ops compares a backend against the CPU reference, so with no accelerator it skips every backend and prints Skipping CPU backend, having proved nothing.

Calling that a pass would be a lie and calling it a failure would block every nightly. So those probes are deferred: named, counted, and never folded into the success line.

ok   inkling: 1/2 device rows decoded and matched CPU;
     projector registry intact over 194 assertions  [1 needs a GPU]
--   iq1-narrow-grids: nothing provable without a GPU (3 check(s) deferred)

all 6 features demonstrated on CPU, 6 check(s) need a GPU and were not run

A feature whose every check needs a GPU prints --, not ok. A run that only ever prints success teaches the reader that green means covered.

What it says on a GPU

Against the fully merged thirteen-pin tree at b10775, CUDA sm_100, B200:

ok   glm5next: 2/3 device rows decoded and matched CPU; 144/144 cases matched the CPU reference
ok   inkling: 2/3 device rows decoded and matched CPU; 13/13 cases matched the CPU reference; projector registry intact over 194 assertions
ok   iq1-narrow-grids: 13/13; 13/13; 13/13 cases matched the CPU reference
ok   kimi-k3: 2/3 device rows decoded and matched CPU; projector registry intact over 194 assertions
ok   projector-registry: projector registry intact over 194 assertions
ok   qwen4exp-mtp: 2/3 device rows decoded and matched CPU; 4/4 cases matched the CPU reference

all 6 features demonstrated on GPU

That is the first time any of these has been demonstrated in the composed tree rather than one PR at a time.

Merge order

…erged

pin_contract.py proves the merge did not lose a pin's code. That is a
different question from whether the feature works, and neither implies the
other. The Inkling banded-attention kernel merged against upstream's sparse
attention is thirteen hunks of CUDA template parameter threading where a
mistake gives wrong attention output, and every static check passes.

feature-checks.json says, per feature, what proves it. Keyed by FEATURE with
the pin as a binding, and not the other way round: when upstream absorbs a
feature the pin is deleted, and deleting the check with it would put the blind
spot back somewhere else. The feature is still in the release, it just arrives
through the base tag now.

The one thing this file has to get right is that a pass is positive evidence.
Both harnesses exit 0 having done nothing:

  test-llama-archs -a diffusion-gemma   excluded, prints SKIP, exits 0
  test-backend-ops test -o TYPO         matches nothing, exits 0

so every probe rejects skip markers and requires a non-zero count of cases it
ran. Without that the whole layer is decoration, and the tests are mostly
about this rather than about the happy path.

No runner in the prebuild pipeline has a GPU, and test-backend-ops compares a
backend against CPU, so with no accelerator it skips every backend and proves
nothing. Those probes are DEFERRED, named and counted, never quietly passed:

  ok   inkling: 1/2 device rows decoded and matched CPU;
       projector registry intact over 194 assertions  [1 needs a GPU]
  all 6 features demonstrated on CPU, 6 check(s) need a GPU and were not run

With --gpu on a B200, against the fully merged tree:

  ok   glm5next: 2/3 device rows decoded and matched CPU; 144/144 cases
  ok   inkling: 2/3 device rows; 13/13 cases; projector registry over 194 assertions
  ok   iq1-narrow-grids: 13/13; 13/13; 13/13 cases matched the CPU reference
  ok   kimi-k3: 2/3 device rows decoded and matched CPU; registry intact
  ok   qwen4exp-mtp: 2/3 device rows decoded and matched CPU; 4/4 cases
  all 6 features demonstrated on GPU

Every pin must be in `features` or in `unchecked`, and the lint fails
otherwise. `unchecked` is a recorded reason, not a hole: it is how
diffusion-gemma went five weeks with no coverage and no record of it. The
lint earned its keep immediately by catching that the manifest still named
#107 after the pin moved to #177.

The preflight runs the matrix after its compile gate, appending to the same
PROBLEMS accumulator that already feeds the alert.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T12:33:39.269887Z 324f152 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92f1412b32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +206 to +209
if ! python3 ../scripts/unsloth/feature_matrix.py \
--build-dir "${RUNNER_TEMP}/gate" \
--feature-checks ../scripts/unsloth/feature-checks.json \
--report "${RUNNER_TEMP}/feature_matrix.json" ; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate the publishing workflow on feature probes

When one of these probes fails, this preflight only appends to PROBLEMS and sends an alert; the release workflow .github/workflows/unsloth-prebuilt.yml still runs its existing llama-only compile gate and never invokes feature_matrix.py. Consequently, if nobody acts on the alert before the nightly starts, the same broken merged tree can still fan out and be published, so this does not actually prevent shipping a feature that the new check found broken.

Useful? React with 👍 / 👎.

Comment on lines +131 to +134
# A pin nobody decided about is the failure this whole file exists to stop.
# Being in `unchecked` with a reason is a fine answer; being in neither map
# is how DiffusionGemma went five weeks with no coverage and no record of it.
- name: Every pin is either checked or knowingly unchecked

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Trigger the lint workflow for feature-check changes

Adding this test and manifest validation here does not make them run when their implementation or data changes: both the push.paths and pull_request.paths lists omit scripts/unsloth/feature_matrix.py and scripts/unsloth/feature-checks.json (the existing test_*.py glob only covers the test file). A manifest-only edit can therefore violate the pin ownership invariant without running this new step, and a runner-only edit can bypass its unit tests; include both new production files in both path filters.

Useful? React with 👍 / 👎.

…ffusion-gemma reason

The manifest said save_models emits the diffusion-gemma fixture. It does
not any more: the saver cannot write attention.sliding_window_pattern,
which that arch reads as required, so the model is excluded there too.
Both blockers are outside the fixture and both are now named.

Also says, in the file someone reads when adding a feature, that the
backend-op checks never run in CI and what to do instead: build on a GPU
box, run feature_matrix.py --gpu, paste the output into the carry PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 834e3ff523

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"silently, so before accepting a carry PR that touches one, build it on a",
"GPU box and run:",
"",
" python3 scripts/unsloth/feature_matrix.py --build-dir build --gpu",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include the required manifest in the GPU command

When a carry-PR author follows this documented command—the stated only place where backend-op checks run—argparse exits with status 2 before executing any probes because feature_matrix.py:133 declares --feature-checks as required. Add --feature-checks scripts/unsloth/feature-checks.json so the prescribed GPU validation can actually run.

Useful? React with 👍 / 👎.

…ten for

The every-pin-is-declared lint compares feature-checks.json against
pr-set.json on this branch, and master's set still lists the retired
pins, so the check fails on pins this manifest was never meant to cover.
Merging #174 in makes it compare against the real set; the diff goes
away when #174 lands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c752e6baf5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

rc, out = run(cmd, b, gpu)
if rc != 0:
raise Unproven(f"{' '.join(cmd[1:])} exited {rc}")
m = re.search(r"(\d+)/(\d+) tests passed", out)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate every backend test summary

On a build exposing multiple non-CPU devices or backends, test-backend-ops prints one tests passed summary per device, but re.search inspects only the first. Since test_backend treats an unsupported filter as a successful 0/0 run, a first device reporting 13/13 followed by another reporting 0/0 still exits successfully and this probe records a pass, leaving that second shipped backend untested. Parse all device summaries and require a nonzero passing count for each visible accelerator.

Useful? React with 👍 / 👎.

Comment on lines +147 to +149
for name, feat in sorted(doc["features"].items()):
if args.only and name != args.only:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject unknown --only feature names

When --only contains a typo or a feature removed from the manifest, every iteration is skipped, failed remains zero, and the command exits successfully after claiming that zero features were demonstrated. This can falsely validate the exact manual single-feature run the option is intended to support; verify that the requested name exists before filtering.

Useful? React with 👍 / 👎.

danielhanchen added 2 commits September 4, 2026 00:42
The blocker was the fixture, not the arch: see the pin. It decodes and
matches CPU on every device, so it moves out of `unchecked` and into
`features` with an arch probe, which is the whole point of keeping that
map honest rather than letting a gap sit unnamed.
@danielhanchen

Copy link
Copy Markdown
Member Author

DiffusionGemma moved from unchecked to features. Its blocker turned out to be the test fixture rather than the architecture (#177 has the detail), so the reason for leaving it uncovered no longer holds.

Seven features on the full thirteen-pin mix at b10786, CUDA sm_100, B200:

ok   diffusion-gemma: 3/3 device rows decoded and matched CPU
ok   glm5next: 2/3 device rows decoded and matched CPU; 144/144 cases matched the CPU reference
ok   inkling: 2/3 device rows decoded and matched CPU; 13/13 cases matched the CPU reference; projector registry intact over 194 assertions
ok   iq1-narrow-grids: 13/13; 13/13; 13/13 cases matched the CPU reference
ok   kimi-k3: 2/3 device rows decoded and matched CPU; projector registry intact over 194 assertions
ok   projector-registry: projector registry intact over 194 assertions
ok   qwen4exp-mtp: 2/3 device rows decoded and matched CPU; 4/4 cases matched the CPU reference

Worth noting what the manifest did here. DiffusionGemma had been uncovered for five weeks with nothing recording it. Writing the gap down with a reason is what made it a question someone would look at, and the answer took an afternoon.

This branch carries the pin set for the lint, so the preflight runs on it
too, and without #170's resolver fix it reports #172 as not merging. That
is a true statement about a state that will never exist on master: #170
lands first. Merging it through the pin-set branch.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b41b099685

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +175 to +177
else:
# Nothing was shown either way. Not a failure here, but it must not
# read as one of the ok lines.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject feature entries with no checks

When a manifest entry has "checks": [], this branch treats the absence of evidence like an intentional GPU deferral: failed is never incremented, the report remains successful, and the final summary claims every feature was demonstrated. The lint also counts that entry's owner as checked, so an accidentally empty feature definition can silently bypass the coverage invariant; distinguish zero configured checks from checks that were actually deferred and fail the former.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 221b7a7569

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/unsloth/pr-set.json Outdated
"https://github.com/ggml-org/llama.cpp/pull/25731/commits/44eb88e9aba218b24c0f374f2ec1c4d7d7920877",
"https://github.com/unslothai/llama.cpp/pull/70/commits/edfd4c1a3b7a653303a85257ddac2a1f3ce39a2f",
"https://github.com/unslothai/llama.cpp/pull/91/commits/c86ed269986f2dced6325c5c58bda966a2e2ead1",
"https://github.com/unslothai/llama.cpp/pull/177/commits/4137a7d3669c3fe94431b68e2e04b8804e620760",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Register the repinned PRs in the feature manifest

The newly added unslothai#177 pin is absent from both the manifest's owner values and unchecked, so the new “Every pin is either checked or knowingly unchecked” step always exits nonzero; the same mismatch affects unslothai#172, #171, and #173. Update the feature owners or add explicit unchecked entries so this commit can pass its own resolver-tests job.

Useful? React with 👍 / 👎.

@danielhanchen
danielhanchen changed the base branch from pin-contract/verify-the-merged-tree to master September 4, 2026 12:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 324f152254

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


def probe_mtmd(check: dict, b: Path, gpu: bool) -> str:
"""The projector registry is intact, including this projector's entry."""
rc, out = run([str(b / "test-mtmd-impl"), "test_projector_registry"], b, gpu)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify the requested projector entry

When a projector is removed or renamed—especially after its owning pin is repinned or deleted—the registry can remain internally consistent and test_projector_registry can still report nonzero assertions. Because this probe never uses check["projector"], the inkling and kimik3 checks then pass without proving that their requested projector still exists; pin_contract.py cannot close this gap once the pin disappears, and a regression inside a repinned PR regenerates its contract. Make this probe assert the named projector rather than only the registry as a whole.

Useful? React with 👍 / 👎.

@danielhanchen
danielhanchen merged commit fbf9abc into master Sep 4, 2026
5 checks passed
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.

1 participant