REUSE: use one byte-size formatter for Files, Mail attachments and Admin quotas #727

Open
opened 2026-10-02 13:06:31 +00:00 by kayg · 4 comments
Owner

Context

Static rev-consistency review for #427 on origin/dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5. CLAUDE.md and DESIGN §38 require reuse before a new helper is added.

Evidence

  • apps/web/src/lib/files/model.ts:329-342 owns formatSize: decimal units, locale-aware numbers, invalid-value handling, and singular bytes. apps/web/src/lib/files/model.test.ts:59-62 already checks this contract.
  • apps/web/src/lib/mail/MailView.svelte:148 defines a second formatter: division by 1024, decimal-point toFixed(1), and only B/KB/MB. It is used for Mail attachments at line 650.
  • apps/web/src/routes/settings/admin/AdminSection.svelte:61-70 defines a third formatter with its own unit list and rounding. It is used for the Instance default quota at line 89.
  • For 1,500 bytes, Files shows 1.5 KB, but the Mail helper produces 1.5 KB from a different divisor (1.4648 rounded). For 1,000,000 bytes the mismatch is clear: Files shows 1.0 MB; Mail produces 976.6 KB. Mail always uses a decimal point, even when the User selected a locale with a decimal comma.

Expected and shared fix

Use one byte-size formatter for Files, Mail attachments and Admin quota values. Retain the existing decimal and locale contract. Keep No limit as an Admin-only interpretation of a zero quota before formatting. Reuse or move formatSize; do not add another formatter.

Test idea

Add cross-surface cases for 0, 1, 999, 1,000, 1,000,000 and a large value, plus a decimal-comma locale. Keep the current Files expectations. Check that saving a Mail attachment to Files shows the same byte-size label. Check that zero quota still says No limit.

Searched open and closed issues for file size, and inspected the full issue title list. #310 covers attachment counts and durations, and explicitly says file-size formatting has one owner; it does not cover these new independent size formatters. #179 covers dates and times. No issue specific to this size-format drift was found.

## Context Static rev-consistency review for #427 on `origin/dev` at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`. CLAUDE.md and DESIGN §38 require reuse before a new helper is added. ## Evidence - `apps/web/src/lib/files/model.ts:329-342` owns `formatSize`: decimal units, locale-aware numbers, invalid-value handling, and singular bytes. `apps/web/src/lib/files/model.test.ts:59-62` already checks this contract. - `apps/web/src/lib/mail/MailView.svelte:148` defines a second formatter: division by 1024, decimal-point `toFixed(1)`, and only B/KB/MB. It is used for Mail attachments at line 650. - `apps/web/src/routes/settings/admin/AdminSection.svelte:61-70` defines a third formatter with its own unit list and rounding. It is used for the Instance default quota at line 89. - For 1,500 bytes, Files shows `1.5 KB`, but the Mail helper produces `1.5 KB` from a different divisor (1.4648 rounded). For 1,000,000 bytes the mismatch is clear: Files shows `1.0 MB`; Mail produces `976.6 KB`. Mail always uses a decimal point, even when the User selected a locale with a decimal comma. ## Expected and shared fix Use one byte-size formatter for Files, Mail attachments and Admin quota values. Retain the existing decimal and locale contract. Keep `No limit` as an Admin-only interpretation of a zero quota before formatting. Reuse or move `formatSize`; do not add another formatter. ## Test idea Add cross-surface cases for 0, 1, 999, 1,000, 1,000,000 and a large value, plus a decimal-comma locale. Keep the current Files expectations. Check that saving a Mail attachment to Files shows the same byte-size label. Check that zero quota still says `No limit`. ## Duplicate search Searched open and closed issues for `file size`, and inspected the full issue title list. #310 covers attachment counts and durations, and explicitly says file-size formatting has one owner; it does not cover these new independent size formatters. #179 covers dates and times. No issue specific to this size-format drift was found.
Author
Owner

Starting the reuse pass for #727, #729, #730 and #799 on branch job/reuse.

Starting commit/base: 2f4482ded066d9c5d9c59130377907f7fd2916c9, the same commit as job/merge-round-7a. I will merge origin/dev and re-merge job/merge-round-7a once before final gates.

Starting the reuse pass for #727, #729, #730 and #799 on branch `job/reuse`. Starting commit/base: `2f4482ded066d9c5d9c59130377907f7fd2916c9`, the same commit as `job/merge-round-7a`. I will merge `origin/dev` and re-merge `job/merge-round-7a` once before final gates.
Author
Owner

Implementation evidence for #727: Mail's 1024-based formatBytes and Admin's local bytes formatter are removed. Both now call Files' formatSize; Admin checks zero first and keeps No limit. Regression coverage now checks 0, 1, 999, 1,000, 1,000,000 and 1.5 PB, a de-DE decimal comma, and that both callers use the shared formatter. The new locale case failed on the old formatSize signature with expected '1,5 KB', received '1.5 KB'; the source reuse test also failed because Mail lacked the shared import. After the change: Test Files 2 passed (2) and Tests 10 passed (10). Commit: 6968673c2.

