Skip to main content
How AtlaSent gates a close-cycle action from intent to audit. Operators can follow the steps in order on a real org and see the full chain on one page.

Who this runbook is for

Controllers, FP&A leads, finance ops engineers, and audit reviewers running an accounting close where AI agents (or humans, or scheduled jobs) interact with the GL, vendor master, sub-ledgers, or close checklists. The runbook reads top-to-bottom in three passes:
  • Operational pass — what each step does to your close calendar.
  • Wire pass — the exact API requests / responses behind each step.
  • Evidence pass — what the auditor sees when they ask “show me every agent action in the period.”
The same primitive applies to any action class your team registers. The worked examples below use close-cycle actions.

Scenarios this runbook supports

Each scenario maps to a runnable example in atlasent-examples/accounting-close/.

The flow

Every step is durable. Decisions are written to the audit chain before the response returns; permits are single-use and TTL-bound; consume is idempotent and binds the executed payload back into the proof.

Vocabulary

1. Register the action class

A close-cycle org typically registers:
  • journal_entry.approve — author / approve a JE before it posts
  • journal_entry.post — write the JE to the GL (separate from approval; can be in a locked period)
  • reconciliation.certify — sign off on a sub-ledger reconciliation
  • account_balance.adjust — manual adjustment to an account balance
  • vendor_master.update — change vendor data; high-risk fields gated separately
  • subledger.lock / period.close — lock the period for write
  • period.emergency_override — controlled, time-bound unlock with multi-party approval
Each is a Protected Action with its own constraints (amount thresholds, required approver roles, ticket linkage, time-of-day windows, materiality assessment). Register once via the console or POST /v1/action-classes.

2. Evaluate the proposed action

The agent or operator’s proposed action is sent to /v1/evaluate before any state changes in your system of record:
The response is one of four decisions: Example allow response:
A deny carries deny_code (short machine code) and deny_reason (operator-readable). A hold or escalate returns no permit; the caller must wait for the human reviewer or approval signal to release the decision. The audit row for this decision is written before the response returns. Denials and holds are part of the proof chain — they cannot be omitted, edited, or reordered without invalidating the chain.

3. Verify the permit before execution

Before changing state in your subledger, verify the permit. This catches clock skew, replay, and revocation in the window between issue and execute:
200 ⇒ still valid. 410 ⇒ expired or consumed; do not proceed. In the SDKs:

4. Execute the action

This is the only step AtlaSent does not perform. Your system of record applies the journal entry, posts the reconciliation, locks the subledger, mutates the vendor master. Capture the executed payload’s hash (the same canonical JSON-Canonicalization-Scheme hash described in Proof verification). You’ll hand it back to consume.

5. Consume the permit

Single call. Binds the executed payload to the issued permit:
A mismatch between the bound payload at issue time and the supplied payload_hash returns 409 payload_binding_mismatch. Use this as your “someone changed the JE between approval and posting” signal. On success, the linked proof row is updated:
  • execution_status → executed
  • execution_hash → the supplied payload hash
  • executed_at → server time
The proof’s audit_hash and signature were written at evaluate time and are unchanged.

6. Replay & audit visibility

Two surfaces:
  • Console. Every decision is visible at /audit and on the action’s detail page, with the full canonical decision object, the matched policy version, and the linked permit and execution.
  • Programmatic. GET /v1/proofs/export returns a self-contained bundle that an auditor can verify offline using the public keys embedded in the bundle. See Proof verification for the algorithm.
For a single decision, GET /v1/decisions/{id} returns the canonical decision object with its proof linkage.

Reversibility, overrides, and tamper-evident evidence

Three principles every controller and audit reviewer should internalise:

Permits are single-use and TTL-bound

A permit authorises one execution, within a named time window, against a specific resource. Replays return 410. Expired permits cannot be revived. There is no “save the permit for later” path; if the action doesn’t run inside the TTL, the operator must re-evaluate.

