row 203 FED R2: cases for missing self, peer id and label (webby-0191 B3)

The pattern test coerces an absent value to the string 'undefined', which
matches, so the typeof halves are the only refusal for a missing value. Adds
a case for each, and M15-M17 in BUILD.md; keeps the config-console-key check
name on purpose. Not run yet.
This commit is contained in:
jason.woltje committed 2026-10-22 15:40:56 -05:00
1 parent 8d34a9e948
commit d5428c1a87
2 files changed
+25 -5

No files matched your search

+18 -5
View File
@@ -105,11 +105,14 @@ mutant. M5 is killed by the self case; M13 covers the duplicate half of the id c
| peers not an array | `federation.peers must be an array` | M9 |
| peer not an object | `federation.peers[0] must be a JSON object` | M10 |
| peer id does not match the pattern | `federation.peers[0].id must match ...` | M11 |
| self missing | `federation.self must match ...` | M15 |
| peer id missing | `federation.peers[0].id must match ...` | M16 |
| peer label missing | `federation.peers[0].label must be ...` | M17 |
| no federation key | loads, no federation output | base |
| B1: target loader refuses federation | `config-console-key` refusal (stack-release.test) | M14 |
Mutant plan (run on Sage's gate only, one edit each, a named test must fail). Before the gate each edit string
must occur exactly once in its file. I checked all of M1 to M14 with grep -cF in this commit: each is 1. The
must occur exactly once in its file. I checked all of M1 to M17 with grep -cF: each is 1. The
gate's mutant runner checks the count again before it applies each edit:
- M1: `rejectUnknownKeys(value, ["self", "peers"], "federation");` removed. Killed by "federation unknown sub-key".
@@ -128,6 +131,11 @@ gate's mutant runner checks the count again before it applies each edit:
- M13: ` ids.add(peer.id);` removed. Killed by "duplicate peer id".
- M14 (stack-release.sh): `||Object.hasOwn(d,"federation")` removed. Killed by the row 203 federation test in
`stack-release.test.mjs`.
- M15: `typeof value.self !== "string" || ` removed. Killed by "federation self missing". Without the typeof
half, an absent self passes the pattern (`/^[a-z]…$/.test(undefined)` is true).
- M16: `typeof peer.id !== "string" || ` removed. Killed by "federation peer id missing". Same reason.
- M17: `typeof peer.label !== "string" || ` removed. Killed by "federation peer label missing". Without it, a
missing label throws a TypeError at `.trim()` (exit 1), not the exit 2 refusal.
## Boundaries
@@ -148,20 +156,25 @@ gate's mutant runner checks the count again before it applies each edit:
- test-config.sh: about 5 min, padded.
- The cli suite: about 5 min, padded.
- stack-release.test.mjs: up to 1800 s, per Sage. It copies the loader, so it runs whole at the gate (Webby N3).
- Mutants M1–M13 each re-run the FED block of test-config.sh. M14 re-runs stack-release.test.mjs.
- Mutants M1–M13 and M15–M17 each re-run the FED block of test-config.sh. M14 re-runs stack-release.test.mjs.
The per-mutant cost is not measured: this run has not been timed.
## Status
- The loader, tests and notes are in e704a18ae, rebased onto f2735bb6a.
- B1, B2, the fixture fix and this notes rewrite are in the second commit on top (sha in the message to Sage).
- e704a18ae: the loader, first tests and notes, rebased onto f2735bb6a.
- 8d34a9e94: B1, B2, the fixture fix and the notes rewrite (Mos approved the two old-test edits, mos-1346).
- Third commit on top: B3 cases M15–M17 and these notes (sha in the message to Sage and Webby).
- NOT YET RUN: no node during Gander's slot. The test-config.sh, cli and stack-release gates run when Sage
announces a CLEAR. `bash -n` passes on both shell scripts.
- Not pushed, not claimed. Per invariant 8 the gate runs before any commit is called green.
## Review notes (Webby, webby-0189, answered here)
- B1: fixed as above (scope per sage-2998).
- B1: fixed as above (scope per sage-2998). The probe's check name `config-console-key` is kept on purpose (Webby
N5, Sage): renaming it would change callers and tests for no gain in this row. The message says "console or
federation key"; the name is the only old word left.
- B3 (webby-0191): missing self, missing peer id, and missing peer label each have a case and a mutant (M15–M17).
The typeof halves are the only thing refusing an absent value, since the pattern test coerces undefined.
- B2: a case and a mutant for each uncovered refusal, plus the trailing-slash case under M4 (N4) and the
duplicate-peer case (M13).
- N1: this file is rewritten with the current base and status.
+7
View File
@@ -242,6 +242,13 @@ expect_fed_refusal "federation duplicate peer id exits 2 naming the key" 'federa
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com","label":"F"},{"id":"factory","origin":"https://other.woltje.com","label":"G"}]}'
expect_fed_refusal "federation peer origin with a trailing slash exits 2 naming the key" "federation.peers[0].origin" \
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com/","label":"F"}]}'
# A missing value: the pattern test coerces undefined to "undefined", which matches, so the typeof half is what refuses.
expect_fed_refusal "federation self missing exits 2 naming the key" "federation.self must match" \
'{"peers":[]}'
expect_fed_refusal "federation peer id missing exits 2 naming the key" "federation.peers[0].id must match" \
'{"self":"hub","peers":[{"origin":"https://mosaic.woltje.com","label":"F"}]}'
expect_fed_refusal "federation peer label missing exits 2 naming the key" "federation.peers[0].label must be" \
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com"}]}'
# Without the key: no federation in the output, and the config still loads (FED R2 boundary).
cfg no-federation.json '{"configVersion":1,"environment":"development","dataRoot":"'$DATA_ROOT'","execution":{"backend":"docker","provider":"zai","model":"m"}}'