feat(collections): custom views should pre-project `fields=` to dodge the 200-record refusal; HTTP 400 needs a help affordance
## Summary
Users authoring a custom collection view via the standard "drop an HTML file in `views/`" workflow hit an opaque **HTTP 400** at runtime once their collection grows past the unselective `getItems` limit (200 records). The view's `fetch(dataUrl)` returns no JSON, the view-side `if (!res.ok)` handler surfaces only `データ読込に失敗: HTTP 400` ("data load failed: HTTP 400"), and the user has no in-product affordance to understand or recover.
Two reproductions surfaced from end-user feedback this week:
1. Collection grew past the unselective threshold; existing custom view stopped loading.
2. New custom-view author was unaware that `fields=` / `ids=` are required at scale.
## Reproduction
1. Create / grow any user collection beyond 200 records.
2. Open a custom view whose `fetch` call passes the raw `dataUrl` with no query string.
3. The view shows `データ読込に失敗: HTTP 400`.
## Root cause (already known, recording for tracking)
`server/agent/mcp-tools/manageCollection.ts:154-155` refuses the call:
```
manageCollection: refused — '<slug>' has <N> records, over the unselective limit of 200.
Pass ids for specific records or fields to project only the columns you need.
```
`server/api/routes/collections.ts:416-421` (`sendToolResult`) sees the refusal string is not JSON and converts it to a `400 { error: <string> }`. The view's `fetch` wrapper has no special-case for this body shape and falls through to its generic "HTTP <status>" toast.
## Proposed fixes
Two complementary changes, ordered by impact:
### 1. Teach the custom-view authoring skill to include `fields=` by default
The skill that scaffolds a custom view (the one Claude follows when authoring `views/<slug>.html`) should:
- Default to constructing the fetch URL as `fetch(dataUrl + "?fields=<comma-joined cols the view actually reads>")`.
- Include a short comment in the generated HTML explaining **why** (the 200-record threshold), so a human-edited view doesn't drift back to the raw form.
- For views that genuinely need full records, the skill should call this out and suggest `ids=` with a windowed fetch pattern.
This is the highest-leverage fix because it prevents the bug at authoring time and matches the existing manageCollection contract (callers must project).
### 2. Surface a "ask for help" affordance on the 400 toast
When a custom view's data fetch returns a non-2xx and the response body is a string (not the expected records JSON):
- Show the **server's actual error message** to the user instead of just `HTTP <status>` — they currently lose all context.
- Add a **"解決策を尋ねる" / "Ask for help"** button on the error toast that opens a chat draft seeded with: the view file path, the collection slug, the server's refusal string, and a prompt like "How do I fix this error in this view?" — closes the loop without forcing the user to copy/paste.
This pairs well with the existing chat-from-view affordance (#1752) — the seed prompt is structured the same way.
### 3. (Optional) Server-side: include `fields` / `ids` hint in the 400 JSON
The server already includes the descriptive refusal text in the string body; restating it as a structured field (`{ error, hint, suggestedAction }`) would let the view auto-render a more useful inline message without having to parse the human-readable string. Lower priority than #1 and #2.
## Files involved
- `server/agent/mcp-tools/manageCollection.ts:154-155` (refusal site)
- `server/api/routes/collections.ts:416-421` (`sendToolResult` 400-mapping)
- The custom-view scaffolding flow (skill / help docs that explain how to write `views/<slug>.html`)
## Notes
This issue records anonymised end-user feedback; the specific collection slug and view filename are intentionally omitted.
0 条评论