Locked periods stay locked unless a controlled override is issued

The period lock, the PERIOD_LOCKED denial, and the automatic re-lock described in this section are implemented by the reference example scripts together with your policy and system of record. They are not a built-in AtlaSent runtime feature. AtlaSent evaluates each request, issues and verifies the permit, and records the outcome in the audit chain.
In the reference example, period.close writes a lock row. Once the lock is in place, every journal_entry.post against that period denies with PERIOD_LOCKED — including agent attempts, scheduled job attempts, and operator attempts. There is no “force post” flag. The only path through is a period.emergency_override, which:
  • requires two named approver roles (e.g. CFO + audit committee chair). One human cannot self-approve.
  • requires an audit_reference (e.g. internal-audit ticket ID) on the request body.
  • requires a materiality_assessment in plain language. Stored on the decision row, not in Slack.
  • issues a permit that is single-use, TTL-bound (typically 60–120 minutes), scoped to a specific JE or set of JEs. The permit cannot be reused for a different JE in the same period.
  • after TTL expiry, the example re-locks the period. There is no manual “leave the door open” path.

The audit chain is tamper-evident and offline-verifiable

Every event — denials, holds, the override request, both approvals, the issued permit, the executed JE, the consume, the auto re-lock — is appended to a SHA-256 hash-linked Ed25519-signed chain. An auditor walks the chain offline using only the published public key. Tampering is detectable; omission is detectable; reordering is detectable. What an auditor cannot do: edit the chain, omit the override request, or claim the period was never unlocked. The full chain of custody is preserved. What an auditor can do: download a self-contained export bundle and verify it years later, with no need to trust AtlaSent’s server at audit time.

What close-operations teams get

  • Execution-time authorization. Every protected action is evaluated before the ERP / GL is touched. Denied requests never reach the system of record.
  • Separation of duties. Roles + named approvers are policy primitives, not conventions. An AP clerk cannot do a controller’s job; one controller cannot self-approve.
  • Deterministic gate. Same inputs, same policy version, same decision. Replayable for diligence.
  • Single-use, TTL-bound permits. Replays are rejected, not retried. Expired permits cannot be revived.
  • Tamper-evident audit. The proof chain detects after-the-fact edits, reorderings, or omissions without trusting AtlaSent at audit time.
  • Operator-shaped escalation. hold and escalate route to a reviewer queue with the full action context and the policy reason.
  • Reversibility on overrides. Override permits are scoped and time-bound; the reference example re-locks the period when the TTL elapses.
  • Controlled overrides with tamper-evident evidence. Overrides do not hide the original deny. The audit chain shows lock → unlock-under- override → re-lock with the full approver provenance.
  • Offline replay. An exported bundle is valid evidence years later with only the public key.

Worked timeline

Worked example — journal entry approval

A 250,000JEcrossesthecontroller′s250,000 JE crosses the controller's 100,000 delegation threshold.
The audit row for the hold is part of the chain — the full provenance (“controller proposed, CFO approved, then posted”) is preserved. Run this scenario:

Worked example — vendor master mutation

AP clerk and controller both attempt to change the bank routing number on vendor V-7821. Bank routing is a high-risk field (separation-of-duties policy applies).
Run this scenario:

Worked example — emergency override of a locked period

Q1 2026 was closed on May 5. On May 10, internal audit discovers a $50,000 misclassification. The reclass JE has to post inside the already-locked period.
The auditor sees seven hash-linked rows: original deny, override request, hold, both approvals, override grant, JE post, both consumes, auto re-lock. The override does not hide the deny; it sits next to it in the chain. Run this scenario:

Worked example — period close

End-of-month / end-of-quarter close.
After this point, in the reference example, every journal_entry.post against 2026-04 denies with PERIOD_LOCKED. To post inside the locked period, the operator must use the emergency-override path (above). Run this scenario: