Search documentation

Find a documentation page by title, topic or keyword.

How events reach the ledger

Every connector, whether it is pushed a webhook or polls an API, follows the same four stages and ends at the same single writer. That uniformity is why adding a tool does not change how the ledger behaves.

The four stages#

  1. Receive      verify authenticity, acknowledge fast, put the raw body on a queue
        |
  2. Process      a worker picks the job up
        |
  3. Normalise    map the tool's payload to the shared event shape
        |         (a pure function: unrecognised input returns nothing)
        |
  4. Append       write through the one ledger writer
What each stage does
StageDetail
ReceiveAuthenticity is checked before anything else: a signature, an HMAC, or a per-connection secret depending on the tool. Governax then acknowledges immediately so the sending tool does not time out and start retrying.
ProcessWork happens off the request path on a queue, so a slow step never delays the acknowledgement or blocks another tenant.
NormaliseA pure mapping from the tool's vocabulary to the shared event shape. It has no side effects and reaches nothing external, which makes connector behaviour testable in isolation.
AppendEvery connector converges on one writer. There is exactly one code path that can add to the ledger.

Some enrichment happens at stage four rather than later, because an append-only record cannot be enriched after the fact. Slack user ids are resolved to email addresses before the row is sealed, for exactly this reason.

Push and poll connectors#

How each connector receives events
ConnectorMechanismTypical delay
SlackWebhookSeconds
GitHubWebhookSeconds
OktaEvent HookSeconds
Google WorkspacePolled every 10 minutesUp to 10 minutes, plus the Reports API's own lag
AWSPolled every 10 minutesUp to 10 minutes, plus CloudTrail's own delivery lag

The two polled connectors are polled because neither tool offers a practical push mechanism to an external service without per-customer infrastructure. Each poll remembers where it got to, so a poll that fails does not lose the window it was covering; the next one picks up from the same point.

The connect-time baseline#

A ledger that only starts recording from the moment you connect answers "what changed since Tuesday" but cannot answer "who has access now". So every connector takes a snapshot of current access at connect time and writes it as access.baseline_observed events carrying baseline: true.

These events carry the connect time as their occurred_at, not the time the access was originally granted, which Governax has no way to know. Read them as "this was already true when we started watching".

Reconnecting a tool takes a fresh snapshot and compares it against history. Differences that must have happened while Governax was disconnected are recorded with reconciled: true in the payload, so an inferred change is always distinguishable from an observed one.

Redeliveries and duplicates#

Tools redeliver. A webhook that times out gets sent again, and a poll window can overlap the previous one. Every event therefore carries the source tool's own identifier, and the combination of entity, tool and that identifier must be unique.

A redelivered event is silently discarded. It is not written twice, it does not extend the chain, and it does not change any hash. This is why you can safely reconnect a tool without worrying about duplicating history.

Events that are skipped#

Normalisers only recognise governance-relevant events. Anything else returns nothing and is skipped silently, with no ledger row and no error. That is deliberate: a tool sending a category of event Governax does not map should not produce noise or failures.

The consequence to be aware of is that "nothing in the ledger" can mean either "nothing happened" or "what happened is not something Governax records". The per-connector pages list exactly which events each tool contributes, and Anatomy of a governance event lists what is deliberately excluded.

Knowing a connector is healthy#

Each connection on the Integrations page shows its status, the time of its last event, and its last error if there was one. A connector can also mark itself disconnected without you doing anything: uninstalling the Slack app or the GitHub App from the tool's own side tells Governax, which records integration.disconnected_remotely and flips the connection.

  • Last event time going stale on a busy tool is the signal worth watching.
  • A last error usually means an expired credential or a revoked permission. Reconnecting is the fix, and the baseline reconcile will fill in what was missed where the tool still reports it.