# Task #25 mutation-red matrix — actual runs on origin/main @ 1d57ebb5
# generated 2026-07-30 by 通信工程马
# discipline: every mutation was actually applied to source, run, captured, reverted.
# no mutation was judged by inspection.

## Purpose

Prove that the 30 assertions in ext-validation-regression.test.ts really
DO pin the current ext-validation behavior — i.e., a future change that
widens or narrows the regex actually turns a test red.

Also (lead d505179d requirement): document HONESTLY which copies of the
regex this suite does NOT cover, since the same-shape check has 4 copies
in uploads.ts and each is independent.

## Mutation 1 — L219 validateIndexEntry: regex → /./  (the copy this suite targets)

- File+line: server/src/uploads.ts:219 (inside validateIndexEntry)
- Change: `(e.ext === "" || /^\.[A-Za-z0-9]{1,16}$/.test(e.ext))` → `(e.ext === "" || /./.test(e.ext))`
- Result: 17 pass / 13 fail (was 30/0 unmutated)
- All 11 SAFETY (malicious) rows turned RED (each independently reported by test id):
    rejects: path-escape prefix — ext="../x"
    rejects: deep traversal to /etc — ext="../../etc/passwd"
    rejects: absolute path — ext="/abs/x"
    rejects: double-dot alone — ext=".."
    rejects: single-dot alone — ext="."
    rejects: chained after legit prefix — ext=".png/../../y"
    rejects: embedded whitespace — ext=".p ng"
    rejects: over-length (>16 chars) — ext=".aaaaaaaaaaaaaaaaa"
    rejects: embedded NUL byte — ext=".p<NUL>ng"
    rejects: backslash traversal — ext=".\\..\\x"
    rejects: double-backslash prefix — ext="..\\x"
  Plus 2 shape assumptions:
    exactly 17 chars after dot is rejected (now accepted → red)
    compound extensions like .tar.gz are rejected (now accepted → red)
- Interpretation (lead d505179d framework corrected in-flight): all 11
  malicious values are protected by THIS regex copy alone — nothing
  else in validateIndexEntry independently rejects any of them. If any
  row had NOT turned red, the correct interpretation would have been
  "that fixture has ANOTHER field malformed" (fixture hygiene), NOT
  "some other mechanism is protecting it".

## Mutation 2 — L141 buildStoragePath: regex → /./  (upload-path build copy)

- File+line: server/src/uploads.ts:141
- Change: `if (ext && !/^\.[A-Za-z0-9]{1,16}$/.test(ext))` → `if (ext && !/./.test(ext))`
- Result: **30 pass / 0 fail** — this suite provides ZERO coverage for the L141 copy.
- This is expected: buildStoragePath is a write-time helper; this test file
  is a pure unit test on validateIndexEntry and never exercises the upload
  code path. Documenting honestly per lead d505179d.

## Mutation 3 — L165 pathForExistingBlob: regex → /./  (download-path build copy)

- File+line: server/src/uploads.ts:165
- Change: `if (ext && !/^\.[A-Za-z0-9]{1,16}$/.test(ext))` → `if (ext && !/./.test(ext))`
- Result: **30 pass / 0 fail** — this suite provides ZERO coverage for the L165 copy.
- Same reason as Mutation 2.

## Mutation 4 — L93 sanitizeExt: capture-group regex → /\.(.+)$/  (client-name parse copy)

- File+line: server/src/uploads.ts:93
- Change: `base.match(/\.([A-Za-z0-9]{1,16})$/)` → `base.match(/\.(.+)$/)`
- Result: **30 pass / 0 fail** — this suite provides ZERO coverage for the L93 copy.
- sanitizeExt has a different shape (no leading `^\.` anchor, has capture group)
  because it parses client-supplied filenames and extracts the extension. Even
  so, it enforces the same character class — and this suite doesn't touch it.

## Coverage summary

| Regex copy                          | Function              | Tests here | Follow-up needed |
|-------------------------------------|-----------------------|------------|------------------|
| L93  sanitizeExt (parse)            | client filename parse | 0          | separate issue   |
| L141 buildStoragePath (write path)  | upload build          | 0          | separate issue   |
| L165 pathForExistingBlob (read path)| download build        | 0          | separate issue   |
| L219 validateIndexEntry (read gate) | download authz gate   | 30 pinned  | —                |

## What this suite does NOT claim

- Does NOT claim "the ext validation is protected system-wide".
- Does NOT claim "the 11 malicious values are rejected by all copies" (only pinned via L219).
- Does NOT claim "widening any of the four copies will be caught here" (only L219).

## What this suite DOES claim

- If someone widens L219 to accept any of the 11 malicious literals,
  the corresponding independently-named row turns red with the specific
  literal in the failure message.
- If someone tightens L219 to reject any of 10+ legitimate common
  extensions or the empty string, the corresponding row turns red.
- If someone shrinks the malicious/legitimate lists to make coverage
  look narrower, the two precondition assertions catch it.

## Follow-up

Regex duplication (4 copies of the same-shape check) is tracked in a
separate issue opened alongside this PR. That issue evaluates whether
the copies can be centralized, and if not, whether each copy needs its
own regression pins.
