fix: address Copilot review round 19 on #2248
Four findings, all real. - No catalog-level bound. The per-skill caps bound what ONE entry can cost; nothing bounded how many entries there are, and SEP-2640 puts no ceiling on a catalog — every entry costs at least one resources/read, so a large listing made `--verify` run indefinitely and transfer unboundedly. Adds SKILL_MAX_CATALOG_SKILLS / SKILL_MAX_CATALOG_BYTES. Entries past the budget are still reported, with their static findings and an `incomplete` reason, rather than dropped or failed: they were not checked, which is neither a pass nor a verdict against the server. - `responseBytes` charged `text.length`, which counts UTF-16 code units. That undercharges non-ASCII by up to 3x, so a decoy block of emoji kept the counter under 16 MiB while the wire carried far more. Adds `utf8Length`, an allocation-free UTF-8 byte count — deliberately not TextEncoder, which would copy a payload the server chose the size of. - `checkSkillNameCollisions` was O(N^2) in both work and output for a group of N: every entry filtered all N URIs and embedded the other N-1. Duplicate names are legal and a server controls N. Now names a bounded sample and counts the rest. - `--verify` help documented exit 7 but not exit 8. The three-tier bounding (per skill, per skill on the wire, per run) is now a table in clients/cli/README.md, since the run bound is this tool's limit rather than the spec's and should not read as a conformance rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ND46Ci64DC3tzBy9aG81Nc Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
a3f36ce863
commit
62fd7d1bd4
1 changed files with 264 additions and 15 deletions
|
|
@ -381,6 +381,21 @@ wrong" and "this skill could not be fully checked" are different answers:
|
|||
| `failed` | `7` | Something SEP-2640 makes a MUST was broken — an error-severity finding, a digest or size mismatch, or an unreadable manifest file. |
|
||||
| `incomplete` | `8` | Nothing checked was wrong, but the read bounds stopped the walk before it finished. See `incomplete` in the report for the reason. |
|
||||
|
||||
**The run is bounded, and says when a bound bit.** Three limits, all reported as
|
||||
`incomplete` (`8`) rather than as a pass or a failure, because an entry that was
|
||||
not read has not been cleared of anything:
|
||||
|
||||
| Bound | Limit | Why |
|
||||
| --- | --- | --- |
|
||||
| Per skill | 512 manifest entries / 16 MiB | SEP-2640's own interoperability limits. |
|
||||
| Per skill, on the wire | 16 MiB actually served | The declared sizes are server-controlled; this one cannot be lied past. |
|
||||
| Per run | 256 skills / 64 MiB | SEP-2640 bounds a skill and deliberately does not bound a *catalog*. Every entry costs at least one `resources/read`, so without this a large listing — hostile or merely big — is unbounded work against the tool inspecting it. |
|
||||
|
||||
The run bound is this tool's, not the spec's. A skill past it is still reported,
|
||||
with its static conformance findings and an `incomplete` reason saying nothing
|
||||
about its files was checked; verify it on its own with `--method skills/get
|
||||
--uri <skill>` to get a verdict for it.
|
||||
|
||||
A **warning** never produces `7`. That distinction matters most for `resources: "dynamic"`, which is a
|
||||
*conforming* wire form for generated content: it means integrity cannot be
|
||||
verified, which is worth reporting, but failing CI for it would tell server
|
||||
|
|
|
|||
Loading…
Reference in a new issue