Skip to content

S1 — appwrite_env logs before it raises (C-71) #182

Closed

Description

@Polichinel

Part of epic #181. Closes register C-71 (Tier 4).

Background

ADR-008:48 requires that "raised structural failures must be logged at ERROR level or higher", and :51 that "raising is not a substitute for logging." C-19 swept the whole repo for this in June — 23 of 24 raises were fixed.

views_postprocessing/unfao/appwrite_env.py was written later (þing-01 P1, #134) and predates nothing — it simply never got the convention. assert_env_declared raises EnvironmentError naming every missing variable, but writes no log record.

How this was found, and why it matters more than a Tier 4 usually would. contract/launch_config.py was written in #149 to deliberately mirror 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 to log-before-raise. The old one was left alone for scope discipline.

So the pair is now inconsistent in exactly the wrong direction: the module written to match the pattern is the one that has it. The next entry-validation module will be written against whichever of the two its author opens first.

Work

views_postprocessing/unfao/appwrite_env.py:

  1. Add a module-level logger = logging.getLogger(__name__), matching launch_config.py.
  2. In assert_env_declared, build the message into a local, logger.error(...) it, then raise it — the same three-line shape as launch_config.assert_contract_mode, including the # ADR-008: logged persistently AND raised comment.

Security constraint, non-negotiable. CONNECTION_ENV contains APPWRITE_DATASTORE_API_KEY, a secret slot. The existing message names variables, never values — missing is a list of names produced by os.getenv(name) being falsy. Adding a log call must not change that. Do not log os.environ, do not log the resolved values, do not add a "current environment" dump for debuggability. tests/test_redaction_guard.py governs this repo's log surface; it must stay green.

Do NOT extract a shared helper between appwrite_env and launch_config. See the epic's WET-before-DRY boundary — the named trigger for revisiting is a third such module.

Acceptance criteria

  • assert_env_declared logs at ERROR before raising; message content is unchanged apart from being captured in a local first.
  • No secret value can reach a log record from this function.
  • A test asserts log-before-raise for both modules, so the pair cannot diverge again.

Testing

New or extended test (suggested home: tests/test_env_declaration.py, which already governs this module):

def test_both_entry_validators_log_before_raising(caplog):
    """ADR-008:48/51 — a structural refusal must leave a persistent record."""
  • Use caplog.at_level(logging.ERROR); assert exactly one ERROR record from each module's refusal path.
  • Assert the record names the missing variable and does not contain any value from os.environ.
  • Parametrise across appwrite_env.assert_env_declared and launch_config.assert_contract_mode so a future third module is a one-line addition rather than a rewrite.

Validation:

ruff check .
pytest -q tests/test_env_declaration.py tests/test_launch_config.py tests/test_redaction_guard.py
pytest -q

Dependencies

None. This is the smallest change in the epic and touches nothing else.

Files

  • views_postprocessing/unfao/appwrite_env.py:44-51 — the fix
  • views_postprocessing/contract/launch_config.py:52-70 — the pattern to match
  • tests/test_env_declaration.py, tests/test_redaction_guard.py — the governing tests
  • docs/ADRs/008_*.md:48,51 — the requirement

Activity

  1. added
    storyA single reviewable unit of an epic
    testingTest/parity/validation work
    on Aug 1, 2026
  2. added a commit that references this issue on Aug 1, 2026
  3. Polichinel commented on Aug 1, 2026

    @Polichinel
    CollaboratorAuthor

    Landed in #193 (squashed to development).

    appwrite_env.assert_env_declared logs at ERROR before raising; the ADR-008 obligation is parametrised over both entry validators so the pair cannot drift again. No shared helper — WET before DRY, named trigger is a third such module.

    Mutation-tested: removing the logger.error line fails 2 of the new tests.

    Review findings F2 (this diff falsified the test file's own module docstring) and F3 (undeclared log side effect) fixed in the same PR. F1 became C-74 / #192.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    implementationCode implementation workstoryA single reviewable unit of an epictestingTest/parity/validation work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions