feat: bump majordomo + support llama-swap(s) provider spellings #7

Merged
steve merged 2 commits from feat/llamaswap-schemes into main 2026-06-27 23:18:57 +00:00
Owner

Per Steve: bump majordomo again, and make sure gadfly supports the llama-swap / llama-swaps provider, including the llamaswaps spelling.

  • majordomo bumped to the latest build (…225659).
  • llama-swap names: gadfly's endpoint switches now accept every spelling — llama-swap / llama-swaps (mirroring majordomo's DSN schemes: llama-swap = http, llama-swaps = https/TLS) and the un-hyphenated llamaswap / llamaswaps — in both the GADFLY_PROVIDER + GADFLY_BASE_URL override and the GADFLY_ENDPOINT_<NAME>="llama-swap|url[|key]" form. Before, only llamaswap matched, so a majordomo-canonical llama-swap hit "unknown provider".
  • The LLM_* DSN path (llama-swap://…, llama-swaps://…) already resolves via majordomo.Parse — no gadfly change needed there; verified it's covered.
  • README providers table + error messages updated; new endpointProvider alias tests.

gofmt/vet/build/test -race green.

🤖 Generated with Claude Code

Per Steve: bump majordomo again, and make sure gadfly supports the `llama-swap` / `llama-swaps` provider, including the `llamaswaps` spelling. - **majordomo** bumped to the latest build (`…225659`). - **llama-swap names**: gadfly's endpoint switches now accept every spelling — `llama-swap` / `llama-swaps` (mirroring majordomo's DSN schemes: `llama-swap` = http, `llama-swaps` = https/TLS) **and** the un-hyphenated `llamaswap` / `llamaswaps` — in both the `GADFLY_PROVIDER` + `GADFLY_BASE_URL` override and the `GADFLY_ENDPOINT_<NAME>="llama-swap|url[|key]"` form. Before, only `llamaswap` matched, so a majordomo-canonical `llama-swap` hit "unknown provider". - The **`LLM_*` DSN path** (`llama-swap://…`, `llama-swaps://…`) already resolves via `majordomo.Parse` — no gadfly change needed there; verified it's covered. - README providers table + error messages updated; new `endpointProvider` alias tests. `gofmt`/`vet`/`build`/`test -race` green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
steve added 1 commit 2026-06-27 23:09:35 +00:00
feat: bump majordomo + support llama-swap(s) provider spellings
Build & push image / build-and-push (pull_request) Successful in 6s
Adversarial Review (Gadfly) / review (pull_request) Successful in 6m8s
a59e61f93c
- Bump majordomo to the latest build (...225659).
- Accept every llama-swap spelling in gadfly's endpoint switches —
  "llama-swap"/"llama-swaps" (mirroring majordomo's DSN schemes: http vs
  https TLS) plus the un-hyphenated "llamaswap"/"llamaswaps" — in both the
  GADFLY_PROVIDER+GADFLY_BASE_URL override and the
  GADFLY_ENDPOINT_<NAME>="llama-swap|url[|key]" form. Previously only the
  un-hyphenated "llamaswap" matched, so a majordomo-canonical "llama-swap"
  hit "unknown provider".
