Skip to content

feat: DEFAULTS covers every config key the engine reads - #11

Merged
SunsetDrifter merged 1 commit into
mainfrom
feat/defaults-full-coverage
Aug 24, 2026
Merged

feat: DEFAULTS covers every config key the engine reads#11
SunsetDrifter merged 1 commit into
mainfrom
feat/defaults-full-coverage

Conversation

@SunsetDrifter

@SunsetDrifter SunsetDrifter commented Aug 24, 2026

Copy link
Copy Markdown
Owner

What

wiki/wikilint/settings.py DEFAULTS now supplies every config key the engine reads (40), not just the twelve opt-in extension points, split into two documented tiers.

Why

The engine reads 40 CONFIG keys but DEFAULTS declared only twelve, so CONFIG[key] raised KeyError for any key a config omitted. Every config therefore had to list all 28 remaining knobs — including ~15 pure "off" switches — which contradicts the module's own documented contract: "a variant only lists a key when it overrides one." A new wiki, or a non-wiki markdown tree, could not start from a minimal config.

It also fixes a latent KeyError: inbox_warn_count / inbox_warn_age_days are read by check_inbox but had no DEFAULTS entry at all, so a config setting inbox_dir without both thresholds crashed mid-run. They now default to 10 / 14, matching the template.

The two tiers

DEFAULTS = {**CORE_DEFAULTS, **EXTENSION_DEFAULTS}

  • CORE_DEFAULTS (28 new) — the schema knobs (page_dirs, required_fields, staleness, adr_dirs, mermaid_*, coverage, taxonomy_file, inbox_*, raw_dir, ...) default to the neutral/disabled value: no pages, no required fields, every optional check off. These knobs have no "before" — they were always config-declared — so a default here can only ever silence a check, never invent one.
  • EXTENSION_DEFAULTS (the pre-existing twelve) keep their original-wiki values, deliberately including the non-off orphans, okf_conformance, types_glossary and log_file: "log.md". A wiki written before an extension existed must keep behaving as it did, so a config that wants one off still lists it as a genuine override.

The tiers are two real dicts rather than a comment so the distinction is machine-checkable — a test asserts they partition DEFAULTS, that every core default is neutral, and that the extension points still carry original-wiki behavior.

Why it is behavior-neutral

The shipped wiki/ template and all three extension config bundles in tests/extension_configs.py (infra, pinned-repo, sharded-repo) set every core knob explicitly, so no new default can reach them. Verified empirically, not by inspection: each one's fully-merged effective CONFIG was dumped before and after and diffed — identical for all four.

wiki/lint.py is untouched. Its config stays fully explicit as self-documentation; trimming the now-redundant entries would be a separate, cosmetic change.

Test plan

  • python -m unittest discover -s tests100 passed (was 91; +9)
  • New tests/test_engine_contract.py derives the engine's key list from its own source (regex over CONFIG[...] / cfg[...] accesses) rather than restating a list that would drift, and pins:
    • DEFAULTS supplies every key the engine reads, and declares no dead knob
    • CORE_DEFAULTS / EXTENSION_DEFAULTS partition DEFAULTS with no overlap
    • every core default is neutral (empty / None / False, or a guarded shape-only value)
    • the extension points still carry original-wiki behavior (orphans, okf_conformance, types_glossary, log_file, index_file)
    • a one-key config ({"page_dirs": ["notes"]}) configures cleanly and survives a full gather_report pass with no errors
    • setting inbox_dir alone no longer KeyErrors — the specific latent bug
  • New test_variants.py case: a config may only set keys the engine knows about, so a typo'd key cannot sit in a lint.py silently doing nothing

Note on the sibling PR

Opened alongside #12. Both are cut from main and are independently mergeable, but they touch adjacent regions of settings.py and the same README bullet, so whichever merges second needs a trivial rebase (no logical conflict).

🤖 Generated with Claude Code

The engine reads 40 CONFIG keys but DEFAULTS supplied only the twelve opt-in
extension points, so `CONFIG[key]` raised KeyError for any key a config
omitted. Every config therefore had to list all 28 remaining knobs,
including ~15 pure "off" switches, contradicting the module's own
documented contract ("a variant only lists a key when it overrides one").

DEFAULTS is now the union of two documented tiers:

* CORE_DEFAULTS -- the schema knobs, defaulting to the neutral/disabled
  value (no pages, no required fields, every optional check off). These
  have no "before": they were always config-declared, so a default can
  only ever silence a check, never invent one.
* EXTENSION_DEFAULTS -- the pre-existing twelve, keeping their original
  values including the non-off `orphans`, `okf_conformance`,
  `types_glossary` and `log_file: "log.md"`, so a wiki that omits one
  still behaves as the original wiki did.

Also fixes a latent KeyError: `inbox_warn_count` / `inbox_warn_age_days`
were read by check_inbox but declared by no DEFAULTS entry at all, so a
config setting `inbox_dir` without both thresholds crashed mid-run.

Behavior-neutral: the shipped wiki template and all three extension config
bundles set every core knob explicitly, so no new default can reach them.
Verified by diffing each one's fully-merged effective CONFIG against main
-- identical for all four.
@SunsetDrifter
SunsetDrifter force-pushed the feat/defaults-full-coverage branch from f517356 to b631748 Compare August 24, 2026 12:35
@SunsetDrifter
SunsetDrifter merged commit 59510bc into main Aug 24, 2026
1 check passed
@SunsetDrifter
SunsetDrifter deleted the feat/defaults-full-coverage branch August 24, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant