story-043: An undeclared config key is refused - #41
Merged
Conversation
Implemented by the l5 harness story workflow.
The documenter wrote 'it replaced tests/test_retired_config_keys.py', which this story deletes. story-038's check requires every tests/ path the document names to exist, and it does not, so the suite went red on main's CI. The sentence was true and the rule is right: a reader following a path in the document should find something. Reworded to keep the history without the dangling path. Nothing in the run could have caught this. The documenter runs after the verifier and after the clean-clone check, so its output is the only stage output no check ever sees. Filed as .harness/requests/the-clean-clone-check-runs-after-the-documenter.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The harness declared the thirteen keys it reads and never checked a config against that declaration.
declared_config_keys' own docstring said so: "no unknown key is refused". So a mistyped key ran, silently used the default, and the developer found out from the behaviour.It also refused exactly one key by name —
clean_clone_python, retired by story-041 — which meant a language name had to live inorchestration/in order to be rejected.What changed
undeclared_config_problemsrefuses any key the schema does not declare, at the same pre-flight point the retired-key refusal used: decidable the moment the config loads, so no run directory, nostate.json, no log, no branch and no agent invoked.RETIRED_CONFIG_KEYS,retired_config_problemsand_refuse_retired_config_keysare deleted. A config still carryingclean_clone_pythonis refused as one more undeclared key, without the harness naming it.orchestration/now holds no target-stack tie. Runningharness_source.scan()reports two findings there, both onPERMANENT_MENTIONSand both statements about this harness's own implementation language rather than about any target.It found a key nobody read
Enabling the refusal exposed
project, which every config carried and nothing ever read. It could not simply be declared: story-039's coverage asserts set equality between the declared keys and the keys the harness actually reads, so declaring a key nothing reads fails that check. It is removed instead — from.harness/config.yaml, from whatl5-initwrites, and from the fixture configs across roughly twenty test modules, which is the one-line deletion repeated through the diff.That is the risk the request named — "a harness that refuses its own config is a bad afternoon" — found and resolved rather than discovered in a run.
The retry is worth reading
Verification failed once and routed to the tester on
validation. The finding was a self-reference the acceptance criteria created: the criterion says the three deleted names must not appear anywhere outside.harness/runs/, and the tester's own module spelled all three as string literals in order to assert their absence. The test making the claim was an instance of the thing it denied.Resolved by composing them:
with
SURVIVING_NAME = "undeclared_config_problems"as the control, so the same scan over the same files is known to be able to see a name at all — without which the absence would be indistinguishable from a search that had stopped matching.Verification
2316 passed, 44 written; verification passed on the second iteration; one retry, routed tovalidation; clean-clone green with the story committedTEMPORARY_TIESis unchanged at 3 — those arethe-test-location-comes-from-configuration's, and emptying that list closes the audit🤖 Generated with Claude Code