row 283 (#1788): E2 per sage-3601: editor values with surrounding whitespace refuse library-mapping-invalid (git trims idents at commit); T3 padded cases per key, mutant M6c; BUILD.md records the departure from DESIGN.md section 1 and the fixture grep (none). Untested

This commit is contained in:
jason.woltje committed 2026-10-23 14:02:37 -05:00
1 parent b9ddb6c5e2
commit 88ec5e8e47
3 files changed
+31

No files matched your search

+23
View File
@@ -121,3 +121,26 @@ on the named test and the restored file's sha256 equals the build tip's.
the commit ident can differ. DESIGN.md section 1 says "non-empty after trim". Refusing the commit ident can differ. DESIGN.md section 1 says "non-empty after trim". Refusing
`value.trim() !== value` would change that approved rule, so it went to Sage instead of into the `value.trim() !== value` would change that approved rule, so it went to Sage instead of into the
build. build.
## 2026-10-23 E2 departure (sage-3601)
A departure from DESIGN.md section 1 (which stays unedited). The design says each `editor` value is
"non-empty after trim". Sage ruled that surrounding whitespace refuses too, because git trims an
ident at commit, so a padded value would save one name and commit another. mapping.mjs now adds
`if (value.trim() !== value) bad(`editor.${key} must not start or end with whitespace`)` after the
IDENT_BAD check. `trim()` covers Unicode whitespace, so U+00A0 and U+3000 refuse as well. Inner
whitespace is kept ("Her Middle Name" passes).
T3 gains a case per key for leading, trailing and both-ends spaces, U+00A0 and U+3000, plus one inner
whitespace pass.
M6 grows a third part:
| Mutant | File | Replace | With | Killed by |
|---|---|---|---|---|
| M6c | src/mapping.mjs | `if (value.trim() !== value) bad(` | `if (false && value.trim() !== value) bad(` | mapping.test "editor is optional" (padded cases) |
Fixture grep: `git grep -nE "\beditor\b|\bauthor\b" -- 'packages/library/tests/*' 'packages/business/tests/*'`,
leaving out mapping.test.mjs, finds nothing. packages/business/tests has no fixtures directory. The
library fixture mapping.json has no `editor`. The positive control (`vaultPrefix` in mapping.json)
matches once. No fixture maps an editor or author with surrounding whitespace.
+2
View File
@@ -63,6 +63,8 @@ export function checkMapping(entry, where = 'library', { fail = raise } = {}) {
const value = entry.editor[key]; const value = entry.editor[key];
if (typeof value !== 'string' || !value.trim() || IDENT_BAD.test(value)) if (typeof value !== 'string' || !value.trim() || IDENT_BAD.test(value))
bad(`editor.${key} must be non-empty text with no control character, < or >`); bad(`editor.${key} must be non-empty text with no control character, < or >`);
// Git trims an ident at commit, so a padded value would save one name and commit another (sage-3601).
if (value.trim() !== value) bad(`editor.${key} must not start or end with whitespace`);
} }
} }
+6
View File
@@ -121,6 +121,12 @@ test('C2-01d: editor is optional, kept when given, and refuses anything but a pl
invalid({ ...editor, name: bad }, /editor.name must be non-empty text with no control character, < or >/); invalid({ ...editor, name: bad }, /editor.name must be non-empty text with no control character, < or >/);
invalid({ ...editor, email: bad }, /editor.email must be non-empty text with no control character, < or >/); invalid({ ...editor, email: bad }, /editor.email must be non-empty text with no control character, < or >/);
} }
// sage-3601: git trims an ident at commit, so surrounding whitespace refuses.
for (const padded of [' Her Name', 'Her Name ', ' Her Name ', '\u00a0Her Name', 'Her Name\u3000']) {
invalid({ ...editor, name: padded }, /editor.name must not start or end with whitespace/);
invalid({ ...editor, email: padded }, /editor.email must not start or end with whitespace/);
}
assert.equal(mapping(e => ({ ...e, editor: { name: 'Her Middle Name', email: '[email protected]' } })).editor.name, 'Her Middle Name');
}); });
test('no playground prefix holds another, and no book folder holds another', () => { test('no playground prefix holds another, and no book folder holds another', () => {