Skip to content

feat(enforcement): add ConflictDetector and live enforcement metadata#16

Merged
kschlt merged 3 commits intomainfrom
feat/conflict-detection-fallback
Mar 26, 2026
Merged

feat(enforcement): add ConflictDetector and live enforcement metadata#16
kschlt merged 3 commits intomainfrom
feat/conflict-detection-fallback

Conversation

@kschlt
Copy link
Copy Markdown
Owner

@kschlt kschlt commented Mar 26, 2026

Why

The enforcement pipeline had two silent failure modes: fragment-config conflicts would silently overwrite user settings on disk, and policy keys that no adapter could handle were dropped without any trace. Both caused config drift that agents could only discover after the fact — too late to prevent harm. This work surfaces both categories as structured, actionable signals.

Approach

ConflictDetector handles two distinct detection paths: policy-contract conflicts (pre-approval, decision-plane validation) and fragment-config conflicts (pre-write, enforcement-plane gating). Keeping both in one class avoids duplicating the TOML/JSON parsing and key-normalisation logic they share.

_build_enforcement_metadata() derives adapter capabilities live from the registry at call time instead of being baked in as a static list. This means creation guidance (what policies are enforceable) and enforcement reality (what adapters are registered) cannot diverge when new adapters are added — they stay in sync by construction.

The pipeline's conflict-gating logic was added as a fallback in EnforcementPipeline.run(): if ConflictDetector finds conflicts for a fragment, the write is skipped and a structured skip-record is appended to the result instead of raising or silently proceeding.

What Was Tested

  • ConflictDetector._detect_fragment_conflicts: ruff adapter, ESLint adapter, unknown format (falls back gracefully)
  • Policy-contract conflict detection: contradicting, non-contradicting, and partial-overlap cases
  • Pipeline skip-on-conflict: fragments with conflicts are skipped, conflict-free fragments are written
  • _build_enforcement_metadata: verified live registry keys match adapter capabilities; verified behaviour when no adapters are registered

Risks

Additive changes only — no existing public API was modified. The conflict-gating path is new code that branches around the existing write path, so previously passing fragments are unaffected. The one pre-existing type: ignore[arg-type] removed from pipeline.py was confirmed unused by mypy before removal.

kschlt added 3 commits March 26, 2026 19:36
Prevent silent failures in the enforcement pipeline: fragment-config
conflicts would previously overwrite user settings without warning, and
unroutable policy keys were silently dropped. ConflictDetector surfaces
both categories so agents can act rather than discover drift later.

_build_enforcement_metadata() derives adapter capabilities live from the
registry so creation guidance and enforcement reality cannot drift apart
when new adapters are added.
…ection

Properly type the _get_ruff_lint return value with dict[str, Any] to
satisfy warn_return_any, and remove a now-unused type: ignore on
_write_fragment that became superfluous after prior type improvements.
@kschlt kschlt merged commit f3cbd58 into main Mar 26, 2026
8 checks passed
@kschlt kschlt deleted the feat/conflict-detection-fallback branch March 26, 2026 19:28
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