Skip to content

orb(config): no unknown-key validation at runtime — a typo silently disables a safety control with zero warning #9065

Description

@JSONbored

unknownTopLevelWarnings (packages/loopover-engine/src/config-lint.ts ~80-97) exists but is wired only into the offline validator (loopover_validate_config, the validate route, the admin dry-run write, scripts/loopover-config-lint.ts). The runtime path — loadRepoFocusManifestparseFocusManifestContentparseFocusManifest (focus-manifest.ts ~4023) — never calls it. An operator editing the mounted file directly (our normal workflow) gets no check at all.

Worse, unknown-key detection is top-level only. Every nested parser reads known keys by name and never enumerates the supplied set, so settings.*, gate.*, features.*, review.* typos are invisible even to the offline linter. (Sole exception: review.enrichment.) The doc comment at focus-manifest.ts ~1999 claiming features unknown keys "are dropped with a warning" is factually wrong — ~2011-2013 iterates CONVERGED_FEATURE_KEYS and never looks at supplied keys.

Typos that silently disable a safety control

Typo Silently disables
settings.agentPause / agent_paused the per-repo kill switch
settings.manualReviewLabel the manual-review hold — falls back to AGENT_LABEL_NEEDS_REVIEW, so your real label no longer matches and labelled PRs auto-merge
settings.autoCloseExemptLogins auto-close exemptions — protected authors become closable
settings.contributorBlacklist per-repo bans
settings.hardGuardrailGlob (singular) your added guardrails (built-in floor survives)
settings.contributorOpenPrCap the open-PR cap
settings.accountAgeThresholdDays new-account protection
settings.moderationRules moderation
top-level gates: / Gate: the entire block
any gate.* / review.* / features.* nested typo that knob, at any depth
a malformed glob in hardGuardrailGlobs that entry — normalizeStringList does no glob validation, so it just never matches

Compounding: malformed layers and warnings both vanish

  • combineConfigLayersWithMeta (src/selfhost/private-config.ts ~189-232) warns only for the shared base. If the global default or per-repo layer fails to parse (YAML typo, a file caught mid-vim-write, a truncated docker cp), it is dropped at ~202-204 with no warning, no log, no metric — that repo silently demotes to fleet house policy with a clean-looking manifest.
  • Private-manifest warnings reach no consumer: the only PR-comment consumer deliberately uses the public manifest (processors.ts ~11617, correctly, to avoid leaking private policy), and adminGetConfig scope "effective" (src/mcp/server.ts ~3995-4004) extracts only loaded.content and discards warnings — so loopover_admin_config_read --scope effective will happily show a config whose gate: block was silently dropped as a type error.
  • Config-mount health is a one-shot boot snapshot (src/server.ts ~403-409, ~916): if the mount is lost or emptied while running, the gauge stays pinned at healthy and every repo silently reverts to defaults — the exact incident src/selfhost/health.ts ~240-245 documents, caught only if it happens before boot.

Verified sound: I exercised mergeConfigOverlay against its documented contract — 8/8 edge cases pass (explicit null clears, arrays replace wholesale, nested maps merge key-by-key, __proto__ does not pollute). The merge core is not the problem.

Fix

  1. Call unknownTopLevelWarnings from parseFocusManifestContent itself, and add per-block known-key sets for settings/gate/features/review.
  2. Warn for every dropped layer, carrying the candidate path.
  3. Log private-manifest warnings as a structured event + counter; return warnings from adminGetConfig --scope effective.
  4. Make the config-dir health gauge a live callback, and add a per-repo "resolved to no local manifest" signal.
  5. Fix the false doc comment at focus-manifest.ts ~1999.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.orbGittensory Orb related - maintainer self-hosting analytics.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions