SECURITY: public links still allow guest editing; §54 says public links are view only #981

Open
opened 2026-10-03 06:47:18 +00:00 by kayg · 24 comments
Owner

Problem

DESIGN §54 (owner grill #479/#461, 2026-10-01) says: "Public links are view only. … Only the edit option is removed from public links (§22)." The code still has a live public guest edit path:

  • crates/calternal-server/src/wire.rs:129 FilesPublicEditAccess → calternal_plugin_files::public_edit_guest_access;
  • crates/calternal-collab/src/session.rs:530 PublicEditAccess / with_public_edits; guest edits are saved as attributed Versions.

So a public link with edit can still let an anonymous visitor change a Note. This is the older §22 behaviour that §54 replaced. Found by the Canvas security review (canvases must never get public edit).

Fix

  • Remove the public edit option from link creation (UI, API, CLI, MCP, WebMCP) and stop honouring existing public edit links: they become view-only (keep the link working as view; no data loss).
  • Remove or hard-deny the guest edit path in the collaboration hub (DenyPublicEdits everywhere), and delete dead code with its tests, keeping tests that prove a public visitor cannot send a document update.
  • Migration: existing public links with edit permission are downgraded to view; record it in the change log for the owner.
  • Update §22 text to point at §54.

Tests

Adversarial: with an old public edit link, open the collab socket as a guest and send an update → disconnected, document unchanged. e2e: a public link page shows no edit affordance.
Authorization hole class → blocks merge of anything that widens it; model Sol medium.

## Problem DESIGN §54 (owner grill #479/#461, 2026-10-01) says: "Public links are view only. … Only the edit option is removed from public links (§22)." The code still has a live public guest edit path: - `crates/calternal-server/src/wire.rs:129` `FilesPublicEditAccess` → `calternal_plugin_files::public_edit_guest_access`; - `crates/calternal-collab/src/session.rs:530` `PublicEditAccess` / `with_public_edits`; guest edits are saved as attributed Versions. So a public link with edit can still let an anonymous visitor change a Note. This is the older §22 behaviour that §54 replaced. Found by the Canvas security review (canvases must never get public edit). ## Fix - Remove the public edit option from link creation (UI, API, CLI, MCP, WebMCP) and stop honouring existing public edit links: they become view-only (keep the link working as view; no data loss). - Remove or hard-deny the guest edit path in the collaboration hub (`DenyPublicEdits` everywhere), and delete dead code with its tests, keeping tests that prove a public visitor cannot send a document update. - Migration: existing public links with edit permission are downgraded to view; record it in the change log for the owner. - Update §22 text to point at §54. ## Tests Adversarial: with an old public edit link, open the collab socket as a guest and send an update → disconnected, document unchanged. e2e: a public link page shows no edit affordance. Authorization hole class → blocks merge of anything that widens it; model Sol medium.
Author
Owner

Started on job/pubedit-981 at base 48c94c9776. I will remove anonymous write authority, preserve existing links and Version attribution, and add focused regression coverage. The merge round will run the full adversarial matrices and e2e suite under the verification policy.

Started on job/pubedit-981 at base 48c94c9776660cee105be86c5a6ace90dd425367. I will remove anonymous write authority, preserve existing links and Version attribution, and add focused regression coverage. The merge round will run the full adversarial matrices and e2e suite under the verification policy.
Author
Owner

Resumed job/pubedit-981 after the reboot at 48c94c9776. Surviving edits were uncommitted; no gate had completed. The patch removes the guest authority adapter and persistence path, preserves historical Version attribution, rejects retired guest REST/socket routes before reading bodies or opening rooms, and downgrades old edit links without changing their URL. Browser expectations are updated because #981 explicitly removes public editing.

Infrastructure: the first clippy run hit unreadable cached rustix metadata after reboot; the job target was cleaned and the check restarted. Normal git fetch fails on damaged shared ref refs/heads/job/moneyfu-984. git fetch --refetch origin dev succeeded without changing that other job ref.

Decisions: retain retired routes as unconditional 403 tombstones; accept legacy edit:false input but omit edit from output and the public schema; clear retired guest credentials and rate buckets, retain historical attribution. The stronger socket invariant rejects upgrade, so no guest document update can be sent. Full adversarial matrices/e2e remain for the merge round under the current verification policy.

Resumed job/pubedit-981 after the reboot at 48c94c9776660cee105be86c5a6ace90dd425367. Surviving edits were uncommitted; no gate had completed. The patch removes the guest authority adapter and persistence path, preserves historical Version attribution, rejects retired guest REST/socket routes before reading bodies or opening rooms, and downgrades old edit links without changing their URL. Browser expectations are updated because #981 explicitly removes public editing. Infrastructure: the first clippy run hit unreadable cached rustix metadata after reboot; the job target was cleaned and the check restarted. Normal git fetch fails on damaged shared ref refs/heads/job/moneyfu-984. git fetch --refetch origin dev succeeded without changing that other job ref. Decisions: retain retired routes as unconditional 403 tombstones; accept legacy edit:false input but omit edit from output and the public schema; clear retired guest credentials and rate buckets, retain historical attribution. The stronger socket invariant rejects upgrade, so no guest document update can be sent. Full adversarial matrices/e2e remain for the merge round under the current verification policy.
Author
Owner

Progress commits: 5de942e9c (sharing contract and isolation classification), 356dcde3f (public UI and dead guest editor removal), 8281e9d68 (legacy security-state probe).

Evidence: production web build succeeded; bun run check reports svelte-check found 0 errors and 0 warnings; focused Vitest reports Test Files 2 passed (2) / Tests 10 passed (10); 11 action-registry tests pass. Offline classification reports Cross-User classification gate: 335 operations classified and Generated entry point classification: 945 tools classified.

Rust checks found remaining fields/imports from the removed guest code and one regression-test shutdown call assuming a Result instead of (). Fixed these. Rust test codegen is progressing after reboot cache recovery. A server build needs the production SPA directory, which is now available. origin/dev 4a871b383 is included; migration 19 remains free.

Progress commits: 5de942e9c (sharing contract and isolation classification), 356dcde3f (public UI and dead guest editor removal), 8281e9d68 (legacy security-state probe). Evidence: production web build succeeded; bun run check reports `svelte-check found 0 errors and 0 warnings`; focused Vitest reports `Test Files 2 passed (2)` / `Tests 10 passed (10)`; 11 action-registry tests pass. Offline classification reports `Cross-User classification gate: 335 operations classified` and `Generated entry point classification: 945 tools classified`. Rust checks found remaining fields/imports from the removed guest code and one regression-test shutdown call assuming a Result instead of (). Fixed these. Rust test codegen is progressing after reboot cache recovery. A server build needs the production SPA directory, which is now available. origin/dev 4a871b383 is included; migration 19 remains free.
Author
Owner

Backend checkpoint 91d670acd preserves the completed security slice while Rust gates run after cold-cache recovery.

First Files gate: test result: FAILED. 144 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 344.00s. Both #981 tests passed: public_edit_is_denied_and_legacy_links_keep_view and version_reads_preserve_historical_guest_attribution.

Finding 1: the existing schema-upgrade test asserted MAX(version)=18, but #981 requires migration 19. Updating this expectation is required by the issue, not a relaxed behavior assertion. The upgrade fixture now also contains an edit-only public link before migration and checks its preserved URL/identity and new view/download grant.

Finding 2: the unchanged reconcile-storm test hit its existing 300-second deadline. It aborts the writer/scanner/watcher before failing; a write at index 600 then reported entry-not-found during fixture teardown. This is a timeout with a teardown consequence, not evidence of a production server crash. The focused retry will keep its original assertions and deadline.

Additional finding: the parity exemption still described guest editing as available. The generator now shares the reviewed retirement list and refuses success responses on those four operations. 13 registry tests and 4 parity tests passed. Generated outputs will come from the new server contract.

Backend checkpoint 91d670acd preserves the completed security slice while Rust gates run after cold-cache recovery. First Files gate: `test result: FAILED. 144 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 344.00s`. Both #981 tests passed: `public_edit_is_denied_and_legacy_links_keep_view` and `version_reads_preserve_historical_guest_attribution`. Finding 1: the existing schema-upgrade test asserted MAX(version)=18, but #981 requires migration 19. Updating this expectation is required by the issue, not a relaxed behavior assertion. The upgrade fixture now also contains an edit-only public link before migration and checks its preserved URL/identity and new view/download grant. Finding 2: the unchanged reconcile-storm test hit its existing 300-second deadline. It aborts the writer/scanner/watcher before failing; a write at index 600 then reported entry-not-found during fixture teardown. This is a timeout with a teardown consequence, not evidence of a production server crash. The focused retry will keep its original assertions and deadline. Additional finding: the parity exemption still described guest editing as available. The generator now shares the reviewed retirement list and refuses success responses on those four operations. 13 registry tests and 4 parity tests passed. Generated outputs will come from the new server contract.
Author
Owner

Checkpoints: 5568fe302 adds the complete Files upgrade regression; 131c95b32 removes edit grants and retired write adapters from the generated API/action surfaces. Source-emitted OpenAPI fragments drive generation; the final server OpenAPI will be compared before completion.

Generator gates: Ran 17 tests in 0.211s / OK; Action registry: 333 operations, 312 generated tools; Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps. Offline classifications: Cross-User classification gate: 335 operations classified; Generated entry point classification: 936 tools classified; Admin coverage: 39 reviewed operations; contract and Rust guards agree. Web: svelte-check found 0 errors and 0 warnings.

The focused Files schema-upgrade regression passes. The unchanged reconciliation storm retry still hits its 300-second deadline; its writer reports entry-not-found after fixture teardown. Its deadline and assertions remain unchanged. This is a SLOW verification gap; no public-link denial/migration failure was found.

Remaining work: per-crate Rust gates, focused real-server UI regression and 24 macOS-emulated screenshots (four affected surfaces, three widths, two themes). Shared prebuilt CURRENT is absent, so a local debug server is required. Full matrices/e2e, release builds, staging and Mac interop are reserved for the merge round per the latest verification policy.

Checkpoints: 5568fe302 adds the complete Files upgrade regression; 131c95b32 removes edit grants and retired write adapters from the generated API/action surfaces. Source-emitted OpenAPI fragments drive generation; the final server OpenAPI will be compared before completion. Generator gates: `Ran 17 tests in 0.211s` / `OK`; `Action registry: 333 operations, 312 generated tools`; `Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps`. Offline classifications: `Cross-User classification gate: 335 operations classified`; `Generated entry point classification: 936 tools classified`; `Admin coverage: 39 reviewed operations; contract and Rust guards agree`. Web: `svelte-check found 0 errors and 0 warnings`. The focused Files schema-upgrade regression passes. The unchanged reconciliation storm retry still hits its 300-second deadline; its writer reports entry-not-found after fixture teardown. Its deadline and assertions remain unchanged. This is a SLOW verification gap; no public-link denial/migration failure was found. Remaining work: per-crate Rust gates, focused real-server UI regression and 24 macOS-emulated screenshots (four affected surfaces, three widths, two themes). Shared prebuilt CURRENT is absent, so a local debug server is required. Full matrices/e2e, release builds, staging and Mac interop are reserved for the merge round per the latest verification policy.
Author
Owner

#981 owner change note: migration 0019 keeps each existing public edit URL, item identity, password, expiry, counters and historical Versions. It converts those links to view/download, which is the view grant in DESIGN §54. New public links cannot give edit access. Anonymous REST write routes and the public collaboration socket now return 403. Authenticated Collaborate remains the way to edit together.

This note is also recorded in DESIGN §22 and the commit history used by scripts/changelog.sh. No content files are rewritten by the migration.

#981 owner change note: migration 0019 keeps each existing public edit URL, item identity, password, expiry, counters and historical Versions. It converts those links to view/download, which is the view grant in DESIGN §54. New public links cannot give edit access. Anonymous REST write routes and the public collaboration socket now return 403. Authenticated Collaborate remains the way to edit together. This note is also recorded in DESIGN §22 and the commit history used by `scripts/changelog.sh`. No content files are rewritten by the migration.
Author
Owner

Head checkpoint: 24d2c00959. All source changes are committed; no push or deploy.

Passing gate output, verbatim:

Files Clippy: Finished \dev` profile [unoptimized + debuginfo] target(s) in 8m 31sNotes Clippy:Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 15sWeb check:svelte-check found 0 errors and 0 warningsEditor tests:Test Files 2 passed (2)/Tests 10 passed (10)WebMCP tests (including #981 callback/schema regression):Test Files 1 passed (1)/Tests 10 passed (10)Generator tests:Ran 17 tests in 0.211s/OK`

The new WebMCP test checks published schema and callback registration; body validation belongs to the server. The Files test proves edit:true fails creation and update, migration preserves the old link and history, retired REST routes deny, and viewing leaves bytes unchanged. The full schema-upgrade regression passes. The unchanged Files reconciliation storm still hits its original 300-second deadline; no deadline or assertion was relaxed.

The existing bench/files-listing-427.py now accepts usual/largest public folder slugs and records public average/burst p50/p95, CPU and RSS. CLI and Python syntax checks pass. No measurement was run: the latest policy limits measurements to performance issues on the locked perf VM. There is no existing public-listing baseline.

Pending: collaboration tests, Notes tests, server gates/build, authoritative full-contract comparison, focused real-server browser regression and screenshots. Full adversarial matrices and full e2e remain for the merge round.

Head checkpoint: 24d2c00959e948ce69b4d765e18483507531085a. All source changes are committed; no push or deploy. Passing gate output, verbatim: Files Clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 8m 31s` Notes Clippy: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 15m 15s` Web check: `svelte-check found 0 errors and 0 warnings` Editor tests: `Test Files 2 passed (2)` / `Tests 10 passed (10)` WebMCP tests (including #981 callback/schema regression): `Test Files 1 passed (1)` / `Tests 10 passed (10)` Generator tests: `Ran 17 tests in 0.211s` / `OK` The new WebMCP test checks published schema and callback registration; body validation belongs to the server. The Files test proves edit:true fails creation and update, migration preserves the old link and history, retired REST routes deny, and viewing leaves bytes unchanged. The full schema-upgrade regression passes. The unchanged Files reconciliation storm still hits its original 300-second deadline; no deadline or assertion was relaxed. The existing `bench/files-listing-427.py` now accepts usual/largest public folder slugs and records public average/burst p50/p95, CPU and RSS. CLI and Python syntax checks pass. No measurement was run: the latest policy limits measurements to performance issues on the locked perf VM. There is no existing public-listing baseline. Pending: collaboration tests, Notes tests, server gates/build, authoritative full-contract comparison, focused real-server browser regression and screenshots. Full adversarial matrices and full e2e remain for the merge round.
Author
Owner

Checkpoint a79564495 adds the screenshot harness correction discovered before browser review: the theme helper used retired #app, but the production layout mounts .app-frame. Fresh public contexts now reuse the tagged storage test seam with no User cache, and public theme captures check rendered CSS without asking for account preferences. The focused mounted-frame regression reports # pass 1 / # fail 0.

The full helper test file reports seven pre-existing window is not defined failures from its old VM fixtures. This is already tracked in #958. I created #1006 before applying the search result and cross-linked that duplicate; no issue was closed and no existing fixture/assertion was relaxed.

Files, Notes and collaboration Clippy have all passed with -D warnings. Collaboration test binaries are linking on this shared host. The new guest denial test has not run yet; Notes/server tests and browser screenshots remain pending. The build has not produced a new server binary, and shared-server/CURRENT is absent. No full-suite, e2e or screenshot pass is claimed.

Checkpoint a79564495 adds the screenshot harness correction discovered before browser review: the theme helper used retired `#app`, but the production layout mounts `.app-frame`. Fresh public contexts now reuse the tagged storage test seam with no User cache, and public theme captures check rendered CSS without asking for account preferences. The focused mounted-frame regression reports `# pass 1` / `# fail 0`. The full helper test file reports seven pre-existing `window is not defined` failures from its old VM fixtures. This is already tracked in #958. I created #1006 before applying the search result and cross-linked that duplicate; no issue was closed and no existing fixture/assertion was relaxed. Files, Notes and collaboration Clippy have all passed with `-D warnings`. Collaboration test binaries are linking on this shared host. The new guest denial test has not run yet; Notes/server tests and browser screenshots remain pending. The build has not produced a new server binary, and shared-server/CURRENT is absent. No full-suite, e2e or screenshot pass is claimed.
Author
Owner

Focused #981 collaboration denial passes using the newly built hostile_clients test binary while the full crate command finishes linking its other binaries. The request has no User session and supplies a retired guest subprotocol token. The hub returns 403 before upgrade; shutdown and a disk read prove the Note is unchanged.

running 1 test
test retired_public_guest_socket_cannot_open_or_change_a_note ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 3.87s

No full collaboration suite pass or browser screenshot pass is claimed yet. Head: a79564495.

Focused #981 collaboration denial passes using the newly built hostile_clients test binary while the full crate command finishes linking its other binaries. The request has no User session and supplies a retired guest subprotocol token. The hub returns 403 before upgrade; shutdown and a disk read prove the Note is unchanged. ```text running 1 test test retired_public_guest_socket_cannot_open_or_change_a_note ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 3.87s ``` No full collaboration suite pass or browser screenshot pass is claimed yet. Head: a79564495.
Author
Owner

Head 83700697bd. The focused #981 socket-denial regression passes, and the full hostile_clients target also passes that new test.

The full collaboration crate command passed its 23 unit tests and the agent-turn, block-apply and cross-language targets, then stopped at two existing post-rejection save deadlines:

test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.62s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 81.22s
test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.15s

The unchanged focused retry passes primitive_value_in_fragment_cannot_truncate_the_note. unrepresentable_update_is_rejected_and_room_keeps_saving still misses its four-second save deadline. The same failure family is already tracked in #81 (intermittent post-rejection save failures on multiple branches). This is not claimed to be a harmless load-only failure. No truncation or accepted malformed update was observed in this run; rejection checks pass. Existing assertions and deadlines remain unchanged. Logs are in artifacts/collab-test.log, primitive-retry.log and unrepresentable-retry.log.

Server Clippy is now checking plugin code after a package-cache lock wait. Notes/server tests, server build, full-contract comparison and screenshots remain pending. The job is approaching its four-hour limit, so any unfinished checks will be named in the final report instead of being claimed as passes.

Head 83700697bda9e8b70cc84a7fbb263f0a7dca284f. The focused #981 socket-denial regression passes, and the full hostile_clients target also passes that new test. The full collaboration crate command passed its 23 unit tests and the agent-turn, block-apply and cross-language targets, then stopped at two existing post-rejection save deadlines: ```text test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.62s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 81.22s test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.15s ``` The unchanged focused retry passes primitive_value_in_fragment_cannot_truncate_the_note. unrepresentable_update_is_rejected_and_room_keeps_saving still misses its four-second save deadline. The same failure family is already tracked in #81 (intermittent post-rejection save failures on multiple branches). This is not claimed to be a harmless load-only failure. No truncation or accepted malformed update was observed in this run; rejection checks pass. Existing assertions and deadlines remain unchanged. Logs are in artifacts/collab-test.log, primitive-retry.log and unrepresentable-retry.log. Server Clippy is now checking plugin code after a package-cache lock wait. Notes/server tests, server build, full-contract comparison and screenshots remain pending. The job is approaching its four-hour limit, so any unfinished checks will be named in the final report instead of being claimed as passes.
Author
Owner

#981 implementation checkpoint — verification incomplete

Head: 83700697bda9e8b70cc84a7fbb263f0a7dca284f on job/pubedit-981. Required origin/dev integration completed once at 4a871b383864dad0d6c87bcd22b7f0d589e3506e. No push, deploy or issue closure. The four-hour job limit stopped the unfinished Notes build. This branch is not reported as merge-ready.

Built

  • Migration 0019 converts old public edit links to view/download. It retains URLs, item IDs, passwords, expiry, counters, content and historical Versions/guest attribution. Retired guest credentials and rate buckets are cleared. The owner change note is in §22, issue comments and the commit history used by the generated changelog.
  • Link creation/update reject edit:true. Legacy edit:false input remains compatible; edit is absent from responses, OpenAPI and generated CLI/MCP/WebMCP input schemas. Retired REST routes and the public collaboration route return 403 before link/body/room lookup. The guest grant/session/editor/write machinery is removed. Authenticated Collaborate remains supported.
  • Updated DESIGN §22, isolation classifications, authorization policies, adapter/parity generation, adversarial share-options checks and e2e sharing expectations. Preserved linked-Note read coverage and old Version attribution coverage.
  • Added the focused real-server browser flow and 24 macOS-emulated screenshot variants: file/folder link dialogs, anonymous Note view and authenticated Note editor, at 390/820/1440 px in light/dark. These captures have NOT run.
  • Extended the existing Files listing benchmark with public average/large-folder burst workloads for p50/p95, CPU and RSS. CLI/Python syntax checks pass. Measurements were not run under the latest policy (performance issues and the locked perf VM only); public listing has no existing baseline.

Gate output (verbatim excerpts)

cargo fmt --check: exit 0, no output.

Files Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 31s

Notes Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 15s

Collaboration Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 58s

Server Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 59s

Web check:

svelte-check found 0 errors and 0 warnings

Focused editor Vitest:

 Test Files  2 passed (2)
      Tests  10 passed (10)

Focused WebMCP Vitest:

 Test Files  1 passed (1)
      Tests  10 passed (10)

Generator tests:

Ran 17 tests in 0.211s
OK

Registry/parity checks:

Action registry: 333 operations, 312 generated tools

Parity check:

Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps

Cross-User classification:

Cross-User classification gate: 335 operations classified
Generated entry point classification: 936 tools classified

Authorization classification:

Admin coverage: 39 reviewed operations; contract and Rust guards agree

Full Files tests (initial schema expectation fixed afterward):

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

Focused Files schema upgrade after its fix:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 146 filtered out; finished in 4.72s

Focused public socket denial:

test retired_public_guest_socket_cannot_open_or_change_a_note ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 3.87s

Collaboration crate tests (stopped on existing integration failures):

test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.62s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 81.22s
test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.15s

Primitive-value focused retry:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 4.94s

Post-rejection save focused retry:

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 11 filtered out; finished in 5.92s

New mounted-frame theme regression:

# tests 1
# pass 1
# fail 0

Full theme helper tests (existing #958 fixture defect):

# tests 9
# pass 2
# fail 7

Known gaps

  • Files reconciliation storm missed its unchanged 300-second deadline twice, with a writer error during fixture teardown. The schema-upgrade expectation was changed from 18 to 19 because this issue adds migration 19; its unchanged identity assertions and new public-link checks pass on the focused run. Public link denial/migration and historical guest attribution tests passed in the full Files run.
  • Collaboration post-rejection save deadlines fail in the full hostile_clients target. The unchanged primitive-value retry passes; the unchanged unrepresentable-update retry still fails its four-second save deadline. This is tracked by existing #81 and is not classified as harmless without evidence. No truncated document or accepted malformed update was observed here.
  • Notes tests were interrupted during compilation at the job limit. Server tests/build and full server OpenAPI comparison have not run. The checked-in contract uses source-emitted Files/collaboration fragments; generator/type checks pass, but full-server regeneration is still required.
  • Focused browser regression and all 24 screenshots remain unrun because no new server binary was built. No screenshots are attached and no visual review pass is claimed.
  • Seven old theme VM tests lack window.__userStorageTest (#958). Their fixtures/expectations remain unchanged. Duplicate #1006 was created before applying the search result and cross-linked to #958; both remain open.

UX gaps closed

Removed the public Edit switch and visitor editor, including misleading guest-edit actions and code. The focused browser flow now covers real download and authenticated saving, but these actions still need the browser run. The screenshot helper now targets the actual mounted app frame and supports anonymous rendered-theme checks without an invented User.

UX gaps left

The real browser walk, pointer/touch/keyboard review, macOS-emulated width/theme screenshots and icon alignment inspection are pending. The orchestrator remains the visual reviewer.

Decisions

  • Keep old write URLs as uniform 403 tombstones, with no client adapters, instead of removing them and changing old callers to 404.
  • Accept legacy edit:false input while rejecting true and hiding the field from published schemas/responses.
  • Clear retired credentials/buckets but retain guest history needed by existing Versions. Old edit-only links receive view and download as required by §54.

For the merge round / follow-up

Use the combined branch and normal migration-number audit. Preserve #81 and #958 assertions until their behavior is resolved.

export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=3 TMPDIR=$PWD/target/tmp
cargo test -p calternal-plugin-notes
cargo test -p calternal-server
# Resolve/verify the tracked failures without relaxing their deadlines:
cargo test -p calternal-collab
cargo test -p calternal-plugin-files
(cd apps/web && bun run build)
cargo build -p calternal-server
"$CARGO_TARGET_DIR/debug/calternal-server" openapi
python3 scripts/action_registry.py --check
python3 scripts/parity_matrix.py --check
(cd packages/api-client && bun run generate)
# Inspect full-server contract differences against the source-emitted checkpoint.
(cd apps/web && CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" PUBEDIT_ONLY=1 SHARE_SHOTS="$PWD/../../artifacts/public-view-only" bun e2e/share.mjs)
# Attach and inspect all 24 PNGs, including icon cap-height alignment.
(cd apps/web && bun run test --maxWorkers=2)
(cd apps/web && bun e2e/share.mjs)
ADVERSARIAL_ROUND2_ONLY=1 ROUND2_SECTIONS=share-options tests/adversarial/run.sh
# Full authorization / Cross-User / robustness matrices, once on the combined branch:
tests/adversarial/run.sh
node --test apps/web/e2e/harness.test.mjs

The focused browser run must prove no Edit affordance, successful public viewing/download with unchanged content, and authenticated Note saving. The adversarial sharing probe must prove all retired REST/socket routes deny even when a disposable fixture still has old edit permissions. Full matrices verify every identity and entry point. Full server generation must confirm no public edit field or supported edit adapter reappears. Release/staging/Mac interop remain merge-round work under the latest policy.

Files

  • apps/web/e2e/harness.mjs
  • apps/web/e2e/harness.test.mjs
  • apps/web/e2e/share.mjs
  • apps/web/src/lib/files/PublicLinkPage.svelte
  • apps/web/src/lib/files/ShareDialog.svelte
  • apps/web/src/lib/notes/NoteEditorSurface.svelte
  • apps/web/src/lib/notes/collab.ts
  • apps/web/src/lib/notes/editorHost.ts
  • apps/web/src/lib/webmcp/generated.test.ts
  • bench/files-listing-427.py
  • contracts/actions.json
  • contracts/openapi.json
  • crates/calternal-collab/src/session.rs
  • crates/calternal-collab/tests/hostile_clients.rs
  • crates/calternal-server/src/wire.rs
  • crates/plugins/files/migrations/0019_public_links_view_only.sql
  • crates/plugins/files/src/lib.rs
  • crates/plugins/files/src/public.rs
  • crates/plugins/notes/src/lib.rs
  • docs/DESIGN.md
  • docs/audits/xuser-472.md
  • docs/parity-exceptions.json
  • docs/parity-matrix.md
  • packages/api-client/src/generated.ts
  • scripts/action_registry.py
  • scripts/parity_matrix.py
  • scripts/test_action_registry.py
  • tests/adversarial/attack2.py
  • tests/adversarial/authz_matrix.py
  • tests/adversarial/xuser_matrix.py

Cleanup: cargo clean and deletion of web build output are running; exact output is in artifacts/clean.log. Logs and source-emitted contract fragments remain in ignored artifacts/. Automatic approval review rejected the first cleanup command because rm -f style commands were not permitted; path-specific filesystem operations replace it.

#981 implementation checkpoint — verification incomplete Head: `83700697bda9e8b70cc84a7fbb263f0a7dca284f` on `job/pubedit-981`. Required origin/dev integration completed once at `4a871b383864dad0d6c87bcd22b7f0d589e3506e`. No push, deploy or issue closure. The four-hour job limit stopped the unfinished Notes build. This branch is not reported as merge-ready. ## Built - Migration 0019 converts old public edit links to view/download. It retains URLs, item IDs, passwords, expiry, counters, content and historical Versions/guest attribution. Retired guest credentials and rate buckets are cleared. The owner change note is in §22, issue comments and the commit history used by the generated changelog. - Link creation/update reject edit:true. Legacy edit:false input remains compatible; edit is absent from responses, OpenAPI and generated CLI/MCP/WebMCP input schemas. Retired REST routes and the public collaboration route return 403 before link/body/room lookup. The guest grant/session/editor/write machinery is removed. Authenticated Collaborate remains supported. - Updated DESIGN §22, isolation classifications, authorization policies, adapter/parity generation, adversarial share-options checks and e2e sharing expectations. Preserved linked-Note read coverage and old Version attribution coverage. - Added the focused real-server browser flow and 24 macOS-emulated screenshot variants: file/folder link dialogs, anonymous Note view and authenticated Note editor, at 390/820/1440 px in light/dark. These captures have NOT run. - Extended the existing Files listing benchmark with public average/large-folder burst workloads for p50/p95, CPU and RSS. CLI/Python syntax checks pass. Measurements were not run under the latest policy (performance issues and the locked perf VM only); public listing has no existing baseline. ## Gate output (verbatim excerpts) `cargo fmt --check`: exit 0, no output. Files Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 31s ``` Notes Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 15s ``` Collaboration Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 58s ``` Server Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 59s ``` Web check: ```text svelte-check found 0 errors and 0 warnings ``` Focused editor Vitest: ```text Test Files 2 passed (2) Tests 10 passed (10) ``` Focused WebMCP Vitest: ```text Test Files 1 passed (1) Tests 10 passed (10) ``` Generator tests: ```text Ran 17 tests in 0.211s OK ``` Registry/parity checks: ```text Action registry: 333 operations, 312 generated tools ``` Parity check: ```text Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps ``` Cross-User classification: ```text Cross-User classification gate: 335 operations classified Generated entry point classification: 936 tools classified ``` Authorization classification: ```text Admin coverage: 39 reviewed operations; contract and Rust guards agree ``` Full Files tests (initial schema expectation fixed afterward): ```text test result: FAILED. 144 passed; 2 failed; 1 ignored; 0 measured; 0 filtered out; finished in 344.00s ``` Focused Files schema upgrade after its fix: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 146 filtered out; finished in 4.72s ``` Focused public socket denial: ```text test retired_public_guest_socket_cannot_open_or_change_a_note ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 3.87s ``` Collaboration crate tests (stopped on existing integration failures): ```text test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.62s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.40s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 81.22s test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.15s ``` Primitive-value focused retry: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 4.94s ``` Post-rejection save focused retry: ```text test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 11 filtered out; finished in 5.92s ``` New mounted-frame theme regression: ```text # tests 1 # pass 1 # fail 0 ``` Full theme helper tests (existing #958 fixture defect): ```text # tests 9 # pass 2 # fail 7 ``` ## Known gaps - Files reconciliation storm missed its unchanged 300-second deadline twice, with a writer error during fixture teardown. The schema-upgrade expectation was changed from 18 to 19 because this issue adds migration 19; its unchanged identity assertions and new public-link checks pass on the focused run. Public link denial/migration and historical guest attribution tests passed in the full Files run. - Collaboration post-rejection save deadlines fail in the full hostile_clients target. The unchanged primitive-value retry passes; the unchanged unrepresentable-update retry still fails its four-second save deadline. This is tracked by existing #81 and is not classified as harmless without evidence. No truncated document or accepted malformed update was observed here. - Notes tests were interrupted during compilation at the job limit. Server tests/build and full server OpenAPI comparison have not run. The checked-in contract uses source-emitted Files/collaboration fragments; generator/type checks pass, but full-server regeneration is still required. - Focused browser regression and all 24 screenshots remain unrun because no new server binary was built. No screenshots are attached and no visual review pass is claimed. - Seven old theme VM tests lack window.__userStorageTest (#958). Their fixtures/expectations remain unchanged. Duplicate #1006 was created before applying the search result and cross-linked to #958; both remain open. ## UX gaps closed Removed the public Edit switch and visitor editor, including misleading guest-edit actions and code. The focused browser flow now covers real download and authenticated saving, but these actions still need the browser run. The screenshot helper now targets the actual mounted app frame and supports anonymous rendered-theme checks without an invented User. ## UX gaps left The real browser walk, pointer/touch/keyboard review, macOS-emulated width/theme screenshots and icon alignment inspection are pending. The orchestrator remains the visual reviewer. ## Decisions - Keep old write URLs as uniform 403 tombstones, with no client adapters, instead of removing them and changing old callers to 404. - Accept legacy edit:false input while rejecting true and hiding the field from published schemas/responses. - Clear retired credentials/buckets but retain guest history needed by existing Versions. Old edit-only links receive view and download as required by §54. ## For the merge round / follow-up Use the combined branch and normal migration-number audit. Preserve #81 and #958 assertions until their behavior is resolved. ```sh export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=3 TMPDIR=$PWD/target/tmp cargo test -p calternal-plugin-notes cargo test -p calternal-server # Resolve/verify the tracked failures without relaxing their deadlines: cargo test -p calternal-collab cargo test -p calternal-plugin-files (cd apps/web && bun run build) cargo build -p calternal-server "$CARGO_TARGET_DIR/debug/calternal-server" openapi python3 scripts/action_registry.py --check python3 scripts/parity_matrix.py --check (cd packages/api-client && bun run generate) # Inspect full-server contract differences against the source-emitted checkpoint. (cd apps/web && CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" PUBEDIT_ONLY=1 SHARE_SHOTS="$PWD/../../artifacts/public-view-only" bun e2e/share.mjs) # Attach and inspect all 24 PNGs, including icon cap-height alignment. (cd apps/web && bun run test --maxWorkers=2) (cd apps/web && bun e2e/share.mjs) ADVERSARIAL_ROUND2_ONLY=1 ROUND2_SECTIONS=share-options tests/adversarial/run.sh # Full authorization / Cross-User / robustness matrices, once on the combined branch: tests/adversarial/run.sh node --test apps/web/e2e/harness.test.mjs ``` The focused browser run must prove no Edit affordance, successful public viewing/download with unchanged content, and authenticated Note saving. The adversarial sharing probe must prove all retired REST/socket routes deny even when a disposable fixture still has old edit permissions. Full matrices verify every identity and entry point. Full server generation must confirm no public edit field or supported edit adapter reappears. Release/staging/Mac interop remain merge-round work under the latest policy. ## Files - `apps/web/e2e/harness.mjs` - `apps/web/e2e/harness.test.mjs` - `apps/web/e2e/share.mjs` - `apps/web/src/lib/files/PublicLinkPage.svelte` - `apps/web/src/lib/files/ShareDialog.svelte` - `apps/web/src/lib/notes/NoteEditorSurface.svelte` - `apps/web/src/lib/notes/collab.ts` - `apps/web/src/lib/notes/editorHost.ts` - `apps/web/src/lib/webmcp/generated.test.ts` - `bench/files-listing-427.py` - `contracts/actions.json` - `contracts/openapi.json` - `crates/calternal-collab/src/session.rs` - `crates/calternal-collab/tests/hostile_clients.rs` - `crates/calternal-server/src/wire.rs` - `crates/plugins/files/migrations/0019_public_links_view_only.sql` - `crates/plugins/files/src/lib.rs` - `crates/plugins/files/src/public.rs` - `crates/plugins/notes/src/lib.rs` - `docs/DESIGN.md` - `docs/audits/xuser-472.md` - `docs/parity-exceptions.json` - `docs/parity-matrix.md` - `packages/api-client/src/generated.ts` - `scripts/action_registry.py` - `scripts/parity_matrix.py` - `scripts/test_action_registry.py` - `tests/adversarial/attack2.py` - `tests/adversarial/authz_matrix.py` - `tests/adversarial/xuser_matrix.py` Cleanup: cargo clean and deletion of web build output are running; exact output is in artifacts/clean.log. Logs and source-emitted contract fragments remain in ignored artifacts/. Automatic approval review rejected the first cleanup command because rm -f style commands were not permitted; path-specific filesystem operations replace it.
Author
Owner

Final cleanup completed. Head remains 83700697bd; git status is clean. Web build output, Python caches and temporary contract executables are removed. Ignored report/log artifacts remain.

Removed 15481 files, 8.0GiB total

The verification gaps in the final report remain: #81 save failure, Notes/server tests and server build/contract/browser/screenshots. No issue was closed, no push or deploy was performed.

Final cleanup completed. Head remains 83700697bda9e8b70cc84a7fbb263f0a7dca284f; git status is clean. Web build output, Python caches and temporary contract executables are removed. Ignored report/log artifacts remain. ```text Removed 15481 files, 8.0GiB total ``` The verification gaps in the final report remain: #81 save failure, Notes/server tests and server build/contract/browser/screenshots. No issue was closed, no push or deploy was performed.
Author
Owner

Resuming verification on job/pubedit-981. Prior head: 83700697bd. Fetched and merged origin/dev once; current head: b50ed94f55. The integration changes DESIGN documentation only. Remaining checks: per-crate Notes/server/Files/collaboration tests, server build and contract comparison, focused live-server regression, public-sharing probe and macOS width/theme screenshots. Cargo uses three build jobs; existing assertions stay unchanged. No push or deploy.

Resuming verification on job/pubedit-981. Prior head: 83700697bda9e8b70cc84a7fbb263f0a7dca284f. Fetched and merged origin/dev once; current head: b50ed94f55bf602a7dae3dc2e35dbcaacca96418. The integration changes DESIGN documentation only. Remaining checks: per-crate Notes/server/Files/collaboration tests, server build and contract comparison, focused live-server regression, public-sharing probe and macOS width/theme screenshots. Cargo uses three build jobs; existing assertions stay unchanged. No push or deploy.
Author
Owner

Verification progress at b50ed94f55: production web build passed. Fresh focused web gates:

svelte-check found 0 errors and 0 warnings
 Test Files  2 passed (2)
      Tests  19 passed (19)
 Test Files  1 passed (1)
      Tests  1 passed (1)

Action/parity checks pass (333 operations, 312 tools, no adapter gaps). Files migration audit: origin/dev ends at 0018; our 0019 remains unique. Notes/server/Files/collaboration Rust tests and the one server build are still running with CARGO_BUILD_JOBS=3. No existing assertion changed.

Verification progress at b50ed94f55bf602a7dae3dc2e35dbcaacca96418: production web build passed. Fresh focused web gates: ```text svelte-check found 0 errors and 0 warnings Test Files 2 passed (2) Tests 19 passed (19) Test Files 1 passed (1) Tests 1 passed (1) ``` Action/parity checks pass (333 operations, 312 tools, no adapter gaps). Files migration audit: origin/dev ends at 0018; our 0019 remains unique. Notes/server/Files/collaboration Rust tests and the one server build are still running with CARGO_BUILD_JOBS=3. No existing assertion changed.
Author
Owner

Notes verification reproduced the unchanged daily_and_composer_preserve_unrelated_bytes failure in the parallel per-crate run. The unchanged test passes in isolation:

test tests::daily_and_composer_preserve_unrelated_bytes ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 166 filtered out; finished in 3.38s

This matches existing #954. Evidence: setup() uses fixed User ID 27b870bd-86ec-47b4-ae93-a019668170fd for separate temporary Homes; USER_LOCKS is process-global and journal_snapshot() uses try_lock_owned() before repairing a missing legacy snapshot, otherwise returning 404. The #981 Notes diff only deletes two unused public-edit path helpers, outside that code. No assertion, fixture or deadline changed. The full Notes run is still finishing its Unicode property test.

Notes verification reproduced the unchanged daily_and_composer_preserve_unrelated_bytes failure in the parallel per-crate run. The unchanged test passes in isolation: ```text test tests::daily_and_composer_preserve_unrelated_bytes ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 166 filtered out; finished in 3.38s ``` This matches existing #954. Evidence: setup() uses fixed User ID 27b870bd-86ec-47b4-ae93-a019668170fd for separate temporary Homes; USER_LOCKS is process-global and journal_snapshot() uses try_lock_owned() before repairing a missing legacy snapshot, otherwise returning 404. The #981 Notes diff only deletes two unused public-edit path helpers, outside that code. No assertion, fixture or deadline changed. The full Notes run is still finishing its Unicode property test.
Author
Owner

Head: 673be10dab. Added the focused #981 verification commands and evidence requirements to the existing Cross-User audit in atomic documentation commit 673be10da. Classification checks pass unchanged. Notes completed with one existing #954 failure:

test result: FAILED. 166 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 312.41s

The unchanged failing test passes alone (1 passed in 3.38s); its full-run failure is 404 versus expected 200, matching #954. Server compilation has reached calternal-server and its plugins with no compile error. Files/collaboration tests, server binary, authoritative contract and live evidence remain pending. Current target uses about 4.4 GiB. No application source changed during this verification continuation.

Head: 673be10dab57b2e5cd79316f54cab6d65ec871ef. Added the focused #981 verification commands and evidence requirements to the existing Cross-User audit in atomic documentation commit 673be10da. Classification checks pass unchanged. Notes completed with one existing #954 failure: ```text test result: FAILED. 166 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 312.41s ``` The unchanged failing test passes alone (1 passed in 3.38s); its full-run failure is 404 versus expected 200, matching #954. Server compilation has reached calternal-server and its plugins with no compile error. Files/collaboration tests, server binary, authoritative contract and live evidence remain pending. Current target uses about 4.4 GiB. No application source changed during this verification continuation.
Author
Owner

The fresh server gate found missing 429 response for get /api/v1/public/{slug}/edit. This is caused by #981: the route is now an unconditional 403 tombstone and no longer calls the public authorization/rate-limit helper. The shared public middleware only resolves client IP; it does not impose a rate limit. Adding 429 to its schema would describe a response this route cannot produce. Updated the server contract test only for the two retired public REST paths: require exactly one response, 403; retain the existing 429 assertions for every active public/auth operation. This expectation change is specifically required by the behavior removed in #981/§54. No production behavior changed.

The separate live-app failure is full_app_setup_session_config_and_backup at wire.rs:7629: its unchanged five-second wait for a background User archive returns Elapsed(()). Investigation/retry is pending; it is not yet attributed to #965 or reported as passing.

The fresh server gate found missing 429 response for get /api/v1/public/{slug}/edit. This is caused by #981: the route is now an unconditional 403 tombstone and no longer calls the public authorization/rate-limit helper. The shared public middleware only resolves client IP; it does not impose a rate limit. Adding 429 to its schema would describe a response this route cannot produce. Updated the server contract test only for the two retired public REST paths: require exactly one response, 403; retain the existing 429 assertions for every active public/auth operation. This expectation change is specifically required by the behavior removed in #981/§54. No production behavior changed. The separate live-app failure is full_app_setup_session_config_and_backup at wire.rs:7629: its unchanged five-second wait for a background User archive returns Elapsed(()). Investigation/retry is pending; it is not yet attributed to #965 or reported as passing.
Author
Owner

Checkpoint 7e26f5a26 records the contract test correction for retired public writes; server Clippy and tests are still queued/running, not claimed passing. Fresh Files public_edit_is_denied_and_legacy_links_keep_view, schema-upgrade and historical guest-attribution cases pass. A diagnostic comparison found that the prior source-fragment export still retains a 429 response for retired REST routes, whereas the real server test reports only 403. This stale generated contract must be replaced by the authoritative server export after the one binary build, followed by adapter generation/checks. The production retired handlers remain unconditional denials. The isolated unchanged server archive test passes (1 passed in 16.80s); its full-run timeout is retained as a failed result, not attributed to #965 without more evidence.

Checkpoint 7e26f5a26 records the contract test correction for retired public writes; server Clippy and tests are still queued/running, not claimed passing. Fresh Files public_edit_is_denied_and_legacy_links_keep_view, schema-upgrade and historical guest-attribution cases pass. A diagnostic comparison found that the prior source-fragment export still retains a 429 response for retired REST routes, whereas the real server test reports only 403. This stale generated contract must be replaced by the authoritative server export after the one binary build, followed by adapter generation/checks. The production retired handlers remain unconditional denials. The isolated unchanged server archive test passes (1 passed in 16.80s); its full-run timeout is retained as a failed result, not attributed to #965 without more evidence.
Author
Owner

Fresh Files run at current branch source: all #981 cases pass (public denial/legacy migration, schema upgrade, historical attribution). The only full-suite failure matches existing #942; no expectation or deadline changed. Verbatim evidence:

---- tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm stdout ----

thread 'tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm' (2383253) panicked at crates/plugins/files/src/lib.rs:5080:14:
writes, reconcile scans, and watcher adoption complete within five minutes: Elapsed(())
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

thread 'tokio-rt-worker' (2383255) panicked at crates/plugins/files/src/lib.rs:5054:45:
atomic write 946 failed: entry not found


failures:
    tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm

test result: FAILED. 145 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 380.16s

The entry-not-found panic follows the timeout in the log. Teardown as its cause remains an inference, as #942 states; this run is not reported as passing. Collaboration tests are queued behind server Clippy.

Fresh Files run at current branch source: all #981 cases pass (public denial/legacy migration, schema upgrade, historical attribution). The only full-suite failure matches existing #942; no expectation or deadline changed. Verbatim evidence: ```text ---- tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm stdout ---- thread 'tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm' (2383253) panicked at crates/plugins/files/src/lib.rs:5080:14: writes, reconcile scans, and watcher adoption complete within five minutes: Elapsed(()) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'tokio-rt-worker' (2383255) panicked at crates/plugins/files/src/lib.rs:5054:45: atomic write 946 failed: entry not found failures: tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm test result: FAILED. 145 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 380.16s ``` The entry-not-found panic follows the timeout in the log. Teardown as its cause remains an inference, as #942 states; this run is not reported as passing. Collaboration tests are queued behind server Clippy.
Author
Owner

Server Clippy passed for checkpoint 7e26f5a26, including the #981 denial-only contract test correction. Verbatim final output:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 52m 57s

Collaboration crate tests are now compiling; the final server test rerun waits for Cargo’s build-directory lock. The stale fragment contract is still pending authoritative regeneration from the one server binary build.

Server Clippy passed for checkpoint 7e26f5a26, including the #981 denial-only contract test correction. Verbatim final output: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 52m 57s ``` Collaboration crate tests are now compiling; the final server test rerun waits for Cargo’s build-directory lock. The stale fragment contract is still pending authoritative regeneration from the one server binary build.
Author
Owner

Fresh collaboration hostile_clients target passes all 12 cases, including the retired public guest socket regression and the two previously failing #81 save cases. Verbatim:

test retired_public_guest_socket_cannot_open_or_change_a_note ... ok
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.92s

No existing expectation or deadline changed. Other collaboration targets pass so far; final doc tests are still finishing. The corrected server test target is compiling and the single server binary build remains queued.

Fresh collaboration hostile_clients target passes all 12 cases, including the retired public guest socket regression and the two previously failing #81 save cases. Verbatim: ```text test retired_public_guest_socket_cannot_open_or_change_a_note ... ok test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.92s ``` No existing expectation or deadline changed. Other collaboration targets pass so far; final doc tests are still finishing. The corrected server test target is compiling and the single server binary build remains queued.
Author
Owner

Final server tests pass at 7e26f5a26, including the corrected denial-only OpenAPI assertion and live_apps_run_in_separate_processes. The prior archive timeout does not recur in this fresh full run. Verbatim:

test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 16.00s

The complete collaboration command also passed, with 72 tests across its targets and no failed cases; the old #81 cases pass without assertion/deadline changes. The one server binary build is now running. Pending: authoritative export/adapter comparison, focused live-server browser/probe and 24 macOS width/theme screenshots.

Final server tests pass at 7e26f5a26, including the corrected denial-only OpenAPI assertion and live_apps_run_in_separate_processes. The prior archive timeout does not recur in this fresh full run. Verbatim: ```text test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 16.00s ``` The complete collaboration command also passed, with 72 tests across its targets and no failed cases; the old #81 cases pass without assertion/deadline changes. The one server binary build is now running. Pending: authoritative export/adapter comparison, focused live-server browser/probe and 24 macOS width/theme screenshots.
Author
Owner

Production screenshots exposed a #981 regression: guest-editor removal also deleted the file/folder {:else} in PublicLinkPage.svelte. Public files incorrectly render This folder is empty, and public folders lose their listing. Restored the existing branch (no new UI unit) and extended the focused real-server flow to create a folder link, open its child with keyboard and touch, download the child, and assert that files have no folder empty state. Added six public-folder width/theme captures; the final evidence set will contain 30 images and supersede the first set. A new production web build/check and focused run are underway. The prior REST sharing probe passed with zero findings and zero SLOW findings; no Rust or API behavior changed in this UI correction.

Production screenshots exposed a #981 regression: guest-editor removal also deleted the file/folder {:else} in PublicLinkPage.svelte. Public files incorrectly render This folder is empty, and public folders lose their listing. Restored the existing branch (no new UI unit) and extended the focused real-server flow to create a folder link, open its child with keyboard and touch, download the child, and assert that files have no folder empty state. Added six public-folder width/theme captures; the final evidence set will contain 30 images and supersede the first set. A new production web build/check and focused run are underway. The prior REST sharing probe passed with zero findings and zero SLOW findings; no Rust or API behavior changed in this UI correction.
Author
Owner

#981 verification complete

Head: dd1c8f1cc638374f890a9b0b7b340359d85e1b5e on job/pubedit-981. Fetched and merged origin/dev once. Files migration 0019 was free: the fetched branch ended at 0018. No push, deploy or issue closure.

What was built

Public links cannot grant edit through the API, CLI, MCP, WebMCP or browser. Existing edit links become view/download links. Their URLs, passwords, expiry, counters, item identities and historical Version attribution stay intact. Retired REST/socket entry points deny before body/link/room lookup. Authenticated Collaborate remains available.

This continuation completed the remaining verification and made four corrections:

  • The server contract test now requires exactly 403 for the two retired REST paths. Active public/auth routes retain their original 429 assertions. This expectation change follows the behavior explicitly removed by #981; no other existing expectation or deadline changed.
  • The authoritative server export replaces the fragment export. It removes stale retired-route 429 responses and refreshes four existing handler descriptions. Generated actions and client types match it.
  • The screenshot helper seeds its review theme after media callbacks and the Appearance save settle. It keeps the existing rendering assertions.
  • Restored the file/folder branch accidentally removed with the guest editor. Public folders show their children again; files no longer show a folder empty state. The focused regression now checks keyboard/touch Quick Look and child download.

Atomic continuation commits: 673be10da (audit commands), 7e26f5a26 (retired contract assertion), 6a470751e (capture ordering), 33eef7657 (authoritative generated files), dd1c8f1cc (public folder regression fix). Source comments were read again before this report.

Gates — verbatim output

cargo fmt --check: exit 0, no output. The prior Files, Notes and collaboration Clippy passes cover unchanged Rust source in this continuation:

Files Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 31s

Notes Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 15s

Collaboration Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 58s

Fresh server Clippy after the test correction:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 52m 57s

Fresh server tests:

test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 16.00s

Fresh collaboration tests (every target passed):

test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.99s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.78s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.60s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 75.81s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.92s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.77s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.34s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.09s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.14s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.69s
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 22.65s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Fresh Notes full run:

test result: FAILED. 166 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 312.41s

Unchanged Notes #954 test in isolation:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 166 filtered out; finished in 3.38s

Fresh Files full run:

test result: FAILED. 145 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 380.16s

The Files public denial/migration, schema upgrade and historical attribution cases pass in that full run:

test tests::dev_files_schema_upgrades_through_share_log_and_sidecar_migrations ... ok
test tests::public_edit_is_denied_and_legacy_links_keep_view ... ok
test tests::version_reads_preserve_historical_guest_attribution ... ok

One server binary build:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 20m 08s

Production web build completed with adapter-static. Final web check:

svelte-check found 0 errors and 0 warnings

Focused provider/WebMCP Vitest:

 Test Files  2 passed (2)
      Tests  19 passed (19)
 Test Files  1 passed (1)
      Tests  1 passed (1)
 Test Files  1 passed (1)
      Tests  10 passed (10)

API-client tests:

 18 pass
 0 fail
Ran 18 tests across 1 file. [949.00ms]

Focused mounted-frame theme regression:

# tests 1
# pass 1
# fail 0

Generator/classification checks:

Ran 13 tests in 0.498s
OK
Action registry: 333 operations, 312 generated tools
Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps
Cross-User classification gate: 335 operations classified
Generated entry point classification: 936 tools classified
Admin coverage: 39 reviewed operations; contract and Rust guards agree

Final focused real-server browser run:

PASS #981 public link creation and visitor page are view only; content unchanged
CSP REPORTS share: 0 across 3 pages

The existing public sharing probe ran once with a 900-second bound, the built server and production web build. It exited 0:

server alive at end: True
==== ROUND 2 FINDINGS 0
==== ROUND 2 SLOW 0

Known gaps and failure evidence

  • Notes #954: the full run reports 404 versus the unchanged expected 200 in daily_and_composer_preserve_unrelated_bytes. Separate test Homes use the same User ID and process-global writer lock. journal_snapshot uses try_lock_owned before legacy ID repair, then returns 404 without a snapshot. The unchanged isolated test passes in 3.38 s. This matches #954; the #981 Notes diff only removes unused guest helpers. The full Notes command remains a failed gate.
  • Files #942: the unchanged reconciliation storm exceeds its five-minute wait, then a background writer reports atomic write 946 failed: entry not found. The full Files command remains a failed gate. Fixture teardown as the writer error's cause is an inference, not a confirmed harmless result. The same timeout/error family is already recorded in #942; no assertion or deadline was relaxed.
  • The initial server run found the retired-route contract mismatch and a five-second User archive timeout. The contract mismatch is fixed. The unchanged archive test passed alone (1 passed in 16.80 s), and all live-app subprocess tests pass in the final full server run. No evidence here establishes #965 as that timeout's cause.
  • The previous #81 collaboration failures do not recur: all 12 hostile-client cases and the complete collaboration command pass without changed expectations.
  • Standalone theme VM fixtures remain tracked by #958. This job ran its focused mounted-frame regression and the real browser flow; the full helper suite remains merge-round work.
  • The inherited repeated phone Share title is filed as #1012. It is cosmetic and was present before #981.
  • No performance measurement ran: the latest verification policy limits measurements to performance issues on the locked perf VM. The existing public-folder profile extension remains in bench/files-listing-427.py; no public-listing baseline exists.

UX gaps closed

Removed public Edit controls and editable content. Restored public folder rows and removed the wrong folder empty state from files. Verified real public view/download, keyboard and touch Quick Look, Escape, child download, unchanged file bytes, and authenticated Note saving. The public row download target is 44 px; primary buttons and rows meet the touch floor. Capture themes no longer race media callbacks. Inspected icons next to text in zoomed production captures; no new alignment defect was found. Visual quality review stays with the orchestrator.

UX gaps left

The inherited phone Share title duplication (#1012). Full sharing-option/gallery/file-drop and platform matrices remain for the merge round. No public edit affordance or writable guest path remains in the focused flow.

Decisions

No new product policy. Retain uniform 403 tombstones for old write URLs; accept legacy edit:false but reject true and omit edit from published schemas/responses; clear retired credentials/rate buckets while preserving historical attribution. Existing edit-only links receive view/download as §54 requires. The server contract assertion checks the new denial-only behavior rather than documenting a nonexistent REST rate-limit response. Restoring the folder branch keeps the original rendering behavior.

Screenshots

The final set below supersedes the first 24-image set. Thirty production captures cover file/folder link dialogs, public folder/Note and authenticated editor: 390, 820 and 1440 px, light/dark, macOS platform emulation. All images are attached to #981 and stay out of Git.

authenticated-note-editor-1440-paper.png
authenticated-note-editor-1440-tokyo-night.png
authenticated-note-editor-390-paper.png
authenticated-note-editor-390-tokyo-night.png
authenticated-note-editor-820-paper.png
authenticated-note-editor-820-tokyo-night.png
public-view-only-folder-1440-paper.png
public-view-only-folder-1440-tokyo-night.png
public-view-only-folder-390-paper.png
public-view-only-folder-390-tokyo-night.png
public-view-only-folder-820-paper.png
public-view-only-folder-820-tokyo-night.png
public-view-only-note-1440-paper.png
public-view-only-note-1440-tokyo-night.png
public-view-only-note-390-paper.png
public-view-only-note-390-tokyo-night.png
public-view-only-note-820-paper.png
public-view-only-note-820-tokyo-night.png
view-only-file-dialog-1440-paper.png
view-only-file-dialog-1440-tokyo-night.png
view-only-file-dialog-390-paper.png
view-only-file-dialog-390-tokyo-night.png
view-only-file-dialog-820-paper.png
view-only-file-dialog-820-tokyo-night.png
view-only-folder-dialog-1440-paper.png
view-only-folder-dialog-1440-tokyo-night.png
view-only-folder-dialog-390-paper.png
view-only-folder-dialog-390-tokyo-night.png
view-only-folder-dialog-820-paper.png
view-only-folder-dialog-820-tokyo-night.png

For the merge round

Run these once on the combined branch under the current owner policy:

(cd apps/web && bun run test --maxWorkers=2)
(cd apps/web && bun e2e/share.mjs)
node --test apps/web/e2e/harness.test.mjs
tests/adversarial/run.sh

The full sharing flow must prove all option combinations, gallery/file-drop and child actions. The full adversarial runner must prove the Cross-User, authorization and robustness matrices. Diagnose the documented #954/#942 baseline failures without weakening assertions. The orchestrator performs visual review, release/staging checks and real Mac interop. No Calendar source changed, so a separate Calendar crate gate is not applicable to this branch.

Files

  • apps/web/e2e/harness.mjs
  • apps/web/e2e/harness.test.mjs
  • apps/web/e2e/share.mjs
  • apps/web/src/lib/files/PublicLinkPage.svelte
  • apps/web/src/lib/files/ShareDialog.svelte
  • apps/web/src/lib/notes/NoteEditorSurface.svelte
  • apps/web/src/lib/notes/collab.ts
  • apps/web/src/lib/notes/editorHost.ts
  • apps/web/src/lib/webmcp/generated.test.ts
  • bench/files-listing-427.py
  • contracts/actions.json
  • contracts/openapi.json
  • crates/calternal-collab/src/session.rs
  • crates/calternal-collab/tests/hostile_clients.rs
  • crates/calternal-server/src/main.rs
  • crates/calternal-server/src/wire.rs
  • crates/plugins/files/migrations/0019_public_links_view_only.sql
  • crates/plugins/files/src/lib.rs
  • crates/plugins/files/src/public.rs
  • crates/plugins/notes/src/lib.rs
  • docs/DESIGN.md
  • docs/audits/xuser-472.md
  • docs/parity-exceptions.json
  • docs/parity-matrix.md
  • packages/api-client/src/generated.ts
  • scripts/action_registry.py
  • scripts/parity_matrix.py
  • scripts/test_action_registry.py
  • tests/adversarial/attack2.py
  • tests/adversarial/authz_matrix.py
  • tests/adversarial/xuser_matrix.py

Cleanup

Cargo cleanup and removal of the web build output completed. The worktree is clean; ignored logs and review artifacts remain.

     Removed 16835 files, 11.7GiB total

READY FOR MERGE: yes

# #981 verification complete Head: `dd1c8f1cc638374f890a9b0b7b340359d85e1b5e` on `job/pubedit-981`. Fetched and merged `origin/dev` once. Files migration 0019 was free: the fetched branch ended at 0018. No push, deploy or issue closure. ## What was built Public links cannot grant edit through the API, CLI, MCP, WebMCP or browser. Existing edit links become view/download links. Their URLs, passwords, expiry, counters, item identities and historical Version attribution stay intact. Retired REST/socket entry points deny before body/link/room lookup. Authenticated Collaborate remains available. This continuation completed the remaining verification and made four corrections: - The server contract test now requires exactly 403 for the two retired REST paths. Active public/auth routes retain their original 429 assertions. This expectation change follows the behavior explicitly removed by #981; no other existing expectation or deadline changed. - The authoritative server export replaces the fragment export. It removes stale retired-route 429 responses and refreshes four existing handler descriptions. Generated actions and client types match it. - The screenshot helper seeds its review theme after media callbacks and the Appearance save settle. It keeps the existing rendering assertions. - Restored the file/folder branch accidentally removed with the guest editor. Public folders show their children again; files no longer show a folder empty state. The focused regression now checks keyboard/touch Quick Look and child download. Atomic continuation commits: `673be10da` (audit commands), `7e26f5a26` (retired contract assertion), `6a470751e` (capture ordering), `33eef7657` (authoritative generated files), `dd1c8f1cc` (public folder regression fix). Source comments were read again before this report. ## Gates — verbatim output `cargo fmt --check`: exit 0, no output. The prior Files, Notes and collaboration Clippy passes cover unchanged Rust source in this continuation: Files Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 31s ``` Notes Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 15s ``` Collaboration Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 58s ``` Fresh server Clippy after the test correction: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 52m 57s ``` Fresh server tests: ```text test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 16.00s ``` Fresh collaboration tests (every target passed): ```text test result: ok. 23 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.99s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.78s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.60s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 75.81s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.92s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.77s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.34s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.09s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.14s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.69s test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 22.65s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Fresh Notes full run: ```text test result: FAILED. 166 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 312.41s ``` Unchanged Notes #954 test in isolation: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 166 filtered out; finished in 3.38s ``` Fresh Files full run: ```text test result: FAILED. 145 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 380.16s ``` The Files public denial/migration, schema upgrade and historical attribution cases pass in that full run: ```text test tests::dev_files_schema_upgrades_through_share_log_and_sidecar_migrations ... ok test tests::public_edit_is_denied_and_legacy_links_keep_view ... ok test tests::version_reads_preserve_historical_guest_attribution ... ok ``` One server binary build: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 20m 08s ``` Production web build completed with adapter-static. Final web check: ```text svelte-check found 0 errors and 0 warnings ``` Focused provider/WebMCP Vitest: ```text Test Files 2 passed (2) Tests 19 passed (19) Test Files 1 passed (1) Tests 1 passed (1) Test Files 1 passed (1) Tests 10 passed (10) ``` API-client tests: ```text 18 pass 0 fail Ran 18 tests across 1 file. [949.00ms] ``` Focused mounted-frame theme regression: ```text # tests 1 # pass 1 # fail 0 ``` Generator/classification checks: ```text Ran 13 tests in 0.498s OK Action registry: 333 operations, 312 generated tools Parity matrix: 333 API actions, 126 shortcuts, 2 static commands, 145 menu actions, 35 settings groups, 0 actions with adapter gaps Cross-User classification gate: 335 operations classified Generated entry point classification: 936 tools classified Admin coverage: 39 reviewed operations; contract and Rust guards agree ``` Final focused real-server browser run: ```text PASS #981 public link creation and visitor page are view only; content unchanged CSP REPORTS share: 0 across 3 pages ``` The existing public sharing probe ran once with a 900-second bound, the built server and production web build. It exited 0: ```text server alive at end: True ==== ROUND 2 FINDINGS 0 ==== ROUND 2 SLOW 0 ``` ## Known gaps and failure evidence - Notes #954: the full run reports 404 versus the unchanged expected 200 in daily_and_composer_preserve_unrelated_bytes. Separate test Homes use the same User ID and process-global writer lock. journal_snapshot uses try_lock_owned before legacy ID repair, then returns 404 without a snapshot. The unchanged isolated test passes in 3.38 s. This matches #954; the #981 Notes diff only removes unused guest helpers. The full Notes command remains a failed gate. - Files #942: the unchanged reconciliation storm exceeds its five-minute wait, then a background writer reports atomic write 946 failed: entry not found. The full Files command remains a failed gate. Fixture teardown as the writer error's cause is an inference, not a confirmed harmless result. The same timeout/error family is already recorded in #942; no assertion or deadline was relaxed. - The initial server run found the retired-route contract mismatch and a five-second User archive timeout. The contract mismatch is fixed. The unchanged archive test passed alone (1 passed in 16.80 s), and all live-app subprocess tests pass in the final full server run. No evidence here establishes #965 as that timeout's cause. - The previous #81 collaboration failures do not recur: all 12 hostile-client cases and the complete collaboration command pass without changed expectations. - Standalone theme VM fixtures remain tracked by #958. This job ran its focused mounted-frame regression and the real browser flow; the full helper suite remains merge-round work. - The inherited repeated phone Share title is filed as #1012. It is cosmetic and was present before #981. - No performance measurement ran: the latest verification policy limits measurements to performance issues on the locked perf VM. The existing public-folder profile extension remains in bench/files-listing-427.py; no public-listing baseline exists. ## UX gaps closed Removed public Edit controls and editable content. Restored public folder rows and removed the wrong folder empty state from files. Verified real public view/download, keyboard and touch Quick Look, Escape, child download, unchanged file bytes, and authenticated Note saving. The public row download target is 44 px; primary buttons and rows meet the touch floor. Capture themes no longer race media callbacks. Inspected icons next to text in zoomed production captures; no new alignment defect was found. Visual quality review stays with the orchestrator. ## UX gaps left The inherited phone Share title duplication (#1012). Full sharing-option/gallery/file-drop and platform matrices remain for the merge round. No public edit affordance or writable guest path remains in the focused flow. ## Decisions No new product policy. Retain uniform 403 tombstones for old write URLs; accept legacy edit:false but reject true and omit edit from published schemas/responses; clear retired credentials/rate buckets while preserving historical attribution. Existing edit-only links receive view/download as §54 requires. The server contract assertion checks the new denial-only behavior rather than documenting a nonexistent REST rate-limit response. Restoring the folder branch keeps the original rendering behavior. ## Screenshots The final set below supersedes the first 24-image set. Thirty production captures cover file/folder link dialogs, public folder/Note and authenticated editor: 390, 820 and 1440 px, light/dark, macOS platform emulation. All images are attached to #981 and stay out of Git. [authenticated-note-editor-1440-paper.png](https://git.kayg.org/attachments/72e5ebc5-cb6a-49dd-aafd-392de303f91b) [authenticated-note-editor-1440-tokyo-night.png](https://git.kayg.org/attachments/beea7855-aab8-4c8d-8503-7bc0f443026e) [authenticated-note-editor-390-paper.png](https://git.kayg.org/attachments/940338ce-b9e0-47a9-805d-a4b553536cdf) [authenticated-note-editor-390-tokyo-night.png](https://git.kayg.org/attachments/81c79a07-1143-4a2b-954d-ae49d5480043) [authenticated-note-editor-820-paper.png](https://git.kayg.org/attachments/e984c374-ffbc-4f14-a976-98245b0235d2) [authenticated-note-editor-820-tokyo-night.png](https://git.kayg.org/attachments/a6acd4f9-4e2d-496a-a03a-44bab2b91e32) [public-view-only-folder-1440-paper.png](https://git.kayg.org/attachments/96dda9db-d2dd-4955-a7a3-de8276589d09) [public-view-only-folder-1440-tokyo-night.png](https://git.kayg.org/attachments/0dafea7a-3026-4aef-acef-bdcb37ded93f) [public-view-only-folder-390-paper.png](https://git.kayg.org/attachments/4d524a9d-ed20-4094-accc-36ee9105c312) [public-view-only-folder-390-tokyo-night.png](https://git.kayg.org/attachments/1214431b-44c4-4501-b798-50735cc40bd9) [public-view-only-folder-820-paper.png](https://git.kayg.org/attachments/c00d77d5-1265-4439-9be5-2b67340513ef) [public-view-only-folder-820-tokyo-night.png](https://git.kayg.org/attachments/08ef43c6-0b5c-4b5a-bde4-8962dbc692c0) [public-view-only-note-1440-paper.png](https://git.kayg.org/attachments/ebe2c3a2-7394-47ac-9137-5d4bc1075a6a) [public-view-only-note-1440-tokyo-night.png](https://git.kayg.org/attachments/bb5ef389-9d92-4079-8829-b3ca829f1efb) [public-view-only-note-390-paper.png](https://git.kayg.org/attachments/bd3322a1-22ec-49cc-9b86-b21e05afb1ba) [public-view-only-note-390-tokyo-night.png](https://git.kayg.org/attachments/723fafdd-bc14-4fa5-9c62-75fdd18ed055) [public-view-only-note-820-paper.png](https://git.kayg.org/attachments/3474f898-8a92-46a9-bd48-cf6f374bd434) [public-view-only-note-820-tokyo-night.png](https://git.kayg.org/attachments/087d0dd8-9f4a-4ff4-90f5-8d5361e0127c) [view-only-file-dialog-1440-paper.png](https://git.kayg.org/attachments/6bfa143f-970b-4ea0-a600-0c1840a13dd0) [view-only-file-dialog-1440-tokyo-night.png](https://git.kayg.org/attachments/71eb64b3-913a-48ca-baa3-cae59c1f9603) [view-only-file-dialog-390-paper.png](https://git.kayg.org/attachments/9745391c-9b48-4640-a387-dad3f86f1846) [view-only-file-dialog-390-tokyo-night.png](https://git.kayg.org/attachments/6b6c57ac-a0a5-4072-af19-f0e5ae0db7cd) [view-only-file-dialog-820-paper.png](https://git.kayg.org/attachments/e1a12bb8-20b0-42e6-9aaa-0aed1bae8030) [view-only-file-dialog-820-tokyo-night.png](https://git.kayg.org/attachments/4d8f74a9-0bb2-47f4-aa41-792750505c32) [view-only-folder-dialog-1440-paper.png](https://git.kayg.org/attachments/76644475-b163-4821-977f-d3871ea1896d) [view-only-folder-dialog-1440-tokyo-night.png](https://git.kayg.org/attachments/68bd1491-856c-46f9-9d27-9f5874d9f422) [view-only-folder-dialog-390-paper.png](https://git.kayg.org/attachments/88e03555-bddd-4403-a7b5-4511ac0b2d2f) [view-only-folder-dialog-390-tokyo-night.png](https://git.kayg.org/attachments/0ea43451-080d-4846-8f09-53b760e2d329) [view-only-folder-dialog-820-paper.png](https://git.kayg.org/attachments/6f821681-4cf8-4c88-9311-7a5d98223115) [view-only-folder-dialog-820-tokyo-night.png](https://git.kayg.org/attachments/241705af-3c6f-48eb-a7d3-a4cbddc0c7d9) ## For the merge round Run these once on the combined branch under the current owner policy: ```sh (cd apps/web && bun run test --maxWorkers=2) (cd apps/web && bun e2e/share.mjs) node --test apps/web/e2e/harness.test.mjs tests/adversarial/run.sh ``` The full sharing flow must prove all option combinations, gallery/file-drop and child actions. The full adversarial runner must prove the Cross-User, authorization and robustness matrices. Diagnose the documented #954/#942 baseline failures without weakening assertions. The orchestrator performs visual review, release/staging checks and real Mac interop. No Calendar source changed, so a separate Calendar crate gate is not applicable to this branch. ## Files - `apps/web/e2e/harness.mjs` - `apps/web/e2e/harness.test.mjs` - `apps/web/e2e/share.mjs` - `apps/web/src/lib/files/PublicLinkPage.svelte` - `apps/web/src/lib/files/ShareDialog.svelte` - `apps/web/src/lib/notes/NoteEditorSurface.svelte` - `apps/web/src/lib/notes/collab.ts` - `apps/web/src/lib/notes/editorHost.ts` - `apps/web/src/lib/webmcp/generated.test.ts` - `bench/files-listing-427.py` - `contracts/actions.json` - `contracts/openapi.json` - `crates/calternal-collab/src/session.rs` - `crates/calternal-collab/tests/hostile_clients.rs` - `crates/calternal-server/src/main.rs` - `crates/calternal-server/src/wire.rs` - `crates/plugins/files/migrations/0019_public_links_view_only.sql` - `crates/plugins/files/src/lib.rs` - `crates/plugins/files/src/public.rs` - `crates/plugins/notes/src/lib.rs` - `docs/DESIGN.md` - `docs/audits/xuser-472.md` - `docs/parity-exceptions.json` - `docs/parity-matrix.md` - `packages/api-client/src/generated.ts` - `scripts/action_registry.py` - `scripts/parity_matrix.py` - `scripts/test_action_registry.py` - `tests/adversarial/attack2.py` - `tests/adversarial/authz_matrix.py` - `tests/adversarial/xuser_matrix.py` ## Cleanup Cargo cleanup and removal of the web build output completed. The worktree is clean; ignored logs and review artifacts remain. ```text Removed 16835 files, 11.7GiB total ``` READY FOR MERGE: yes
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#981
No description provided.