Files
Charon/docs/plans/current_spec.md

7.1 KiB

Active Plan: PR-0 Spec Correction Pass (Security Notifications Provider Events)

Date: 2026-02-20 Status: Active and authoritative (supersedes all prior appended sections in this file)

1) Scope and Intent

  • This is a spec-only correction pass for compatibility, migration determinism, and rollout safety.
  • Security notifications are provider-event subscriptions, not a single global destination.
  • Notify-only runtime remains fail-closed; legacy fallback dispatch remains blocked.

2) Compatibility GET Aggregation Rules (Exact)

Compatibility endpoint in scope:

  • GET /api/v1/notifications/settings/security

Aggregation source of truth:

  • Active provider rows in notification_providers after filtering enabled=true and supported notify-only types.

Derived booleans (OR semantics):

  • security_waf_enabled = OR(provider.notify_security_waf_blocks)
  • security_acl_enabled = OR(provider.notify_security_acl_denies)
  • security_rate_limit_enabled = OR(provider.notify_security_rate_limit_hits)

Deterministic conflict behavior when providers disagree:

  • If any active provider has true for a category, compatibility GET returns true for that category.
  • Returns false only when all active providers are false (or no active providers exist).
  • Provider order never affects result.

Legacy destination reporting:

  • If compatibility payload still includes destination, it is read-only compatibility metadata.
  • destination is emitted only when exactly one active managed-legacy provider is in scope.
  • If zero or more than one candidate exists, destination is returned as empty string and destination_ambiguous=true is set in compatibility metadata.

3) Compatibility PUT Translation Semantics (Exact)

Compatibility endpoint in scope:

  • PUT /api/v1/notifications/settings/security

Deterministic target set:

  • If one or more managed-legacy providers exist, target set is exactly that managed set.
  • If none exist and request is valid, create one managed-legacy provider and use it as the target set.
  • Non-managed providers are never mutated by compatibility PUT.

Translation mode: replace on managed set (not global merge)

  • For each target provider, set security event booleans exactly to request values:
    • notify_security_waf_blocks = request.security_waf_enabled
    • notify_security_acl_denies = request.security_acl_enabled
    • notify_security_rate_limit_hits = request.security_rate_limit_enabled
  • Existing non-security provider event booleans remain unchanged.
  • Existing provider transport fields remain unchanged unless destination mapping applies (Section 5).

Idempotency:

  • Repeating identical PUT payload produces no state drift and same compatibility GET output.
  • Write timestamps may change only when effective values change.

Conflict handling:

  • If target set cannot be resolved deterministically (for example data corruption with duplicate managed identity keys), return 409 Conflict and do not partially write.
  • If request includes unsupported destination mapping shape, return 422 Unprocessable Entity and do not mutate providers.
  • All compatibility PUT writes are transactional: all target providers updated or none.

4) Migration Marker Storage and Deterministic Re-Run

Marker storage:

  • Table: settings
  • Key: notifications.security_provider_events.migration.v1
  • Value JSON schema:
    • version (string, fixed v1)
    • checksum (string, deterministic hash of legacy source fields used for migration)
    • last_completed_at (RFC3339 timestamp)
    • result (completed | completed_with_warnings)

Deterministic boot-time re-run behavior:

  1. Read legacy source (notification_configs) and compute checksum.
  2. Read migration marker.
  3. If marker missing: run migration and write marker.
  4. If marker exists with same checksum: skip mutation (no-op).
  5. If marker exists but checksum differs: re-run migration in upsert mode, then replace marker.

Determinism constraints:

  • Migration is pure over legacy source + managed provider key.
  • Upsert key for managed provider is fixed identity managed_legacy_security=true plus name Migrated Security Notifications (Legacy).
  • Re-run does not create duplicate managed providers.

5) Legacy Destination-to-Provider Mapping Rules

Supported destination mappings for compatibility PUT:

  • webhook_url present:
    • map to provider type webhook, set endpoint URL from webhook_url.
  • discord_webhook_url present:
    • map to provider type discord, set endpoint URL from discord_webhook_url.
  • slack_webhook_url present:
    • map to provider type slack, set endpoint URL from slack_webhook_url.
  • gotify_url + gotify_token present:
    • map to provider type gotify, set URL/token fields.

Unsupported/ambiguous destination handling (fail-safe):

  • If multiple destination types are simultaneously present in one request, return 422.
  • If destination type is unknown or incomplete for required fields, return 422.
  • On 422, no provider rows are created/updated and compatibility state remains unchanged.

6) Feature Flag as Explicit Rollout Gate

Primary gate:

  • feature.notifications.security_provider_events.enabled

Required defaults:

  • Default in production: false
  • Default in development/test: true

Behavior when flag is false:

  • Provider-based security dispatch path is disabled.
  • Compatibility GET/PUT remain available.
  • Runtime dispatch uses compatibility translation path only.
  • Managed migration may run in read-only dry-evaluate mode, but must not mutate providers.

Behavior when flag is true:

  • Provider-based security dispatch is authoritative.
  • Compatibility GET is derived projection from providers.
  • Compatibility PUT writes managed set via translation semantics defined above.

Operational rule:

  • This flag is mandatory for rollout and rollback; it is not optional/recommended.

7) Authoritative Plan Boundary and Cleanup

  • This document is now the single authoritative plan for this scope.
  • All previously appended certificate flaky-test and QA remediation sections are removed from active plan scope.
  • Any future unrelated plan content must go to a separate plan file under docs/plans/.

8) PR Slicing Strategy

Decision: two PR slices.

  • PR-0 (this pass): spec correction only in docs/plans/current_spec.md.
  • PR-1: backend compatibility, migration marker, and feature-flag gate implementation.
  • PR-2: frontend alignment and compatibility deprecation messaging.

9) Acceptance Criteria (Spec Pass)

  1. Compatibility GET rules define exact OR aggregation and disagreement behavior.
  2. Compatibility PUT defines deterministic target set, replace semantics, idempotency, and transaction/conflict behavior.
  3. Migration marker key/storage and deterministic re-run logic are explicit.
  4. Destination mapping rules cover supported non-webhook legacy forms and fail-safe unsupported behavior.
  5. File contains one authoritative plan with stale duplicate trailing sections removed.
  6. Feature flag is defined as explicit mandatory rollout gate with defaults and disable behavior.

10) Handoff

  • Delegate PR-1 implementation to Supervisor using this plan as the sole baseline.