diff --git a/agents/gander/work/config-checks-any-key/ASSERTION-PRESERVATION.json b/agents/gander/work/config-checks-any-key/ASSERTION-PRESERVATION.json new file mode 100644 index 000000000..835d1a9e0 --- /dev/null +++ b/agents/gander/work/config-checks-any-key/ASSERTION-PRESERVATION.json @@ -0,0 +1,7 @@ +{ + "base": "01983cd3f", + "test": "packages/cli/tests/stack-release.test.mjs", + "base_is_byte_exact_prefix": true, + "old_assertions_changed": 0, + "old_console_refusal_text_unchanged": true +} diff --git a/agents/gander/work/config-checks-any-key/BUILD.md b/agents/gander/work/config-checks-any-key/BUILD.md new file mode 100644 index 000000000..a76cc27ba --- /dev/null +++ b/agents/gander/work/config-checks-any-key/BUILD.md @@ -0,0 +1,37 @@ +# Target config validation for every key implementation plan + +Goal: #1797, mos-1353, brief f0e3dcdf4:docs/plans/2026-10-22_config-checks-any-key-brief.md. Base01983cd3f, branchgander/config-checks-any-key. Reviewer Duckworth. Queue number pending Sage; packet moves to queue-N when assigned. No Node, test or push before Sage gap/CLEAR. Rows270/271/203 land first; rebase under a new branch name before the gate. + +Architecture: config_checks classifies missing/parseable/unreadable config independently of console presence. With a loader, every existing parseable config goes through the target's own validate. Missing config passes. Malformed JSON refuses. With no loader, allow only the oldest four top-level keys: configVersion, environment, dataRoot, execution. Evidence: c3d29e796:scripts/mosaic-config.mjs:114, the first loader commit, rejectUnknownKeys; row200 fixture's LOADER_OLD has the same list. A missing loader plus a later key refuses and names that key, without inventing validation support. The legacy public refusal code config-console-key and existing console-specific message stay byte-identical; new non-console refusals name the loader's first diagnostic and preserve restore-config-backup instruction. No config values are printed. + +Files: scripts/stack-release.sh config_checks/comment only; packages/cli/tests/stack-release.test.mjs appended regression coverage only; docs/TOOLS.md broadens the current console-only release-check description. Existing row200 tests and assertions stay unchanged. No fixture-module edit, flags, pointers, migration, schema, data, live unit or host change. + +Tests to write before implementation, unrun until CLEAR: +- A target loader rejecting a non-console key refuses activate and rollback before any unit stop/start, pointer/unit/store mutation; one refused log entry; --plan preserves state and lists refusal. Reuse refused() and planOnly(). Use execution, already known to the current loader, to prove console-free dispatch before row270 integration; add compactionReadBytes/compactionStreams cases on final post270 base if needed. +- An accepting target loader is actually called with validate and the selected MOSAIC_CONFIG, succeeds activate/rollback without console, and resolved stdout is not leaked. +- Missing-loader target permits oldest-key config but rejects a later key with backup instruction. A stand-in rejecting the existing execution key exercises the generic target-validation branch; missing-loader later-key test may use console until final post270 base supplies non-console new keys. +- Missing file passes the isolated real config_checks function; malformed JSON refuses there, since load_config otherwise exits before this function. Tests extract only that function and provide copies/path/check_refuse stand-ins, never live state. +- Existing console-key row200 tests and malformed-load test run whole unchanged. + +Mutants, each unique target, syntax preflight and byte-identical restore: +M1 restores the console-only skip, killed by the named non-console activate/rollback refusal test. +M2 ignores failed target validation, killed by the same refusal assertions. +M3 allows a missing-loader target with a later key, killed by the explicit missing-loader regression. +M4 treats malformed JSON as absence, killed by isolated parse guard test. +M5 skips the loader for an oldest-key config, killed by accepting-loader invocation witness. + +Gate after static review and required rebases: intended RED/GREEN; touched stack-release.test.mjs whole, CLI suite whole and every scripts/test-*.sh whole; M1-M5 with fresh passing controls, no timeout counted as kill, restored bytes/status before next. TMPDIR mktemp-d /mnt/storage/scratch/tmp/gXXX; pipefail/tee and busy check before each start. Node timeout-k10 uses at least3x measured duration plus margin; stack-release prior full receipt around584s implies at least1871s, to be recorded from actual receipts before CLEAR. Shell3x table retained with receipts. No test ran and no behavior passes claimed. + +Review focus: parser races after load_config; target stderr naming only the refused key, stdout never persisted; current versus target loader selection; unknown key with no console; missing loader compatibility set from immutable history; upcoming row270 loader-list fixture drift. Final integration audits every test dependency and hash pin against the named base. Session registration remains Sage's. + + +Implementation ready, unrun. Four appended tests cover full activate/rollback refusal and plan; actual accepting validate witness/configpath and stdout nonleak; oldest-only missing loader with both compaction keys; missing/invalid JSON isolated realfunction. Stand-in loaders are ESM, matching .mjs. Every old test byte is preserved as a prefix. Existing console refusal text including missing-loader diagnostic is unchanged. Missing-loader compatibility is top-level key compatibility only; current load_config still validates the whole config before normal release operations. Three-path manifest, no fixture-module changes. Static target uniqueness M1-M5 passes. No Node parse, Bash execution or behavior run. Exact full compaction activate/rollback cases must be added against post270 loader, before final gate. + + +Execution state: +- [x] Read brief, config_checks and row200 assertions. +- [x] Pin oldest key set from immutable loader history. +- [x] Write regression tests, implement bounded scope, prepare unique mutants. +- [ ] Duckworth static review. +- [ ] Move packet to queue-N on assignment, rebase after270/271/203 and add full compaction-key cases. +- [ ] On CLEAR run intendedRED/GREEN, touched whole file, CLI whole, M1-M5, ten shells; commit/push records only when authorized. diff --git a/agents/gander/work/config-checks-any-key/MANIFEST.sha256 b/agents/gander/work/config-checks-any-key/MANIFEST.sha256 new file mode 100644 index 000000000..2bad87501 --- /dev/null +++ b/agents/gander/work/config-checks-any-key/MANIFEST.sha256 @@ -0,0 +1,3 @@ +eea06caad07c746d194f793603052b210e437b7184009f8b1617c88db49a5517 docs/TOOLS.md +a35c49c5703e02f35073450e4a98e1b90cffcda581490f97a70cbdc6d2afee59 packages/cli/tests/stack-release.test.mjs +f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150 scripts/stack-release.sh diff --git a/agents/gander/work/config-checks-any-key/SHAS.json b/agents/gander/work/config-checks-any-key/SHAS.json new file mode 100644 index 000000000..24ecb4c13 --- /dev/null +++ b/agents/gander/work/config-checks-any-key/SHAS.json @@ -0,0 +1,5 @@ +{ + "docs/TOOLS.md": "eea06caad07c746d194f793603052b210e437b7184009f8b1617c88db49a5517", + "packages/cli/tests/stack-release.test.mjs": "a35c49c5703e02f35073450e4a98e1b90cffcda581490f97a70cbdc6d2afee59", + "scripts/stack-release.sh": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150" +} diff --git a/agents/gander/work/config-checks-any-key/SOURCE.json b/agents/gander/work/config-checks-any-key/SOURCE.json new file mode 100644 index 000000000..e5d8c0ccf --- /dev/null +++ b/agents/gander/work/config-checks-any-key/SOURCE.json @@ -0,0 +1,14 @@ +{ + "issue": 1797, + "row": "pending Sage assignment", + "branch": "gander/config-checks-any-key", + "base": "01983cd3f", + "source": "0585b321309e4d8a199afb1a1024cf6091f56770", + "manifest": "d6226d281c778677a45e90993bbd9c985de89ba0f870d4a3ca12b6923a497e4a", + "runtime": "NOT RUN; no Node, tests or push authorized", + "after": [ + 270, + 271, + 203 + ] +} diff --git a/agents/gander/work/config-checks-any-key/UNIQUENESS.json b/agents/gander/work/config-checks-any-key/UNIQUENESS.json new file mode 100644 index 000000000..a72e0a227 --- /dev/null +++ b/agents/gander/work/config-checks-any-key/UNIQUENESS.json @@ -0,0 +1,32 @@ +[ + { + "id": "M1", + "occurrences": 1, + "before": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150", + "after": "804a86442527f2728f633f485eaeca02552df66a34350eac5101127046415188" + }, + { + "id": "M2", + "occurrences": 1, + "before": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150", + "after": "1c2acb6397e29ab898d8a89bc5bc691a294be749ca7d7f7897c83ec1b3e9f9ef" + }, + { + "id": "M3", + "occurrences": 1, + "before": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150", + "after": "954c9a9735904e1c566d844001b2e85c13cd16eb16e7b4b91b752974bb6dc754" + }, + { + "id": "M4", + "occurrences": 1, + "before": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150", + "after": "953d91bf28073b11e4bc5a6da516a0db1b8dfff892083cd3e6fcebe9c47b6bbf" + }, + { + "id": "M5", + "occurrences": 1, + "before": "f8fe1348796d40a096362fb0c6d5072c15ca68ff8fe10384a3eaa708eb92c150", + "after": "310c32b16f0fc554d5a7ffeeb0742ea7dd9fc84e1ddafabb25d7ca3f449865ef" + } +] diff --git a/agents/gander/work/config-checks-any-key/changes.json b/agents/gander/work/config-checks-any-key/changes.json new file mode 100644 index 000000000..b6b62a23f --- /dev/null +++ b/agents/gander/work/config-checks-any-key/changes.json @@ -0,0 +1,37 @@ +[ + { + "id": "M1", + "file": "scripts/stack-release.sh", + "old": " [ \"$key\" != 1 ] || return 0\n if [ \"$key\" != 0 ]; then", + "new": " [ \"$key\" != 1 ] || return 0\n [ \"$extra\" = '\"console\"' ] || return 0\n if [ \"$key\" != 0 ]; then", + "killer": "config-any-key: a non-console target refusal" + }, + { + "id": "M2", + "file": "scripts/stack-release.sh", + "old": "elif out=\"$(MOSAIC_CONFIG=\"$cfg\" node \"$loader\" validate 2>&1 >/dev/null)\"; then return 0", + "new": "elif out=\"$(MOSAIC_CONFIG=\"$cfg\" node \"$loader\" validate 2>&1 >/dev/null)\" || true; then return 0", + "killer": "config-any-key: a non-console target refusal" + }, + { + "id": "M3", + "file": "scripts/stack-release.sh", + "old": " [ -n \"$extra\" ] || return 0", + "new": " return 0 # drop missing-loader later-key refusal", + "killer": "config-any-key: missing-loader copies" + }, + { + "id": "M4", + "file": "scripts/stack-release.sh", + "old": " if [ \"$key\" != 0 ]; then\n check_refuse config-console-key", + "new": " if [ \"$key\" = 99 ]; then\n check_refuse config-console-key", + "killer": "config-any-key: missing config passes but malformed JSON refuses" + }, + { + "id": "M5", + "file": "scripts/stack-release.sh", + "old": " if [ ! -f \"$loader\" ]; then", + "new": " [ -n \"$extra\" ] || return 0\n if [ ! -f \"$loader\" ]; then", + "killer": "config-any-key: accepting loaders run validate" + } +]