[PR #20] [CLOSED] fix(generate-3d): retarget partner discovery at partner/3d and document the does-not-serve-type fall-through (BE-8101) #18

Closed
opened 2026-10-26 22:34:01 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Comfy-Org/comfy-skills/pull/20
Author: @mattmillerai
Created: 8/20/2026
Status: ❌ Closed

Base: main ← Head: matt/be-8101-generate-3d-partner-prefix


📝 Commits (1)

  • 6b93a54 fix(generate-3d): route partner discovery at partner/3d, not the empty api node/

📊 Changes

1 file changed (+2 additions, -2 deletions)

View changed files

📝 claude-code/commands/generate-3d.md (+2 -2)

📄 Description

ELI-5

/comfy-cloud:generate-3d told itself to find Meshy/Tripo/Rodin/Tencent nodes by asking search_nodes for category: "api node/3d". Nothing in the catalog has ever been filed under api node/ — the real prefix is partner/ — so the lookup came back empty and the command could tell a user the provider isn't wired up. This points it at partner/3d (32 nodes, exactly those four providers) and, because the shortcut now actually reaches partner_generate for the first time, documents the one rejection it will get there and where to go next.

The dead prefix, measured

claude-code/commands/generate-3d.md is the canonical, shipping copy — README.md:47 (re-read verbatim at authoring time): "claude-code/ — the comfy-cloud Claude Code plugin: commands/ (the slash commands) … Edit commands here.", with skills/ marked "legacy … Frozen". cf7949d fixed the legacy skills/ copy and missed this one.

Counted against the live catalog snapshot (Comfy-Org/comfy-cloud-mcp-server data/object_info.json.gz @ 67eeb5ff, 3621 nodes), read-only:

search_nodes category prefix nodes matched
api node/ 0
api node/3d 0
partner/ 231
partner/3d 32 — categories partner/3d/{Meshy,Rodin,Tripo,Tencent}

Those four are precisely the providers the command's own prose names ("Meshy, Tripo, Rodin, Tencent, and so on"), so the shortcut was inert for every provider it advertises.

What changed

Two lines in one file, both ported from the blessed skills/comfy-generate-3d.md wording:

Line Change
claude-code/commands/generate-3d.md:9 (Step 0) category: "api node/3d" → category: "partner/3d"; api node/3d/... → partner/3d/...; fall-through extended to cover the "does not serve type" rejection and route on to the template path.
claude-code/commands/generate-3d.md:15 (step 2 bullet) category: "3d" or category: "api node/3d" → category: "3d" or category: "partner/3d".

Both lines are now byte-identical to skills/comfy-generate-3d.md:5 and :11. In fact the two files are now identical in full apart from the commands copy's 3-line YAML frontmatter and one blank line — diff <(tail -n +4 claude-code/commands/generate-3d.md) skills/comfy-generate-3d.md reports only that blank line. No frontmatter was touched.

Negative-claim falsification (the #581 rule)

The diff adds the string "does not serve type", which trips the capability-denial trigger, so I went and looked rather than asserting it. Two separate claims, both checked read-only against the comfy-cloud-mcp-server clone @ 67eeb5ff — no dispatch, no network, no credits:

  1. The rejection is real. src/partner/client/registry/threed.ts is export const THREED_MODELS = {} as Readonly<Record<string, ModelEntry>> — zero registered 3D partner models — and src/tools-execution.ts:2330 emits partner_generate does not serve type "${type}" — no ${type} partner model is registered. for exactly that case. So a partner_generate({type: "3d"}) call reached via the newly-working node lookup does get this error, which is why the sentence is needed at all: without it the fixed shortcut would dead-end where the broken one merely fell through.
  2. The redirect target genuinely works, so this is not a dead-end. The sentence's user-facing outcome is "continue below — the template path in step 1 does generate 3D on Comfy Cloud", and step 1 already calls search_templates with tag: "Image to 3D". Against data/templates.json (580 templates): 45 carry 3D content, the live 3D-ish tags are 3D, Image to 3D and 3D Model, and both template ids the server's own partner playbook names for 3D — api_hunyuan3d_text_to_model and api_rodin3d_gen2_5_text_to_3d — are present.

The net direction is capability-expanding: before this PR the shortcut matched nothing and could conclude the provider was unwired; after it, the shortcut runs, and its one failure mode is documented with a working route onward. The same wording is corroborated by three independent shipping surfaces in that server — src/instructions.ts:55, src/partner-playbook.ts:91, and the regression test src/classify-error.test.ts:426 (BE-2519) — and by skills/comfy-generate-3d.md:5, already on main here.

Scope

Deliberately confined to generate-3d.md. Open PR #19 (fix/partner-generate-guess-and-bounce) owns claude-code/commands/generate-{audio,image,video}.md and skills/comfy-generate-{audio,image,video}.md; I confirmed its file list via gh pr view 19 --json files — zero overlap with this PR. #19's own Residual section names claude-code/commands/generate-3d.md:9,15 as deferred to a follow-up; this is that follow-up.

Sweep of the half this PR does not fix: after this change, grep -rn 'api node/' across the repo returns 2 remaining lines in 2 files — claude-code/commands/generate-audio.md:9 and claude-code/commands/generate-image.md:9, both owned by #19. claude-code/commands/generate-video.md and all four skills/*.md are already clean on main. So the repo-wide count goes 4 → 2 here and 2 → 0 when #19 merges. Not touched by this PR, by the ticket's explicit instruction.

Residual — the canonical surface has no automated guard

The lint that catches this class of bug — Comfy-Org/comfy-cloud-mcp-server src/guide-capability-assertions.ts, whose advertisedNodeCategories() reads every category: value out of the rendered corpus and fails any that matches zero nodes — cannot see this file. Its corpus (renderGuideCorpus() in src/guide-corpus.ts) is the server's own surfaces plus data/skills.json, and .github/workflows/refresh-skills.yml:3 mirrors Comfy-Org/comfy-skills/skills/*.md only. So the lint guards the copy this repo's README calls legacy and frozen and not the copy it calls canonical, which is exactly how skills/ got fixed by cf7949d while the shipping command sat broken for weeks. This PR fixes the instance; the coverage gap is untouched and can produce the same drift again. Extending the refresh/lint corpus to claude-code/commands/*.md is a change in another repo and out of scope here.

Because of that residual this is a Refs, not a Closes — and the ticket's own repo-wide grep -rn 'api node/' . acceptance check cannot go empty until #19 merges either.

Verification

No test or lint toolchain exists in this repo (no package.json, no Makefile, no pre-commit config — confirmed by inspection; the sole CI workflow is detect-unreviewed-merge.yml), so verification is the plugin validator plus the checks the ticket names:

  • claude plugin validate ./claude-code → ✔ Validation passed
  • grep -rn 'api node/' claude-code/commands/generate-3d.md → no hits
  • diff <(sed -n '9p' claude-code/commands/generate-3d.md) <(sed -n '5p' skills/comfy-generate-3d.md) → byte-identical; same for :15 vs :11
  • git diff --stat origin/main...HEAD → 1 file, 2 insertions, 2 deletions; line count unchanged (pure in-line rewording, no structural edits)
  • The catalog / registry / template probes tabled above, all read-only

Judgment calls

  • Ported the fall-through verbatim, including its em-dash, rather than normalising punctuation to the ASCII hyphens this file uses elsewhere — the ticket asked for the skills/ wording verbatim, byte-equality with the blessed copy is a checkable property worth more than local punctuation consistency, and the sibling command files (generate-audio.md, generate-image.md) already use em-dashes.
  • Did not sync anything else between the two 3D files. They happened to converge to full equality with just these two lines, so no further edit was warranted; the wider skills/ ↔ claude-code/commands/ drift that #19 flags for the video command is a human decision, not a sync, and is not touched here.

Unexercised artifacts

  • partner_generate was never actually called, and neither was search_nodes against a live server. All verification is static/read-only against the pinned comfy-cloud-mcp-server clone @ 67eeb5ff (catalog snapshot, registry source, template index, error-emitting call site). A real 3D generation spends credits, so it is out of bounds for an unattended run; the claims under test are fully determined by the data and source read above.
  • Ground truth is pinned to that commit and to comfy-skills origin/main @ 2e6ec4a. If the partner catalog re-files 3D nodes again, this prose needs a re-read.
  • The originating spike ticket's own findings comment could not be read from this environment — only its identifier was available. The premise it recorded was re-derived independently from the catalog and source above rather than taken on trust, and it held.

Provenance

  • Authored by: agent-work loop
  • Verified: claude plugin validate ./claude-code → "✔ Validation passed"; grep -rn 'api node/' claude-code/commands/generate-3d.md → 0 hits; lines 9 and 15 diffed byte-for-byte against skills/comfy-generate-3d.md lines 5 and 11 → identical, and the two files are identical in full apart from frontmatter; git diff --stat origin/main...HEAD → 1 file, +2/−2; repo has no test/lint suite (no package.json / Makefile / pre-commit — confirmed by inspection, sole workflow is detect-unreviewed-merge.yml); read-only Node probe of data/object_info.json.gz @ 67eeb5ff produced the 0 / 0 / 231 / 32 category counts tabled above; data/templates.json probe → 45 of 580 templates 3D, both playbook-named 3D template ids present; src/partner/client/registry/threed.ts, src/tools-execution.ts:2330, src/guide-corpus.ts, src/guide-capability-assertions.ts and .github/workflows/refresh-skills.yml read verbatim; README.md:47 read verbatim. No partner dispatch, no network calls, no credits spent.
  • Deviations: none against the ticket's plan — all three substring edits landed and both named verify checks pass. The ticket's repo-wide grep -rn 'api node/' . check still returns 2 hits (generate-audio.md, generate-image.md), which the ticket itself scopes to open PR #19; this PR does not touch those files. Closure claim downgraded to Refs on the lint-coverage residual named above.

Refs BE-8101.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Comfy-Org/comfy-skills/pull/20 **Author:** [@mattmillerai](https://github.com/mattmillerai) **Created:** 8/20/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `matt/be-8101-generate-3d-partner-prefix` --- ### 📝 Commits (1) - [`6b93a54`](https://github.com/Comfy-Org/comfy-skills/commit/6b93a5485921fcb06294bedcad5b24809bc6079d) fix(generate-3d): route partner discovery at `partner/3d`, not the empty `api node/` ### 📊 Changes **1 file changed** (+2 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `claude-code/commands/generate-3d.md` (+2 -2) </details> ### 📄 Description ## ELI-5 `/comfy-cloud:generate-3d` told itself to find Meshy/Tripo/Rodin/Tencent nodes by asking `search_nodes` for `category: "api node/3d"`. Nothing in the catalog has ever been filed under `api node/` — the real prefix is `partner/` — so the lookup came back empty and the command could tell a user the provider isn't wired up. This points it at `partner/3d` (32 nodes, exactly those four providers) and, because the shortcut now actually reaches `partner_generate` for the first time, documents the one rejection it will get there and where to go next. ## The dead prefix, measured `claude-code/commands/generate-3d.md` is the **canonical, shipping** copy — `README.md:47` (re-read verbatim at authoring time): "**`claude-code/`** — the `comfy-cloud` Claude Code plugin: `commands/` (the slash commands) … **Edit commands here.**", with `skills/` marked "*legacy* … Frozen". `cf7949d` fixed the legacy `skills/` copy and missed this one. Counted against the live catalog snapshot (`Comfy-Org/comfy-cloud-mcp-server` `data/object_info.json.gz` @ `67eeb5ff`, 3621 nodes), read-only: | `search_nodes` category prefix | nodes matched | |---|---| | `api node/` | **0** | | `api node/3d` | **0** | | `partner/` | 231 | | `partner/3d` | **32** — categories `partner/3d/{Meshy,Rodin,Tripo,Tencent}` | Those four are precisely the providers the command's own prose names ("Meshy, Tripo, Rodin, Tencent, and so on"), so the shortcut was inert for every provider it advertises. ## What changed Two lines in one file, both ported from the blessed `skills/comfy-generate-3d.md` wording: | Line | Change | |---|---| | `claude-code/commands/generate-3d.md:9` (Step 0) | `category: "api node/3d"` → `category: "partner/3d"`; `api node/3d/...` → `partner/3d/...`; fall-through extended to cover the `"does not serve type"` rejection and route on to the template path. | | `claude-code/commands/generate-3d.md:15` (step 2 bullet) | `category: "3d"` or `category: "api node/3d"` → `category: "3d"` or `category: "partner/3d"`. | Both lines are now **byte-identical** to `skills/comfy-generate-3d.md:5` and `:11`. In fact the two files are now identical in full apart from the commands copy's 3-line YAML frontmatter and one blank line — `diff <(tail -n +4 claude-code/commands/generate-3d.md) skills/comfy-generate-3d.md` reports only that blank line. No frontmatter was touched. ## Negative-claim falsification (the `#581` rule) The diff adds the string `"does not serve type"`, which trips the capability-denial trigger, so I went and looked rather than asserting it. Two separate claims, both checked read-only against the `comfy-cloud-mcp-server` clone @ `67eeb5ff` — **no dispatch, no network, no credits**: 1. **The rejection is real.** `src/partner/client/registry/threed.ts` is `export const THREED_MODELS = {} as Readonly<Record<string, ModelEntry>>` — zero registered 3D partner models — and `src/tools-execution.ts:2330` emits `partner_generate does not serve type "${type}" — no ${type} partner model is registered.` for exactly that case. So a `partner_generate({type: "3d"})` call reached via the newly-working node lookup does get this error, which is why the sentence is needed at all: without it the fixed shortcut would dead-end where the broken one merely fell through. 2. **The redirect target genuinely works, so this is not a dead-end.** The sentence's user-facing outcome is "continue below — the template path in step 1 does generate 3D on Comfy Cloud", and step 1 already calls `search_templates` with `tag: "Image to 3D"`. Against `data/templates.json` (580 templates): 45 carry 3D content, the live 3D-ish tags are `3D`, `Image to 3D` and `3D Model`, and both template ids the server's own partner playbook names for 3D — `api_hunyuan3d_text_to_model` and `api_rodin3d_gen2_5_text_to_3d` — are **present**. The net direction is capability-**expanding**: before this PR the shortcut matched nothing and could conclude the provider was unwired; after it, the shortcut runs, and its one failure mode is documented with a working route onward. The same wording is corroborated by three independent shipping surfaces in that server — `src/instructions.ts:55`, `src/partner-playbook.ts:91`, and the regression test `src/classify-error.test.ts:426` (`BE-2519`) — and by `skills/comfy-generate-3d.md:5`, already on `main` here. ## Scope Deliberately confined to `generate-3d.md`. Open PR **#19** (`fix/partner-generate-guess-and-bounce`) owns `claude-code/commands/generate-{audio,image,video}.md` and `skills/comfy-generate-{audio,image,video}.md`; I confirmed its file list via `gh pr view 19 --json files` — **zero overlap** with this PR. #19's own Residual section names `claude-code/commands/generate-3d.md:9,15` as deferred to a follow-up; this is that follow-up. **Sweep of the half this PR does not fix:** after this change, `grep -rn 'api node/'` across the repo returns **2 remaining lines in 2 files** — `claude-code/commands/generate-audio.md:9` and `claude-code/commands/generate-image.md:9`, both owned by #19. `claude-code/commands/generate-video.md` and all four `skills/*.md` are already clean on `main`. So the repo-wide count goes 4 → 2 here and 2 → 0 when #19 merges. Not touched by this PR, by the ticket's explicit instruction. ## Residual — the canonical surface has no automated guard The lint that catches this class of bug — `Comfy-Org/comfy-cloud-mcp-server` `src/guide-capability-assertions.ts`, whose `advertisedNodeCategories()` reads every `category:` value out of the rendered corpus and fails any that matches zero nodes — **cannot see this file**. Its corpus (`renderGuideCorpus()` in `src/guide-corpus.ts`) is the server's own surfaces plus `data/skills.json`, and `.github/workflows/refresh-skills.yml:3` mirrors `Comfy-Org/comfy-skills/skills/*.md` **only**. So the lint guards the copy this repo's README calls *legacy and frozen* and not the copy it calls canonical, which is exactly how `skills/` got fixed by `cf7949d` while the shipping command sat broken for weeks. This PR fixes the instance; the coverage gap is untouched and can produce the same drift again. Extending the refresh/lint corpus to `claude-code/commands/*.md` is a change in another repo and out of scope here. Because of that residual this is a `Refs`, not a `Closes` — and the ticket's own repo-wide `grep -rn 'api node/' .` acceptance check cannot go empty until #19 merges either. ## Verification No test or lint toolchain exists in this repo (no `package.json`, no `Makefile`, no pre-commit config — confirmed by inspection; the sole CI workflow is `detect-unreviewed-merge.yml`), so verification is the plugin validator plus the checks the ticket names: - `claude plugin validate ./claude-code` → **✔ Validation passed** - `grep -rn 'api node/' claude-code/commands/generate-3d.md` → **no hits** - `diff <(sed -n '9p' claude-code/commands/generate-3d.md) <(sed -n '5p' skills/comfy-generate-3d.md)` → **byte-identical**; same for `:15` vs `:11` - `git diff --stat origin/main...HEAD` → 1 file, 2 insertions, 2 deletions; line count unchanged (pure in-line rewording, no structural edits) - The catalog / registry / template probes tabled above, all read-only ## Judgment calls - **Ported the fall-through verbatim**, including its em-dash, rather than normalising punctuation to the ASCII hyphens this file uses elsewhere — the ticket asked for the `skills/` wording verbatim, byte-equality with the blessed copy is a checkable property worth more than local punctuation consistency, and the sibling command files (`generate-audio.md`, `generate-image.md`) already use em-dashes. - **Did not sync anything else between the two 3D files.** They happened to converge to full equality with just these two lines, so no further edit was warranted; the wider `skills/` ↔ `claude-code/commands/` drift that #19 flags for the video command is a human decision, not a sync, and is not touched here. ## Unexercised artifacts - **`partner_generate` was never actually called**, and neither was `search_nodes` against a live server. All verification is static/read-only against the pinned `comfy-cloud-mcp-server` clone @ `67eeb5ff` (catalog snapshot, registry source, template index, error-emitting call site). A real 3D generation spends credits, so it is out of bounds for an unattended run; the claims under test are fully determined by the data and source read above. - **Ground truth is pinned** to that commit and to `comfy-skills` `origin/main` @ `2e6ec4a`. If the partner catalog re-files 3D nodes again, this prose needs a re-read. - **The originating spike ticket's own findings comment could not be read** from this environment — only its identifier was available. The premise it recorded was re-derived independently from the catalog and source above rather than taken on trust, and it held. ## Provenance - **Authored by:** agent-work loop - **Verified:** `claude plugin validate ./claude-code` → "✔ Validation passed"; `grep -rn 'api node/' claude-code/commands/generate-3d.md` → 0 hits; lines 9 and 15 diffed byte-for-byte against `skills/comfy-generate-3d.md` lines 5 and 11 → identical, and the two files are identical in full apart from frontmatter; `git diff --stat origin/main...HEAD` → 1 file, +2/−2; repo has no test/lint suite (no `package.json` / `Makefile` / pre-commit — confirmed by inspection, sole workflow is `detect-unreviewed-merge.yml`); read-only Node probe of `data/object_info.json.gz` @ `67eeb5ff` produced the 0 / 0 / 231 / 32 category counts tabled above; `data/templates.json` probe → 45 of 580 templates 3D, both playbook-named 3D template ids present; `src/partner/client/registry/threed.ts`, `src/tools-execution.ts:2330`, `src/guide-corpus.ts`, `src/guide-capability-assertions.ts` and `.github/workflows/refresh-skills.yml` read verbatim; `README.md:47` read verbatim. No partner dispatch, no network calls, no credits spent. - **Deviations:** none against the ticket's plan — all three substring edits landed and both named verify checks pass. The ticket's repo-wide `grep -rn 'api node/' .` check still returns 2 hits (`generate-audio.md`, `generate-image.md`), which the ticket itself scopes to open PR #19; this PR does not touch those files. Closure claim downgraded to `Refs` on the lint-coverage residual named above. Refs BE-8101. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/comfy-skills#18
No description provided.