fix: address Copilot review round 6 (#2263)

Four findings — two inline, two in the review's suppressed block.

"Expand all" wrote `sectionIds` — the sections rendered at that instant — into
`openSections`, which outlives any one skill. Pressing it while the SKILL.md
read was still in flight dropped `frontmatter`, so the section arrived collapsed
with the control offering to expand all over again; a dynamic skill did the same
to `resources`. It now expands to the complete set, and `sectionIds` decides
only the toggle's label. The new test is verified to detect the defect: with
`sectionIds` restored it fails.

`inferMimeFromUri` matched the raw path, so a percent-encoded suffix such as
`reference%2Emd` produced no MIME at all — no markdown renderer and no
frontmatter split — even though `skillUriIdentity` already treats that spelling
as the same file. It now decodes defensively, falling back to the raw path on a
malformed escape rather than throwing inside what is only a guess.

Two comment fixes, both cases of a deliberate decision being contradicted by the
prose around it. `theme/Accordion.ts` still asserted "sized to content and never
shrink; overflow moves to the root" after round 5 moved the sections back to
`flex: 0 1 auto` with a floor — the exact stale rationale that makes a
load-bearing layout easy to regress. And the component doc, the
`onReadSkillFile` doc in `useServerCommands.tsx` and a `test-servers` fixture
comment all still said skill files are read only when the user asks to verify
them, one of them still naming the removed "View SKILL.md" button. All three now
separate reading (on selection, and not a load under SEP-2640) from verification
(strictly on demand).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4441JdNLZerCVM7mDDSfB
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-06 01:21:54 -04:00
commit d78089892b

View file

@ -216,9 +216,10 @@ export interface ServerCommands {
uri: string,
) => Promise<Awaited<ReturnType<InspectorClient["readResource"]>>["result"]>;
/**
* Read one skill file's contents (SEP-2640), for digest verification. Returns
* the single content block that answers the URI, narrowed to the two fields
* the digest is taken over.
* Read one skill file's contents (SEP-2640) — for display in the Skills
* screen's viewer, and for digest verification. Returns the single content
* block that answers the URI, narrowed to the two fields the digest is taken
* over.
*/
onReadSkillFile: (uri: string) => Promise<SkillFileContents>;
/** Re-fetch one skill entry through `skills/get` (SEP-2640). */
@ -947,9 +948,13 @@ export function useServerCommands({
runCommandInBackground(() => resourcesPagination.onLoadMore(), "ambient"),
[resourcesPagination, runCommandInBackground],
);
// Skill files are fetched on demand, never pre-fetched: SEP-2640 is explicit
// that a `resources/read` of a skill file is not a load and confers no
// standing, so the Inspector reads only what the user asks it to verify.
// Skill files are still never pre-fetched in bulk — nothing walks the
// manifest reading everything. What IS read without being asked is the single
// `SKILL.md` of whichever skill is selected, so the file is on screen (#2263);
// SEP-2640 is explicit that a `resources/read` of a skill file is not a load
// and confers no standing, so that claims nothing on the user's behalf.
// Digest verification remains strictly on demand.
//
// Routed through `onReadResourceContents` so a skill read gets the same
// auth-recovery retry every other read does.
const onReadSkillFile = useCallback(