Skip to content

fix(push): repoint the model card's quickstart to the pushed repo (#109) - #115

Merged
anirudTT merged 4 commits into
mainfrom
fix/push-repo-card-mismatch-109
Oct 1, 2026
Merged

anirudTT merged 4 commits into
mainfrom
fix/push-repo-card-mismatch-109

Conversation

@ezietlowTT

Copy link
Copy Markdown
Contributor

What

tt-model push --repo <other> published a model card whose Quickstart pointed at the authored repo, not the one the package was actually pushed to (issue #109). A reader following the card's tt-model pull/tt-model serve lines would hit a repo that isn't there.

Why

render_model_card bakes the manifest's repo into the two quickstart command lines at package time — before any push --repo override exists. Nothing downstream realigned them, so a redirected push shipped a stale card.

Fix

push_container now repoints those two command lines from the packaged repo (container.built.repo) to the real push target (repo_id) whenever they differ:

  • exact swap of the tt-model pull <repo> --with-weights and tt-model serve <repo> lines — the only two places the card names the repo, so the swap is complete;
  • a no-op when the repos match or the card is absent (plain push is unaffected);
  • emits a repointed the card's quickstart to <repo> note when it fires.

Tests

Three tests in tests/test_container_cli.py:

  • test_repoint_card_quickstart_swaps_only_the_command_lines — helper swaps both lines and nothing else;
  • test_push_container_repoints_the_card_when_repo_is_overridden — end-to-end push with an overridden repo rewrites the staged card;
  • test_a_rendered_card_repoints_cleanly_end_to_end — render → repoint round-trip, guarding against quickstart format drift in build.render_model_card.

Verified the tests fail without the source fix (the regression genuinely reproduces #109), and the full suite is green: 896 passed.

Closes #109

🤖 Generated with Claude Code

`render_model_card` bakes the manifest's repo into the card's `tt-model pull`
/`tt-model serve` quickstart lines at package time, before any `push --repo`
override is known. Pushing a package to a different repo then published a card
whose quickstart pointed a reader at a repo that isn't there.

`push_container` now repoints those two command lines from the packaged repo
(`container.built.repo`) to the actual push target when they differ. Those lines
are the only place the card names the repo, so the swap is complete; a no-op when
the repos match or the card is missing.

Closes #109

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jashansinghTT
jashansinghTT self-requested a review September 15, 2026 18:31
@anirudTT
anirudTT self-requested a review September 16, 2026 13:51

@anirudTT anirudTT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for picking this up — I filed #109, and the diagnosis here is right. But I think the fix swaps my bug for a slightly different one.

_repoint_card_quickstart edits README.md in the staged dir in place, but matches on built.repo, which never moves. So the anchor is fixed and the file isn't. After the first push --repo, the card no longer contains built.repo anywhere, and every push after that quietly does nothing.

I checked out the branch and ran it. Two cases:

package for tenstorrent/devstral, then
  push --repo anirud/devstral   card says anirud/devstral        ok
  push                          uploads to tenstorrent/devstral,
                                card still says anirud/devstral
  push --repo a/devstral        card says a/devstral             ok
  push --repo b/devstral        bytes go to b, card still says a,
                                and no note is printed

The second is #109 again with different names. The first is arguably worse — a plain push right after a redirected one publishes someone else's repo name onto the canonical repo, silently.

The staged dir isn't temporary either. It's ~/tt-model-builds/<name>, and people push from it more than once, so this sticks.

Fix is small, I think: anchor on the command prefix instead of the old repo name, so the swap doesn't care what's currently in the file.

_QUICKSTART = re.compile(r"(?m)^tt-model (pull  |serve )\S+")
...
swapped = _QUICKSTART.sub(lambda mo: f"tt-model {mo.group(1)}{new_repo}", text)

I ran that against a real render_model_card output — authored → a/x → b/x lands correctly, no trace of either earlier repo, reapplying is a no-op. The existing swapped == text check then covers the nothing-to-do case on its own, so the old_repo == new_repo early return becomes optional rather than the thing holding it up.

One thing to watch with the regex: the author's own card.quickstart gets appended after the generated block, so a whole-file sub would rewrite command lines there too. Probably what you want, but if you'd rather keep the blast radius tight, scope the sub to the first fenced block.

Smaller stuff:

  • The docstring says those two command lines are the only place the card names the repo. True for the generated part, but card.description and card.quickstart are author prose and can name it too. Worth softening.
  • The write happens before the upload, so if push_large_folder throws you're left with a card naming a repo it never got pushed to. With the anchoring fix that heals itself on the next push; right now it doesn't.
  • built.repo staying put is correct — its only consumer is the default target at cli.py:1717. Just flagging that the published tt-model.yaml and README.md will disagree about the repo after a redirected push. Fine by me, noting it for the record.
  • Tests: 896 pass, confirmed locally. test_repoint_card_quickstart_swaps_only_the_command_lines mentions "no write of an identical file" but only asserts on the return value, which short-circuits before any write anyway. The render → repoint round-trip test is the valuable one, definitely keep that. Worth adding the two sequential-push cases above as regressions.

ezietlowTT and others added 2 commits September 22, 2026 19:02
… repo (#109)

Addresses @anirudTT's review of #115. The first version of this fix matched on the
authored repo (`built.repo`), which never moves in the manifest — so it only worked for
the first `push --repo`: once the card no longer literally contained the old repo, every
later push matched nothing and silently no-op'd. Worse, a plain push after a redirected
one left the canonical repo's card advertising someone else's repo.

Anchor on the command prefix instead, so the swap replaces whatever repo is currently on
the line regardless of history — self-healing and idempotent. Also handles all four
generated command lines, including the `tt model pull` / `tt serve` (tt-cli) pair that
#133 added since this branch was opened; the old two-line swap would have missed them.
Requiring a `namespace/name` after the prefix keeps a stray prose line from matching, and
`card.description` / an author's appended `card.quickstart` prose are left alone.

- Reworked `_repoint_card_quickstart` (drops the `old_repo` arg; the no-op case is the
  `swapped == text` check now).
- Regression tests: repeated/redirected pushes stay correct (canonical -> a -> canonical
  -> b), the tt-cli lines are repointed, prose is untouched, and the end-to-end render ->
  repoint test now covers all four commands to guard format drift.
- Merged current main (picks up #133's new card format). Full offline suite: 991 passed.

Closes #109

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ezietlowTT
ezietlowTT requested a review from a team as a code owner September 22, 2026 19:04
@ezietlowTT

Copy link
Copy Markdown
Contributor Author

Thanks @anirudTT — you were exactly right, and the sequential-push case (redirect then plain push publishing someone else's repo name onto the canonical repo) is the worse one. Fixed in 072a1fd.

Done:

  • Anchored on the command prefix, not the old repo. _QUICKSTART_CMD matches the command lines and swaps whatever repo is on them, so it's self-healing and idempotent — no dependence on built.repo, which as you said never moves. I verified against the old code that canonical → push --repo a/m → plain push left the card on a/m; the new anchoring restores canonical.
  • Handles all four command lines. feat(card): document the consumer flow and derive Using it #133 merged since I opened this and reworked the Quickstart to lead with the tt CLI (tt model pull / tt serve) and keep tt-model as the second fence — the old two-line swap would now miss the primary commands. The regex covers both pairs.
  • Blast radius. I kept it whole-file but required a namespace/name (\S+/\S+) after the prefix, so a bare prose line like tt serve is the fast path isn't mistaken for a command (a repo id always has exactly one slash). card.description and an author's appended card.quickstart prose are left alone — there's a test for the prose case.
  • Docstring softened — no longer claims those lines are the only place a repo can appear; it says it repoints the generated command lines and leaves author prose alone.
  • Write-before-upload now self-heals on the next push thanks to the anchoring, as you noted.
  • Tests: dropped the old_repo arg (the no-op case is the swapped == text check now); added the sequential-push regressions (canonical → a → canonical → b), the tt-cli-lines case, and the prose-not-touched case; the render→repoint round-trip now asserts all four commands to catch format drift.

Left built.repo as-is per your note — the published tt-model.yaml and README.md disagreeing about the repo after a redirect is expected, since built.repo only feeds the default target at cli.py.

Merged current main too, so it's up to date with the new card format. Full offline suite: 991 passed. Ready for another look when you have a minute.

@jashansinghTT jashansinghTT 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.

Tested end to end from a clean venv on a QB2 box with four real pushes to private HF repos (override → plain push back to canonical → second override → idempotent re-push): the published card's quickstart named the right repo on the Hub every time while current main still shipped the authored repo, and the full offline suite is green — LGTM; one small non-blocking follow-up is that the generated "open a discussion at https://huggingface.co//discussions" line still names the authored repo after a redirected push.

@anirudTT anirudTT mentioned this pull request Oct 1, 2026

@anirudTT anirudTT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

deferring to @jashansinghTT approval

@anirudTT
anirudTT merged commit 7994e0a into main Oct 1, 2026
7 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.

push --repo publishes a model card pointing at the manifest's repo, not the pushed one

3 participants