Generated download tools cannot read valid attachments, Versions or ZIPs above 1 MiB #760

Open
opened 2026-10-02 13:09:45 +00:00 by kayg · 15 comments
Owner

Context: #427 rev-mcp-api review, #484, DESIGN §41. Source base c4a61e8cf090170f35b1bed3350d9de20c83ecd5. Priority: Medium. No product edits or live reproduction in this review.

Evidence:

  • crates/calternal-server/src/mcp.rs:311, crates/calternal-cli/src/remote_commands.rs:343 and packages/api-client/src/index.ts:456 stop generated responses above 1 MiB.
  • contracts/actions.json declares no Range or continuation input for mail_download_attachment, download_version or download_zip; scripts/action_registry.py:49 supplies Range only to other download actions.
  • crates/plugins/mail/src/routes.rs:45 permits attachments up to 25 MiB; :1439 reads a whole attachment and accepts no Range header.
  • crates/plugins/files/src/lib.rs:3620 streams a complete Version without a Range input. crates/plugins/files/src/archive.rs:1 streams a complete ZIP.

Impact:

These HTTP operations and the UI accept valid results larger than the adapter cap. The generated CLI, MCP and WebMCP tools fail on those results. The error recommends a smaller page or range that these operations do not accept. CLI Mail export is a separate path; it does not make the MCP or WebMCP tools complete.

Expected:

Keep bounded tool outputs and provide a declared continuation or range path for these downloads, or an explicit supported transfer result. Map it to the existing server operation. Do not raise the cap without a memory bound.

Regression test idea:

Use a synthetic 2 MiB attachment, saved Version and ZIP. Verify complete transfer with bounded chunks through each generated adapter. Assert that small transfers still retain their current output shape.

Duplicate check:

Searched all issue states for mail_download_attachment, attachment, pagination, and 1 MiB. #484 and #472 mention the operation inventory; no specific large-download parity issue found.

Context: #427 rev-mcp-api review, #484, DESIGN §41. Source base `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`. Priority: Medium. No product edits or live reproduction in this review. Evidence: - `crates/calternal-server/src/mcp.rs:311`, `crates/calternal-cli/src/remote_commands.rs:343` and `packages/api-client/src/index.ts:456` stop generated responses above 1 MiB. - `contracts/actions.json` declares no Range or continuation input for `mail_download_attachment`, `download_version` or `download_zip`; `scripts/action_registry.py:49` supplies Range only to other download actions. - `crates/plugins/mail/src/routes.rs:45` permits attachments up to 25 MiB; `:1439` reads a whole attachment and accepts no Range header. - `crates/plugins/files/src/lib.rs:3620` streams a complete Version without a Range input. `crates/plugins/files/src/archive.rs:1` streams a complete ZIP. Impact: These HTTP operations and the UI accept valid results larger than the adapter cap. The generated CLI, MCP and WebMCP tools fail on those results. The error recommends a smaller page or range that these operations do not accept. CLI Mail export is a separate path; it does not make the MCP or WebMCP tools complete. Expected: Keep bounded tool outputs and provide a declared continuation or range path for these downloads, or an explicit supported transfer result. Map it to the existing server operation. Do not raise the cap without a memory bound. Regression test idea: Use a synthetic 2 MiB attachment, saved Version and ZIP. Verify complete transfer with bounded chunks through each generated adapter. Assert that small transfers still retain their current output shape. Duplicate check: Searched all issue states for `mail_download_attachment`, `attachment`, `pagination`, and `1 MiB`. #484 and #472 mention the operation inventory; no specific large-download parity issue found.
Author
Owner

Starting calternal #760 and the linked agent-surface fixes #814, #815, #817, #818, and #821.

Branch: job/agentfix. Starting HEAD: 2f4482ded066d9c5d9c59130377907f7fd2916c9. Base: origin/dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5. The worktree is clean. I will reconcile origin/dev and job/merge-round-7a before final gates as requested.

Starting calternal #760 and the linked agent-surface fixes #814, #815, #817, #818, and #821. Branch: `job/agentfix`. Starting HEAD: `2f4482ded066d9c5d9c59130377907f7fd2916c9`. Base: `origin/dev` at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`. The worktree is clean. I will reconcile `origin/dev` and `job/merge-round-7a` before final gates as requested.
Author
Owner

Finding for #815: three revision-gated writes (block reminder create/delete and public edit) and nine tus operations require protocol headers in their handlers, but those headers were absent from OpenAPI. The generator had been supplementing them, so the adapter schema looked valid while the published API contract was incomplete. I added an OpenAPI regression covering the required headers and am moving those declarations into the route annotations before removing the supplements.

Finding for #815: three revision-gated writes (block reminder create/delete and public edit) and nine tus operations require protocol headers in their handlers, but those headers were absent from OpenAPI. The generator had been supplementing them, so the adapter schema looked valid while the published API contract was incomplete. I added an OpenAPI regression covering the required headers and am moving those declarations into the route annotations before removing the supplements.
Author
Owner

Finding for #817: the same legacy WebMCP names described different schemas and results across surfaces. Files listing discarded stable item IDs, total and next_cursor in the browser and had no cursor in MCP; MCP Mail list inputs also had no cursor. I aligned search input names with a q compatibility field, separated browser navigation from Note reading, preserved Files page data and IDs, and added cursor/limit support to WebMCP and MCP Mail pages. I added schema and page traversal regressions and am running the remaining Rust and web checks.

Finding for #817: the same legacy WebMCP names described different schemas and results across surfaces. Files listing discarded stable item IDs, total and next_cursor in the browser and had no cursor in MCP; MCP Mail list inputs also had no cursor. I aligned search input names with a q compatibility field, separated browser navigation from Note reading, preserved Files page data and IDs, and added cursor/limit support to WebMCP and MCP Mail pages. I added schema and page traversal regressions and am running the remaining Rust and web checks.
Author
Owner

Finding for #814: the shared retry helper replayed clonable POST/PATCH requests after 429, 502, 503 or 504 even though a create could already have committed. The server has no #667 operation receipt contract yet. I changed retries to safe HTTP methods only; transient write results now return an actionable unknown-result error, and added regressions for one-attempt writes and safe-read retry.

Finding for #814: the shared retry helper replayed clonable POST/PATCH requests after 429, 502, 503 or 504 even though a create could already have committed. The server has no #667 operation receipt contract yet. I changed retries to safe HTTP methods only; transient write results now return an actionable unknown-result error, and added regressions for one-attempt writes and safe-read retry.
Author
Owner

