AID Docs

Automation Activity and audit policy

How AID explains Automation decisions, attributes actions, preserves investigation evidence, and controls retention.

Decision and implementation status: ADR-0023 is Accepted. It defines the required behavior. The Activity schema and writers are being implemented incrementally in Phase 4; this page does not claim that every screen or fact writer is already available. The cancellation-request command is the first active writer: it atomically records its HTTP actor, reason, Document, request evidence, snapshots, and approved intervention-retention horizon. Other fact kinds and Activity readers remain incomplete.

Why Automation needs its own Activity history

The current Automation rows answer:

What is happening now?

Activity answers:

What happened before, who or what caused it, and what did a person do about it?

Those are different questions. A Step that succeeds today may have been blocked by a name collision yesterday. If AID kept only its current state, the collision and the administrator's intervention could disappear from the explanation.

A realistic example

  1. The Invoice naming Automation tries to rename a clean invoice.
  2. A Document with the intended name already exists.
  3. The Step becomes Action required.
  4. Farid fixes the conflicting name and chooses Continue after fixing.
  5. The Automation runs again and succeeds.

The current Step truth eventually says succeeded. Activity preserves the business story:

  • Invoice naming encountered a name collision.
  • Farid continued the work after fixing the conflict.
  • Invoice naming renamed the Document successfully.

Database retries or queue redeliveries between those facts remain engineering telemetry. They do not clutter the customer's business history.

Activity, current state, and telemetry are different

InformationQuestion it answersExample
Current dispatch/run/Step truthWhat needs attention now?This Step is blocked by a name collision.
Append-only ActivityWhat business or security event happened?Farid continued the blocked Step after fixing the collision.
Operational telemetryWhy did the software behave slowly or retry?The worker retried after a database timeout.

Activity is not used to decide whether a Step may run. The current SQL state machine remains authoritative. Activity is durable evidence explaining how that state changed.

What AID records

The focused Automation stream records business and security facts such as:

  • publication, activation, deactivation, pause, and resume;
  • capability enablement and disablement;
  • dispatch planned, no match, budget blocked, or system failed;
  • run and Step blockers and terminal outcomes;
  • cancellation request and the actual result at the safe boundary;
  • Continue after fixing, permitted Skip, targeted new run, and control release;
  • incident recovery; and
  • external-effect preparation and resolution when that foundation is enabled.

A technical retry is not a new business fact. Attempts, leases, queue delivery, timings, stack traces, and provider diagnostics remain in job truth, metrics, logs, and traces.

Who performed an automated action?

Automation execution is attributed to the pinned Automation version, not to the person who published it.

For example:

Renamed by Automation “Invoice naming,” version 3, published by Nurul.

It does not say Nurul renamed the Document. She approved the behavior, but the Automation executed it later. If Farid subsequently continues blocked work, that separate Activity fact names Farid.

AID distinguishes:

workspace user | Automation | system | operator | control

This prevents a system recovery from being presented as a customer action, or a publisher from being blamed for a later automated execution. Workspace users and internal operators are human actors: both need a stable identity and frozen display name. An HTTP-origin actor also needs complete request evidence. A runbook operator instead needs a trusted human identity, unique runbook execution ID, and frozen process principal; AID does not invent an HTTP route, browser session, user agent, or IP address. Automation, system, and control actors use the machine origin and carry no human request or correlation fields.

For example, after a restore Activity can say that operator Priya ran recovery execution REC-2026-0041 through the recovery-epoch principal. The database role proves which program executed; it does not replace Priya as the human actor.

Comprehensive investigation snapshots

The product owner selected comprehensive audit snapshots. Depending on the fact kind, Activity can retain:

  • Document and Automation names;
  • actor display identity;
  • bounded user-entered reasons;
  • relevant old and new business values;
  • request and correlation IDs;
  • client IP address and user agent;
  • HTTP method, normalized route template, and public session identity; and
  • stable Document, definition, dispatch, run, Step, incident, and control IDs.

These snapshots may outlive a rename, member removal, or Document disposal. That is useful during an investigation, but it also increases privacy, breach, access-request, storage, backup, and erasure consequences.

Comprehensive does not mean indiscriminate

Every fact kind has a versioned allowlist and byte limits. Activity never accepts an arbitrary request or database-row dump. It excludes:

  • authentication and authorization headers;
  • cookies, session tokens, passwords, and secrets;
  • raw URLs and query strings;
  • complete request bodies;
  • file or OCR content;
  • raw provider payloads; and
  • exception text or stack traces.

A human request receives a server-generated request ID. The direct peer address is used unless deployment configuration explicitly enables a trusted proxy. A caller-supplied X-Forwarded-For header is not trusted automatically.

