-
[OPIK-7352] [BE] reject non-UUIDv7 referenced ids on ingest (#7553)
发布于
2026-07-22 15:30:37 +00:00 - [OPIK-7352] [BE] reject non-UUIDv7 referenced ids on ingest
Retention sweeps spans/traces via an id-range predicate that assumes the
referenced id is a time-ordered UUIDv7 (SpanDAO orders by the trace_id
range; TraceDAO by the id range). Ingest validated an entity's own id but
not the ids it references, so a client could store a span with a
non-UUIDv7 trace_id and have those rows ordered lexicographically instead
of chronologically — deleted or retained against the wrong window.Validate referenced ids on ingest with a not-in-future policy (version 7
required, future-dated rejected, past allowed — referencing older
entities such as late spans on old traces is legitimate). Renames
validateIdForUpdate -> validateIdNotInFuture and reuses it for both the
update paths and referenced ids; adds a public sync overload.Covered paths: span traceId/parentSpanId (create, batch, update,
batch-update, and the experiment-items bulk path via batch create); single
and batch feedback-score entity ids; trace/span/thread comment entity ids;
attachment entity ids; dataset-item trace/span ids (batch, patch,
from-traces, from-spans); annotation-queue item ids.Version enforcement is always on (mirrors own-id validation); the
not-in-future check is gated by the existing uuidValidation kill-switch.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] validate config-entity referenced ids on ingest
Extends referenced-id validation to config-entity references (verify-then-
enforce: confirmed zero non-UUIDv7 ids across prod projects, datasets,
dataset_versions, prompts, prompt_versions, alerts, dashboards, webhooks,
automation_rules, and guardrails, so enforcement rejects no existing data).Adds null-safe validateIdNotInFutureIfPresent(Async) helpers and validates:
projectId across span/trace update + batch-update, feedback scores (single- batch), guardrails, assertion results, annotation queues, experiments,
optimizations, alerts, automation-rule evaluators, prompts + prompt
versions, dashboards, and thread open/close; feedback/guardrail
sourceQueueId; guardrail secondaryId; experiment optimizationId +
datasetVersionId; dataset-item datasetId + copy-from ids. Upgrades the
guardrail/assertion referenced entityId from version-only to the shared
not-in-future policy.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] only validate referenced ids that are persisted
Refine scope to the rule: validate a referenced id iff the operation
persists it to the entity's table. Drop validation where the id is not
written by the operation:- Thread open/close: projectId only resolves/locates an already-existing
thread (its project_id was written at trace ingestion), so nothing is
persisted here. - Dataset item batch copy-from ids: only a read source for carry-forward
rows, never stored as version lineage.
All create/update paths that write the referenced id to a column keep their
validation (spans trace_id/parent_span_id, feedback/comment/attachment/
guardrail/assertion entity ids, dataset-item trace/span + dataset ids,
annotation-queue items, and projectId/optimizationId/datasetVersionId/
sourceQueueId on the rows that store them).Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] test: use UUIDv7 for validated referenced ids
Existing tests assigned random v4 UUIDs to referenced ids that are now
validated as UUIDv7 (guardrail secondaryId, experiment optimizationId /
datasetVersionId). Switch that test data to generator.generate() so the
tests exercise the intended paths (the invalid-version conflict test now
uses a v7-but-nonexistent id, preserving its 409 expectation).Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] drop projectId validation where input isn't persisted; fix test data
Address reviewer + CI findings:
- Remove projectId validation in GuardrailsService and AssertionResultService:
both resolve the project by name and overwrite projectId with the resolved
project.id() before persistence, so the client-supplied projectId is never
stored — validating it only breaks clients that send arbitrary project ids. - Fix remaining test data to use current UUIDv7 (never v4 or future-dated) for
validated referenced ids: span traceId, dataset-item trace/span ids,
annotation-queue item ids, feedback sourceQueueId, alert projectId,
automation-rule projectIds, experiment optimizationId. 404/409 negative
tests use a v7-but-nonexistent id to preserve their intent. - Strengthen createWithOldTraceIdSucceeds to round-trip and assert the old
traceId is persisted verbatim; add a batch non-v7 parentSpanId rejection test.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] validate span batch ids before side effects; dedupe checks
Addresses reviewer findings:
- create(SpanBatch) validated traceId/parentSpanId inside bindSpanToProjectAndId,
which runs AFTER deleteAutoStrippedAttachments + project getOrCreate — so a bad
batch could delete attachments / create projects before failing 400. Move the id
checks up front (before any side effect) so a rejected batch never mutates state. - Extract a shared validateSpanReferences(traceId, parentSpanId) helper used by every
span write path (single/batch create, single/batch update) so the reference-id
rules can't drift between them.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7352] [BE] scope config-id validation to unchecked refs; reviewer fixes
Address reviewer feedback (andrescrz):
- Drop UUIDv7 validation on referenced config ids that are already existence-checked
(so a bad id fails with the proper 404/409, not 400): projectId on span/trace update,
prompt, experiment, optimization, dashboard (all go through validateProjectIdExists /
resolveProjectIdOrCreate / get); feedback-batch projectId (overwritten by the
name-resolved project); datasetVersionId (FK-checked) and datasetId (findById). - Keep it where the ref is persisted WITHOUT an existence check, so a UUIDv4 orphan
can't be ingested: alert projectId, annotation-queue projectId, automation-rule
projectIds, experiment optimizationId, feedback sourceQueueId. - Move validateIdNotInFutureIfPresent(Async) bodies out of the IdGenerator interface
into IdGeneratorImpl. - Tests: route added generators through TestIdGeneratorFactory (static final) instead of
local TimeBasedEpochGenerator fields; parameterize the span invalid-reference tests.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com
下载附件