Implementation evidence for #727: Mail's 1024-based `formatBytes` and Admin's local `bytes` formatter are removed. Both now call Files' `formatSize`; Admin checks zero first and keeps `No limit`. Regression coverage now checks 0, 1, 999, 1,000, 1,000,000 and 1.5 PB, a `de-DE` decimal comma, and that both callers use the shared formatter. The new locale case failed on the old `formatSize` signature with `expected '1,5 KB', received '1.5 KB'`; the source reuse test also failed because Mail lacked the shared import. After the change: `Test Files 2 passed (2)` and `Tests 10 passed (10)`. Commit: `6968673c2`.
Author
Owner

Screenshot evidence attempt: the Files production capture stopped in mediaSandboxEnv() before server startup. tests/adversarial/prepare-media-runtime.sh reported too many local threads for the bounded media sandbox test: 6188. The helper caps the namespace setup at 4096, and no prebuilt e2e-media-runtime was available under the shared job targets. I left the sandbox cap unchanged; the required real-server screenshots are a known evidence gap for this host run.

Screenshot evidence attempt: the Files production capture stopped in `mediaSandboxEnv()` before server startup. `tests/adversarial/prepare-media-runtime.sh` reported `too many local threads for the bounded media sandbox test: 6188`. The helper caps the namespace setup at 4096, and no prebuilt `e2e-media-runtime` was available under the shared job targets. I left the sandbox cap unchanged; the required real-server screenshots are a known evidence gap for this host run.
Author
Owner

Final report — reuse issues #727, #729, #730 and #799

Head: b5544daedac6d8027a323167d9b188a5262d6eb5 on job/reuse.
Merged origin/dev (7e53ad538) and the current job/merge-round-7a (a563e4cb9) before the final gates. The final commit after gates only adds comments; it does not change executable behavior.

Built

  • #727: Mail attachments and Admin quota use Files' decimal, locale-aware formatSize. Admin still shows No limit for zero. Added boundary, locale and cross-surface regression checks.
  • #729: Extended the motion-token scanner to transition helpers, aliases, option constants, flipGroup, and script-created transition strings. DraftStack, AttachmentDeck and flipGroup now use shared timing/easing roles.
  • #730: Added saveBrowserDownload for prepared URLs and Blobs. Recent, Public link, and recovery-key downloads use the shared save action; Public link password headers remain on its fetch.
  • #799: Consolidated the literal 1/2/4/8/16 px blur recipe in ProgressiveBlur.svelte; directional masks and unsupported-filter/reduced-transparency fallbacks remain covered. Removed the unused duplicate token selector.
  • Added macOS emulation and current-build routing to the affected production screenshot contexts.

Files

  • Files sizing: apps/web/src/lib/files/model.ts, model.test.ts, size-format-reuse.test.ts, apps/web/src/lib/mail/MailView.svelte, apps/web/src/routes/settings/admin/AdminSection.svelte.
  • Motion: apps/web/scripts/check-motion-tokens.mjs, apps/web/src/lib/styles/motion-token-check.test.js, apps/web/src/lib/flip.ts, packages/ui/src/components/composer/DraftStack.svelte, packages/ui/src/components/calendar/AttachmentDeck.svelte.
  • Downloads: apps/web/src/lib/browserDownload.ts, browserDownload.test.ts, apps/web/src/lib/files/transfer.ts, RecentView.svelte, PublicLinkPage.svelte, apps/web/src/lib/auth/components/RecoveryKeyWords.svelte.
  • Blur and screenshot support: packages/ui/src/components/ProgressiveBlur.svelte, packages/ui/src/tokens.css, apps/web/src/lib/themes.test.ts, apps/web/e2e/auth.mjs, composer.mjs, glass-audit.mjs.
  • The requested merges also brought the current media-sandbox guard and authz/E2E updates from the merged branches.

Gates

bun run check passed on executable code at b02e9ffa5; b5544daed is a comment-only follow-up. Output:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/reuse/apps/web
Getting Svelte diagnostics...
svelte-check found 0 errors and 0 warnings

Full bun run test --maxWorkers=1 output:

Test Files  5 failed | 151 passed (156)
      Tests  7 failed | 1075 passed (1082)
   Start at  17:38:49
   Duration  3563.01s (transform 43%, import 31%, environment 11%, tests 8%, setup 7%)
error: script "test" exited with code 1

All seven reported test failures were explicit 5-second or 30-second timeouts; Vitest also terminated the BklitTooltipMaterial.test.ts worker at its 30-second limit. These are SLOW-only host-load findings. No test expectation changed. Focused regressions passed: size formatter 10 tests, motion scanner 8, browser download helper 3, progressive blur 2. bun run build passed. No Rust source changed, so no Rust crate gates applied. cargo clean output: Removed 1 file, 356B total.

UX gaps closed / left

Closed: byte labels now agree across the touched surfaces and respect locale; zero quota keeps its plain-language meaning; pointer/keyboard motion uses the same shared roles; download actions share URL cleanup without moving caller-specific auth; all four blur edges use one recipe and preserve calm fallbacks.

