You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(hub): verify community bundles by copying them into the Tenstorrent org - #132
Adds tt-model verify <repo>, the command a Tenstorrent reviewer runs to make a community bundle verified (DEVSTACK-423).
It copies the bundle into the Tenstorrent HF org, named after its weights repo (someone/qwen3-32b-blackhole-v51 becomes Tenstorrent/Qwen3-32B). Only the DX team can write to that org, so being there is what "verified" means. Authors can't grant it to themselves.
The copy is made on the Hub itself, so no data moves, and the author's repo is never touched. The original stays listed as unverified.
The copy stays private until it's finished: copy, record the review, list, then make public. A run that fails partway leaves nothing public.
The copy's card credits the author in its first line and records the source, revision, reviewer and date. It's a snapshot: later commits to the original aren't covered.
If an earlier run stopped partway, running it again finishes that copy instead of refusing it. A Hub copy doesn't keep the source's commit history, so it's recognised by its files matching the source at the revision being verified.
If the name is already taken by another bundle's copy, the command refuses, says which copy has it, and says to delete that copy on the Hub if it's abandoned.
tt-model unverify Tenstorrent/<name> takes the copy out of the catalog but keeps the repo.
Board builds of one model still share a name. Naming is a separate change, pending a decision on the convention.
The matching tt model list change is tt-cli #35, which reads the tt_verified_source key this writes.
Tested live on 2026-09-30 with stisiTT/smollm2-135m-instruct-p150: a run stopped after the copy, the re-run finished it (private until the last step), a third run re-recorded without a second copy or credit, tt-cli #35 listed the copy as verified and the original as unverified, and unverify delisted it. The test copy was deleted afterwards. Offline suite: 1017 passed; 3 container-run tests fail on the test machine because they see its real boards, with or without this change.
Re-reading the GA scope doc's Whitelisting section, the requirement is that
"whitelisting is implemented by adding models to the tenstorrent HF repo" —
i.e. the reviewed model gets a TT-owned copy under our org, and org membership is the whitelist. This PR instead keeps a JSON file that points at models
still owned by their community authors, which means a whitelisted repo can be
re-pushed after review while the ✓ stays. The spec'd design can't do that,
needs no cross-repo constant contract, and makes the whitelist browsable at
huggingface.co/tenstorrent.
That design is mine, not the spec's, so this needs rework rather than review.
Tracking the decision on DEVSTACK-423 (the one open question is licensing /
attribution when TT becomes publisher-of-record for third-party code).
Two pieces here are worth keeping either way and will be split out: hub.repo_state (replacing is_listed's fail-to-False as an authorization
gate) and the reviewer-facing tt-model whitelist <repo> interface, whose
implementation becomes "copy the bundle into the org" instead of "append to a
file".
#131 below it is unaffected and stays ready for review.
Early review (it's a draft, so not approving yet — and it stacks on #131, which should merge first). Reviewed the whole diff and ran it: test_whitelist.py + test_catalog_publish.py = 42 passed, full offline suite = 955 passed.
This is excellent work, and I want to call out the parts I specifically checked and think are right:
Storage location is the correct design. A dataset repo only TT can write, not a repo tag (author owns their frontmatter) and not a manifest field (author writes it) — a review someone else granted genuinely can't live in author-controlled space. Good call, and the docstring makes the reasoning legible.
Clean layer split: pure doc functions in whitelist.py (no network), bytes in hub.py. dumps is canonical (sorted, indented, trailing newline) and the fixture is asserted to already be in that form, so the first real write won't reformat the whole file — nice.
Optimistic concurrency is real, not decorative.fetch_whitelist reads the dataset sha first and downloads the file at that revision with force_download, push_whitelist commits against that parent_commit, and _edit_whitelist re-fetches + re-applies exactly once on 409/412. Crucially, it refuses to proceed when the Hub reports no head commit rather than committing with parent=None (which would silently disable the whole guarantee) — and that's tested.
The offline-vs-missing ordering (LocalEntryNotFoundError caught before EntryNotFoundError) is the same subclass hazard as fix(hub): classify Hub failures by exception type, not class name #131, handled correctly, and tested with a message carrying no network keyword so only the class distinguishes it.
repo_state raises (unlike is_listed, which fails to False) because it feeds a decision — a network blip must not read as "not listed" and hand the reviewer a remedy that would make a private repo public. Good distinction, and tested.
unpublish's advisory is read-only/best-effort and can't fail a successful delist; it names the reviewer's command instead of trying to edit the dataset it has no write access to. Right.
Test coverage is thorough (pure shape, CLI gates, hub layer, concurrency retry/give-up, case-insensitive keys, null-revision, no-op withdraw before first review). I didn't find correctness issues.
Two small things to confirm before you flip it out of draft — neither blocking:
The reader side (tt model list --community --whitelisted) lives in tt-cli and the dataset repo is created by hand — both are noted, just make sure those land alongside so the feature is usable end to end.
_edit_whitelist catching BaseException around the push is deliberate (you re-raise typer.Exit and classify the rest), but it's worth a comment there noting KeyboardInterrupt also flows through the classifier path.
Ping me when it's out of draft and #131 is merged and I'll give it a formal approve.
stisiTT
changed the title
feat(hub): whitelist reviewed bundles in a Tenstorrent-controlled allowlist
feat(hub): verify community bundles by copying them into the Tenstorrent org
Sep 29, 2026
The reason will be displayed to describe this comment to others. Learn more.
Resume does not work: if the review step fails after the copy lands, re-running verify rejects its own copy as a name collision (it has no tt_verified_source yet) and the suggested unverify cannot free the name because it keeps the repo, while that copy is already public, listed and shown as verified with no credit (reproduced live); there is also no way to choose the target name, so 11 of the 58 listed bundles (e.g. the four Qwen3.8-27B board builds) can never be verified.
@jashansinghTT Resume is fixed in f725277: the copy stays private until finished, a re-run finishes its own unfinished copy (matched by its files, since a Hub copy doesn't keep history), and the collision message no longer suggests unverify. Tested live. Naming (the shared-name bundles) is a separate change pending Nate's call on the convention.
… org
DEVSTACK-423 specifies that whitelisting is implemented by adding models to
the tenstorrent HF org, gated by org membership, which the whole DX team has.
This implements that. The previous approach in this branch -- a JSON allowlist
in a separate dataset repo, pointing at bundles that stayed in their authors'
namespaces -- was invented during implementation rather than taken from the
requirement, and it was weaker on the one property the whitelist exists to
provide: a pointer can go stale after review (the author re-pushes, the mark
stays), while a copy cannot.
Whitelisting IS the copy. A bundle under Tenstorrent/ has been reviewed by
definition, because only the DX team can write that namespace -- an author
cannot grant it to themselves, which is what a tag on their own repo could
never prevent. There is no index to fetch and nothing to keep in sync: "has
Tenstorrent reviewed this" reduces to "is this repo ours", answerable from the
repo id alone. That deletes the whitelist module, its schema, the four mirrored
constants and the shared fixture, and with them the optimistic-concurrency
retry that only existed because one file had many writers.
duplicate_repo is a server-side copy, so a review costs one request and moves
no bundle data even for a multi-GB image, and the author's repo is never
written to. The copy is named after the weights repo rather than the bundle,
which yields the canonical model name (Tenstorrent/Qwen3-32B) instead of a
packaging slug, and matches the naming DEVSTACK-449 asks for.
The review record goes in the copy's own card -- source repo, source revision,
reviewer, date, plus an attribution line naming the original -- so it cannot
drift from the artifact it describes, and tt-cli can read it straight off a
listing response with no extra request. card.data is mutated rather than
rebuilt, for the reason tag_repo documents: a fresh block drops the author's
license and pipeline_tag. Unlike tag_repo there is deliberately no empty-card
fallback, because this writes the body too and a transient read failure must
not replace a real README with nothing.
A name collision refuses and names the existing copy: two board targets of one
model derive the same name, and a reviewed artifact someone may be relying on
is not ours to overwrite. A run that copied but failed to annotate resumes
instead of being blocked by its own partial state. unwhitelist delists the copy
and keeps the repo, so anyone who pinned it can still reach it and the original
reappears in listings.
The team agreed a whitelisted model's community author is credited in the
top line of the card: the copy earns the Tenstorrent org's traffic, and the
visibility that buys the author is the reason they should accept being
copied at all. Attribution appended as a trailing section put the credit
below the model's own documentation, which inverts that.
The block now opens the body, above the model's heading, and links the
author's profile as well as the source repo so the credit leads somewhere.
It is also bracketed by HTML comment markers and replaced rather than
appended. `whitelist` resumes an interrupted run by re-annotating a copy it
already wrote, so the old code stacked a second credit under the first on
every re-run -- with the marker, re-recording a review rewrites it in place.
Drops the "snapshot of that revision" wording when the Hub reported no sha,
where it referred to nothing.
The team moved to a verified/unverified vocabulary (DEVSTACK-423):
`tt model list` shows verified models by default, and --unverified adds
community bundles Tenstorrent has not reviewed. This command is what
makes a bundle verified, so it takes the same name.
`tt-model whitelist` / `unwhitelist` become `verify` / `unverify`, and
the card keys become tt_verified_source, tt_verified_revision,
tt_verified_by and tt_verified_at (marker tt-verified-attribution).
Nothing has been written with the old keys yet, since no bundle has
been copied into the org, so there is nothing to migrate. tt-cli reads
tt_verified_source and changes in step.
Also corrects messages that still described the original being hidden
once a copy existed. It never is: the original stays listed as
unverified next to its copy.
A copy was public from the moment it landed and carried the source catalog
tag, so a run that failed before recording the review left a copy shown as
verified with no credit to the author. The copy is now made private and
made public only after its review is recorded and it is listed.
Re-running verify on that half-finished copy refused it as a name
collision, because it had no recorded source yet. It is now recognised as
this run's copy when its files match the source at the revision being
verified, and finished. A Hub duplicate does not keep the source's commit
history, but it keeps every file byte for byte, so the blob ids and LFS
hashes are compared. A copy of an older revision still refuses.
The collision message suggested unverify, which only delists and cannot
free the name. It now says to delete an abandoned copy on the Hub.
The reason will be displayed to describe this comment to others. Learn more.
Resume works now. I re-tested it live from a fresh install: interrupted mid-copy, stopped before the publish step, stale and foreign unfinished copies, collisions, unverify then re-verify, and a real 263-file bundle. The offline suite passes (1116). One blocker is left:
Re-running verify after the source has moved on records a revision the copy doesn't contain. The recorded == source branch (cli.py:2001) re-annotates with the source's currentstate.sha without checking the copy. To reproduce: verify a bundle at A, push B to the source, then run verify again. It reports "re-recorded … (at B)", and the card says tt_verified_revision: B / "a snapshot of that revision", but the files are still A. is_copy_of's docstring says this must not happen, and it hides drift from anything that compares revisions. Only re-record when the recorded revision equals state.sha. Otherwise refuse, and say the copy holds the recorded revision while the source is now at state.sha.
Two smaller ones on the same path:
Wrong diagnosis for a token that can't write to the org. Without write access to Tenstorrent, the /duplicate call returns 403, and it's classified against the source (cli.py:2035): "rejected this token for … may lack read scope", followed by tt-model login. The real problem is that the token can't write to Tenstorrent. That's probably the most common failure for a reviewer, so it's worth its own message.
Misleading message after an interrupted copy. If the duplicate request is interrupted or times out after the Hub has created the repo, the card still says "nothing was copied into Tenstorrent" (cli.py:2036), even though a private copy exists. A re-run finishes it fine, so the wording just needs hedging.
@jashansinghTT Thanks for the thorough re-test. All three are fixed in 819880a. I also rebased onto main.
Revision drift:verify re-records only when the recorded revision equals the source's current head. Otherwise it refuses, names both revisions, and says to delete the copy on the Hub to verify the newer one. A copy with no recorded revision is refused the same way.
403 on the copy: it now gets its own "cannot write to Tenstorrent" diagnosis, with hf auth whoami and a login with a write token, instead of blaming read access to the source.
Interrupted copy: the message no longer says nothing was copied. It says nothing was made public, and a re-run finishes a private copy if one was created.
Each has a regression test. Full offline suite: 1129 passed.
One known gap I left alone: the source's head is read before the copy starts, so a push to the source during the copy would still record a revision the copy doesn't hold. Happy to close it here or in a follow-up.
…a 403
Re-running verify on a source that had moved on since its copy was made
re-recorded the review at the source's current sha, so the card claimed a
revision the copy's files are not. That hides drift from anything that
compares revisions. Re-record only when the recorded revision equals the
source's head; otherwise refuse and name both revisions. Replacing the copy
is the way to verify a newer revision, and unverify cannot free the name,
so the message says to delete the copy on the Hub.
A 403 from the server-side copy was classified against the source and
blamed read scope. The source has just been read as public by then, so a
403 can only be the Tenstorrent org refusing the token, which is the most
likely failure for a reviewer. It now gets its own diagnosis.
The copy-failure consequence said nothing was copied, which is false when
the request times out or is interrupted after the Hub created the repo. It
now says nothing was made public and that a re-run finishes a private copy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
tt-model verify <repo>, the command a Tenstorrent reviewer runs to make a community bundle verified (DEVSTACK-423).It copies the bundle into the
TenstorrentHF org, named after its weights repo (someone/qwen3-32b-blackhole-v51becomesTenstorrent/Qwen3-32B). Only the DX team can write to that org, so being there is what "verified" means. Authors can't grant it to themselves.tt-model unverify Tenstorrent/<name>takes the copy out of the catalog but keeps the repo.Board builds of one model still share a name. Naming is a separate change, pending a decision on the convention.
The matching
tt model listchange is tt-cli #35, which reads thett_verified_sourcekey this writes.Tested live on 2026-09-30 with
stisiTT/smollm2-135m-instruct-p150: a run stopped after the copy, the re-run finished it (private until the last step), a third run re-recorded without a second copy or credit, tt-cli #35 listed the copy as verified and the original as unverified, andunverifydelisted it. The test copy was deleted afterwards. Offline suite: 1017 passed; 3 container-run tests fail on the test machine because they see its real boards, with or without this change.