Import of a backup holding PDF attachments: the content resolver parses a url
as a url, and the three mutants guarding it are registered. The user-visible
change is documented in 4a84734, which carries both changelog entries — this
merge adds no behaviour of its own.
Code review r2 green (docs/reviews/CODE-REVIEW-225-r2.md). The third pass was
a rebase over #226, not a fix — owner arbitration on the review-4 the cycle
counter raised for it (PROCESS.md §4; counter defect filed as #227).
Issue: #225
User-Visible: no
Review CODE-REVIEW-225-r1.
M1: urlsplit(url).path was trusted even when the url carried a scheme or an
authority, so "https://evil.example/houseplan_files/files/m1/doc.pdf"
resolved onto a local file while _looks_internal kept calling it external —
the mirror image of the inconsistency this resolver exists to prevent. Only a
same-document reference is resolved by its path now.
M2: the three mutants the spec described are registered in
scripts/mutation-gate.mjs instead of living as a one-off manual run. The
traversal entry drops both structural checks at once on purpose: taken one at
a time the defence is layered (sanitize_marker_id turns ".." into "misc") and
the mutant would be equivalent — established by running it.
Issue: #225
User-Visible: no
A backup holding a PDF attachment could not be imported back: legacy links
carry a cache-buster (".../files/m1/doc.pdf?v=1783170649"), and the resolver
compared the raw tail with its sanitized form, so the query made the name
differ from itself. The reference then read as internal by prefix and
non-canonical by name, which is exactly the combination _content_state must
refuse — every such document failed with invalid_content.
Parse the url as a url: the path addresses the file, the query and the
fragment address the transfer. Path segments keep doing the guarding, so
dropping the query cannot widen what a segment is allowed to be.
Issue: #225
User-Visible: yes
The reviewer prompt was identical for every round, and the canon said
nothing about the scope of a repeat pass, so r2 re-derived the product
framing and re-checked acceptance criteria the fix never touched: the r2
pass on #150 cost a full pipeline run over one line in a test fixture.
From the second cycle on, the subject is the delta against the SHA the
previous verdict was given on: each earlier finding must be shown closed
by a line of code or text, only the criteria the delta can reach are
re-verified, and whatever is carried over is listed with the round and SHA
it came from. Cheap gates still run every round.
The scope shrinks, the strictness does not. A fix can break a criterion an
earlier round accepted — that is how regression #102 happened — so the
boundary is the findings plus everything the delta can reach, and a
non-local delta (a rebase onto a moved dev, a behaviour contract change, a
new subsystem) still gets the full pass.
Issue: #214
User-Visible: no
The reviewer prompt was identical for every round, and the canon said
nothing about the scope of a repeat pass, so r2 re-derived the product
framing and re-checked acceptance criteria the fix never touched: the r2
pass on #150 cost a full pipeline run over one line in a test fixture.
From the second cycle on, the subject is the delta against the SHA the
previous verdict was given on: each earlier finding must be shown closed
by a line of code or text, only the criteria the delta can reach are
re-verified, and whatever is carried over is listed with the round and SHA
it came from. Cheap gates still run every round.
The scope shrinks, the strictness does not. A fix can break a criterion an
earlier round accepted — that is how regression #102 happened — so the
boundary is the findings plus everything the delta can reach, and a
non-local delta (a rebase onto a moved dev, a behaviour contract change, a
new subsystem) still gets the full pass.
Issue: #214
User-Visible: no