---
id: WF-CMT-MTG-009
title: Freeze a Decision at Opening
trigger: Staff open a draft directly or another business step creates an open decision.
product_area: committees
module: meetings
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-committees: 36129c24daeaadcdb339218c38cdeaff9861359d
implements:
  - CAP-CMT-MTG-010
  - CAP-CMT-MTG-011
moves:
  - STATE-CMT-MTG-006
crosses:
  - SVC-CMT-MTG-decisions
  - SVC-PFM-NOT-communications
idempotency: >-
  Only draft decisions can open. Recipient notice keys identify the decision,
  while database numbering uniqueness prevents reuse within its committee.
concurrency: >-
  The committee lock serializes numbering. The decision lock protects lifecycle
  checks, and explicit staff opening compares its version.
hops:
  - 'n': 1
    actor_or_service: Decisions API
    action: >-
      Lock the draft and committee and load effective decision rules, using the
      implemented defaults when absent.
    anchor: >-
      services-committees:modules/decisions/services/persistence/decisions.ts:openRow
    seam: sync
    on_failure: Reject an invalid opening.
    left_inconsistent: No open record.
    observer: The operation response.
    provenance: observed
    source: >-
      services-committees:modules/decisions/services/persistence/decisions.ts:openRow
  - 'n': 2
    actor_or_service: Decisions API
    action: >-
      Check voting method, meeting association, closing time and named
      threshold.
    anchor: >-
      services-committees:modules/decisions/services/rules/decision-rules.ts:openingRefusal
    seam: sync
    on_failure: Return the validation refusal.
    left_inconsistent: No snapshot is committed.
    observer: The operation response.
    provenance: observed
    source: >-
      services-committees:modules/decisions/services/rules/decision-rules.ts:openingRefusal
  - 'n': 3
    actor_or_service: Decisions API
    action: >-
      Capture dated voters, authorized seats and meeting attendance and allocate
      the committee’s yearly sequence number.
    anchor: >-
      services-committees:modules/decisions/services/persistence/decisions.ts:takeNumber
    seam: sync
    on_failure: Roll back the opening transaction.
    left_inconsistent: No number or snapshot survives failure.
    observer: The saved decision result.
    provenance: observed
    source: >-
      services-committees:modules/decisions/services/persistence/decisions.ts:takeNumber
  - 'n': 4
    actor_or_service: Ballot port
    action: >-
      For a secret ballot invoke the ballot port inside the transaction; the
      production port is unavailable.
    anchor: >-
      services-committees:modules/decisions/ports/ballot-service.ts:ballotService
    seam: sync
    on_failure: Reject opening while no ballot implementation exists.
    left_inconsistent: A future synchronous external implementation could act before a rollback.
    observer: The operation response.
    provenance: observed
    source: >-
      services-committees:modules/decisions/ports/ballot-service.ts:ballotService
  - 'n': 5
    actor_or_service: Decisions API
    action: Persist the open event and prepare each voter’s notice.
    anchor: >-
      services-committees:modules/decisions/services/notifications/decision-notifications.ts:notifyVoters
    seam: sync
    on_failure: Log a skipped notice without a recovery ledger.
    left_inconsistent: Some voters may never receive the call to vote.
    observer: Decision-notice warning entries.
    provenance: observed
    source: >-
      services-committees:modules/decisions/services/notifications/decision-notifications.ts:notifyVoters
branches: []
waits: []
evidence:
  - >-
    services-committees at 36129c24:
    modules/decisions/services/persistence/decisions.ts:openRow;
    services/rules/decision-rules.ts; services/persistence/voting-rosters.ts;
    ports/ballot-service.ts; lib/governance/decision-engine.ts
controls:
  - TC-IAM-006
  - TC-AZ-001
  - TC-AZ-002
  - TC-AZ-003
  - TC-AZ-004
  - TC-AZ-006
  - TC-TEN-001
  - TC-TEN-002
  - TC-TEN-003
  - TC-TEN-004
  - TC-SEC-001
  - TC-SEC-004
  - TC-DAT-001
  - TC-DAT-002
  - TC-DAT-003
  - TC-LOG-001
  - TC-LOG-002
  - TC-LOG-003
  - TC-LOG-004
  - TC-LOG-005
  - TC-AVL-004
  - TC-MON-001
  - TC-MON-002
  - TC-PI-001
  - TC-PI-002
  - TC-PI-003
  - TC-PI-004
  - TC-PI-005
  - TC-PRV-001
  - TC-PRV-002
---
# Freeze a Decision at Opening

## What It Does

Staff open a draft directly or another business step creates an open decision. The stored snapshot determines later evaluation even if membership or rules change. Secret voting cannot open with the production port at these commits. The port’s intended outbox behavior is a future requirement, not a built external election service.

## The Flow

```mermaid
flowchart TD
  H1["Lock the draft and committee and load effective decision rules, using the implemented defaults when absent."]

  H2["Check voting method, meeting association, closing time and named threshold."]
  H3["Capture dated voters, authorized seats and meeting attendance and allocate the committee’s yearly sequence num"]
  H4["For a secret ballot invoke the ballot port inside the transaction"]
  H5["Persist the open event and prepare each voter’s notice."]
  H1 --> H2
  H2 --> H3
  H3 --> H4
  H4 --> H5
```

Lock the draft and committee and load effective decision rules, using the implemented defaults when absent. Check voting method, meeting association, closing time and named threshold. Capture dated voters, authorized seats and meeting attendance and allocate the committee’s yearly sequence number. For a secret ballot invoke the ballot port inside the transaction; the production port is unavailable. Persist the open event and prepare each voter’s notice.

## When Something Fails

Reject an invalid opening. No open record. Return the validation refusal. No snapshot is committed. Roll back the opening transaction. No number or snapshot survives failure. Reject opening while no ballot implementation exists. A future synchronous external implementation could act before a rollback. Log a skipped notice without a recovery ledger. Some voters may never receive the call to vote.

## Open Design Questions

The stored snapshot determines later evaluation even if membership or rules change. Secret voting cannot open with the production port at these commits. The port’s intended outbox behavior is a future requirement, not a built external election service.
