gabriel / muse public
Closed #44
filed by gabriel human · 33 days ago

mist read: owner/ID form sends request to wrong API path

0 Anchors
Blast radius
Churn 30d
0 Proposals

muse mist read: owner/ID form sends request to wrong API path

Background

muse mist read accepts two input forms:

  • Bare ID: muse mist read H7XFVEzeDfqk
  • Owner-qualified: muse mist read gabriel/H7XFVEzeDfqk

The help text and docstring both document the owner/ID form as valid. But when run_read detects a / in the input, it constructs the wrong API path:

# muse/cli/commands/mist.py:616 — BUG
api_path = f"/api/{owner_part}/mists/{id_part}"

The server has no route at /api/{owner}/mists/{id}. The real route is GET /api/mists/{mist_id} — owner is not part of the API path. The result is an HTTP 404 that surfaces to the user as:

❌ Hub returned HTTP 0: Server returned invalid JSON: Expecting value: line 1 column 1 (char 0)

The error message is also misleading: the underlying 404 body is {"detail": "Not Found"} — valid JSON — but the CLI swallows the HTTP status and reports a JSON parse failure instead.

Root cause

run_read is the only mist command that got the path wrong. Every other command that handles owner/ID input correctly discards the owner and routes to /api/mists/{id}:

Command Line Path built Correct?
run_read 616 /api/{owner}/mists/{id} bug
run_delete 903 /api/mists/{id}
run_update 994 /api/mists/{id}
run_forks 1053 /api/mists/{id}/forks
run_raw 1113 /api/mists/{id}/raw
run_embed 811 /api/{owner}/mists/{id}/embed ✅ (embed route intentionally needs owner)

The run_fork command (line 690–696) was also checked — it correctly extracts just the id_part for /api/mists/{id}/fork.

Goal

muse mist read gabriel/H7XFVEzeDfqk --hub https://staging.musehub.ai --json returns the mist JSON. Both the bare-ID and the owner/ID form work identically.

Phases

Phase 1 — Fix run_read

One-line change in muse/cli/commands/mist.py.

Deliverable
  • MR_01 — Change line 616:

    # Before
    api_path = f"/api/{owner_part}/mists/{id_part}"
    # After
    api_path = f"/api/mists/{id_part}"
    

    The owner_part variable becomes unused; remove the assignment too (lines 613–614 can simplify to extracting only id_part).


Phase 2 — Fix the misleading 404 error message

When _hub_api receives a non-2xx response, the caller sees a JSON-parse error instead of the actual HTTP status. The error should surface the HTTP status code and the response body so the user can diagnose it.

Deliverable
  • MR_02_hub_api (or its caller in run_read) raises a clear error on non-2xx HTTP: ❌ Hub returned HTTP 404: {"detail": "Not Found"}. The current "Server returned invalid JSON" message must not appear for a response that actually contains valid JSON.

Phase 3 — Tests

No test currently exercises run_read with the owner/ID form. Add tests to prevent regression.

Deliverables
  • MR_03 — Unit test: run_read with "gabriel/H7XFVEzeDfqk" calls _hub_api with path /api/mists/H7XFVEzeDfqk (not /api/gabriel/mists/…). Mock _hub_api and assert the api_path argument.
  • MR_04 — Unit test: run_read with bare "H7XFVEzeDfqk" calls _hub_api with path /api/mists/H7XFVEzeDfqk. Existing happy-path smoke, now with explicit path assertion.
  • MR_05 — Unit test: run_read with "owner/ID" does NOT include the owner in the path — the owner portion is silently discarded (it is advisory information only; the ID alone uniquely identifies a mist).
  • MR_06 — Unit test: when _hub_api receives a 404, run_read exits with a message containing the HTTP status code (validates MR_02 fix).

Phase 4 — Staging smoke

  • MR_07muse mist read gabriel/H7XFVEzeDfqk --hub https://staging.musehub.ai --json returns the mist JSON with mist_id == "H7XFVEzeDfqk".
  • MR_08muse mist read H7XFVEzeDfqk --hub https://staging.musehub.ai --json returns identical output (both forms are equivalent).

Acceptance criteria

  1. muse mist read owner/ID and muse mist read ID return identical JSON output.
  2. HTTP 404 from the server surfaces as ❌ Hub returned HTTP 404: … — not a JSON parse error.
  3. MR_03–MR_06 tests green.
  4. Staging smoke passes (MR_07–MR_08).

Out of scope

  • Validating that the owner in owner/ID matches the mist's actual owner (the server owns that check; the CLI's job is just to extract the ID)
  • Changing the server-side routes
  • Other mist subcommands — all others already handle owner/ID correctly
Activity1
gabriel opened this issue 33 days ago
gabriel 18 days ago

Fixed on dev (sha256:96c357b8), both phases from the plan.

Phase 1: run_read now builds /api/mists/{id} for both bare-ID and owner/ID input — the owner segment is discarded, matching every other mist subcommand.

Phase 2: _hub_api's 404 branch now reads ❌ Hub returned HTTP 404: {detail}, consistent with every other status branch, so a 404 with a valid JSON body is never confused with a JSON-parse failure.

Phase 3: 5 new tests in tests/test_mist_read_api_path.py covering MR_02–MR_06 (owner/ID uses correct path, bare-ID unchanged, owner discarded not embedded, both forms produce identical output, 404 surfaces HTTP status). All 92 existing test_mist_cli.py tests still pass.

Phase 4 (staging smoke, MR_07/MR_08) is left for you to verify against a live mist, since it needs a real staging hub round-trip outside this session's scope.

closed this issue 18 days ago