Finding during #760 implementation: both new Range routes silently treated a non-text header value as if Range were absent. In Mail this would fetch the full attachment from the provider; in Version downloads it could return the full saved Version. The routes now reject invalid header bytes as malformed, and Mail rejects malformed or unsatisfiable ranges before it opens the provider connection. The regression probe covers multipart and unsatisfiable Mail ranges on a real local server.

Finding during #760 implementation: both new Range routes silently treated a non-text header value as if Range were absent. In Mail this would fetch the full attachment from the provider; in Version downloads it could return the full saved Version. The routes now reject invalid header bytes as malformed, and Mail rejects malformed or unsatisfiable ranges before it opens the provider connection. The regression probe covers multipart and unsatisfiable Mail ranges on a real local server.
Author
Owner

Started work on branch job/agentfix, based on job/merge-round-7a at 2f4482ded066d9c5d9c59130377907f7fd2916c9.

Confirmed the two central failure paths in the source: generated base64 actions rejected every response above 1 MiB without declared continuation for Mail attachments, saved Versions and ZIPs (#760); send_with_retry replayed clonable non-safe writes after transient 429/502/503/504 responses, even when the upstream may have committed the request (#814). The implementation now bounds download chunks and reports an unknown write result instead of replaying writes. OpenAPI and adapter-contract generation is in progress.

Started work on branch `job/agentfix`, based on `job/merge-round-7a` at `2f4482ded066d9c5d9c59130377907f7fd2916c9`. Confirmed the two central failure paths in the source: generated base64 actions rejected every response above 1 MiB without declared continuation for Mail attachments, saved Versions and ZIPs (#760); `send_with_retry` replayed clonable non-safe writes after transient 429/502/503/504 responses, even when the upstream may have committed the request (#814). The implementation now bounds download chunks and reports an unknown write result instead of replaying writes. OpenAPI and adapter-contract generation is in progress.
Author
Owner

While reviewing the bounded Range path, I found a malformed-header fallback in the existing Files download route: a Range value with non-text bytes was silently treated as no Range and could trigger a full response. Files and Mail now reject non-text or repeated Range fields. Added route-parser unit coverage and a repeated-header local-server probe; the probe is included in the focused adversarial round.

While reviewing the bounded Range path, I found a malformed-header fallback in the existing Files download route: a Range value with non-text bytes was silently treated as no Range and could trigger a full response. Files and Mail now reject non-text or repeated Range fields. Added route-parser unit coverage and a repeated-header local-server probe; the probe is included in the focused adversarial round.
Author
Owner

Work completed

Implemented Forgejo #760, #814, #815, #817, #818 and #821 on job/agentfix.

  • Bounded binary tool responses and added byte-range reads for Files, Saved Versions, Mail attachments, and ZIP continuations. ZIP continuations stream bounded windows. Added malformed, unsatisfiable, and oversized range coverage, plus a 25 MiB download benchmark profile and seed.
  • Changed CLI retry behavior so safe reads retry, while an ambiguous write result is returned without replay until the server has operation receipts/idempotency support (#667).
  • Declared transfer and revision headers on the OpenAPI routes and regenerated OpenAPI, API client, and action contracts.
  • Aligned MCP/WebMCP search, file listing, stable Note opening, Mail cursors, tool naming, aliases, and actionable parameter errors.
  • Added the missing adversarial header classifications for Range, conditional validators, and TUS headers. The preflight now covers 342 operations and 966 generated tools.

Files

  • Agent routes: crates/plugins/files/{archive.rs,lib.rs,public.rs,uploads.rs}, crates/plugins/mail/src/routes.rs, crates/plugins/notes/src/reminders_api.rs, crates/plugins/photos/src/routes.rs, crates/plugins/video/src/routes.rs.
  • API and CLI: crates/calternal-api/{src/actions.rs,src/lib.rs}, crates/calternal-cli/{src/main.rs,src/remote_commands.rs}, crates/calternal-sync/{src/lib.rs,src/remote.rs}, crates/calternal-server/src/mcp.rs.
  • Contracts and adapters: contracts/{action-overrides.json,actions.json,openapi.json}, packages/api-client/src/{generated.ts,index.ts,index.test.ts}, apps/web/src/lib/webmcp/{generated.ts,generated.test.ts,tools.ts,tools.test.ts}, scripts/{action_registry.py,test_action_registry.py}, docs/action-registry.md.
  • Performance and hostile-input coverage: bench/mcp-scenarios-download-760.json, bench/mcp-seed-current.py, tests/adversarial/{attack2.py,prepare-media-runtime.sh,run.sh,xuser_matrix.py}.

Decisions and known gaps

  • CLI writes with ambiguous transport outcomes are not replayed because the server does not yet provide operation receipts. The CLI reports an unknown write result.
  • ZIP continuations regenerate the archive for each requested window. This bounds memory but can repeat compression work; the benchmark profile was added but not measured before the four-hour cutoff.
  • No rendered UI surface changed. UX gaps closed/left: agent adapters now preserve pagination and stable identities; no pointer, touch, keyboard, or visual UI changes apply.
  • The focused adversarial script passed its OpenAPI/authz classification preflight, then was interrupted during media-sandbox setup at the four-hour cutoff. It did not reach the real-server download/API probes.
  • calternal-server clippy was interrupted while compiling after the shared sccache stopped. Its tests were not reached. Final clippy/test gates were also not run for calternal-plugin-files, calternal-plugin-mail, calternal-plugin-notes, calternal-plugin-photos, or calternal-plugin-video.

Gate output

Verbatim outputs observed:

cargo fmt --check
(exit 0; no output)

cargo clippy -p calternal-sync --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 55.71s

cargo test -p calternal-sync
    test result: ok. 57 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.83s
    test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

apps/web: bun run check
svelte-check found 0 errors and 0 warnings

apps/web: bun run test
 Test Files  154 passed (154)
      Tests  1076 passed (1076)
   Duration  82.20s (transform 54%, import 17%, environment 15%, tests 10%, setup 4%)

packages/api-client: bun run test -- --testTimeout=15000
19 passed, 0 failed, 51 expect calls

scripts/test_action_registry.py
Ran 15 tests in 0.477s
OK
Action registry: 340 operations, 322 generated tools

XUSER_CLASSIFY_ONLY=1 python3 tests/adversarial/xuser_matrix.py
Cross-User classification gate: 342 operations classified
Generated entry point classification: 966 tools classified

XUSER_CLASSIFY_ONLY=1 python3 tests/adversarial/authz_matrix.py
Admin coverage: 39 reviewed operations; contract and Rust guards agree

cargo clippy -p calternal-server --all-targets -- -D warnings
interrupted (exit 130) while compiling; no success result

calternal-api and calternal-cli clippy/test gates passed. The API test output reported 13 passed; CLI reported 34 unit tests and 15 output-contract tests passed. WebMCP focused tests reported 19 passed. These passed before the final test-only .await correction in sync; sync and web gates were rerun after that correction. The full real-server adversarial round and server/plugin crate gates remain outstanding.

cargo clean completed: Removed 13753 files, 7.3GiB total.

Head: 2a06e563ad12fe355d4656ceee39e20b28ef860d. Working tree is clean. No push, deploy, or merge was performed.

## Work completed Implemented Forgejo #760, #814, #815, #817, #818 and #821 on `job/agentfix`. - Bounded binary tool responses and added byte-range reads for Files, Saved Versions, Mail attachments, and ZIP continuations. ZIP continuations stream bounded windows. Added malformed, unsatisfiable, and oversized range coverage, plus a 25 MiB download benchmark profile and seed. - Changed CLI retry behavior so safe reads retry, while an ambiguous write result is returned without replay until the server has operation receipts/idempotency support (#667). - Declared transfer and revision headers on the OpenAPI routes and regenerated OpenAPI, API client, and action contracts. - Aligned MCP/WebMCP search, file listing, stable Note opening, Mail cursors, tool naming, aliases, and actionable parameter errors. - Added the missing adversarial header classifications for Range, conditional validators, and TUS headers. The preflight now covers 342 operations and 966 generated tools. ## Files - Agent routes: `crates/plugins/files/{archive.rs,lib.rs,public.rs,uploads.rs}`, `crates/plugins/mail/src/routes.rs`, `crates/plugins/notes/src/reminders_api.rs`, `crates/plugins/photos/src/routes.rs`, `crates/plugins/video/src/routes.rs`. - API and CLI: `crates/calternal-api/{src/actions.rs,src/lib.rs}`, `crates/calternal-cli/{src/main.rs,src/remote_commands.rs}`, `crates/calternal-sync/{src/lib.rs,src/remote.rs}`, `crates/calternal-server/src/mcp.rs`. - Contracts and adapters: `contracts/{action-overrides.json,actions.json,openapi.json}`, `packages/api-client/src/{generated.ts,index.ts,index.test.ts}`, `apps/web/src/lib/webmcp/{generated.ts,generated.test.ts,tools.ts,tools.test.ts}`, `scripts/{action_registry.py,test_action_registry.py}`, `docs/action-registry.md`. - Performance and hostile-input coverage: `bench/mcp-scenarios-download-760.json`, `bench/mcp-seed-current.py`, `tests/adversarial/{attack2.py,prepare-media-runtime.sh,run.sh,xuser_matrix.py}`. ## Decisions and known gaps - CLI writes with ambiguous transport outcomes are not replayed because the server does not yet provide operation receipts. The CLI reports an unknown write result. - ZIP continuations regenerate the archive for each requested window. This bounds memory but can repeat compression work; the benchmark profile was added but not measured before the four-hour cutoff. - No rendered UI surface changed. UX gaps closed/left: agent adapters now preserve pagination and stable identities; no pointer, touch, keyboard, or visual UI changes apply. - The focused adversarial script passed its OpenAPI/authz classification preflight, then was interrupted during media-sandbox setup at the four-hour cutoff. It did not reach the real-server download/API probes. - `calternal-server` clippy was interrupted while compiling after the shared sccache stopped. Its tests were not reached. Final clippy/test gates were also not run for `calternal-plugin-files`, `calternal-plugin-mail`, `calternal-plugin-notes`, `calternal-plugin-photos`, or `calternal-plugin-video`. ## Gate output Verbatim outputs observed: ```text cargo fmt --check (exit 0; no output) cargo clippy -p calternal-sync --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 55.71s cargo test -p calternal-sync test result: ok. 57 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.83s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s apps/web: bun run check svelte-check found 0 errors and 0 warnings apps/web: bun run test Test Files 154 passed (154) Tests 1076 passed (1076) Duration 82.20s (transform 54%, import 17%, environment 15%, tests 10%, setup 4%) packages/api-client: bun run test -- --testTimeout=15000 19 passed, 0 failed, 51 expect calls scripts/test_action_registry.py Ran 15 tests in 0.477s OK Action registry: 340 operations, 322 generated tools XUSER_CLASSIFY_ONLY=1 python3 tests/adversarial/xuser_matrix.py Cross-User classification gate: 342 operations classified Generated entry point classification: 966 tools classified XUSER_CLASSIFY_ONLY=1 python3 tests/adversarial/authz_matrix.py Admin coverage: 39 reviewed operations; contract and Rust guards agree cargo clippy -p calternal-server --all-targets -- -D warnings interrupted (exit 130) while compiling; no success result ``` `calternal-api` and `calternal-cli` clippy/test gates passed. The API test output reported 13 passed; CLI reported 34 unit tests and 15 output-contract tests passed. WebMCP focused tests reported 19 passed. These passed before the final test-only `.await` correction in sync; sync and web gates were rerun after that correction. The full real-server adversarial round and server/plugin crate gates remain outstanding. `cargo clean` completed: `Removed 13753 files, 7.3GiB total`. Head: `2a06e563ad12fe355d4656ceee39e20b28ef860d`. Working tree is clean. No push, deploy, or merge was performed.
Author
Owner

Independent review of job/agentfix

Review issue: #760. Related issues: #814, #815, #817, #818 and #821.
Reviewed source: 2a06e563ad12fe355d4656ceee39e20b28ef860d.
Comparison base: origin/dev at
c4faf184df726a9375ae0c13bdfb6018ac2cf57e.
Review branch: job/rev2-agentfix, from the same base.

Read CLAUDE.md, CONTEXT.md and relevant DESIGN decisions, including §§2, 6,
21, 22, 26, 41 and 48. Inspected the requested three-dot diff. That diff also
contains merged work from other jobs. Findings below concern the agent
adapter changes and their owning routes.

Findings

  1. P1 — ZIP continuation can combine different archives (#760).
    crates/plugins/files/src/archive.rs:36, :234 and :294 accept only
    paths and byte windows, then read current source files into a new ZIP on
    every call. An ordinary edit between calls can mix old bytes with a new
    CRC or central directory. Size or folder changes can shift later offsets.
    Bind all chunks to one representation or reject a stale continuation.
    Test ordinary edits between chunks. This is a data-corruption merge blocker.
  2. P2 — ZIP windows do not bound source work or cancellation (#760).
    crates/plugins/files/src/archive.rs:168 sends selected bytes only, but
    :177 accepts every later write. :237 and :295 still read and finish
    the full archive for each chunk. After the selected window, channel-based
    cancellation cannot stop later reads. Reuse a transfer representation or
    stop at the window boundary, and check cancellation while skipping input.
    No load or latency measurement was made. Keep this with the ZIP owner.
  3. P2 — Old browser tool calls lose compatibility (#817).
    apps/web/src/lib/webmcp/tools.ts:199 replaces the former
    calternal_open href input with required id. :209 replaces
    calternal_today with calternal_today_agenda, without an old-name
    wrapper. Commit d0674d64a shows the removals. Preserve the former calls
    with explicit wrappers. Check both old and new calls and their access gates.
  4. P2 — Legacy Files pagination rejects valid API cursors (#817).
    crates/calternal-server/src/mcp.rs:900 and
    apps/web/src/lib/webmcp/tools.ts:129 cap cursors at 1,024 bytes.
    crates/plugins/files/src/listing.rs:18 permits 8,192 bytes. Its cursor
    contains the full folder path and encodes JSON plus a signature (:187,
    :521). A valid long folder path can return a first-page cursor that both
    adapters reject on the second call. Match the API limit and test a returned
    cursor above 1,024 bytes.

No separate P3 finding is reported. audit-findings.md contains the full
evidence, duplicate searches, rules and test ideas. Existing issues #760 and
#817 own all four findings. No new issue is needed.

Checks from source

  • Retry safety (#814): send_with_retry now checks safe methods before
    retrying transient statuses and transport failures. POST, PUT, PATCH and
    DELETE do not enter its replay path. Both generated and ergonomic CLI calls
    use it. This resolves the reported automatic replay path. Server operation
    receipts remain outside this fix (#667).
  • Memory and ranges (#760): generated base64 output has a 720 KiB raw
    limit. CLI and browser readers enforce it before retaining another chunk;
    MCP first reads at most 1 MiB and then checks the raw base64 limit. Versions
    seek and stream the selected range. Mail still fetches and decodes the whole
    attachment within its 25 MiB bound and four-provider-read limit. Thus Mail
    ranges bound output, not upstream transfer cost. The shared parser rejects
    multipart ranges and handles suffix, open-ended, empty and unsatisfiable
    representations. Duplicate and non-text Range checks exist on Files and
    Versions downloads and Mail attachments. Public preview retains its older
    header extraction; this review does not claim uniform header handling.
  • Pagination (#817): Mail forwards both before_received_ms and
    before_id from the returned next object. Files forwards cursor, limit
    and fixed name sort, and returns the API page with IDs. F4 remains.
  • Contracts (#815): required reminder/public-edit revision headers and
    tus headers now come from route annotations. Transfer headers appear in
    generated contracts. Revision checks stay in the route handlers.
  • Input errors (#818): Rust and browser parameter errors now name the
    action and field path and give an expected type without printing the value.
  • Generated aliases (#821): registry overrides preserve old generated
    names. CLI, MCP and WebMCP resolve each alias through the same operation,
    schema and policy. F3 concerns manually registered browser tools.

Authorization review

The agent changes do not add an independent write route. MCP dispatch passes
the original credential to the API middleware and uses McpDispatch only
to select the protocol surface (crates/calternal-server/src/mcp.rs:228).
Aliases use that same dispatch. WebMCP uses the current browser session.

Files downloads use live Share resolution. ZIP checks requested paths before
streaming and rechecks Shared entries during the walk. Versions use the
User's Home, consistent with owner-only Version history (DESIGN §26).
Home-limited App Password checks include ZIP and Version downloads
(crates/plugins/files/src/lib.rs:1990, :2003). Mail obtains the User from
the request context and performs User-scoped message, account and folder
lookups before provider access (crates/plugins/mail/src/routes.rs:1570).

The other touched route declarations are public edit/preview/tus, private tus,
Photos tus, Note block reminders and Video reads. They retain their existing
public-grant, request-principal and owning-route checks. The annotation changes
do not replace those checks. No new authorization bypass was found in the
reviewed agent changes. Static review does not prove live denial behavior.

Verification and limits

LIGHT rules prohibit builds, tests, servers and browsers. None were run.
No runtime reproduction, screenshots or performance result is claimed.
Dependencies were not added or changed by this review.

The source branch's issue report lists incomplete server and plugin gates and
an interrupted real-server probe. Those results are not this review's gates.
The review does not certify the other merged jobs in the three-dot diff.

For the merge round, run these commands after the fixes:

cargo fmt --check
cargo clippy -p calternal-plugin-files --all-targets -- -D warnings
cargo test -p calternal-plugin-files
cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings
cargo test -p calternal-plugin-mail
cargo clippy -p calternal-server --all-targets -- -D warnings
cargo test -p calternal-server
cd apps/web
bun run check
bunx vitest run src/lib/webmcp/tools.test.ts src/lib/webmcp/generated.test.ts --maxWorkers=2

The ZIP tests must check revision consistency and bounded source reads. The
adapter tests must preserve legacy calls and traverse a long signed cursor.
Run node apps/web/e2e/webmcp.mjs --transports-only and
node apps/web/e2e/webmcp.mjs --authorization-check from the repository root
with built server and CLI binaries. They must prove bounded transfer and live
route denial on the combined branch. Add focused regression cases for F1–F4;
the existing commands alone do not cover those cases.

Decisions and UX gaps

No product design decision was made. Findings use existing owners instead
of duplicate issues. The specific LIGHT rules take precedence over build and
cleanup instructions. No build output exists to clean. The review records
source conclusions separately from runtime evidence.

UX gaps closed: none; this is a read-only review. UX gaps left: legacy browser
calls and long Files cursors need the #817 fixes above.

Review deliverables and head

Built: two review documents; no product code.
Files: audit-findings.md, review-agentfix.md.
Review head: 2873ca5748245104458abf8f990bda11564415b3.
Commits: 7024238a1 records the first findings; 2873ca574 completes the review.
Summary: one P1 and three P2 findings. #760 owns ZIP consistency and work bounds;
#817 owns legacy browser compatibility and Files cursor limits. Evidence was
added to #817. No new issue was created, and no issue was closed.

Verification output:

git merge --no-edit origin/dev
Already up to date.

git diff --check HEAD~2 HEAD exited 0 with no output.
git status --short returned no output. No product gates were run under LIGHT.
No merge commit, push or deploy was made. Product defects remain for build jobs.

# Independent review of job/agentfix Review issue: #760. Related issues: #814, #815, #817, #818 and #821. Reviewed source: `2a06e563ad12fe355d4656ceee39e20b28ef860d`. Comparison base: `origin/dev` at `c4faf184df726a9375ae0c13bdfb6018ac2cf57e`. Review branch: `job/rev2-agentfix`, from the same base. Read CLAUDE.md, CONTEXT.md and relevant DESIGN decisions, including §§2, 6, 21, 22, 26, 41 and 48. Inspected the requested three-dot diff. That diff also contains merged work from other jobs. Findings below concern the agent adapter changes and their owning routes. ## Findings 1. **P1 — ZIP continuation can combine different archives (#760).** `crates/plugins/files/src/archive.rs:36`, `:234` and `:294` accept only paths and byte windows, then read current source files into a new ZIP on every call. An ordinary edit between calls can mix old bytes with a new CRC or central directory. Size or folder changes can shift later offsets. Bind all chunks to one representation or reject a stale continuation. Test ordinary edits between chunks. This is a data-corruption merge blocker. 2. **P2 — ZIP windows do not bound source work or cancellation (#760).** `crates/plugins/files/src/archive.rs:168` sends selected bytes only, but `:177` accepts every later write. `:237` and `:295` still read and finish the full archive for each chunk. After the selected window, channel-based cancellation cannot stop later reads. Reuse a transfer representation or stop at the window boundary, and check cancellation while skipping input. No load or latency measurement was made. Keep this with the ZIP owner. 3. **P2 — Old browser tool calls lose compatibility (#817).** `apps/web/src/lib/webmcp/tools.ts:199` replaces the former `calternal_open` `href` input with required `id`. `:209` replaces `calternal_today` with `calternal_today_agenda`, without an old-name wrapper. Commit `d0674d64a` shows the removals. Preserve the former calls with explicit wrappers. Check both old and new calls and their access gates. 4. **P2 — Legacy Files pagination rejects valid API cursors (#817).** `crates/calternal-server/src/mcp.rs:900` and `apps/web/src/lib/webmcp/tools.ts:129` cap cursors at 1,024 bytes. `crates/plugins/files/src/listing.rs:18` permits 8,192 bytes. Its cursor contains the full folder path and encodes JSON plus a signature (`:187`, `:521`). A valid long folder path can return a first-page cursor that both adapters reject on the second call. Match the API limit and test a returned cursor above 1,024 bytes. No separate P3 finding is reported. `audit-findings.md` contains the full evidence, duplicate searches, rules and test ideas. Existing issues #760 and #817 own all four findings. No new issue is needed. ## Checks from source - **Retry safety (#814):** `send_with_retry` now checks safe methods before retrying transient statuses and transport failures. POST, PUT, PATCH and DELETE do not enter its replay path. Both generated and ergonomic CLI calls use it. This resolves the reported automatic replay path. Server operation receipts remain outside this fix (#667). - **Memory and ranges (#760):** generated base64 output has a 720 KiB raw limit. CLI and browser readers enforce it before retaining another chunk; MCP first reads at most 1 MiB and then checks the raw base64 limit. Versions seek and stream the selected range. Mail still fetches and decodes the whole attachment within its 25 MiB bound and four-provider-read limit. Thus Mail ranges bound output, not upstream transfer cost. The shared parser rejects multipart ranges and handles suffix, open-ended, empty and unsatisfiable representations. Duplicate and non-text Range checks exist on Files and Versions downloads and Mail attachments. Public preview retains its older header extraction; this review does not claim uniform header handling. - **Pagination (#817):** Mail forwards both `before_received_ms` and `before_id` from the returned `next` object. Files forwards cursor, limit and fixed name sort, and returns the API page with IDs. F4 remains. - **Contracts (#815):** required reminder/public-edit revision headers and tus headers now come from route annotations. Transfer headers appear in generated contracts. Revision checks stay in the route handlers. - **Input errors (#818):** Rust and browser parameter errors now name the action and field path and give an expected type without printing the value. - **Generated aliases (#821):** registry overrides preserve old generated names. CLI, MCP and WebMCP resolve each alias through the same operation, schema and policy. F3 concerns manually registered browser tools. ## Authorization review The agent changes do not add an independent write route. MCP dispatch passes the original credential to the API middleware and uses `McpDispatch` only to select the protocol surface (`crates/calternal-server/src/mcp.rs:228`). Aliases use that same dispatch. WebMCP uses the current browser session. Files downloads use live Share resolution. ZIP checks requested paths before streaming and rechecks Shared entries during the walk. Versions use the User's Home, consistent with owner-only Version history (DESIGN §26). Home-limited App Password checks include ZIP and Version downloads (`crates/plugins/files/src/lib.rs:1990`, `:2003`). Mail obtains the User from the request context and performs User-scoped message, account and folder lookups before provider access (`crates/plugins/mail/src/routes.rs:1570`). The other touched route declarations are public edit/preview/tus, private tus, Photos tus, Note block reminders and Video reads. They retain their existing public-grant, request-principal and owning-route checks. The annotation changes do not replace those checks. No new authorization bypass was found in the reviewed agent changes. Static review does not prove live denial behavior. ## Verification and limits LIGHT rules prohibit builds, tests, servers and browsers. None were run. No runtime reproduction, screenshots or performance result is claimed. Dependencies were not added or changed by this review. The source branch's issue report lists incomplete server and plugin gates and an interrupted real-server probe. Those results are not this review's gates. The review does not certify the other merged jobs in the three-dot diff. For the merge round, run these commands after the fixes: ```sh cargo fmt --check cargo clippy -p calternal-plugin-files --all-targets -- -D warnings cargo test -p calternal-plugin-files cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings cargo test -p calternal-plugin-mail cargo clippy -p calternal-server --all-targets -- -D warnings cargo test -p calternal-server cd apps/web bun run check bunx vitest run src/lib/webmcp/tools.test.ts src/lib/webmcp/generated.test.ts --maxWorkers=2 ``` The ZIP tests must check revision consistency and bounded source reads. The adapter tests must preserve legacy calls and traverse a long signed cursor. Run `node apps/web/e2e/webmcp.mjs --transports-only` and `node apps/web/e2e/webmcp.mjs --authorization-check` from the repository root with built server and CLI binaries. They must prove bounded transfer and live route denial on the combined branch. Add focused regression cases for F1–F4; the existing commands alone do not cover those cases. ## Decisions and UX gaps No product design decision was made. Findings use existing owners instead of duplicate issues. The specific LIGHT rules take precedence over build and cleanup instructions. No build output exists to clean. The review records source conclusions separately from runtime evidence. UX gaps closed: none; this is a read-only review. UX gaps left: legacy browser calls and long Files cursors need the #817 fixes above. ## Review deliverables and head Built: two review documents; no product code. Files: `audit-findings.md`, `review-agentfix.md`. Review head: `2873ca5748245104458abf8f990bda11564415b3`. Commits: `7024238a1` records the first findings; `2873ca574` completes the review. Summary: one P1 and three P2 findings. #760 owns ZIP consistency and work bounds; #817 owns legacy browser compatibility and Files cursor limits. Evidence was added to #817. No new issue was created, and no issue was closed. Verification output: ```text git merge --no-edit origin/dev Already up to date. ``` `git diff --check HEAD~2 HEAD` exited 0 with no output. `git status --short` returned no output. No product gates were run under LIGHT. No merge commit, push or deploy was made. Product defects remain for build jobs.
Author
Owner

Review fixes started on job/agentfix, base/head 2a06e563ad. Read review-agentfix.md. Fetched and merged origin/dev: Already up to date. Scope: ZIP snapshot consistency and bounded/cancellable source reads (#760); legacy browser calls and API-sized Files cursors (#817). No dependency changes planned.

Review fixes started on job/agentfix, base/head 2a06e563ad12fe355d4656ceee39e20b28ef860d. Read review-agentfix.md. Fetched and merged origin/dev: Already up to date. Scope: ZIP snapshot consistency and bounded/cancellable source reads (#760); legacy browser calls and API-sized Files cursors (#817). No dependency changes planned.
Author
Owner

Confirmed review failures with focused regressions: legacy WebMCP href rejects with Unexpected tool input field; returned long Files cursor rejects with Invalid cursor. Browser fix committed as 1cdf26946: current and legacy calls share the live Apps gate, and cursors accept the API's 8192-byte bound. Web checks: svelte-check found 0 errors and 0 warnings; 21 focused tests passed.

ZIP decision: use a stateless, sorted inventory of immutable source inode revisions. First chunk returns an ETag; later chunks must copy it to body.revision. An ordinary source or folder membership change returns retryable 409 before body bytes. Opened source handles are checked against the inventory to catch races after validation. Stop source reads at the requested window and check cancellation even while skipping a prefix. Prefix reads remain necessary for ZIP checksums. Bound continuation inventory to 10000 entries and 8 MiB of path text; larger selections return 413 and should be split. Complete app ZIP streams retain their existing selection limits. The generated contract and help declare this continuation protocol. No disk transfer cache, dependency, migration, or rendered UI change.

Rust dependencies are compiling in the job's previously empty target directory with four build jobs. Files and server gates are still in progress. Full live matrices and transfer/authorization e2e are reserved for the merge round by the verification policy.

Confirmed review failures with focused regressions: legacy WebMCP href rejects with `Unexpected tool input field`; returned long Files cursor rejects with `Invalid cursor`. Browser fix committed as 1cdf26946: current and legacy calls share the live Apps gate, and cursors accept the API's 8192-byte bound. Web checks: `svelte-check found 0 errors and 0 warnings`; 21 focused tests passed. ZIP decision: use a stateless, sorted inventory of immutable source inode revisions. First chunk returns an ETag; later chunks must copy it to body.revision. An ordinary source or folder membership change returns retryable 409 before body bytes. Opened source handles are checked against the inventory to catch races after validation. Stop source reads at the requested window and check cancellation even while skipping a prefix. Prefix reads remain necessary for ZIP checksums. Bound continuation inventory to 10000 entries and 8 MiB of path text; larger selections return 413 and should be split. Complete app ZIP streams retain their existing selection limits. The generated contract and help declare this continuation protocol. No disk transfer cache, dependency, migration, or rendered UI change. Rust dependencies are compiling in the job's previously empty target directory with four build jobs. Files and server gates are still in progress. Full live matrices and transfer/authorization e2e are reserved for the merge round by the verification policy.
Author
Owner

Rust verification hit a shared build-cache failure before tests: error: error writing dependencies to /home/kayg/Developer/calternal-wt/authfix/target/tmp/sccacheIXNUcD/deps.d: No such file or directory (os error 2) followed by error: could not compile tokio (lib) due to 1 previous error. The shared sccache daemon retained another job's deleted TMPDIR. Retrying with RUSTC_WRAPPER unset for this job only, preserving built dependencies in its prescribed target directory. No cache daemon was stopped and no other job's files were changed.

Rust verification hit a shared build-cache failure before tests: `error: error writing dependencies to /home/kayg/Developer/calternal-wt/authfix/target/tmp/sccacheIXNUcD/deps.d: No such file or directory (os error 2)` followed by `error: could not compile tokio (lib) due to 1 previous error`. The shared sccache daemon retained another job's deleted TMPDIR. Retrying with RUSTC_WRAPPER unset for this job only, preserving built dependencies in its prescribed target directory. No cache daemon was stopped and no other job's files were changed.
Author
Owner

Independent review fixes: the original ZIP route failed the new source-edit regression with left: 200, right: 409. The bounded route now returns an ETag for its inventory and requires that revision on continuations; stale inventory returns a retryable 409. Source reads stop at the requested window, and disconnected readers stop prefix work. Files clippy passed (Finished dev profile [unoptimized + debuginfo] target(s) in 14m 44s). Files tests and the server gates are running on the shared host. Web check reports svelte-check found 0 errors and 0 warnings; focused WebMCP tests report Test Files 2 passed (2) and Tests 21 passed (21). No live matrices or VM measurements were run under the latest verification policy.

Independent review fixes: the original ZIP route failed the new source-edit regression with `left: 200`, `right: 409`. The bounded route now returns an ETag for its inventory and requires that revision on continuations; stale inventory returns a retryable 409. Source reads stop at the requested window, and disconnected readers stop prefix work. Files clippy passed (`Finished `dev` profile [unoptimized + debuginfo] target(s) in 14m 44s`). Files tests and the server gates are running on the shared host. Web check reports `svelte-check found 0 errors and 0 warnings`; focused WebMCP tests report `Test Files 2 passed (2)` and `Tests 21 passed (21)`. No live matrices or VM measurements were run under the latest verification policy.
Author
Owner

ZIP fix committed at 6750a43d7. Native regressions passed for changed source revisions, folder membership, complete reassembly, source replacement after validation, source-read cutoffs, and disconnects during prefix work. The real long-folder signed-cursor API regression passed. The completed Files suite reported:

test result: FAILED. 165 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 772.66s

One failure was the new contract test using Utoipa Path::path (a string) instead of Path::operation. This test is corrected and its focused rerun is queued. The other is the unchanged internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm test hitting its existing five-minute timeout (Elapsed(())); its log then records a late write failing after fixture cleanup. No existing assertion was changed. The server clippy attempt needed apps/web/build for RustEmbed; the production web build has now passed, and server clippy is queued again.

ZIP fix committed at 6750a43d7. Native regressions passed for changed source revisions, folder membership, complete reassembly, source replacement after validation, source-read cutoffs, and disconnects during prefix work. The real long-folder signed-cursor API regression passed. The completed Files suite reported: ```text test result: FAILED. 165 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 772.66s ``` One failure was the new contract test using Utoipa Path::path (a string) instead of Path::operation. This test is corrected and its focused rerun is queued. The other is the unchanged internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm test hitting its existing five-minute timeout (Elapsed(())); its log then records a late write failing after fixture cleanup. No existing assertion was changed. The server clippy attempt needed apps/web/build for RustEmbed; the production web build has now passed, and server clippy is queued again.
Author
Owner

Independent review fixes for #760 and #817 are committed on job/agentfix.

Head: 03b708e838bf8928a1c0bd16558696b24b6985ab. Review source: 2a06e563ad12fe355d4656ceee39e20b28ef860d. Both requested origin/dev merges were already up to date. No push or deployment was performed.

Built

  • ZIP continuations carry the first window's ETag in revision. The ordered inventory binds paths, folder membership and immutable inode fingerprints. Changed sources return 409 with restart instructions; replacement after validation aborts the body instead of returning mixed bytes.
  • Source reads stop at the requested window and check disconnects before each read, including skipped prefixes. Regression tests cover cutoffs, cancellation during prefixes, replacement races and complete reassembly.
  • WebMCP preserves calternal_open with legacy href and current id, plus calternal_today and calternal_today_agenda. Both forms retain the live Apps access gate.
  • Legacy browser and MCP Files tools accept the API's 8192-byte cursor bound. A real signed cursor from a long folder continues its API page. The native MCP mapper regression and browser callback regressions pass.
  • Updated contracts, generated client types, transfer documentation, merge-round probes and the ZIP header-window benchmark profile. Simplified one existing redundant error-mapping closure to pass server lint.

Files

  • apps/web/e2e/webmcp.mjs
  • apps/web/src/lib/webmcp/tools.test.ts
  • apps/web/src/lib/webmcp/tools.ts
  • bench/mcp-scenarios-download-760.json
  • contracts/action-overrides.json
  • contracts/actions.json
  • contracts/openapi.json
  • crates/calternal-server/src/mcp.rs
  • crates/plugins/files/src/archive.rs
  • crates/plugins/files/src/lib.rs
  • docs/action-registry.md
  • packages/api-client/src/generated.ts
  • scripts/test_action_registry.py
  • tests/adversarial/attack2.py

Gate output (result lines, verbatim)

cargo fmt --check exited 0 with no output. Files and server clippy exited 0. Web check, focused Vitest, registry tests and production web build exited 0.

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 11m 45s
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 34m 08s
test result: FAILED. 165 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 772.66s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 161 filtered out; finished in 6.39s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 168 filtered out; finished in 0.00s
test result: ok. 164 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 37.06s
svelte-check found 0 errors and 0 warnings
 Test Files  2 passed (2)
      Tests  21 passed (21)
Ran 16 tests in 0.603s
OK
  Wrote site to "build"
  ✔ done
     Removed 15612 files, 7.3GiB total

The full Files run's two failures were the new contract test using the wrong Utoipa accessor and the unchanged atomic-write/reconcile storm hitting its existing five-minute deadline. The contract test was corrected and passed with all seven archive tests. The storm log reports Elapsed(()), then a late task reports atomic write 165 failed: entry not found after abort/fixture cleanup. No existing storm assertion was changed.

Server verification used the compiled test binary. The first focused Cargo filter matched zero tests because the module is wire::mcp; the correct exact test then passed, and the complete compiled binary passed 164 tests with 5 ignored. The standard Cargo full-suite command started a refreshed build and was interrupted at the job time limit. This is not a claim that that Cargo invocation passed.

Full logs are in this worktree's ignored artifacts/ directory: files-tests.log, files-clippy-final.log, files-regression-tests.log, server-clippy-corrected.log, server-cursor-regression-verified.log, server-binary-tests.log, web-check.log, web-tests.log, contracts-tests.log, web-build.log, and cargo-clean.log. Cargo output and web build output were removed. The working tree is clean.

Known gaps

  • The existing Files storm timeout needs merge-round review/rerun. The standard server Cargo test invocation needs completion on the combined branch; compiled server unit tests passed separately.
  • Live browser, CLI/MCP transfer and cross-User checks remain for the merge round under the current verification policy. No screenshots or performance measurements are claimed. The benchmark profile was extended for the existing runner.

Decisions

  • Use a stateless revision inventory rather than retain archive files or open handles between requests.
  • Bound continuation inventories to 10000 entries and 8 MiB of path text; larger selections return 413 with smaller-selection instructions. Traditional full ZIP downloads keep their existing selection limits.
  • Re-read prefixes for ZIP checksums, then stop at the window boundary. Describe this cost and retry behavior in generated tool help.

UX gaps closed

Legacy browser names and inputs work, valid returned cursors continue, stale ZIP windows give restart instructions, and disconnected windows stop source work. No visual components were changed.

UX gaps left

Live cross-surface interaction evidence remains for the merge round.

For the merge round

Build the combined server, CLI and web first; set the harness binary paths to those builds. Run the standard crate tests to complete Cargo verification and review the storm timeout. The live browser run proves legacy calls and a real long signed cursor; the transport run proves bounded transfer; authorization and cross-User runs prove route denial. Screenshot mode captures macOS glyphs at 390, 820 and 1440 pixels in light and dark.

cargo test -p calternal-plugin-files -- --test-threads=4
cargo test -p calternal-server -- --test-threads=4
node apps/web/e2e/webmcp.mjs --screenshots artifacts/agentfix-review
node apps/web/e2e/webmcp.mjs --transports-only
node apps/web/e2e/webmcp.mjs --authorization-check
XUSER_MATRIX_ONLY=1 tests/adversarial/run.sh
Independent review fixes for #760 and #817 are committed on `job/agentfix`. Head: `03b708e838bf8928a1c0bd16558696b24b6985ab`. Review source: `2a06e563ad12fe355d4656ceee39e20b28ef860d`. Both requested origin/dev merges were already up to date. No push or deployment was performed. **Built** - ZIP continuations carry the first window's ETag in `revision`. The ordered inventory binds paths, folder membership and immutable inode fingerprints. Changed sources return 409 with restart instructions; replacement after validation aborts the body instead of returning mixed bytes. - Source reads stop at the requested window and check disconnects before each read, including skipped prefixes. Regression tests cover cutoffs, cancellation during prefixes, replacement races and complete reassembly. - WebMCP preserves `calternal_open` with legacy `href` and current `id`, plus `calternal_today` and `calternal_today_agenda`. Both forms retain the live Apps access gate. - Legacy browser and MCP Files tools accept the API's 8192-byte cursor bound. A real signed cursor from a long folder continues its API page. The native MCP mapper regression and browser callback regressions pass. - Updated contracts, generated client types, transfer documentation, merge-round probes and the ZIP header-window benchmark profile. Simplified one existing redundant error-mapping closure to pass server lint. **Files** - `apps/web/e2e/webmcp.mjs` - `apps/web/src/lib/webmcp/tools.test.ts` - `apps/web/src/lib/webmcp/tools.ts` - `bench/mcp-scenarios-download-760.json` - `contracts/action-overrides.json` - `contracts/actions.json` - `contracts/openapi.json` - `crates/calternal-server/src/mcp.rs` - `crates/plugins/files/src/archive.rs` - `crates/plugins/files/src/lib.rs` - `docs/action-registry.md` - `packages/api-client/src/generated.ts` - `scripts/test_action_registry.py` - `tests/adversarial/attack2.py` **Gate output (result lines, verbatim)** `cargo fmt --check` exited 0 with no output. Files and server clippy exited 0. Web check, focused Vitest, registry tests and production web build exited 0. ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 11m 45s Finished `dev` profile [unoptimized + debuginfo] target(s) in 34m 08s test result: FAILED. 165 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 772.66s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 161 filtered out; finished in 6.39s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 168 filtered out; finished in 0.00s test result: ok. 164 passed; 0 failed; 5 ignored; 0 measured; 0 filtered out; finished in 37.06s svelte-check found 0 errors and 0 warnings Test Files 2 passed (2) Tests 21 passed (21) Ran 16 tests in 0.603s OK Wrote site to "build" ✔ done Removed 15612 files, 7.3GiB total ``` The full Files run's two failures were the new contract test using the wrong Utoipa accessor and the unchanged atomic-write/reconcile storm hitting its existing five-minute deadline. The contract test was corrected and passed with all seven archive tests. The storm log reports `Elapsed(())`, then a late task reports `atomic write 165 failed: entry not found` after abort/fixture cleanup. No existing storm assertion was changed. Server verification used the compiled test binary. The first focused Cargo filter matched zero tests because the module is `wire::mcp`; the correct exact test then passed, and the complete compiled binary passed 164 tests with 5 ignored. The standard Cargo full-suite command started a refreshed build and was interrupted at the job time limit. This is not a claim that that Cargo invocation passed. Full logs are in this worktree's ignored `artifacts/` directory: `files-tests.log`, `files-clippy-final.log`, `files-regression-tests.log`, `server-clippy-corrected.log`, `server-cursor-regression-verified.log`, `server-binary-tests.log`, `web-check.log`, `web-tests.log`, `contracts-tests.log`, `web-build.log`, and `cargo-clean.log`. Cargo output and web build output were removed. The working tree is clean. **Known gaps** - The existing Files storm timeout needs merge-round review/rerun. The standard server Cargo test invocation needs completion on the combined branch; compiled server unit tests passed separately. - Live browser, CLI/MCP transfer and cross-User checks remain for the merge round under the current verification policy. No screenshots or performance measurements are claimed. The benchmark profile was extended for the existing runner. **Decisions** - Use a stateless revision inventory rather than retain archive files or open handles between requests. - Bound continuation inventories to 10000 entries and 8 MiB of path text; larger selections return 413 with smaller-selection instructions. Traditional full ZIP downloads keep their existing selection limits. - Re-read prefixes for ZIP checksums, then stop at the window boundary. Describe this cost and retry behavior in generated tool help. **UX gaps closed** Legacy browser names and inputs work, valid returned cursors continue, stale ZIP windows give restart instructions, and disconnected windows stop source work. No visual components were changed. **UX gaps left** Live cross-surface interaction evidence remains for the merge round. **For the merge round** Build the combined server, CLI and web first; set the harness binary paths to those builds. Run the standard crate tests to complete Cargo verification and review the storm timeout. The live browser run proves legacy calls and a real long signed cursor; the transport run proves bounded transfer; authorization and cross-User runs prove route denial. Screenshot mode captures macOS glyphs at 390, 820 and 1440 pixels in light and dark. ```sh cargo test -p calternal-plugin-files -- --test-threads=4 cargo test -p calternal-server -- --test-threads=4 node apps/web/e2e/webmcp.mjs --screenshots artifacts/agentfix-review node apps/web/e2e/webmcp.mjs --transports-only node apps/web/e2e/webmcp.mjs --authorization-check XUSER_MATRIX_ONLY=1 tests/adversarial/run.sh ```
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#760
No description provided.