Son of Anton Docs
Architecture

Observability and Cost

Trace lifecycle, persistence failures and cost estimates without treating missing telemetry as zero spend.

Tracing described here belongs to son-of-anton-review on feat/cloudflare-native, the deployed-engine lineage. The Cloudflare trace-reading API belongs to unmerged feat/greptile-operator-parity. The Node dashboard has a different trace contract. A working native engine does not imply that either dashboard API is deployed alongside it.

Traces are observations, not a complete ledger of attempts

src/trace-emitter.js creates an in-memory trace with a generated trace ID and spans. The general tracing switch is on unless GILF_TRACING is exactly 0 or false. The native container explicitly creates its injected tracer with enabled: true, and GILF_TRACING is not forwarded by the container allowlist. Setting that variable only on the Worker therefore does not disable native tracing.

Tracer methods guard their own errors and can disable further tracing. A flush is attempted once per tracer; a synchronous sink error is swallowed by the guard. This is best-effort telemetry, not proof that every accepted webhook or failed attempt produced a durable trace. A retry can create another trace ID for the same review key.

On the native path, the entrypoint owns the trace through publication. A later failure to flush the buffered trace to D1 can fail the review response even though the in-memory tracer itself does not throw.

Sources: engine src/trace-emitter.js:9-10,60-82,88-97,261-277; cloudflare-native/container/entrypoint.mjs:126-176,378-385,421-450; cloudflare-native/src/container-env.js:15-85.

Phase spans

SpanMeaning when emitted
agent.workflowRoot workflow
repo.prepareRepository preparation
context.loadPreflight context assembly
context.graphGraph build within preflight
chat.primaryPrimary semantic model call
validation.cf-sandbox, validation.e2bValidation lanes named by provider
publishNative service publication stage
http.model-priceOpenRouter price-check phase
hypothesis.primary, hypothesis.shadow, chat.shadowOptional runner paths

There is no fixed seven-span contract for every attempt. Early failures, policy skips, durable-analysis recovery and optional execution paths produce different span sets. A shadow-lane error does not necessarily make the trace's final status error: the entrypoint can explicitly end a successfully completed review as ok while an individual shadow span failed.

Spans support timing, status, error, model, token counts, cost, attributes, events and optional input/output. On trace failure, unfinished spans become errors and the cause is copied to trace metadata. Missing usage and cost remain null unless some span reports a value; totals sum only reported values.

Sources: engine src/codex-review-runner.js:34-60,1112-1149; src/trace-emitter.js:18-39,111-173,186-229; cloudflare-native/container/entrypoint.mjs:95-155.

Storage and disclosure

Native traces map to D1 review_traces and review_trace_spans. The buffer replaces a snapshot with the same trace ID; the bridge restores drained snapshots when a flush fails. State is written before traces in the HTTP handler, so they are not an atomic snapshot across both operations.

The native row mapper can persist input_json, output_json, attributes, events and errors. It does not implement universal redaction. The parity API omits input/output fields from its returned DTO, and the parity UI has only Attributes and Events tabs. That omission is not proof that raw input/output can never exist in D1 or that arbitrary attributes are sanitized.

The Node trace store is selected through GILF_DB_PATH; without a trace store, the local trace-list API returns an empty list. It also returns an empty list on a caught trace read error, so empty results alone cannot establish absence of reviews.

Sources: engine cloudflare-native/src/trace-buffer.js:32-54,62-118; cloudflare-native/src/d1-store-adapter.js:303-350; cloudflare-native/src/state-transport.js:558-564; server.mjs:27-35; src/operator-dashboard.js:291-313; parity cloudflare/src/review-trace-queries.js:14-64; UI src/components/TraceObservability.tsx:321-388.

Model cost

estimateProviderCostUsd uses input and output token counts and USD-per-million-token rates. A model-specific GILF_MODEL_PRICES entry wins over the built-in provider table. OpenAI and Anthropic have static code tables; OpenRouter and Codex tables are empty. These are configured estimates, not live price verification or invoices.

The checked-in native configuration supplies this model-price entry:

{"z-ai/glm-5.3-flash":{"input":0.075,"output":0.25}}

No usage or no resolved price returns null. With a price present, missing/non-numeric token fields or rate components are coerced to zero by the arithmetic. A displayed zero therefore deserves inspection of the inputs; it is not automatically proof of a free call.

Sources: engine src/model-provider.js:44-93; cloudflare-native/wrangler.jsonc:154-161.

Validation cost

The code uses costModel: estimate:wall-clock, calculated as seconds multiplied by CPU, memory and disk rates. It does not query provider billing.

ExecutorCPU USD/vCPU-secondMemory USD/GiB-secondDisk USD/GB-secondFallback shape
managed-cf-sandbox0.0000200.00000250.000000072 vCPU, 8192 MB, 16 GB disk
managed-e2b0.0000140.000004502 vCPU, 512 MB, 0 disk contribution

GILF_VALIDATION_COST_RATES merges partial executor rate overrides over the built-ins; malformed JSON falls back. Actual reported CPU/memory values can replace the fallback shape. The estimate excludes unrelated orchestration, Worker, database, storage and network charges.

Missing or invalid elapsed input normally prevents a rate estimate, but explicit null values undergo JavaScript numeric coercion. validationSpanAttributes can likewise convert explicit null costUsd or seconds to zero. Do not promise that all unknown values are perfectly represented as null.

Source: engine src/validation-executor.js:146-245.

Reading averages and budgets

The Node-only /operator/api/trace-stats computes means over traces reporting each metric and excludes root spans from phase/type breakdowns. Nested and concurrent spans still overlap, so summed phase duration need not equal wall-clock duration.

The parity Worker instead exposes /operator/api/traces and /operator/api/traces/:id. Its dashboard computes PR averages from up to five recent trace details, not all historical runs.

The E2B budget gate sums all recorded validation.e2b costs, without date, repository or role filtering. Missing costs and concurrent work make it unsuitable as a hard billing cap. The parity Test Lab must read the same data and budget setting for its display to agree with the native gate.

Sources: engine src/operator-dashboard.js:326-402; parity cloudflare/src/review-state-api.js:876-899; UI src/lib/api.ts:149-158; engine cloudflare-native/src/container-env.js:100-141.

The implemented observability path is the custom tracer and stores. No Langfuse or OpenTelemetry exporter was found in the audited engine source and root package manifest. See Cost and traces for the operator workflow.

On this page