Repository navigation
S1 (#182) — appwrite_env logs before it raises; ADR-008 pinned across both entry validators - #193
Merged
Conversation
…ver both entry validators ADR-008:48 requires raised structural failures to be logged at ERROR; :51 that "raising is not a substitute for logging." `assert_env_declared` raised `EnvironmentError` naming every missing variable and wrote no log record, so an operator reading logs after a refused run found nothing (register C-71). The two-line fix matters less than why it was missing. `contract/launch_config.py` was written in #149 by mirroring this module, inherited the flaw, was fixed in review, and left the module it copied as the odd one out. The new test therefore parametrises the ADR-008 obligation over BOTH validators rather than pinning one: adding a third is one line, and the pair cannot drift again. Deliberately NOT extracted into a shared helper. WET before DRY — they answer different questions (did the launcher assemble the environment / did it declare the delivery mode) against different sources (os.getenv / a passed dict). Named trigger to revisit: a third entry-validation module. Recorded in epic #181. Logging here is only safe because `missing` holds NAMES: membership is decided by `os.getenv(name)` being falsy and the resolved value is never read. CONNECTION_ENV carries the APPWRITE_DATASTORE_API_KEY secret slot, so a second test sets a sentinel value and asserts it never reaches a record — a future "log the current environment for debuggability" cannot land quietly. Mutation-tested: removing the logger.error line fails 2 of the new tests. Also registers C-74, found by this story's own review. tests/test_redaction_guard.py pins the þing-01 #135 redaction audit over five module roots; #153 moved the machinery from unfao/ to contract/ and four were never re-pointed. rglob on a nonexistent directory yields nothing rather than raising, so the guard scans 6 files instead of ~16 and passes. Not a leak — the relocated modules are still credential-blind — but C-57 and Cluster I both vouched for that guard in writing, and both are corrected in place. Tracked as #192. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 1, 2026
Polichinel
added a commit
that referenced
this pull request
Aug 2, 2026
…l day (#205) assert_env_declared has logged before raising since #193. The entry stayed under Open while eight further stories shipped, in the epic whose entire thesis is that a record should not outlive the thing it describes. S2's guard did not catch it, and that is by design rather than by defect: it matches two declarative phrasings, and this entry's closing language is prose — "a two-line change; the natural place to take it is S8". That is the false negative S2 deliberately accepted, and the cost came due within hours. Widening the guard would be the wrong fix; no regex separates "describes work that is done" from prose. The gap is that #182 was closed without disposing of the entry it named in the same change. The generalisable rule — a story that names a register entry disposes of it in the same PR — goes to S9's ADR question alongside the CIC lagging three consecutive stories. Both are records updated by memory rather than by the change that invalidates them. Co-authored-by: Claude Opus 5 (1M context) <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.
Closes #182. Part of epic #181. Registers C-74 and files #192.
What
appwrite_env.assert_env_declarednow logs at ERROR before raising, per ADR-008:48/51. Two lines.Why it was missing, which is the interesting part
contract/launch_config.pywas written in #149 by deliberately mirroring this module — same shape, same failure style, same dependency-light constraint. It inherited the flaw, the S1 diff review caught it in the new code, and the new module was fixed. The old one was left alone for scope discipline.So the pair ended up inconsistent in the wrong direction: the module written to match the pattern was the only one that had it.
The test therefore parametrises the ADR-008 obligation over both validators rather than pinning one. Adding a third is one line in
_REFUSALS, not a new test.WET before DRY — explicitly refused
No shared
assert_declaredhelper. They answer different questions (did the launcher assemble the environment vs did it declare the delivery mode) against different sources (os.getenvvs a passed dict). Named trigger to revisit: a third entry-validation module. Recorded in #181 so the next contributor's instinct to extract meets an argument rather than a silence.The secret
CONNECTION_ENVcarriesAPPWRITE_DATASTORE_API_KEY. Logging a refusal is only safe becausemissingholds names: membership is decided byos.getenv(name)being falsy and the resolved value is never read. A second test sets a sentinel value and asserts it never reaches a record, so a future "log the environment for debuggability" cannot land quietly.Mutation-tested
Removing the
logger.errorline fails 2 of the new tests. A guard that passes on the bug it was written for is decoration.Review found something bigger — C-74, now #192
Reading
tests/test_redaction_guard.py(cited by the new test as "the wider rule") showed it is not enforcing that rule. It pins the þing-01 #135 audit over five module roots; #153 moved the machinery fromunfao/tocontract/and four were never re-pointed:unfao/wiredeliveryunfao/historical.pyunfao/track_a_source.pyunfao/frame_extraction.pySilent by construction:
rglobon a nonexistent directory yields nothing rather than raising, so a missing root and a clean root look identical. 6 files scanned instead of ~16, passing.Not a leak — the relocated modules were checked directly and are still credential-blind. What is gone is the thing that would notice them ceasing to be.
Two register claims corrected in place: C-57 said the redaction clause was "already mechanically enforced", and Cluster I's fix strategy cites this exact file as the guard pattern working. Both were written in good faith; both were overclaims.
Sixth instance of the stale-claim class in two days. The shape has a name now: a move leaves prose and paths behind, and nothing here asserts that a declared path exists. Handed to S9's ADR question.
Review findings addressed
test_env_declaration.py's own module docstring ("Imports onlyunfao.appwrite_env"). Fixed. Introducing a stale claim in an epic about stale claims would have been a poor look.assert_env_declared's docstring now declares the log side effect and carriesArgs:/Raises:, matchinglaunch_config.Verification
Note: the epic's freeze check originally said
main, notorigin/main. A stale localmainreported 10 changed fixture files on a branch that touched none. Corrected in #181/#186/#190/#191 — a verification command that cries wolf gets ignored, which would have defeated the point.🤖 Generated with Claude Code