发布

  • [OPIK-7402] [BE] Add audit (shadow / log-only) mode to UUIDv7 ingestion validation (#7573)

    frostbyte_neo 发布于 2026-07-24 11:19:12 +00:00

    • [OPIK-7402] [BE] Add audit (shadow / log-only) mode to UUIDv7 ingestion validation

    Adds a third auditOnly state to uuidValidation on top of the enabled
    kill-switch. When enabled=true and auditOnly=true, out-of-window UUIDv7 ids
    are counted and logged but NOT rejected, so clients emitting them surface in
    real time without breaking ingestion. Effective mode:
    enabled=false -> disabled; enabled=true & auditOnly=true -> audit;
    enabled=true & auditOnly=false -> reject (HTTP 400, unchanged).

    • New UuidValidationMetrics records opik.ingestion.uuid_v7.rejected in audit
      mode, tagged mode=audit + reason + resource + workspace_id (shares the
      instrument with InvalidUUIDExceptionMapper's reject-path counter).
    • Validator gains resource/workspaceId params; audit branch emits + logs
      instead of throwing. Scope is the window check; the always-on NOT_V7
      version check is unchanged.
    • workspaceId is read from the reactive context on the async paths and
      threaded through the batch bind on the sync path.
    • Unit test covers disabled/reject/audit.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Tag the reject path with mode=reject on the shared counter

    Address review: InvalidUUIDExceptionMapper recorded opik.ingestion.uuid_v7.rejected
    without a mode label, so the shared counter had series with and without mode and a
    mode=reject query would miss enforced rejections. Add mode=reject on the reject
    path (workspace_id stays audit-only, as the mapper has no threaded workspace), and
    align the UuidValidationMetrics contract javadoc: mode is always present; workspace_id
    is audit-only; the reject path additionally carries http_route.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Address review: async test coverage, log prefix, trimmed javadoc
    • Add IdGeneratorAsyncValidationTest covering validateIdAsync /
      validateIdForUpdateAsync reject+audit behavior, with and without
      RequestContext.WORKSPACE_ID in the reactive context (the deferContextual
      workspace lookup + UNKNOWN fallback).
    • Keep a fixed, searchable prefix on the audit log line and move the variable
      fields to the end.
    • Trim the IdGenerator#validateId javadoc to validation semantics +
      InvalidUUIDException; keep workspaceId threading (the sync/batch path is the
      primary ingestion route where per-workspace attribution is the goal).

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Reconcile audit mode with merged OPIK-7352 foreign-id validation

    Resolve the semantic overlap after merging main (#7553): unify IdGenerator on
    the merged API — implement validateIdNotInFuture / validateIdNotInFutureAsync
    (and the IfPresent variants) and drop the superseded validateIdForUpdate*.
    Own-id validateId stays workspace-tagged for the audit metric; referenced-id
    validateIdNotInFuture falls back to UNKNOWN on the sync path and resolves the
    workspace from the reactive context on the async path.

    Keep #7553's fail-fast (validate before side effects) for span batches, now run
    inside deferContextual so the batch's own ids attribute to the request workspace;
    bindSpanToProjectAndId no longer re-validates. Trace batches keep validating in
    bindTraceToProjectAndId with the workspace threaded through.

    Update the async test to the renamed methods.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Make trace batch validation symmetric with spans

    bindTraceToProjectAndId validated own ids only after deleteAutoStrippedAttachments
    and project getOrCreate, so a bad trace id in a batch still mutated state before
    failing (unlike spans, which #7553 validates fail-fast). Hoist trace own-id
    validation into a leading deferContextual that runs before any side effect and
    attributes the audit metric to the request workspace, and stop re-validating in
    bindTraceToProjectAndId — mirroring create(SpanBatch).

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Address review: centralize counter, simplify async, tidy nits
    • Centralize the opik.ingestion.uuid_v7.rejected counter and its label constants
      in UuidValidationMetrics; InvalidUUIDExceptionMapper now injects it and delegates
      via recordReject(reason, httpRoute), dropping its duplicate counter/constants.
    • Drop the redundant nested Mono.fromCallable inside deferContextual on the async
      validation paths (validate has no blocking work and there is no subscribeOn, so
      it ran on the subscribing thread either way; deferContextual already maps a thrown
      exception to onError).
    • Let resource fall back to unknown like workspaceId (relax @NonNull); the metric
      recorder defaults blank values.
    • Test: make the id generators static final and rename to constant case.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • [OPIK-7402] [BE] Review: centralize IdGenerator + workspace overloads; factor metric assembly
    • IdGenerator: single core validateIdNotInFuture(id, resource, workspaceId); the
      2-arg form and the async form delegate to it (no more duplicated version+window
      logic), and a workspace-parameterized overload is offered for callers that carry
      the request workspace. Same for validateIdNotInFutureIfPresent. The many
      config-entity callers keep the 2-arg form, defaulting to unknown by choice.
    • UuidValidationMetrics: factor the shared counter/mode/reason assembly into a
      private record(...) helper; recordAudit/recordReject only supply their
      path-specific tags.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com


    Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com

    下载附件