Clinic appointment · policy foundation

Turn clinic-specific booking rules into reproducible policy

Combine tenant defaults and clinic overrides as typed policy, bind every command to a trusted actor, and preserve the effective snapshot used by each consequential scheduling decision.

FUTURE_ONLY Immutable snapshot CAS + idempotency Authoritative generation
Normative sourceKorean Markdown design
Visual baselineStarted at commit 9008d3e
PresentationHybrid · simulation is the default view
Related changePR #185

Simulation · Default view

A policy change travels from draft to reproducible snapshot

An operator never writes a clinic override directly into live configuration. Compilation and preview explain its effect; approvals and compare-and-set protect the immutable snapshot used by new decisions.

01 · DRAFT

Edit in scope

Author a clinic override relative to its tenant baseline.

02 · COMPILE

Enforce ceilings

Merge typed payloads and reject attempts to relax non-negotiable safety rules.

03 · PREVIEW

Explain impact

Show affected decisions, constraint changes, a bounded sample, and metrics.

04 · APPROVE

Bind authority

Require the right assurances and reject stale revisions or out-of-scope actors.

05 · ACTIVATE

Advance the head

Use CAS to advance generation and write the immutable snapshot plus outbox atomically.

NEW DECISION

Use the new generation

Read the authoritative scope head and record snapshot version and hash.

VALID HOLD

Keep the held promise

The previous snapshot remains valid through explicit expiry.

CONFIRMED

Protect the customer promise

Activation never silently cancels or rewrites an existing confirmation.

A stale cache is more dangerous than a cache miss. Activation events optimize eviction. Every effective read checks the database scope-head generation and fails closed instead of returning a stale snapshot when authority is unavailable.

History · Decision provenance

Preserve why a rule was approved and activated

This visual companion supports understanding. The Markdown design remains normative for detailed contracts and acceptance criteria.

2026-07-27 · Issue #182 defines the foundation

Issue #182 records the need for reproducible clinic-specific scheduling policy.

2026-07-27 · Typed envelope and immutable snapshot approved

The normative design defines lifecycle, compiler, approval, generation, cache correctness, and failure semantics.

2026-07-29 · Bilingual visual history becomes verifiable

The companion design and delivery plan add provenance and fail-closed publication rules.

Problem and selected approach

Configuration values alone cannot reproduce a past decision

REJECTED

One normalized table per policy

Strong SQL constraints, but migrations and compiler branches multiply with every policy kind.

REJECTED

One untyped JSON document

Easy to extend, but lifecycle, revision, interval uniqueness, and typed validation become weak.

SELECTED

Envelope + typed payload

Normalize lifecycle, concurrency, and audit fields while validating payloads as Kotlin sealed types.

Policy model

Compile baseline and override into an immutable effective snapshot

Tenant baseline

Defines defaults and hard ceilings that clinic policy cannot relax.

Clinic override

Changes only allowed typed fields within the clinic and actor scope.

Effective snapshot

Stores compiler version, canonical payload, source revisions, hash, generation, and activation interval.

Actor context

Derives tenant, clinic, subject, assurance, and permissions from trusted gateway identity rather than request payload.

Activation safety

One transaction owns the state transition

Revision and preview

Reject stale drafts and previews whose revision or generation no longer matches.

Approval assurance

Require policy-specific approval count and actor assurance before activation.

CAS + outbox

Advance the scope head, persist the snapshot, and emit the activation event atomically and idempotently.

Storage contract

Schema names and immutable evidence are stable

SurfaceResponsibilityInvariant
scheduling_policy_setScope and lifecycle envelopeTenant/clinic ownership never comes from caller-controlled payload.
scheduling_policy_versionTyped draft and revision historyAccepted revisions are append-oriented and auditable.
scheduling_policy_snapshotCompiled effective policyPayload, hash, compiler version, and source revisions are immutable.
scheduling_policy_scope_headAuthoritative generation pointerCAS prevents concurrent activation from silently winning.
The existing scheduling_* Flyway schema names are a compatibility contract and are not renamed by this design.

Failure semantics

Stable codes tell callers what action is safe

Correct the command

POLICY_PAYLOAD_INVALID, POLICY_OVERRIDE_FORBIDDEN, and POLICY_ACTOR_FORBIDDEN require payload, scope, or authority correction.

Refresh decision context

POLICY_DRAFT_STALE, POLICY_PREVIEW_STALE, and POLICY_ACTIVATION_CONFLICT require a fresh read or preview.

Do not replay a different intent

POLICY_IDEMPOTENCY_CONFLICT means the same key was used for a different command.

Bound automatic retry

Only POLICY_PREVIEW_LIMITED is automatically retryable, and callers honor Retry-After.

Operations

Roll out evidence before consumers

Shadow compile

Start behind a disabled flag, compile without effect, and compare results before activating reads.

Observe authority

Measure activation lateness, compile latency, generation reads, stale rejection, preview deadlines, and outbox state.

Forward repair

Activate a previous compatible version as a new snapshot. Never mutate old evidence or rely on destructive down migration.

Delivery boundary

This issue delivers policy infrastructure, not the booking state machine

THIS FOUNDATION

Policy lifecycle

Typed policy, actor context, compiler, snapshot, approval, generation, preview, cache, generic outbox, and admin API.

FOLLOW-UP

Appointment commitment

PROPOSED, HELD, CONFIRMED, customer consent, allocation, waitlist, disruption, and overbooking.