Left: the required macOS production screenshot matrix was not captured. The Files screenshot runner stopped before server startup because prepare-media-runtime.sh counted 6,188 local threads and refused setup above its 4,096 cap. No screenshot artifact was produced or committed; the guard was left intact.

Decisions

  • Keep formatSize in the existing Files model and add an optional locale argument; this preserves its decimal-unit contract and lets tests pin a decimal-comma locale.
  • Use the existing 60-second Blob URL retention for the shared browser-save action, matching Files' established behavior.
  • Keep literal blur strengths in the shared component and keep masks/fallback gradients directional.
  • Use existing DUR/EASE_CSS roles; no new motion values were introduced.
# Final report — reuse issues #727, #729, #730 and #799 Head: `b5544daedac6d8027a323167d9b188a5262d6eb5` on `job/reuse`. Merged `origin/dev` (`7e53ad538`) and the current `job/merge-round-7a` (`a563e4cb9`) before the final gates. The final commit after gates only adds comments; it does not change executable behavior. ## Built - #727: Mail attachments and Admin quota use Files' decimal, locale-aware `formatSize`. Admin still shows `No limit` for zero. Added boundary, locale and cross-surface regression checks. - #729: Extended the motion-token scanner to transition helpers, aliases, option constants, `flipGroup`, and script-created transition strings. DraftStack, AttachmentDeck and `flipGroup` now use shared timing/easing roles. - #730: Added `saveBrowserDownload` for prepared URLs and Blobs. Recent, Public link, and recovery-key downloads use the shared save action; Public link password headers remain on its fetch. - #799: Consolidated the literal 1/2/4/8/16 px blur recipe in `ProgressiveBlur.svelte`; directional masks and unsupported-filter/reduced-transparency fallbacks remain covered. Removed the unused duplicate token selector. - Added macOS emulation and current-build routing to the affected production screenshot contexts. ## Files - Files sizing: `apps/web/src/lib/files/model.ts`, `model.test.ts`, `size-format-reuse.test.ts`, `apps/web/src/lib/mail/MailView.svelte`, `apps/web/src/routes/settings/admin/AdminSection.svelte`. - Motion: `apps/web/scripts/check-motion-tokens.mjs`, `apps/web/src/lib/styles/motion-token-check.test.js`, `apps/web/src/lib/flip.ts`, `packages/ui/src/components/composer/DraftStack.svelte`, `packages/ui/src/components/calendar/AttachmentDeck.svelte`. - Downloads: `apps/web/src/lib/browserDownload.ts`, `browserDownload.test.ts`, `apps/web/src/lib/files/transfer.ts`, `RecentView.svelte`, `PublicLinkPage.svelte`, `apps/web/src/lib/auth/components/RecoveryKeyWords.svelte`. - Blur and screenshot support: `packages/ui/src/components/ProgressiveBlur.svelte`, `packages/ui/src/tokens.css`, `apps/web/src/lib/themes.test.ts`, `apps/web/e2e/auth.mjs`, `composer.mjs`, `glass-audit.mjs`. - The requested merges also brought the current media-sandbox guard and authz/E2E updates from the merged branches. ## Gates `bun run check` passed on executable code at `b02e9ffa5`; `b5544daed` is a comment-only follow-up. Output: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/reuse/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` Full `bun run test --maxWorkers=1` output: ```text Test Files 5 failed | 151 passed (156) Tests 7 failed | 1075 passed (1082) Start at 17:38:49 Duration 3563.01s (transform 43%, import 31%, environment 11%, tests 8%, setup 7%) error: script "test" exited with code 1 ``` All seven reported test failures were explicit 5-second or 30-second timeouts; Vitest also terminated the `BklitTooltipMaterial.test.ts` worker at its 30-second limit. These are SLOW-only host-load findings. No test expectation changed. Focused regressions passed: size formatter 10 tests, motion scanner 8, browser download helper 3, progressive blur 2. `bun run build` passed. No Rust source changed, so no Rust crate gates applied. `cargo clean` output: `Removed 1 file, 356B total`. ## UX gaps closed / left Closed: byte labels now agree across the touched surfaces and respect locale; zero quota keeps its plain-language meaning; pointer/keyboard motion uses the same shared roles; download actions share URL cleanup without moving caller-specific auth; all four blur edges use one recipe and preserve calm fallbacks. Left: the required macOS production screenshot matrix was not captured. The Files screenshot runner stopped before server startup because `prepare-media-runtime.sh` counted 6,188 local threads and refused setup above its 4,096 cap. No screenshot artifact was produced or committed; the guard was left intact. ## Decisions - Keep `formatSize` in the existing Files model and add an optional locale argument; this preserves its decimal-unit contract and lets tests pin a decimal-comma locale. - Use the existing 60-second Blob URL retention for the shared browser-save action, matching Files' established behavior. - Keep literal blur strengths in the shared component and keep masks/fallback gradients directional. - Use existing `DUR`/`EASE_CSS` roles; no new motion values were introduced.
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#727
No description provided.