Genace

generation job log schema: correlate submission, observation, and delivery

An operation can involve one creation request, many status reads, a refund reconciliation, and several artifact transfers. A single generic request log makes those phases look alike and can inflate apparent render counts. Define an application event schema that names the phase and keeps operation identity separate from individual HTTP attempts.

Choose stable correlation fields

Give each business operation an application operation ID. Give each network attempt a separate attempt ID. Save the Genace job ID once it is known, and retain a trace reference when your own instrumentation provides one. These fields have different meanings and should not be populated by copying one identifier into every column.

{
  "schema_version": 1,
  "event": "generation.observe.completed",
  "operation_id": "application-operation-42",
  "attempt_id": "application-attempt-8",
  "remote_job_id": "saved-job-id",
  "http_status": 200,
  "remote_state": "failed",
  "error_code": "UPSTREAM_SUBMISSION_FAILED",
  "accounting_state": "pending_reconciliation",
  "duration_ms": 214
}

This is a local logging schema, not a Genace response. The example deliberately shows HTTP 200 and failed remote state together. A successful read can describe a failed job, and failed state can coexist with unsettled credits.

Name events by the action they record

Use separate event names for submission started, acceptance saved, observation completed, reconciliation pending, and delivery verified. Define whether a duration measures an HTTP attempt, a worker action, or total elapsed operation time. Do not mix those values in one latency histogram.

Count accepted creations from the saved acceptance milestone rather than counting every POST attempt as a completed render. Count delivered assets from verified local artifact records rather than repeated terminal snapshots. These distinctions keep retry traffic from distorting product and cost metrics.

Preserve API fields without inventing guarantees

A successful POST provides top-level job_id; an explicit submission failure can provide error.job_id; GET snapshots use id. Normalize them into a clearly named local remote_job_id field while retaining their original source category where useful.

HTTP errors can include an optional upstream_request_id, while job errors may use upstreamRequestId. Neither is guaranteed. Leave absent identifiers null instead of fabricating them. The current SSE stream has no event sequence ID, so local stream record counts are not replay cursors.

Keep sensitive context out of the common schema

Do not include Authorization headers, raw prompts, signed URLs, or unrestricted exception objects. If an incident requires detailed payload evidence, store a restricted attachment with its own access and retention controls. Safe operation correlation should remain useful without those values.

Version schema changes and validate emitted records in tests. Keep error codes bounded and structured. Treat user-controlled operation labels as data rather than concatenated log-line syntax.

Acceptance checks

Run fixtures for accepted, pending, failed, canceled, refund-pending, and delivery-failed outcomes. Verify each emits the intended event family and preserves HTTP versus job state. Assert synthetic secrets are absent and repeated observations do not inflate creation counts. Confirm dashboards can find all attempts for one operation without assuming a complete upstream event history.

See log redaction, trace correlation, and observability fundamentals.

Continue with production operations

Where these facts come from

  • Editorial keyword hypothesis; search volume not measured
  • codebase: src/ai/jobs/http.ts
  • codebase: src/ai/api/errors.ts
  • codebase: src/ai/jobs/worker.ts