Skip to content
AM

Period close and lock

Closing a period locks the books for that range — no more posts, no more edits without an explicit reopen. This page covers the two controls (close and reopen), what closing actually does behind the scenes, and how the AI COO interacts with them.

What this is

A period in InBlack is a span of dates with a status:

  • OPEN — entries can be posted with dates in this range.
  • CLOSED — entries cannot be posted with in-range dates. Drafts saved in-range are flagged. Reports against the period are stable.
  • LOCKED — same as closed but explicitly cannot be reopened. (For ongoing periods, locked is the terminal state.)

The two controls are:

  • Close periodOPENCLOSED. High-risk; runs side-effects.
  • Reopen periodCLOSEDOPEN. Permanent administrative toggle. Cannot reopen LOCKED.

Both are gated by tenant policy and write immutable audit-log rows. Both require an idempotencyKey. The AI COO and MCP versions also require a reason.

The operator controls are on the Reconciliation page. An admin can close the selected period once all blocking readiness checks pass. An owner can reopen a selected closed period; locked periods remain terminal.

When you’d use it

  • Close — at month-end (or quarter-end / year-end) once the Reconciliation dashboard shows readiness is green. Closing freezes the period so reports stay stable and downstream consumers (CPA handoff, tax filings) can rely on the numbers.
  • Reopen — when a material error is discovered post-close that can’t wait for the next period’s adjustment. Reopen is administrative; treat it as a controlled action, not a routine one.

What closing actually does

Beyond the status change, closePeriod runs two side-effects:

  1. FX revaluation. When the ledger and currency services are configured, the platform runs FX revaluation before the period state changes — within the same tenant transaction. This means revaluation either lands with the close or neither happens.
  2. Revenue-recognized event publication. After commit, the platform publishes revenue-recognized events for downstream consumers (reporting projections, integrations). This is best-effort post-commit: the audit row records the close, and publication failures are logged but don’t unwind the close.

Both side-effects are documented in the close audit row.

What reopening does (and doesn’t)

reopenPeriod flips status CLOSEDOPEN and writes an audit row. It does not:

  • Reverse FX revaluation entries created at close time.
  • Un-publish revenue-recognized events from the prior close.
  • Re-derive aggregates.

Once you reopen, post your adjustments, then run close again. The second close emits a new audit row and runs side-effects again. The audit history shows the full sequence (close → reopen → close).

If you only need to make a single adjustment, the platform team recommends that pattern be a separate, scoped tool that couples reopen + post-adjustment + re-close in one control flow — that tool does not exist today. For now, the manual three-step pattern is what’s supported.

Walkthrough

The close flow is:

  1. Confirm readiness on the Reconciliation page — every blocking check passing, every reconcilable account COMPLETED.
  2. Trigger Close period for the period in question. Supply a reason (required for AI COO / MCP, optional but recommended for direct UI use).
  3. The platform runs FX revaluation, writes the close, and publishes downstream events.
  4. The period status flips to CLOSED; reports against it are now stable.

For reopen:

  1. Trigger Reopen period for the closed period. Supply a reason (required).
  2. The platform flips status to OPEN and writes an audit row.
  3. Post your adjustment(s).
  4. Re-close.

AI COO interaction

inblack_close_period and inblack_reopen_period are T3 confirmation tools. Both require a non-empty reason. When the AI COO proposes a close or reopen:

  1. The Worker stages a pending action with the tool name, normalized args (including the reason), and a preview describing what will happen.
  2. You approve or reject from Pending actions or inline in the Conversation Theatre.
  3. On approval, the Worker executes with an idempotency key derived from the pending-action ID. Approval emits an AuditCore agent.action_approved event whose ID is carried into the close as a trusted source-event reference.
  4. The accounting audit row records both the operator’s reason and the source-event reference, tying the operator intent to the platform-level audit.

Tenant policy can promote these tools to T4 (hard-blocked) if your organization wants close/reopen to be UI-only.

Idempotency

Both closePeriod and reopenPeriod require an idempotencyKey. Retries with the same key return the cached response without appending a duplicate audit row. Cache keys are scoped by operation + request fingerprint — reusing a key with different inputs is treated as a conflict, not a replay. This prevents accidental cross-operation state mixing.

The AI COO derives its idempotency key from the pending-action ID, so an approval that is retried (network blip, replay) consistently lands once.

Programmatic access

  • GraphQL (accounting-api):
    • closePeriod(startDate, endDate, reason, idempotencyKey) — closes a period. Reason optional at the GraphQL boundary for direct API compatibility.
    • reopenPeriod(id, reason, idempotencyKey) — reopens a closed (non-locked) period. Reason and key required.
  • MCP tools:
    • inblack_close_period (T3, requires reason).
    • inblack_reopen_period (T3, requires reason).
    • inblack_simulate_close_period and inblack_simulate_reopen_period — the auto-generated simulate twins. Use these to preview the side-effects before approving.
  • Audit: both controls write to inblack.audit_log with actions CLOSE_PERIOD and REOPEN_PERIOD respectively. The rows are immutable. See The audit log.

Hard lines

  • Open periods cannot be reopened. The state transition only works on closed periods.
  • Locked periods cannot be reopened. LOCKED is terminal.
  • The reason field is not optional for AI COO / MCP. Direct GraphQL accepts a missing reason for backward compat, but agentic flows must justify the action.
  • The source event reference is not accepted as public GraphQL caller input. Only the AI COO Worker can supply it, via a trusted internal header.