What is recorded
Seven tables carry the same seven columns:
The server sets them, never the client. A
BEFORE INSERT OR UPDATE trigger
(creator_attribution_stamp) copies them from the request-scoped app.audit_ctx
setting that every attributed write already carries (see
Audit actor model). A value the client writes into
these columns is overwritten. An update keeps the creator columns from the old
row. An update that only touches bookkeeping columns (updated_at, and the
table’s ignore_columns in audit.table_config, such as sync claims) is not a
change: it leaves the modifier alone and emits nothing.
An edit stored on a child table is an edit to its object. An offer’s
per-day fees, seats and times live on crew_offer_days. A non-system write to a
day (insert, update or delete) marks the parent offer through the
transaction-local app.creator_attribution_touch setting and touches it, so the
offer records the modifier and queues its update under the same per-request
key. Bookkeeping-only day updates (times_changed_at) do not count. Crew
responses (crew_offer_recipients, crew_offer_recipient_days) are not edits to
the offer and are not attached.
NULL means “not measured”. Rows written before the migration
(20261103090000_creator_attribution) keep NULL attribution. Nothing guesses it.
How the kind is decided
creatorKindOf (api-events/src/systems/audit/auditContext.ts) maps the audit
actor to a kind. The derivation happens where the caller is known:
The CheckAI assertion. CheckAI calls the REST API with the user’s own Clerk
token, so the token cannot say an agent is acting. CheckAI therefore signs each
request:
v1.<unix seconds>.<c0|c1>.<HMAC> over the timestamp, the confirm flag
and a SHA-256 of the bearer token. The key is derived from
SLACK_CHANNEL_CHECKAI_SECRET, which both services already hold, under its own
label. An assertion is valid for 5 minutes (60 s of clock skew) and only with
the token it was minted for. Without a valid one, a Soundcheck-Client: mcp
call is attributed to an external agent: the fallback is “not ours”.
External agent identity. Until AgentID (PRO-579 / PRO-581) lands, an
external agent is identified by its OAuth client (oauth:<client_id>).
An agent-driven import is an import. runAsImport sets the creator kind
and rail but keeps the actor, so the audit log still says CheckAI ran it.
sor_write
One PostHog event per object written per request. The same trigger tables run an
AFTER INSERT OR UPDATE trigger (creator_attribution_sor_write) that queues an
effect_outbox row of kind sor_write, keyed
sor_write:<write scope>:<object type>:<row id> with ON CONFLICT DO NOTHING.
The write scope is a server-generated id per request (writeScopeId), never a
client-supplied correlation id:
- Once per write. A create plus edits in the same request are one
create. A retried HTTP request is a new request; it emits again only if it writes again (duplicate creates are ENG-1232, not a signal problem). - Never for a rolled-back write. The outbox row is in the writer’s transaction.
- Never duplicated on delivery. The outbox row id is the PostHog
uuid, so a redelivered batch is deduplicated by PostHog. - Not for
SYSTEMwrites, nor for a message with no gig (no org to file it under), nor for ledger lines other thanPAYABLE. - One message per send. A send to 40 crew writes 40
Notificationrows and onemessageevent per gig.
effectOutboxSweepHandler, every 5 minutes) delivers these
rows in their own lane, runSorWriteEffects: up to 20 batches of 100 per tick
through PostHog /batch/. Accepted rows are settled DONE and kept for a
day, so a later write in the same request still hits the key, then the lane
prunes them. Rows that exhaust their retries are dead-lettered and reported to
Sentry like any other effect. The shared lane skips sor_write so analytics
volume never delays calendar, Twilio or email effects. With no
POSTHOG_API_KEY the rows are settled without being sent.
confirm_gated is true when the write followed an accepted MCP confirmation
token in the same tool call (requireConfirmation marks the call; see
toolCallConfirmed in @soundcheck/mcp). For CheckAI the flag travels inside
the signed assertion.
Properties are listed in the
analytics taxonomy.
Metric definitions (draft, pending Product Analytics sign-off)
These definitions are the proposal for Product Analytics to sign off. Until they do, no dashboard number is quoted as a baseline. System-of-record write. Onesor_write event. Only person, checkai,
external_agent and import writes exist as events. system writes are not
emitted.
Agent-created share (weekly).
count(sor_write where operation = create and agent_created) ÷
count(sor_write where operation = create), per ISO week, overall, by org_id
and by object_type, split by creator_kind. Internal and test orgs must be
excluded; which cohort or org property does that is part of the sign-off.
Writes on sample gigs (Event.is_sample) should be excluded too. “Not reverted
within 7 days” is applied once the activity log with undo (PRO-653) records
reverts. Until then the insight is labelled “before revert exclusion”.
Completed gig. A gig whose status reaches completed or settled
(event_completed / event_settled) in the window.
Clicks per completed gig. PostHog $autocapture clicks on web and mobile
capture interactions carrying that gig’s event_id, from the gig’s
event_created to its settle, by operator roles only (crew excluded).
Active minutes per completed gig. The number of distinct minutes, in the same
create → staff → pay window, in which an operator sent at least one interaction
for that gig. A minute with no interaction is idle and not counted.
Guardrail line. Median and p75 active minutes per completed gig against the
existing under-10-minutes goal (PRO-540), split by gigs with at least one agent
sor_write and gigs with none. No other target is set.
Baselines are recorded as “measured on <date>” once the dashboard has
8 weeks of data. None is quoted before then.
Not in this change
- The PostHog dashboard and insights (agent-created share, clicks and minutes per completed gig). They need the definitions above signed off and PostHog project access.
- Client instrumentation for clicks and active minutes. Web and mobile
interactions need the gig’s
event_idon them before the per-gig counts above are computable. - The 7-day revert exclusion (PRO-653).
- Sub-rails for the app (
templates,staffingin PRO-402). Person writes areappuntil the routes that own them set a rail.