- The LLM_* DSN path (llama-swap:// / llama-swaps://) already works via
  majordomo.Parse — no gadfly change needed there.
- README providers table + error messages updated; new endpointProvider
  alias tests.

gofmt clean, go vet quiet, go test -race green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

🪰 Gadfly — live review status

9/9 reviewers finished · updated 2026-06-27 23:15:42Z

claude-code/opus · claude-code — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

claude-code/opus:max · claude-code — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

claude-code/sonnet · claude-code — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

deepseek-v4-pro:cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

glm-5.1:cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

glm-5.2:cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

minimax-m3:cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

nemotron-3-super:cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — No material issues found
  • error-handling — No material issues found

qwen3-coder:480b-cloud · ollama-cloud — done

  • security — No material issues found
  • correctness — Blocking issues found
  • error-handling — No material issues found

Live status board. Findings are posted in each model's own comment. Advisory only — does not block merge.

<!-- gadfly-status-board --> ## 🪰 Gadfly — live review status 9/9 reviewers finished · updated 2026-06-27 23:15:42Z #### `claude-code/opus` · claude-code — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `claude-code/opus:max` · claude-code — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `claude-code/sonnet` · claude-code — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `deepseek-v4-pro:cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `glm-5.1:cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `glm-5.2:cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `minimax-m3:cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `nemotron-3-super:cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — No material issues found - ✅ **error-handling** — No material issues found #### `qwen3-coder:480b-cloud` · ollama-cloud — ✅ done - ✅ **security** — No material issues found - ✅ **correctness** — Blocking issues found - ✅ **error-handling** — No material issues found <sub>Live status board. Findings are posted in each model's own comment. Advisory only — does not block merge.</sub>

🪰 Gadfly review — claude-code/sonnet (claude-code)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

Verdict: No material issues found

The change adds four provider-name spellings to two switch statements in endpointProvider and resolveModel, then bumps majordomo. I verified the full code in both functions.

  • Input sources are operator-controlled env vars only. GADFLY_PROVIDER, GADFLY_BASE_URL, GADFLY_API_KEY, and GADFLY_ENDPOINT_* all come from the container environment set by whoever deploys Gadfly — not from PR content or any untrusted input. No new tainted-input path is introduced.

  • The new cases are mechanically identical to the pre-existing "llamaswap" case. llamaswap.WithBaseURL(baseURL) / llamaswap.WithToken(apiKey) calls are unchanged; only the matching strings expanded. There is no new code executing, no new URL construction, and no new credential handling.

  • endpointProvider raw-string parsing (strings.SplitN(raw, "|", 3)) is pre-existing and already used for all other providers. A |-separated format with a fixed max-split of 3 prevents any injection of extra fields. No change here.

  • API keys are not logged. The only fmt.Fprintln(os.Stderr, ...) at line 48 prints the error string from endpointProvider, which never includes the key value — verified at model.go:207 and model.go:216.

  • Dependency bump: go.sum hash integrity is the normal Go module trust mechanism. No code-level concern from the diff; I cannot inspect the private module's internals, but that is outside this lens's purview and no evidence of concern exists in the diff.

Nothing in this change widens the security perimeter.

🎯 Correctness — No material issues found

No material issues found

Verified by reading model.go and model_test.go in full.

  • Switch consistency (model.go:83, model.go:226): Both resolveModel() and endpointProvider() were updated with the same four spellings ("llamaswap", "llamaswaps", "llama-swap", "llama-swaps"). The two switch arms are in sync — no spelling is handled in one but not the other.

  • Semantics of GADFLY_BASE_URL path (model.go:83): When GADFLY_BASE_URL is set, the scheme is determined entirely by the URL itself (e.g. http:// vs https://), so conflating the TLS variants (llamaswaps/llama-swaps) with the plaintext ones in a single case arm is correct behavior, as the in-code comment accurately explains.

  • baseURL == "" path: All four spellings pass through buildSpec() and then majordomo.Parse() before ever reaching the switch; majordomo owns DSN resolution there, and the PR description confirms llama-swap:///llama-swaps:// are already understood by majordomo. No gadfly-side correctness gap.

  • Test coverage (model_test.go:53–65): The new loop tests "llama-swap", "llama-swaps", and "llamaswaps" against endpointProvider. The original "llamaswap" is covered by the pre-existing "llamaswap registers under its name" / "llamaswap without token" tests. All four spellings are exercised. No loop-variable capture hazard: go.mod declares go 1.26.2, where per-iteration scoping applies.

  • Error messages: Both default-case messages were updated and neither is misleading — they guide users toward the canonical hyphenated form, which is fine.

The logic is internally consistent and the semantics match the stated intent.

🧯 Error handling & edge cases — No material issues found

No material issues found

Reviewed through the error-handling & edge-cases lens.

  • resolveModel new cases (model.go:80): The three new spellings fall into identical code as the original "llamaswap" — same opts-building, same llamaswap.WithBaseURL(baseURL) + optional WithToken, same llamaswap.New(...).Model(model) return. No new error paths, no new nil/empty risks. The GADFLY_BASE_URL == "" early-return at line 64 guards all four spellings consistently. Verified by reading the full switch.

  • endpointProvider new cases (model.go:181): Same pattern. The existing pre-condition checks (len(parts) < 2 → error, baseURL == "" → error) cover all four spellings uniformly. Verified that no spelling bypasses these guards.

  • Test loop (model_test.go:38–44): Tests the three newly-added spellings in endpointProvider. Original "llamaswap" is already covered by the named subtests above (lines 27–36), so coverage is complete across all four spellings. No goroutine capture or global-state concern — loop is sequential, endpointProvider doesn't call RegisterProvider.

  • resolveModel with no base URL: All four spellings fall through to majordomo.Parse(buildSpec(provider, model)) at line 65. "llama-swap/model" as a majordomo spec behaves the same as the pre-existing "llamaswap/model" — both rely on the caller having an LLM_* DSN or alias configured. No regression.

Nothing in the unhappy paths introduced by this diff is materially different from the existing "llamaswap" handling.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 5m 56s

<!-- gadfly-review:ollama:claude-code/sonnet --> ### 🪰 Gadfly review — `claude-code/sonnet` (claude-code) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> **Verdict: No material issues found** The change adds four provider-name spellings to two `switch` statements in `endpointProvider` and `resolveModel`, then bumps majordomo. I verified the full code in both functions. - **Input sources are operator-controlled env vars only.** `GADFLY_PROVIDER`, `GADFLY_BASE_URL`, `GADFLY_API_KEY`, and `GADFLY_ENDPOINT_*` all come from the container environment set by whoever deploys Gadfly — not from PR content or any untrusted input. No new tainted-input path is introduced. - **The new cases are mechanically identical to the pre-existing `"llamaswap"` case.** `llamaswap.WithBaseURL(baseURL)` / `llamaswap.WithToken(apiKey)` calls are unchanged; only the matching strings expanded. There is no new code executing, no new URL construction, and no new credential handling. - **`endpointProvider` raw-string parsing** (`strings.SplitN(raw, "|", 3)`) is pre-existing and already used for all other providers. A `|`-separated format with a fixed max-split of 3 prevents any injection of extra fields. No change here. - **API keys are not logged.** The only `fmt.Fprintln(os.Stderr, ...)` at line 48 prints the error string from `endpointProvider`, which never includes the key value — verified at `model.go:207` and `model.go:216`. - **Dependency bump:** `go.sum` hash integrity is the normal Go module trust mechanism. No code-level concern from the diff; I cannot inspect the private module's internals, but that is outside this lens's purview and no evidence of concern exists in the diff. Nothing in this change widens the security perimeter. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> **No material issues found** Verified by reading `model.go` and `model_test.go` in full. - **Switch consistency** (`model.go:83`, `model.go:226`): Both `resolveModel()` and `endpointProvider()` were updated with the same four spellings (`"llamaswap"`, `"llamaswaps"`, `"llama-swap"`, `"llama-swaps"`). The two switch arms are in sync — no spelling is handled in one but not the other. - **Semantics of `GADFLY_BASE_URL` path** (`model.go:83`): When `GADFLY_BASE_URL` is set, the scheme is determined entirely by the URL itself (e.g. `http://` vs `https://`), so conflating the TLS variants (`llamaswaps`/`llama-swaps`) with the plaintext ones in a single case arm is correct behavior, as the in-code comment accurately explains. - **`baseURL == ""` path**: All four spellings pass through `buildSpec()` and then `majordomo.Parse()` before ever reaching the switch; majordomo owns DSN resolution there, and the PR description confirms `llama-swap://`/`llama-swaps://` are already understood by majordomo. No gadfly-side correctness gap. - **Test coverage** (`model_test.go:53–65`): The new loop tests `"llama-swap"`, `"llama-swaps"`, and `"llamaswaps"` against `endpointProvider`. The original `"llamaswap"` is covered by the pre-existing `"llamaswap registers under its name"` / `"llamaswap without token"` tests. All four spellings are exercised. No loop-variable capture hazard: `go.mod` declares `go 1.26.2`, where per-iteration scoping applies. - **Error messages**: Both default-case messages were updated and neither is misleading — they guide users toward the canonical hyphenated form, which is fine. The logic is internally consistent and the semantics match the stated intent. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> **No material issues found** Reviewed through the error-handling & edge-cases lens. - **`resolveModel` new cases (model.go:80)**: The three new spellings fall into identical code as the original `"llamaswap"` — same opts-building, same `llamaswap.WithBaseURL(baseURL)` + optional `WithToken`, same `llamaswap.New(...).Model(model)` return. No new error paths, no new nil/empty risks. The `GADFLY_BASE_URL == ""` early-return at line 64 guards all four spellings consistently. Verified by reading the full switch. - **`endpointProvider` new cases (model.go:181)**: Same pattern. The existing pre-condition checks (`len(parts) < 2` → error, `baseURL == ""` → error) cover all four spellings uniformly. Verified that no spelling bypasses these guards. - **Test loop (model_test.go:38–44)**: Tests the three newly-added spellings in `endpointProvider`. Original `"llamaswap"` is already covered by the named subtests above (lines 27–36), so coverage is complete across all four spellings. No goroutine capture or global-state concern — loop is sequential, `endpointProvider` doesn't call `RegisterProvider`. - **`resolveModel` with no base URL**: All four spellings fall through to `majordomo.Parse(buildSpec(provider, model))` at line 65. `"llama-swap/model"` as a majordomo spec behaves the same as the pre-existing `"llamaswap/model"` — both rely on the caller having an `LLM_*` DSN or alias configured. No regression. Nothing in the unhappy paths introduced by this diff is materially different from the existing `"llamaswap"` handling. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 5m 56s</sub>

🪰 Gadfly review — minimax-m3:cloud (ollama-cloud)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

VERDICT: No material issues found

Reviewed through the 🔒 Security lens only. The change is purely a provider-name spelling expansion and a dependency bump — there is no new authn/authz, injection surface, deserialization, SSRF, secret handling, or input-validation boundary introduced.

Notes verified by reading cmd/gadfly/model.go (lines 43-261), cmd/gadfly/model_test.go (lines 5-69), and grepping for llamaswap|llama-swap|llamaswaps:

  • No new secret/credential leakage. The GADFLY_API_KEY (line 60) and the per-endpoint key parsed from GADFLY_ENDPOINT_* (lines 214-217) are already plumbed into llamaswap.WithToken/openai.WithAPIKey/etc. The PR doesn't add new code paths that echo or log these values; the existing key-handling is unchanged.
  • No new input-validation gap. endpointProvider already requires a provider|base-url[|key] shape and rejects empty URLs (model.go:209-220); adding more accepted aliases to the switch (model.go:229) does not weaken that validation. The new alias names flow straight into the same llamaswap.New(...).WithBaseURL(baseURL) call, where baseURL was already validated non-empty.
  • No new injection surface. The base URL is passed through as a string into the provider constructor — no shell, SQL, template, or path concatenation is introduced. The existing strings.SplitN(raw, "|", 3) parser is unchanged.
  • No SSRF or untrusted-URL expansion introduced. The same GADFLY_BASE_URL and per-endpoint URL semantics already existed; alias expansion does not alter which strings reach WithBaseURL.
  • No unsafe deserialization or insecure default. The new aliases default to the same llamaswap provider with the same options; nothing becomes opt-in to a weaker mode.
  • Error-message updates (lines 111, 259) only reword the help text — no information-disclosure concern beyond what was already present.

The majordomo version bump (go.mod) is a transitive dependency upgrade outside the gadfly call surface I can audit from this repo's checked-out state; nothing in the diff itself propagates tainted input to new code paths.

Outside my lens: nothing severe spotted that another lens would obviously miss; this PR is a cosmetic alias-expansion + dep bump.

🎯 Correctness — No material issues found

VERDICT: No material issues found

Verification summary:

  • cmd/gadfly/model.go:83 (the resolveModel override switch) now accepts "llamaswap", "llamaswaps", "llama-swap", "llama-swaps", all routing to the identical llamaswap.New(opts...).Model(model) construction with WithBaseURL(baseURL) + optional WithToken. Read full switch (lines 70-112). The comment correctly notes that with an explicit GADFLY_BASE_URL the scheme is whatever the URL says, so collapsing the four spellings into one branch is semantically correct.
  • cmd/gadfly/model.go:229 (endpointProvider switch) does the same. Read lines 222-258 — verified all four spellings produce an equivalent llamaswap.New(WithName, WithBaseURL, WithToken) provider.
  • cmd/gadfly/model_test.go:49-61 adds loop-driven tests for the three previously-untested spellings (llama-swap, llama-swaps, llamaswaps); the fourth (llamaswap) was already covered by the pre-existing subtests at lines 35-48. Read the whole test file — coverage of all four aliases is complete.
  • Error messages at model.go:111 and model.go:259 now mention llama-swap. Note these only fire in the default branch when the provider is not recognized, so the four new aliases never hit them — the spelling-in-the-error concern doesn't apply.
  • No constants, formulas, units, or thresholds are touched by this PR — correctness lens has nothing numeric to re-derive.
  • Worker/selector paths (resolveWorkerModel, resolveSelectorModel in auto.go:34) both go through majordomo.Parse and don't touch the override switch, so no parallel alias list is needed there. Verified at cmd/gadfly/main.go:167 and cmd/gadfly/auto.go:43.
  • go.mod/go.sum majordomo bump is a dependency-version change only; no correctness risk visible at the call sites used here.

Minor observation (not material): the resolveModel override switch (line 83) has no direct unit test for its new alias cases — coverage is only via the structurally identical endpointProvider path. Logic is trivial enough that this is a coverage nit, not a correctness defect.

🧯 Error handling & edge cases — No material issues found

VERDICT: No material issues found

Through the error-handling & edge-cases lens:

  • Verified cmd/gadfly/model.go:83 and cmd/gadfly/model.go:229 widen the switch consistently to all four spellings (llamaswap, llamaswaps, llama-swap, llama-swaps), both funneling into the same llamaswap.New(opts...).Model(model) / …Provider path. No new failure mode or panic surface is introduced — apiKey/key are guarded by if … != "" and baseURL is trimmed-and-checked at cmd/gadfly/model.go:218-220.
  • Verified cmd/gadfly/model.go:207-220 still rejects malformed entries (len(parts) < 2, empty baseURL) and the default: arm at model.go:111/model.go:259 returns a descriptive error rather than nil. No swallowed errors, no missing cleanup/rollback on the new paths.
  • Verified the new cmd/gadfly/model_test.go:51-61 test loop exercises each spelling through endpointProvider and asserts p.Name() == "ls"; the existing "rejects …" loop still covers empty/garbage inputs.
  • The existing pre-PR flows for empty GADFLY_MODEL (model.go:52-54), unset GADFLY_PROVIDER falling back to defaultProvider (model.go:56-58), and the no-GADFLY_BASE_URL delegation to majordomo.Parse (model.go:65-67) are untouched.

Minor non-blocking observations (not in my lane enough to escalate, noting only for completeness):

  • model.go:111 error message lists llama-swap but model.go:259 says llama-swap(s); cosmetic, no behavioral impact.
  • The new test only covers the spellings through endpointProvider, not through resolveModel's switch at model.go:83. Same constructor either way, so not a defect — just a coverage gap if you wanted symmetric tests.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 52s

<!-- gadfly-review:ollama:minimax-m3:cloud --> ### 🪰 Gadfly review — `minimax-m3:cloud` (ollama-cloud) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> ## VERDICT: No material issues found Reviewed through the 🔒 Security lens only. The change is purely a provider-name spelling expansion and a dependency bump — there is no new authn/authz, injection surface, deserialization, SSRF, secret handling, or input-validation boundary introduced. Notes verified by reading `cmd/gadfly/model.go` (lines 43-261), `cmd/gadfly/model_test.go` (lines 5-69), and grepping for `llamaswap|llama-swap|llamaswaps`: - **No new secret/credential leakage.** The `GADFLY_API_KEY` (line 60) and the per-endpoint `key` parsed from `GADFLY_ENDPOINT_*` (lines 214-217) are already plumbed into `llamaswap.WithToken`/`openai.WithAPIKey`/etc. The PR doesn't add new code paths that echo or log these values; the existing key-handling is unchanged. - **No new input-validation gap.** `endpointProvider` already requires a `provider|base-url[|key]` shape and rejects empty URLs (`model.go:209-220`); adding more accepted aliases to the switch (`model.go:229`) does not weaken that validation. The new alias names flow straight into the same `llamaswap.New(...).WithBaseURL(baseURL)` call, where baseURL was already validated non-empty. - **No new injection surface.** The base URL is passed through as a string into the provider constructor — no shell, SQL, template, or path concatenation is introduced. The existing `strings.SplitN(raw, "|", 3)` parser is unchanged. - **No SSRF or untrusted-URL expansion introduced.** The same `GADFLY_BASE_URL` and per-endpoint URL semantics already existed; alias expansion does not alter which strings reach `WithBaseURL`. - **No unsafe deserialization or insecure default.** The new aliases default to the same `llamaswap` provider with the same options; nothing becomes opt-in to a weaker mode. - **Error-message updates** (lines 111, 259) only reword the help text — no information-disclosure concern beyond what was already present. The majordomo version bump (`go.mod`) is a transitive dependency upgrade outside the gadfly call surface I can audit from this repo's checked-out state; nothing in the diff itself propagates tainted input to new code paths. Outside my lens: nothing severe spotted that another lens would obviously miss; this PR is a cosmetic alias-expansion + dep bump. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> **VERDICT: No material issues found** Verification summary: - **`cmd/gadfly/model.go:83`** (the `resolveModel` override switch) now accepts `"llamaswap", "llamaswaps", "llama-swap", "llama-swaps"`, all routing to the identical `llamaswap.New(opts...).Model(model)` construction with `WithBaseURL(baseURL)` + optional `WithToken`. Read full switch (lines 70-112). The comment correctly notes that with an explicit `GADFLY_BASE_URL` the scheme is whatever the URL says, so collapsing the four spellings into one branch is semantically correct. - **`cmd/gadfly/model.go:229`** (`endpointProvider` switch) does the same. Read lines 222-258 — verified all four spellings produce an equivalent `llamaswap.New(WithName, WithBaseURL, WithToken)` provider. - **`cmd/gadfly/model_test.go:49-61`** adds loop-driven tests for the three previously-untested spellings (`llama-swap`, `llama-swaps`, `llamaswaps`); the fourth (`llamaswap`) was already covered by the pre-existing subtests at lines 35-48. Read the whole test file — coverage of all four aliases is complete. - **Error messages at `model.go:111` and `model.go:259`** now mention `llama-swap`. Note these only fire in the `default` branch when the provider is *not* recognized, so the four new aliases never hit them — the spelling-in-the-error concern doesn't apply. - **No constants, formulas, units, or thresholds** are touched by this PR — correctness lens has nothing numeric to re-derive. - **Worker/selector paths** (`resolveWorkerModel`, `resolveSelectorModel` in `auto.go:34`) both go through `majordomo.Parse` and don't touch the override switch, so no parallel alias list is needed there. Verified at `cmd/gadfly/main.go:167` and `cmd/gadfly/auto.go:43`. - **`go.mod`/`go.sum` majordomo bump** is a dependency-version change only; no correctness risk visible at the call sites used here. Minor observation (not material): the `resolveModel` override switch (line 83) has no direct unit test for its new alias cases — coverage is only via the structurally identical `endpointProvider` path. Logic is trivial enough that this is a coverage nit, not a correctness defect. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> **VERDICT: No material issues found** Through the error-handling & edge-cases lens: - Verified `cmd/gadfly/model.go:83` and `cmd/gadfly/model.go:229` widen the switch consistently to all four spellings (`llamaswap`, `llamaswaps`, `llama-swap`, `llama-swaps`), both funneling into the same `llamaswap.New(opts...).Model(model)` / `…Provider` path. No new failure mode or panic surface is introduced — `apiKey`/`key` are guarded by `if … != ""` and `baseURL` is trimmed-and-checked at `cmd/gadfly/model.go:218-220`. - Verified `cmd/gadfly/model.go:207-220` still rejects malformed entries (`len(parts) < 2`, empty `baseURL`) and the `default:` arm at `model.go:111`/`model.go:259` returns a descriptive error rather than nil. No swallowed errors, no missing cleanup/rollback on the new paths. - Verified the new `cmd/gadfly/model_test.go:51-61` test loop exercises each spelling through `endpointProvider` and asserts `p.Name() == "ls"`; the existing "rejects …" loop still covers empty/garbage inputs. - The existing pre-PR flows for empty `GADFLY_MODEL` (`model.go:52-54`), unset `GADFLY_PROVIDER` falling back to `defaultProvider` (`model.go:56-58`), and the no-`GADFLY_BASE_URL` delegation to `majordomo.Parse` (`model.go:65-67`) are untouched. Minor non-blocking observations (not in my lane enough to escalate, noting only for completeness): - `model.go:111` error message lists `llama-swap` but `model.go:259` says `llama-swap(s)`; cosmetic, no behavioral impact. - The new test only covers the spellings through `endpointProvider`, not through `resolveModel`'s switch at `model.go:83`. Same constructor either way, so not a defect — just a coverage gap if you wanted symmetric tests. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 52s</sub>

🪰 Gadfly review — glm-5.1:cloud (ollama-cloud)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

VERDICT: No material issues found

  • Alias expansion is a strict whitelist: All four spellings (llamaswap, llamaswaps, llama-swap, llama-swaps) fall through to the same well-bounded case branch. Unrecognized providers still hit the default error path. No injection or authz gap introduced.
  • Secret/API-key handling unchanged: GADFLY_API_KEY and the |key segment from GADFLY_ENDPOINT_* are passed to llamaswap.WithToken the same way every other provider passes keys — no new credential exposure.
  • No URL validation is pre-existing, not new: Base URLs are used verbatim across all providers (lines 72–109, 224–257). Adding more aliases to the same pattern doesn't widen attack surface. The "swaps = TLS" semantic exists only in majordomo's DSN parser, which this diff doesn't touch; the explicit-base-URL path correctly documents that "the scheme is whatever the URL says" (line 87).
🎯 Correctness — No material issues found

VERDICT: No material issues found

The change is a straightforward alias expansion that is consistent and correct:

  • Both switch statements (resolveModel at line 83, endpointProvider at line 229) accept the same four spellings (llamaswap, llamaswaps, llama-swap, llama-swaps), all routing to the same llamaswap.New() path.
  • All four spellings have test coverage: the pre-existing llamaswap tests plus the new loop covering llama-swap, llama-swaps, and llamaswaps.
  • The comment at line 87 ("With an explicit GADFLY_BASE_URL the scheme is whatever the URL says, so all behave the same") is semantically correct: the HTTP/HTTPS distinction between llama-swap/llama-swaps only matters in majordomo DSN schemes (llama-swap:// vs llama-swaps://), not when an explicit base URL overrides the scheme.
  • Error messages updated in both default branches to reflect the new canonical spelling (llama-swap(s)).
  • modelProvider() returns the raw environment string and is used for exact-key matching in concurrency overrides. A user who sets GADFLY_PROVIDER=llama-swap must write llama-swap=3 (not llamaswap=3) in their concurrency map, but this is pre-existing exact-match semantics, not a bug introduced here.
🧯 Error handling & edge cases — No material issues found

VERDICT: No material issues found

The change adds alias spellings (llama-swap, llama-swaps, llamaswaps, llamaswap) to two existing switch statements in cmd/gadfly/model.go (resolveModel line 83, endpointProvider line 229) and updates error message strings. Through the error-handling / edge-case lens:

  • Both switch sites have identical case lists — no mismatch where one alias works in one path but not the other.
  • Existing validation (len(parts) < 2, baseURL == "") still applies uniformly to all spellings; no new input shapes are introduced.
  • Empty/nil guard paths (empty baseURL, empty key, missing pipe delimiter) are unchanged and still cover all aliases.
  • The modelProvider() function returns the raw env value, which is only used for concurrency-map lookups — no new nil/zero/negative or boundary concern.
  • Test coverage: the new loop tests llama-swap, llama-swaps, and llamaswaps; the pre-existing test covers llamaswap — all four aliases are exercised.

No swallowed errors, missing cleanups, panics on bad input, or unhandled edge cases introduced.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 14s

<!-- gadfly-review:ollama:glm-5.1:cloud --> ### 🪰 Gadfly review — `glm-5.1:cloud` (ollama-cloud) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> VERDICT: No material issues found - **Alias expansion is a strict whitelist**: All four spellings (`llamaswap`, `llamaswaps`, `llama-swap`, `llama-swaps`) fall through to the same well-bounded `case` branch. Unrecognized providers still hit the `default` error path. No injection or authz gap introduced. - **Secret/API-key handling unchanged**: `GADFLY_API_KEY` and the `|key` segment from `GADFLY_ENDPOINT_*` are passed to `llamaswap.WithToken` the same way every other provider passes keys — no new credential exposure. - **No URL validation is pre-existing, not new**: Base URLs are used verbatim across all providers (lines 72–109, 224–257). Adding more aliases to the same pattern doesn't widen attack surface. The "swaps = TLS" semantic exists only in majordomo's DSN parser, which this diff doesn't touch; the explicit-base-URL path correctly documents that "the scheme is whatever the URL says" (line 87). </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> **VERDICT: No material issues found** The change is a straightforward alias expansion that is consistent and correct: - **Both switch statements** (`resolveModel` at line 83, `endpointProvider` at line 229) accept the same four spellings (`llamaswap`, `llamaswaps`, `llama-swap`, `llama-swaps`), all routing to the same `llamaswap.New()` path. - **All four spellings have test coverage**: the pre-existing `llamaswap` tests plus the new loop covering `llama-swap`, `llama-swaps`, and `llamaswaps`. - **The comment** at line 87 ("With an explicit `GADFLY_BASE_URL` the scheme is whatever the URL says, so all behave the same") is semantically correct: the HTTP/HTTPS distinction between `llama-swap`/`llama-swaps` only matters in majordomo DSN schemes (`llama-swap://` vs `llama-swaps://`), not when an explicit base URL overrides the scheme. - **Error messages** updated in both `default` branches to reflect the new canonical spelling (`llama-swap(s)`). - **`modelProvider()`** returns the raw environment string and is used for exact-key matching in concurrency overrides. A user who sets `GADFLY_PROVIDER=llama-swap` must write `llama-swap=3` (not `llamaswap=3`) in their concurrency map, but this is pre-existing exact-match semantics, not a bug introduced here. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> **VERDICT: No material issues found** The change adds alias spellings (`llama-swap`, `llama-swaps`, `llamaswaps`, `llamaswap`) to two existing `switch` statements in `cmd/gadfly/model.go` (`resolveModel` line 83, `endpointProvider` line 229) and updates error message strings. Through the error-handling / edge-case lens: - Both switch sites have **identical** case lists — no mismatch where one alias works in one path but not the other. - Existing validation (`len(parts) < 2`, `baseURL == ""`) still applies uniformly to all spellings; no new input shapes are introduced. - Empty/nil guard paths (empty `baseURL`, empty `key`, missing pipe delimiter) are unchanged and still cover all aliases. - The `modelProvider()` function returns the raw env value, which is only used for concurrency-map lookups — no new nil/zero/negative or boundary concern. - Test coverage: the new loop tests `llama-swap`, `llama-swaps`, and `llamaswaps`; the pre-existing test covers `llamaswap` — all four aliases are exercised. No swallowed errors, missing cleanups, panics on bad input, or unhandled edge cases introduced. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 14s</sub>

🪰 Gadfly review — claude-code/opus (claude-code)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

Investigation complete. The changed code only adds additional string cases to provider-name switch statements, plus doc/test/dependency updates. I traced the data flow to confirm there's no security-relevant change.

VERDICT: No material issues found

Findings (Security lens):

  • No new tainted-input surface. The only behavioral change is widening switch provider cases to accept llama-swap/llama-swaps/llamaswaps alongside llamaswap, in both resolveModel (cmd/gadfly/model.go:83) and endpointProvider (model.go:229). All inputs feeding these switches — GADFLY_PROVIDER, GADFLY_BASE_URL, GADFLY_API_KEY, GADFLY_ENDPOINT_* — are operator-supplied environment config (verified: read via os.Getenv/os.Environ at model.go:51-60,181-185), not PR/attacker-controlled data. No injection, SSRF, or path-traversal vector is introduced or widened.

  • Credential handling unchanged. Token/key plumbing (llamaswap.WithToken, WithBaseURL) is identical to the pre-existing llamaswap branch; the new cases reuse the same option-building, so no new secret-leakage path. Keys still come only from explicit env (apiKey, or the optional 3rd |key field at model.go:215-216). Verified by reading both branches.

  • Dependency bump is hash-pinned. go.mod/go.sum move majordomo to …225659-aa25b2c33462 with both h1: and /go.mod hashes updated, so the module is integrity-checked at build (the go.mod hash is even unchanged from the prior version). Nothing in this diff alters how untrusted data reaches majordomo. I cannot review the upstream module contents from here — that's an inherent trust assumption, not a flaw in this diff.

Nothing in the security lane is materially wrong here.

🎯 Correctness — No material issues found

I've verified the change against the actual code. Here's my correctness review.

VERDICT: No material issues found

The change is purely additive — three new spellings (llamaswaps, llama-swap, llama-swaps) added to the two provider switch statements that previously matched only llamaswap, plus doc/error-string and README updates. I verified the following:

  • Both switch sites are updated consistently. cmd/gadfly/model.go:83 (override path in resolveModel) and cmd/gadfly/model.go:229 (endpointProvider) both gain the same four-spelling case. grep across all .go files confirms these are the only places provider strings are matched against llamaswap — no other comparator (e.g. in auto.go, modelProvider, delegate code) was left checking the old single spelling, so there's no spelling-divergence bug.
  • Override-path behavior is correct. Both branches feed baseURL verbatim into llamaswap.WithBaseURL, so all four spellings produce identical behavior. The inline comment at model.go:84-87 correctly states that with an explicit GADFLY_BASE_URL the URL's own scheme wins and the http/https spelling distinction is moot — that matches the code (the scheme is never re-derived from the provider word). No false implication of TLS enforcement.
  • Test correctness. model_test.go:51-61 loops {"llama-swap","llama-swaps","llamaswaps"} through endpointProvider("ls", name+"|https://swap.lan:8080|tok"); the existing cases at lines 35-48 cover llamaswap, so all four spellings are exercised. SplitN(raw,"|",3) yields the expected (provider, baseURL, key) triple and WithName("ls") makes the p.Name()=="ls" assertion valid. Verified by tracing endpointProvider.

Notes / things I could not verify from here (not findings):

  • The PR's claim that the LLM_* DSN path (llama-swap://, llama-swaps://) resolves via majordomo.Parse, and the comment's mapping (llama-swap=http / llama-swaps=https), depend on the bumped majordomo module. The module cache is outside the sandboxed working directory, so I could not inspect it. These are not changed by this diff; gadfly's no-baseURL path simply hands buildSpec(provider, model) to majordomo.Parse (model.go:66), so correctness there rests entirely on majordomo.
  • Minor, and outside the correctness lens (maintainability): the README row (README.md:69) now advertises only the hyphenated llama-swap/llama-swaps as GADFLY_PROVIDER values, while the code still accepts the un-hyphenated llamaswap/llamaswaps. Not a behavior bug — just an under-documentation of still-supported spellings.

Nothing in the correctness lens is materially wrong.

🧯 Error handling & edge cases — No material issues found

I've read the full model.go and the diff. This is a purely additive change — it widens existing switch cases to accept more provider spellings and updates doc/error strings. Through my lens (error handling & edge cases), I checked the unhappy paths:

  • resolveModel (model.go:83) and endpointProvider (model.go:229) — the new spellings are added to existing cases that already construct llamaswap with the same option pattern. No new error path, no swallowed error.
  • Trimming/empty handlingprovider is TrimSpaced in both call sites (model.go:55, model.go:212), and baseURL empty-check (model.go:218) is unchanged and still guards the endpoint path.
  • default error branches (model.go:111, model.go:259) — only the human-readable string changed; the failure behavior (return error, don't panic) is intact.
  • Edge cases — no nil/empty-collection/overflow/boundary surface is introduced; the change is string-match additions only. Case-sensitivity (e.g. Llama-Swap) is unchanged pre-existing behavior, not a regression here.

VERDICT: No material issues found

  • No new error-handling or edge-case surface is introduced by this diff. The change only adds provider-name aliases to existing switch arms and updates doc comments / error message wording; all error returns, trimming, and empty-input guards are unchanged and remain correct (verified by reading cmd/gadfly/model.go:43-261).

(Anything about whether the new llama-swap(s) spellings actually map to majordomo's intended http-vs-https DSN semantics is a correctness concern, which falls outside my lens.)

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 37s

<!-- gadfly-review:ollama:claude-code/opus --> ### 🪰 Gadfly review — `claude-code/opus` (claude-code) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> Investigation complete. The changed code only adds additional string cases to provider-name `switch` statements, plus doc/test/dependency updates. I traced the data flow to confirm there's no security-relevant change. VERDICT: No material issues found Findings (Security lens): - **No new tainted-input surface.** The only behavioral change is widening `switch provider` cases to accept `llama-swap`/`llama-swaps`/`llamaswaps` alongside `llamaswap`, in both `resolveModel` (`cmd/gadfly/model.go:83`) and `endpointProvider` (`model.go:229`). All inputs feeding these switches — `GADFLY_PROVIDER`, `GADFLY_BASE_URL`, `GADFLY_API_KEY`, `GADFLY_ENDPOINT_*` — are operator-supplied environment config (verified: read via `os.Getenv`/`os.Environ` at `model.go:51-60,181-185`), not PR/attacker-controlled data. No injection, SSRF, or path-traversal vector is introduced or widened. - **Credential handling unchanged.** Token/key plumbing (`llamaswap.WithToken`, `WithBaseURL`) is identical to the pre-existing `llamaswap` branch; the new cases reuse the same option-building, so no new secret-leakage path. Keys still come only from explicit env (`apiKey`, or the optional 3rd `|key` field at `model.go:215-216`). Verified by reading both branches. - **Dependency bump is hash-pinned.** `go.mod`/`go.sum` move majordomo to `…225659-aa25b2c33462` with both `h1:` and `/go.mod` hashes updated, so the module is integrity-checked at build (the `go.mod` hash is even unchanged from the prior version). Nothing in this diff alters how untrusted data reaches majordomo. I cannot review the upstream module contents from here — that's an inherent trust assumption, not a flaw in this diff. Nothing in the security lane is materially wrong here. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> I've verified the change against the actual code. Here's my correctness review. ## VERDICT: No material issues found The change is purely additive — three new spellings (`llamaswaps`, `llama-swap`, `llama-swaps`) added to the two `provider` switch statements that previously matched only `llamaswap`, plus doc/error-string and README updates. I verified the following: - **Both switch sites are updated consistently.** `cmd/gadfly/model.go:83` (override path in `resolveModel`) and `cmd/gadfly/model.go:229` (`endpointProvider`) both gain the same four-spelling case. `grep` across all `.go` files confirms these are the *only* places provider strings are matched against `llamaswap` — no other comparator (e.g. in `auto.go`, `modelProvider`, delegate code) was left checking the old single spelling, so there's no spelling-divergence bug. - **Override-path behavior is correct.** Both branches feed `baseURL` verbatim into `llamaswap.WithBaseURL`, so all four spellings produce identical behavior. The inline comment at `model.go:84-87` correctly states that with an explicit `GADFLY_BASE_URL` the URL's own scheme wins and the http/https spelling distinction is moot — that matches the code (the scheme is never re-derived from the provider word). No false implication of TLS enforcement. - **Test correctness.** `model_test.go:51-61` loops `{"llama-swap","llama-swaps","llamaswaps"}` through `endpointProvider("ls", name+"|https://swap.lan:8080|tok")`; the existing cases at lines 35-48 cover `llamaswap`, so all four spellings are exercised. `SplitN(raw,"|",3)` yields the expected `(provider, baseURL, key)` triple and `WithName("ls")` makes the `p.Name()=="ls"` assertion valid. Verified by tracing `endpointProvider`. Notes / things I could not verify from here (not findings): - The PR's claim that the `LLM_*` DSN path (`llama-swap://`, `llama-swaps://`) resolves via `majordomo.Parse`, and the comment's mapping (`llama-swap`=http / `llama-swaps`=https), depend on the bumped majordomo module. The module cache is outside the sandboxed working directory, so I could not inspect it. These are not changed by this diff; gadfly's no-`baseURL` path simply hands `buildSpec(provider, model)` to `majordomo.Parse` (`model.go:66`), so correctness there rests entirely on majordomo. - Minor, and outside the correctness lens (maintainability): the README row (`README.md:69`) now advertises only the hyphenated `llama-swap`/`llama-swaps` as `GADFLY_PROVIDER` values, while the code still accepts the un-hyphenated `llamaswap`/`llamaswaps`. Not a behavior bug — just an under-documentation of still-supported spellings. Nothing in the correctness lens is materially wrong. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> I've read the full `model.go` and the diff. This is a purely additive change — it widens existing `switch` cases to accept more provider spellings and updates doc/error strings. Through my lens (error handling & edge cases), I checked the unhappy paths: - **`resolveModel` (model.go:83)** and **`endpointProvider` (model.go:229)** — the new spellings are added to existing cases that already construct `llamaswap` with the same option pattern. No new error path, no swallowed error. - **Trimming/empty handling** — `provider` is `TrimSpace`d in both call sites (model.go:55, model.go:212), and `baseURL` empty-check (model.go:218) is unchanged and still guards the endpoint path. - **`default` error branches** (model.go:111, model.go:259) — only the human-readable string changed; the failure behavior (return error, don't panic) is intact. - **Edge cases** — no nil/empty-collection/overflow/boundary surface is introduced; the change is string-match additions only. Case-sensitivity (e.g. `Llama-Swap`) is unchanged pre-existing behavior, not a regression here. --- **VERDICT: No material issues found** - No new error-handling or edge-case surface is introduced by this diff. The change only adds provider-name aliases to existing `switch` arms and updates doc comments / error message wording; all error returns, trimming, and empty-input guards are unchanged and remain correct (verified by reading `cmd/gadfly/model.go:43-261`). (Anything about whether the *new* `llama-swap(s)` spellings actually map to majordomo's intended http-vs-https DSN semantics is a correctness concern, which falls outside my lens.) </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 37s</sub>

🪰 Gadfly review — glm-5.2:cloud (ollama-cloud)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

VERDICT: No material issues found

  • Verified cmd/gadfly/model.go (both resolveModel at line 83 and endpointProvider at line 229). The change only widens an exact-match switch case set for the provider string to include llama-swap/llama-swaps/llamaswap/llamaswaps, all routing to the same llamaswap.New(...) constructor with identical option handling. No new code paths, no new parsing, no new trust boundary.
  • The provider string is sourced solely from operator-controlled env vars (GADFLY_PROVIDER, GADFLY_ENDPOINT_*), not from untrusted input, so expanding accepted spellings introduces no injection/authz surface. baseURL/key continue to be passed through verbatim — consistent with every other provider case and pre-existing behavior.
  • No lowercasing/normalization gap is introduced: the value is TrimSpace-only (lines 55, 212), matching the prior case-sensitive compare used for all other providers; the added spellings are exact and lowercase, mirroring the existing llamaswap handling. No aliasing ambiguity or privilege-routing concern results.

Nothing in the security lens is materially affected by this change.

🎯 Correctness — No material issues found

VERDICT: No material issues found

  • Verified cmd/gadfly/model.go:83 and :229 — both switches now route all four spellings (llamaswap, llamaswaps, llama-swap, llama-swaps) to the identical llamaswap.New(...) construction. The behavior is purely additive aliasing; no semantic divergence between spellings in the GADFLY_BASE_URL override path (the URL's own scheme governs http/https, as the comment correctly states).
  • Checked modelProvider() (model.go:146) and its callers (main.go:282, emit.go:105): it returns the raw GADFLY_PROVIDER/model-prefix verbatim and is not expected to normalize aliases — this matches the pre-existing pattern where ollama vs ollama-cloud are distinct lanes. The new spellings introduce no regression here; a user keying a concurrency override must simply use the same spelling they set, same as before.
  • Verified the new test (model_test.go:49-61) exercises three of the four new aliases via endpointProvider; the original llamaswap is covered by the existing cases at lines 35–48. No gap that affects correctness.
  • The go.mod/go.sum bump is a straight version hash change with matching h1:/go.mod lines; no correctness dimension to check beyond that.

Nothing in the correctness lane is materially wrong.

🧯 Error handling & edge cases — No material issues found

Verdict: No material issues found

The change is purely additive within two switch statements (resolveModel and endpointProvider), expanding the llamaswap case to accept four spellings. Through the error-handling / edge-case lens:

  • Unknown-provider path preserved. Both default: branches still return a non-nil error, so a bad GADFLY_PROVIDER / endpoint provider string still fails cleanly rather than falling through. Verified at cmd/gadfly/model.go:111 and :259.
  • Empty/malformed input unchanged. endpointProvider still guards len(parts) < 2 (:209) and empty base URL (:218); the "" and "ollama" (no-pipe) cases in the reject test table (model_test.go:62) continue to exercise these and are unaffected by the new aliases.
  • No new nil/zero/overflow surface. The new case bodies reuse the existing llamaswap.Option construction path; no new slicing, arithmetic, or dereferences introduced. model is guaranteed non-empty upstream in resolveModel (:52), and endpointProvider doesn't take a model.
  • Alias test loop (model_test.go:51) correctly asserts both no-error and Name(), covering the happy path for the three new spellings (the original llamaswap is covered by the earlier subtests at :35/:44).

Nothing in the error-handling/edge-case lane is materially wrong here.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 26s

<!-- gadfly-review:ollama:glm-5.2:cloud --> ### 🪰 Gadfly review — `glm-5.2:cloud` (ollama-cloud) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> VERDICT: No material issues found - Verified `cmd/gadfly/model.go` (both `resolveModel` at line 83 and `endpointProvider` at line 229). The change only widens an exact-match `switch` case set for the provider string to include `llama-swap`/`llama-swaps`/`llamaswap`/`llamaswaps`, all routing to the same `llamaswap.New(...)` constructor with identical option handling. No new code paths, no new parsing, no new trust boundary. - The provider string is sourced solely from operator-controlled env vars (`GADFLY_PROVIDER`, `GADFLY_ENDPOINT_*`), not from untrusted input, so expanding accepted spellings introduces no injection/authz surface. `baseURL`/`key` continue to be passed through verbatim — consistent with every other provider case and pre-existing behavior. - No lowercasing/normalization gap is introduced: the value is `TrimSpace`-only (lines 55, 212), matching the prior case-sensitive compare used for all other providers; the added spellings are exact and lowercase, mirroring the existing `llamaswap` handling. No aliasing ambiguity or privilege-routing concern results. Nothing in the security lens is materially affected by this change. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> **VERDICT: No material issues found** - Verified `cmd/gadfly/model.go:83` and `:229` — both switches now route all four spellings (`llamaswap`, `llamaswaps`, `llama-swap`, `llama-swaps`) to the identical `llamaswap.New(...)` construction. The behavior is purely additive aliasing; no semantic divergence between spellings in the `GADFLY_BASE_URL` override path (the URL's own scheme governs http/https, as the comment correctly states). - Checked `modelProvider()` (`model.go:146`) and its callers (`main.go:282`, `emit.go:105`): it returns the raw `GADFLY_PROVIDER`/model-prefix verbatim and is *not* expected to normalize aliases — this matches the pre-existing pattern where `ollama` vs `ollama-cloud` are distinct lanes. The new spellings introduce no regression here; a user keying a concurrency override must simply use the same spelling they set, same as before. - Verified the new test (`model_test.go:49-61`) exercises three of the four new aliases via `endpointProvider`; the original `llamaswap` is covered by the existing cases at lines 35–48. No gap that affects correctness. - The `go.mod`/`go.sum` bump is a straight version hash change with matching `h1:`/`go.mod` lines; no correctness dimension to check beyond that. Nothing in the correctness lane is materially wrong. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> **Verdict: No material issues found** The change is purely additive within two `switch` statements (`resolveModel` and `endpointProvider`), expanding the `llamaswap` case to accept four spellings. Through the error-handling / edge-case lens: - **Unknown-provider path preserved.** Both `default:` branches still return a non-nil error, so a bad `GADFLY_PROVIDER` / endpoint provider string still fails cleanly rather than falling through. Verified at `cmd/gadfly/model.go:111` and `:259`. - **Empty/malformed input unchanged.** `endpointProvider` still guards `len(parts) < 2` (`:209`) and empty base URL (`:218`); the `""` and `"ollama"` (no-pipe) cases in the reject test table (`model_test.go:62`) continue to exercise these and are unaffected by the new aliases. - **No new nil/zero/overflow surface.** The new case bodies reuse the existing `llamaswap.Option` construction path; no new slicing, arithmetic, or dereferences introduced. `model` is guaranteed non-empty upstream in `resolveModel` (`:52`), and `endpointProvider` doesn't take a model. - **Alias test loop** (`model_test.go:51`) correctly asserts both no-error and `Name()`, covering the happy path for the three *new* spellings (the original `llamaswap` is covered by the earlier subtests at `:35`/`:44`). Nothing in the error-handling/edge-case lane is materially wrong here. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 26s</sub>

🪰 Gadfly review — deepseek-v4-pro:cloud (ollama-cloud)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

Verdict: No material issues found

Security review of this change:

  • No new injection vectors. The diff adds only new case labels ("llamaswaps", "llama-swap", "llama-swaps") to two existing switch blocks. The baseURL and apiKey/key values flow through the same pre-existing paths — no new parsing, no new interpolation, no new external calls. Verified by reading cmd/gadfly/model.go:70-112 and cmd/gadfly/model.go:222-260 in full.

  • No secret leakage. The two error messages updated in the diff (lines 111 and 259) interpolate only the provider variable — not the API key, not the base URL. Confirmed by reading the surrounding code; no fmt/log call in the file includes apiKey or key.

  • No authn/authz regression. The change doesn't alter how credentials are sourced (GADFLY_API_KEY env, or the |key segment of endpoint specs) or how they're passed to provider constructors. The llamaswap.WithToken() call is identical to the pre-existing one — only the set of matching provider strings expanded.

  • No insecure defaults. The default provider remains ollama-cloud (line 20). No new fallback behavior was introduced.

  • Pre-existing concerns (not introduced by this diff): The baseURL from GADFLY_BASE_URL and GADFLY_ENDPOINT_* is passed to HTTP clients without URL validation or scheme restriction. This is a potential SSRF vector if an attacker controls the environment, but it exists identically for all providers (ollama, openai, anthropic, google, foreman) and is not worsened by this change.

🎯 Correctness — No material issues found

Verdict: No material issues found

After verifying the full file at cmd/gadfly/model.go and the test file at cmd/gadfly/model_test.go, the change is logically consistent:

  • Both resolveModel() (line 83) and endpointProvider() (line 229) accept the identical set of four spellings: "llamaswap", "llamaswaps", "llama-swap", "llama-swaps".
  • All four spellings construct the same llamaswap.New(...) provider with the same options — no divergence.
  • The GADFLY_BASE_URL path uses the URL's own scheme, so the http-vs-https distinction that majordomo's DSN schemes encode (llama-swap vs llama-swaps) is correctly irrelevant there.
  • The test covers all four spellings: the original "llamaswap" via the pre-existing sub-tests (lines 35–48), and "llama-swap", "llama-swaps", "llamaswaps" via the new loop (line 51).
  • The baseURL == "" guard in endpointProvider() (line 218) fires before the switch, so the new cases can't accidentally accept an empty URL.

One observation (not a bug — the concurrency system has always used exact string matching):

  • modelProvider() (line 146) returns the raw provider string from the environment. If a user switches from GADFLY_PROVIDER=llamaswap to GADFLY_PROVIDER=llama-swap, any existing GADFLY_PROVIDER_LENS_CONCURRENCY="llamaswap=N" entry would silently stop matching because providerOverride() (line 291) does an exact != comparison. The user just needs to use the same spelling in both places — no normalization is promised.
🧯 Error handling & edge cases — No material issues found

Verdict: No material issues found

The diff is purely additive — it expands two switch cases to accept hyphenated (llama-swap, llama-swaps) and the pre-existing llamaswaps spelling alongside the original llamaswap. No new code paths, no new error conditions, no changed control flow.

I verified the following by reading the full files (not just the diff hunks):

  • resolveModel() (line 83): The new spellings fall into the same llamaswap.New(opts...).Model(model) path. The baseURL is already guarded by the if baseURL == "" check at line 65, so it's always non-empty here. The apiKey empty-check at line 89 is unchanged. No regression.

  • endpointProvider() (line 229): Same pattern. The baseURL == "" guard at line 218 and the key != "" guard at line 231 are unchanged. The name parameter is always non-empty (guaranteed by the len(key) > len("GADFLY_ENDPOINT_") check at line 184 in the caller).

  • modelProvider() (line 146): Unchanged by this PR. It returns whatever raw provider string the user set. If a user sets GADFLY_PROVIDER=llama-swap, the concurrency key becomes "llama-swap" — they'd need the same spelling in GADFLY_PROVIDER_CONCURRENCY / GADFLY_PROVIDER_LENS_CONCURRENCY. This is consistent, transparent behavior (the function has always returned the verbatim prefix), and the hyphen passes through providerOverride()'s strings.Cut/TrimSpace parsing without issue.

  • Error messages (lines 111, 259): Updated to mention llama-swap instead of llamaswap. Purely cosmetic.

  • Tests (model_test.go): The new loop at line 51 covers llama-swap, llama-swaps, and llamaswaps — the three added spellings. The original llamaswap spelling was already covered by the existing tests at lines 35–47. Coverage is complete for the new aliases.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 52s

<!-- gadfly-review:ollama:deepseek-v4-pro:cloud --> ### 🪰 Gadfly review — `deepseek-v4-pro:cloud` (ollama-cloud) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> ## Verdict: No material issues found **Security review of this change:** - **No new injection vectors.** The diff adds only new `case` labels (`"llamaswaps"`, `"llama-swap"`, `"llama-swaps"`) to two existing `switch` blocks. The `baseURL` and `apiKey`/`key` values flow through the same pre-existing paths — no new parsing, no new interpolation, no new external calls. Verified by reading `cmd/gadfly/model.go:70-112` and `cmd/gadfly/model.go:222-260` in full. - **No secret leakage.** The two error messages updated in the diff (lines 111 and 259) interpolate only the `provider` variable — not the API key, not the base URL. Confirmed by reading the surrounding code; no `fmt`/`log` call in the file includes `apiKey` or `key`. - **No authn/authz regression.** The change doesn't alter how credentials are sourced (`GADFLY_API_KEY` env, or the `|key` segment of endpoint specs) or how they're passed to provider constructors. The `llamaswap.WithToken()` call is identical to the pre-existing one — only the set of matching provider strings expanded. - **No insecure defaults.** The default provider remains `ollama-cloud` (line 20). No new fallback behavior was introduced. - **Pre-existing concerns (not introduced by this diff):** The `baseURL` from `GADFLY_BASE_URL` and `GADFLY_ENDPOINT_*` is passed to HTTP clients without URL validation or scheme restriction. This is a potential SSRF vector if an attacker controls the environment, but it exists identically for all providers (`ollama`, `openai`, `anthropic`, `google`, `foreman`) and is not worsened by this change. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> **Verdict: No material issues found** After verifying the full file at `cmd/gadfly/model.go` and the test file at `cmd/gadfly/model_test.go`, the change is logically consistent: - Both `resolveModel()` (line 83) and `endpointProvider()` (line 229) accept the identical set of four spellings: `"llamaswap"`, `"llamaswaps"`, `"llama-swap"`, `"llama-swaps"`. - All four spellings construct the same `llamaswap.New(...)` provider with the same options — no divergence. - The `GADFLY_BASE_URL` path uses the URL's own scheme, so the http-vs-https distinction that majordomo's DSN schemes encode (`llama-swap` vs `llama-swaps`) is correctly irrelevant there. - The test covers all four spellings: the original `"llamaswap"` via the pre-existing sub-tests (lines 35–48), and `"llama-swap"`, `"llama-swaps"`, `"llamaswaps"` via the new loop (line 51). - The `baseURL == ""` guard in `endpointProvider()` (line 218) fires before the switch, so the new cases can't accidentally accept an empty URL. One observation (not a bug — the concurrency system has always used exact string matching): - `modelProvider()` (line 146) returns the raw provider string from the environment. If a user switches from `GADFLY_PROVIDER=llamaswap` to `GADFLY_PROVIDER=llama-swap`, any existing `GADFLY_PROVIDER_LENS_CONCURRENCY="llamaswap=N"` entry would silently stop matching because `providerOverride()` (line 291) does an exact `!=` comparison. The user just needs to use the same spelling in both places — no normalization is promised. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> ## Verdict: No material issues found The diff is purely additive — it expands two `switch` cases to accept hyphenated (`llama-swap`, `llama-swaps`) and the pre-existing `llamaswaps` spelling alongside the original `llamaswap`. No new code paths, no new error conditions, no changed control flow. I verified the following by reading the full files (not just the diff hunks): - **`resolveModel()` (line 83)**: The new spellings fall into the same `llamaswap.New(opts...).Model(model)` path. The `baseURL` is already guarded by the `if baseURL == ""` check at line 65, so it's always non-empty here. The `apiKey` empty-check at line 89 is unchanged. No regression. - **`endpointProvider()` (line 229)**: Same pattern. The `baseURL == ""` guard at line 218 and the `key != ""` guard at line 231 are unchanged. The `name` parameter is always non-empty (guaranteed by the `len(key) > len("GADFLY_ENDPOINT_")` check at line 184 in the caller). - **`modelProvider()` (line 146)**: Unchanged by this PR. It returns whatever raw provider string the user set. If a user sets `GADFLY_PROVIDER=llama-swap`, the concurrency key becomes `"llama-swap"` — they'd need the same spelling in `GADFLY_PROVIDER_CONCURRENCY` / `GADFLY_PROVIDER_LENS_CONCURRENCY`. This is consistent, transparent behavior (the function has always returned the verbatim prefix), and the hyphen passes through `providerOverride()`'s `strings.Cut`/`TrimSpace` parsing without issue. - **Error messages (lines 111, 259)**: Updated to mention `llama-swap` instead of `llamaswap`. Purely cosmetic. - **Tests (model_test.go)**: The new loop at line 51 covers `llama-swap`, `llama-swaps`, and `llamaswaps` — the three added spellings. The original `llamaswap` spelling was already covered by the existing tests at lines 35–47. Coverage is complete for the new aliases. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 52s</sub>

🪰 Gadfly review — nemotron-3-super:cloud (ollama-cloud)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

No material issues found

After reviewing the changes through the security lens (authentication/authorization gaps, injection risks, SSRF, secrets leakage, input validation, unsafe defaults), no material security concerns were identified.

The changes primarily:

  1. Update the majordomo dependency to a newer version (security improvement via dependency update)
  2. Add support for additional spelling variants of the llama-swap provider (llama-swap, llama-swaps, llamaswap, llamaswaps)
  3. Update documentation and error messages to reflect the new spelling variants
  4. Add test cases for the new provider spellings

All changes are confined to:

  • Provider string validation (switch statements and error messages)
  • Documentation updates
  • Test additions
  • Dependency version bumps

The provider string validation uses simple string equality checks in switch statements, which poses no injection risk. The environment variables (GADFLY_PROVIDER, GADFLY_BASE_URL, GADFLY_ENDPOINT_, LLM_ DSNs) are used as-is but only passed to provider constructors after validation - no shell/SQL/template usage is introduced.

The dependency update to majordomo v0.0.0-20260627225659-aa25b2c33462 may include security fixes, but that's outside the scope of this diff review.

No authentication bypasses, credential leaks, SSRF vectors, or input validation gaps were introduced by these changes.

No material issues found

🎯 Correctness — No material issues found

No material issues found

🧯 Error handling & edge cases — No material issues found

No material issues found

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 51s

<!-- gadfly-review:ollama:nemotron-3-super:cloud --> ### 🪰 Gadfly review — `nemotron-3-super:cloud` (ollama-cloud) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> ## No material issues found After reviewing the changes through the security lens (authentication/authorization gaps, injection risks, SSRF, secrets leakage, input validation, unsafe defaults), no material security concerns were identified. The changes primarily: 1. Update the majordomo dependency to a newer version (security improvement via dependency update) 2. Add support for additional spelling variants of the llama-swap provider (llama-swap, llama-swaps, llamaswap, llamaswaps) 3. Update documentation and error messages to reflect the new spelling variants 4. Add test cases for the new provider spellings All changes are confined to: - Provider string validation (switch statements and error messages) - Documentation updates - Test additions - Dependency version bumps The provider string validation uses simple string equality checks in switch statements, which poses no injection risk. The environment variables (GADFLY_PROVIDER, GADFLY_BASE_URL, GADFLY_ENDPOINT_*, LLM_* DSNs) are used as-is but only passed to provider constructors after validation - no shell/SQL/template usage is introduced. The dependency update to majordomo v0.0.0-20260627225659-aa25b2c33462 may include security fixes, but that's outside the scope of this diff review. No authentication bypasses, credential leaks, SSRF vectors, or input validation gaps were introduced by these changes. <verdict>No material issues found</verdict> </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> No material issues found </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> No material issues found </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 2m 51s</sub>

🪰 Gadfly review — qwen3-coder:480b-cloud (ollama-cloud)

Verdict: Blocking issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

No material issues found.

🎯 Correctness — Blocking issues found

VERDICT: Blocking issues found

  • cmd/gadfly/model.go:83 and cmd/gadfly/model.go:229: The new case statements include "llamaswaps" and "llama-swaps" as aliases for the llama-swap provider. However, the existing test suite in model_test.go does not include "llamaswap" (the original, unhyphenated singular form) in its alias verification loop. This is a logic gap: if "llamaswap" is still a valid and supported spelling (as implied by the PR description and prior code), it must also be included in the alias test to ensure consistency. The omission creates an untested code path for the base unhyphenated singular form under the new multi-case structure.

  • README.md:69: The table entry for llama-swap now lists llama-swap/llama-swaps as the primary spellings but omits mention of the backward-compatible llamaswap/llamaswaps forms. This is inconsistent with the implementation in model.go which still accepts all four spellings. The documentation should either explicitly note all supported aliases or be corrected to match the reduced set — currently it misrepresents the full set of supported aliases.

🧯 Error handling & edge cases — No material issues found

No material issues found.

The changes correctly add support for multiple spellings of the llama-swap provider ("llamaswap", "llamaswaps", "llama-swap", "llama-swaps") in both the resolveModel and endpointProvider functions. The error messages and documentation have been updated accordingly. Tests have been added to verify the new provider spellings work correctly. No error handling or edge case issues were found in the diff.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 44s

<!-- gadfly-review:ollama:qwen3-coder:480b-cloud --> ### 🪰 Gadfly review — `qwen3-coder:480b-cloud` (ollama-cloud) **Verdict: Blocking issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> No material issues found. </details> <details><summary><b>🎯 Correctness</b> — Blocking issues found</summary> VERDICT: Blocking issues found - **cmd/gadfly/model.go:83** and **cmd/gadfly/model.go:229**: The new `case` statements include `"llamaswaps"` and `"llama-swaps"` as aliases for the llama-swap provider. However, the existing test suite in `model_test.go` does **not** include `"llamaswap"` (the original, unhyphenated singular form) in its alias verification loop. This is a logic gap: if `"llamaswap"` is still a valid and supported spelling (as implied by the PR description and prior code), it must also be included in the alias test to ensure consistency. The omission creates an untested code path for the base unhyphenated singular form under the new multi-case structure. - **README.md:69**: The table entry for llama-swap now lists `llama-swap`/`llama-swaps` as the primary spellings but omits mention of the backward-compatible `llamaswap`/`llamaswaps` forms. This is inconsistent with the implementation in `model.go` which still accepts all four spellings. The documentation should either explicitly note all supported aliases or be corrected to match the reduced set — currently it misrepresents the full set of supported aliases. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> No material issues found. The changes correctly add support for multiple spellings of the llama-swap provider ("llamaswap", "llamaswaps", "llama-swap", "llama-swaps") in both the `resolveModel` and `endpointProvider` functions. The error messages and documentation have been updated accordingly. Tests have been added to verify the new provider spellings work correctly. No error handling or edge case issues were found in the diff. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 44s</sub>

🪰 Gadfly review — claude-code/opus:max (claude-code)

Verdict: No material issues found — 3 reviewers: security, correctness, error-handling

🔒 Security — No material issues found

I've verified the changed code in cmd/gadfly/model.go. My assessment through the security lens:

VERDICT: No material issues found

  • The diff only adds string spellings (llamaswaps/llama-swap/llama-swaps) to two existing switch provider statements (model.go:83 and model.go:229), plus README/error-message/test updates and a dependency bump. I read both switches in full and confirmed the new cases route to the same llamaswap.New(...) construction the pre-existing llamaswap case already used — no new code path, just additional labels selecting it.
  • No new tainted-input flow. provider, baseURL, and key all originate from operator-controlled env vars (GADFLY_PROVIDER/GADFLY_BASE_URL/GADFLY_API_KEY/GADFLY_ENDPOINT_*), parsed at model.go:55-60 and model.go:208-217. None of this is influenced by the untrusted PR diff under review, so the added cases don't widen any injection/SSRF surface. The base-URL-verbatim behavior (the one place that could matter for SSRF) is unchanged by this PR.
  • No secret leakage introduced. The token/key options (WithToken/WithAPIKey) are wired identically to the existing cases; nothing new is logged. The registerEnvProviders error path (model.go:48,188) prints the env key name and wrapped error, not the value — unchanged here.
  • Dependency bump (majordomo…225659, go.mod/go.sum): hashes are pinned in go.sum, so the supply-chain pin is intact. I cannot inspect the private module's contents with these tools, so its diff is unverified — but nothing in the gadfly-side change depends on new majordomo behavior in a security-relevant way.

Nothing in the security lane is materially wrong with this change.

🎯 Correctness — No material issues found

I've verified the key paths by reading cmd/gadfly/model.go in full and grepping every llamaswap/llama-swap reference in the repo. I could not inspect the bumped majordomo module (it lives outside the sandboxed working directory), so the dependency-internal claims are noted as unverified below.

VERDICT: No material issues found

Reviewed through the Correctness lens.

What I verified (by reading cmd/gadfly/model.go and grepping the repo):

  • Both provider switches — the endpoint-override path in resolveModel (model.go:83) and the named-endpoint path in endpointProvider (model.go:229) — are updated symmetrically to accept all four spellings (llamaswap, llamaswaps, llama-swap, llama-swaps), each routing to the same llamaswap provider construction. No spelling is handled in one switch but missed in the other.
  • The llamaswap package is imported (model.go:12) and the option constructors used (WithBaseURL/WithToken/WithName) are the same ones already in use pre-PR, so the new cases are well-typed.
  • The added test (model_test.go) exercises llama-swap, llama-swaps, llamaswaps through endpointProvider and asserts Name() == "ls" with no error — these inputs do hit the new case, and the negative cases ("", mystery|..., etc.) still fall through to the default error branch. The test is correct (it intentionally omits the already-covered llamaswap).
  • The semantic claim in the comment (model.go:84-87) holds for these code paths: with an explicit GADFLY_BASE_URL (or endpoint base URL), the wire scheme comes from the URL verbatim, so all four spellings produce an identical provider. There is no enforced http-vs-https difference here — but that is the PR's stated intent and is consistent with how foreman/ollama already treat the base URL as authoritative. Not a bug.
  • Error strings (model.go:111, :259) and the doc comment are cosmetic and don't affect control flow.

Could not verify (dependency-internal, outside the sandbox):

  • The PR's claim that the LLM_* DSN path and the no-BASE_URL majordomo.Parse("llama-swap/model") path resolve llama-swap/llama-swaps correctly depends entirely on the bumped majordomo (…225659). When GADFLY_BASE_URL is empty, resolveModel bypasses these switches and calls majordomo.Parse with the provider prefix verbatim (model.go:66), so a GADFLY_PROVIDER=llama-swap with no base URL relies on majordomo recognizing that exact provider name. I couldn't read the majordomo module to confirm, but this is dependency behavior, not a defect in the diff.

Nothing in the correctness lane is materially wrong with this change.

Outside my lens (one line): the new README row and the accepted-spellings in code now diverge slightly — the table documents only llama-swap/llama-swaps while the code still accepts the un-hyphenated llamaswap/llamaswaps; worth a docs-lens glance for completeness.

🧯 Error handling & edge cases — No material issues found

VERDICT: No material issues found

I reviewed this change through the error-handling & edge-cases lens, verifying against cmd/gadfly/model.go (the two switch statements at lines 70–113 and 222–259) and the surrounding error paths.

Findings:

  • The diff is purely additive: it widens two switch provider cases to also match "llamaswaps", "llama-swap", "llama-swaps" alongside the existing "llamaswap". No error path, cleanup, or boundary logic is altered. The default: arms still return an error (no panic, no fall-through), and the malformed-spec guards in endpointProvider (model.go:208-220 — too few parts, empty base URL) remain intact and ahead of the switch.
  • No new nil/empty/zero/overflow surface is introduced — the added cases construct providers identically to the pre-existing "llamaswap" case, including the if key != "" / if apiKey != "" guards.
  • Bad endpoint entries remain best-effort: resolveModel (model.go:47-49) logs and skips them via registerEnvProviders rather than aborting — unchanged and still correct.

One observation I checked and concluded is not a new bug: provider is TrimSpace'd but not lowercased in either function, so a mixed-case Llama-Swap would still hit default. This is pre-existing behavior shared by every provider (ollama, openai, etc.), not something this diff introduces, so it's out of scope as a finding here.

Nothing in the error-handling / edge-case lane is materially wrong.

Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 5s

<!-- gadfly-review:ollama:claude-code/opus:max --> ### 🪰 Gadfly review — `claude-code/opus:max` (claude-code) **Verdict: No material issues found** — 3 reviewers: security, correctness, error-handling <details><summary><b>🔒 Security</b> — No material issues found</summary> I've verified the changed code in `cmd/gadfly/model.go`. My assessment through the security lens: **VERDICT: No material issues found** - The diff only adds string spellings (`llamaswaps`/`llama-swap`/`llama-swaps`) to two existing `switch provider` statements (`model.go:83` and `model.go:229`), plus README/error-message/test updates and a dependency bump. I read both switches in full and confirmed the new cases route to the same `llamaswap.New(...)` construction the pre-existing `llamaswap` case already used — no new code path, just additional labels selecting it. - **No new tainted-input flow.** `provider`, `baseURL`, and `key` all originate from operator-controlled env vars (`GADFLY_PROVIDER`/`GADFLY_BASE_URL`/`GADFLY_API_KEY`/`GADFLY_ENDPOINT_*`), parsed at `model.go:55-60` and `model.go:208-217`. None of this is influenced by the untrusted PR diff under review, so the added cases don't widen any injection/SSRF surface. The base-URL-verbatim behavior (the one place that could matter for SSRF) is unchanged by this PR. - **No secret leakage introduced.** The token/key options (`WithToken`/`WithAPIKey`) are wired identically to the existing cases; nothing new is logged. The `registerEnvProviders` error path (`model.go:48,188`) prints the env *key name* and wrapped error, not the value — unchanged here. - **Dependency bump** (`majordomo` → `…225659`, go.mod/go.sum): hashes are pinned in `go.sum`, so the supply-chain pin is intact. I cannot inspect the private module's contents with these tools, so its diff is unverified — but nothing in the gadfly-side change depends on new majordomo behavior in a security-relevant way. Nothing in the security lane is materially wrong with this change. </details> <details><summary><b>🎯 Correctness</b> — No material issues found</summary> I've verified the key paths by reading `cmd/gadfly/model.go` in full and grepping every `llamaswap`/`llama-swap` reference in the repo. I could not inspect the bumped majordomo module (it lives outside the sandboxed working directory), so the dependency-internal claims are noted as unverified below. ## VERDICT: No material issues found Reviewed through the **Correctness** lens. **What I verified (by reading `cmd/gadfly/model.go` and grepping the repo):** - Both provider switches — the endpoint-override path in `resolveModel` (`model.go:83`) and the named-endpoint path in `endpointProvider` (`model.go:229`) — are updated **symmetrically** to accept all four spellings (`llamaswap`, `llamaswaps`, `llama-swap`, `llama-swaps`), each routing to the same `llamaswap` provider construction. No spelling is handled in one switch but missed in the other. - The `llamaswap` package is imported (`model.go:12`) and the option constructors used (`WithBaseURL`/`WithToken`/`WithName`) are the same ones already in use pre-PR, so the new cases are well-typed. - The added test (`model_test.go`) exercises `llama-swap`, `llama-swaps`, `llamaswaps` through `endpointProvider` and asserts `Name() == "ls"` with no error — these inputs do hit the new case, and the negative cases (`""`, `mystery|...`, etc.) still fall through to the `default` error branch. The test is correct (it intentionally omits the already-covered `llamaswap`). - The semantic claim in the comment (`model.go:84-87`) holds for these code paths: with an explicit `GADFLY_BASE_URL` (or endpoint base URL), the wire scheme comes from the URL verbatim, so all four spellings produce an identical provider. There is no enforced http-vs-https difference here — but that is the PR's stated intent and is consistent with how `foreman`/`ollama` already treat the base URL as authoritative. Not a bug. - Error strings (`model.go:111`, `:259`) and the doc comment are cosmetic and don't affect control flow. **Could not verify (dependency-internal, outside the sandbox):** - The PR's claim that the `LLM_*` DSN path and the no-`BASE_URL` `majordomo.Parse("llama-swap/model")` path resolve `llama-swap`/`llama-swaps` correctly depends entirely on the bumped majordomo (`…225659`). When `GADFLY_BASE_URL` is empty, `resolveModel` bypasses these switches and calls `majordomo.Parse` with the provider prefix verbatim (`model.go:66`), so a `GADFLY_PROVIDER=llama-swap` with no base URL relies on majordomo recognizing that exact provider name. I couldn't read the majordomo module to confirm, but this is dependency behavior, not a defect in the diff. Nothing in the correctness lane is materially wrong with this change. Outside my lens (one line): the new README row and the accepted-spellings in code now diverge slightly — the table documents only `llama-swap`/`llama-swaps` while the code still accepts the un-hyphenated `llamaswap`/`llamaswaps`; worth a docs-lens glance for completeness. </details> <details><summary><b>🧯 Error handling & edge cases</b> — No material issues found</summary> **VERDICT: No material issues found** I reviewed this change through the error-handling & edge-cases lens, verifying against `cmd/gadfly/model.go` (the two switch statements at lines 70–113 and 222–259) and the surrounding error paths. Findings: - The diff is purely additive: it widens two `switch provider` cases to also match `"llamaswaps"`, `"llama-swap"`, `"llama-swaps"` alongside the existing `"llamaswap"`. No error path, cleanup, or boundary logic is altered. The `default:` arms still return an error (no panic, no fall-through), and the malformed-spec guards in `endpointProvider` (`model.go:208-220` — too few parts, empty base URL) remain intact and ahead of the switch. - No new nil/empty/zero/overflow surface is introduced — the added cases construct providers identically to the pre-existing `"llamaswap"` case, including the `if key != ""` / `if apiKey != ""` guards. - Bad endpoint entries remain best-effort: `resolveModel` (`model.go:47-49`) logs and skips them via `registerEnvProviders` rather than aborting — unchanged and still correct. One observation I checked and concluded is *not* a new bug: `provider` is `TrimSpace`'d but not lowercased in either function, so a mixed-case `Llama-Swap` would still hit `default`. This is pre-existing behavior shared by every provider (ollama, openai, etc.), not something this diff introduces, so it's out of scope as a finding here. Nothing in the error-handling / edge-case lane is materially wrong. </details> <sub>Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 3m 5s</sub>
steve added 1 commit 2026-06-27 23:18:35 +00:00
docs: note un-hyphenated llamaswap/llamaswaps aliases (PR #7 review)
Build & push image / build-and-push (pull_request) Successful in 8s
5ee6568252
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
steve merged commit b23eeb8cbf into main 2026-06-27 23:18:57 +00:00
steve deleted branch feat/llamaswap-schemes 2026-06-27 23:18:57 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steve/gadfly#7