A worker action has no invented IP address, user agent, request ID, or request correlation ID. Its stable job, dispatch, run, and Step identities provide correlation instead. A runbook operator is different from a worker: it retains the authenticated person, execution ID, and process principal, while leaving HTTP-only fields empty.

Access remains current

Historical IDs and snapshots never grant access.

Until the broader access model is ratified:

  • workspace-wide Automation issues and definition history are administrator-only;
  • Document-specific Activity requires the viewer's current Document-read permission; and
  • internal operator diagnostics are not returned through the customer Activity API.

Raw snapshot JSON is not a general-purpose API response. Each endpoint returns only the authorized, stable fields required by its user experience.

Retention has no silent default

Gate A does not write Activity and is not a customer-beta state. Before a workspace advances into Gate B, an authorized product, legal, or records owner must approve a versioned Activity retention policy.

The policy gives each fact category:

  • a legal-basis code; and
  • a concrete retention horizon.

Different categories may use different approved horizons. A later policy may lengthen existing retention, but it cannot silently shorten facts already written. Ordinary Automation administrators cannot invent the company's legal retention policy through the Automation settings screen.

After Gate B enrollment, a missing or incomplete current policy fails closed: AID does not perform a mandatory audited business action while silently dropping its Activity evidence. Before enrollment, a Gate A workspace has no retention policy, writes no Activity, and keeps its existing Automation lifecycle actions available. A policy without the atomic activity.coverage_started fact is an invalid partial enrollment and fails closed. The ordinary enrollment command deliberately refuses to legitimize an ambiguous existing policy. Production recovery currently requires database- operator incident response; a disposable development database should be reset.

Enrolling a workspace into Gate B

Enrollment is a signed operational action. It is not part of db:seed, and an ordinary workspace administrator cannot invoke it. Deployment must give the one-shot process a database login whose only capability role is aid_activity_policy_operator, then provide a short-lived RUNBOOK_OPERATOR_ASSERTION for action automation_activity_policy_enroll, bound to process profile activity-policy-operator.

The rules file is a JSON array containing exactly one object for each of coverage, governance, consideration, execution, intervention, and external_effect. Every object has only factCategory, legalBasisCode, and horizonDays; those values come from the approved policy, not from an engineering default.

After the matching application artifact has been staged, run its enrollment launcher while Automation is drained:

pnpm --filter @aid/api activity:enroll-policy \
  --workspace-id <workspace-uuid> \
  --effective-at <approved-ISO-timestamp> \
  --approval-reason "<approved reason>" \
  --rules-file <approved-rules.json>

The migration-owned command atomically creates the complete initial policy and its activity.coverage_started fact. Retrying the same signed runbook execution returns the committed policy without duplicating coverage. A workspace with an existing policy is refused; later immutable policy-generation changes require their own reviewed command and Activity contract.

Legal-hold interaction, final erasure and disposal procedures, and the production legal-basis vocabulary remain cross-product decisions that must be closed before production promotion.

What happens to older Automation work?

AID does not fabricate a historical timeline from current rows.

After an approved policy is provisioned, AID records a coverage-start fact. The product can then say:

Detailed Automation Activity is available from 15 August 2026.

A cancellation requested before Gate B can be swept again after enrollment if new work becomes terminalizable. In that case Activity honestly begins with automation.cancellation_completed and has no preceding automation.cancellation_requested fact. Readers must use activity.coverage_started as the history boundary rather than treating that sequence as missing evidence.

Earlier run and dispatch state may still be shown where useful, but it is not misrepresented as a complete immutable Activity history.

No-match facts and storage growth

When AID considers an event and no Automation matches, the terminal dispatch creates at most one no-match Activity fact. It never creates one fact for every definition.

The pilot collector must count Activity rows and retained bytes. A mandatory review is triggered by:

  • more than 100,000 no-match fan-out rows per day;
  • more than 1 GiB per month of measured no-match storage growth; or
  • the existing loaded latency threshold.

Crossing a threshold starts a design and policy review. It does not automatically authorize deleting evidence, shortening a legally approved horizon, or suppressing real Automation work.

Privacy-hardening backlog

Comprehensive snapshots are the accepted initial policy, but the decision is not forgotten permanently. A privacy-policy review is mandatory:

  • within twelve months of the first production Automation rollout; or
  • earlier when required by a legal or privacy review, a customer commitment, a data-subject request, or measured storage growth.

The review must consider:

  • collecting fewer fields;
  • hashing or tokenizing identifiers;
  • more granular access tiers;
  • shorter category-specific horizons; and
  • how to migrate or dispose of snapshots already retained.

Immutable evidence is never silently rewritten during that review.

Engineering source of truth

ADR-0023 is the canonical decision. Database truth belongs in the Drizzle schema and forward migrations under apps/api; this guide explains the resulting behavior and must not become a second schema.

On this page