Skip to content

Commit 4dc98c5

Browse files
authored
Merge branch 'main' into thiagoh/OPIK-7773-fail-fast-traces-topology-assertion
2 parents 4181c45 + d9a9621 commit 4dc98c5

117 files changed

Lines changed: 12348 additions & 870 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build_and_push_docker.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ jobs:
181181
182182
- name: Build and Push Docker Image
183183
id: build
184-
uses: docker/build-push-action@v6
184+
uses: docker/build-push-action@v7
185185
with:
186186
context: apps/${{ inputs.image }}/
187187
platforms: linux/${{ matrix.platform }}
@@ -239,7 +239,7 @@ jobs:
239239
echo "image_name=$IMAGE_NAME" >> "$GITHUB_OUTPUT"
240240
241241
- name: Download digests
242-
uses: actions/download-artifact@v4
242+
uses: actions/download-artifact@v8
243243
with:
244244
path: /tmp/digests/${{ steps.set_vars.outputs.image_name }}
245245
pattern: ${{ github.run_id }}-${{ steps.set_vars.outputs.image_name }}-digest-*

.github/workflows/code_quality.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ jobs:
240240

241241
- name: Download timing fragments
242242
if: needs.detect.outputs.has_legs == 'true'
243-
uses: actions/download-artifact@v4
243+
uses: actions/download-artifact@v8
244244
with:
245245
path: /tmp/fragments
246246
pattern: timing-*
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
name: Frontend Private Plugin Checks
2+
run-name: "Frontend Private Plugin Checks ${{ github.ref_name }} by @${{ github.actor }}"
3+
4+
# The comet frontend image compiles comet-ml/opik-plugin-ai-spend, checked out at
5+
# build time into src/plugins/ai-spend. Nothing else here compiles it, so a
6+
# breaking change to a shared surface it imports passes every check on the PR
7+
# that makes it and only fails later, in the image build. This runs the frontend
8+
# checks with the plugin staged the same way the image stages it.
9+
#
10+
# For a change that intentionally breaks the plugin, name the plugin branch that
11+
# adapts to it in the PR body, then merge the plugin PR first:
12+
#
13+
# ai-spend-plugin-ref: someone/my-branch
14+
#
15+
# Same-repo PRs get the token; that is the standard model this repo already
16+
# uses for other secrets (e.g. typescript_sdk_e2e_tests.yml), and this repo
17+
# additionally requires maintainer approval before any workflow runs for a
18+
# first-time/outside contributor. Fork PRs get no token at all, from GitHub
19+
# itself, regardless of what any workflow file says.
20+
21+
permissions:
22+
contents: read
23+
24+
on:
25+
pull_request:
26+
# edited: the ai-spend-plugin-ref override lives in the PR body, so adding
27+
# it after opening the PR must retrigger this -- default types
28+
# (opened, synchronize, reopened) do not cover an edited description.
29+
types: [opened, synchronize, reopened, edited]
30+
paths:
31+
- "apps/opik-frontend/**"
32+
# A change to this check, or to the workflow that controls how the real
33+
# image stages this same plugin, should re-run it.
34+
- ".github/workflows/frontend_private_plugin_checks.yml"
35+
- ".github/workflows/build_and_push_docker.yaml"
36+
workflow_dispatch:
37+
inputs:
38+
ai_spend_plugin_ref:
39+
type: string
40+
required: false
41+
description: ai-spend plugin ref
42+
default: "main"
43+
44+
concurrency:
45+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
46+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
47+
48+
jobs:
49+
checks:
50+
name: Checks with ai-spend plugin
51+
runs-on: ubuntu-latest
52+
timeout-minutes: 20
53+
steps:
54+
- name: Checkout code
55+
uses: actions/checkout@v7
56+
with:
57+
fetch-depth: 1
58+
persist-credentials: false
59+
60+
# Token availability checked first: without one, the job exits green with
61+
# a notice, before ref parsing -- a malformed ai-spend-plugin-ref must
62+
# never fail a fork event, since nothing downstream would use it anyway.
63+
- name: Resolve plugin ref and token availability
64+
id: resolve
65+
env:
66+
HAS_TOKEN: ${{ secrets.OPIK_PLUGIN_AI_SPEND_TOKEN != '' }}
67+
DISPATCH_REF: ${{ inputs.ai_spend_plugin_ref }}
68+
PR_BODY: ${{ github.event.pull_request.body }}
69+
run: |
70+
set -euo pipefail
71+
echo "has_token=${HAS_TOKEN}" >> "$GITHUB_OUTPUT"
72+
73+
if [ "${HAS_TOKEN}" != "true" ]; then
74+
echo "::notice title=ai-spend plugin not checked::No access to the private plugin repository from this event. The plugin was not checked."
75+
exit 0
76+
fi
77+
78+
# Fenced blocks are skipped: a PR that documents this syntax in an
79+
# example must not be taken as using it. CR stripped first: a body
80+
# edited in the GitHub web UI is CRLF, and awk's default field
81+
# separator does not treat \r as one, so it would otherwise stay
82+
# attached to the captured ref and fail the validation below on an
83+
# otherwise valid value.
84+
ref="${DISPATCH_REF:-}"
85+
if [ -z "${ref}" ]; then
86+
ref="$(printf '%s' "${PR_BODY:-}" \
87+
| tr -d '\r' \
88+
| awk '/^[[:space:]]*```/ { fenced = !fenced; next } !fenced' \
89+
| grep -iEm1 '^[[:space:]]*ai-spend-plugin-ref:[[:space:]]*[^[:space:]]+' \
90+
| sed -E 's/^[^:]*:[[:space:]]*//' \
91+
| awk '{print $1}' || true)"
92+
fi
93+
ref="${ref:-main}"
94+
95+
if ! printf '%s' "${ref}" | grep -qE '^[A-Za-z0-9._/-]+$'; then
96+
echo "::error title=Invalid ai-spend-plugin-ref::'${ref}' is not a valid git ref."
97+
exit 1
98+
fi
99+
100+
echo "ref=${ref}" >> "$GITHUB_OUTPUT"
101+
echo "Plugin ref: ${ref}"
102+
103+
if [ "${ref}" != "main" ]; then
104+
echo "::warning title=Checking against a non-main plugin ref::This run verifies against '${ref}', not the plugin's main -- nothing enforces that branch is merged before this PR merges."
105+
fi
106+
107+
# Ahead of the plugin checkout: npm ci's PR-controlled postinstall runs
108+
# with no private plugin source on disk yet.
109+
- name: Set up Node.js
110+
if: steps.resolve.outputs.has_token == 'true'
111+
uses: actions/setup-node@v7
112+
with:
113+
node-version: "20"
114+
115+
- name: Install dependencies
116+
if: steps.resolve.outputs.has_token == 'true'
117+
run: npm ci
118+
working-directory: apps/opik-frontend
119+
120+
- name: Checkout ai-spend plugin (private)
121+
if: steps.resolve.outputs.has_token == 'true'
122+
uses: actions/checkout@v7
123+
with:
124+
repository: comet-ml/opik-plugin-ai-spend
125+
ref: ${{ steps.resolve.outputs.ref }}
126+
token: ${{ secrets.OPIK_PLUGIN_AI_SPEND_TOKEN }}
127+
path: .ai-spend-plugin
128+
fetch-depth: 1
129+
persist-credentials: false
130+
131+
# Same staging as the image build. Asserted non-empty, and specifically
132+
# checked for the manifest PluginsStore actually loads by name -- a layout
133+
# change that drops or misnames manifest.ts would otherwise leave
134+
# production silently without the plugin's routes while this still passed
135+
# on an unrelated .ts file count. The source directory is checked before
136+
# copying: cp -R against a missing/renamed src fails under set -e with a
137+
# raw cp error, before the friendlier "produced nothing" message below.
138+
- name: Stage ai-spend plugin into frontend src
139+
if: steps.resolve.outputs.has_token == 'true'
140+
run: |
141+
set -euo pipefail
142+
if [ ! -d .ai-spend-plugin/src ]; then
143+
echo "::error title=Plugin src directory missing::.ai-spend-plugin/src does not exist. The plugin's src layout likely changed."
144+
exit 1
145+
fi
146+
147+
mkdir -p apps/opik-frontend/src/plugins/ai-spend
148+
cp -R .ai-spend-plugin/src/. apps/opik-frontend/src/plugins/ai-spend/
149+
rm -rf .ai-spend-plugin
150+
151+
count="$(find apps/opik-frontend/src/plugins/ai-spend -type f \( -name '*.ts' -o -name '*.tsx' \) | wc -l | tr -d ' ')"
152+
if [ "${count}" -eq 0 ]; then
153+
echo "::error title=Plugin staging produced nothing::Copied 0 TypeScript files. The plugin's src layout likely changed."
154+
exit 1
155+
fi
156+
157+
manifest=apps/opik-frontend/src/plugins/ai-spend/manifest.ts
158+
if [ ! -f "${manifest}" ] || ! grep -qE "name:[[:space:]]*['\"]ai-spend['\"]" "${manifest}"; then
159+
echo "::error title=Plugin manifest missing or misnamed::PluginsStore loads plugins by the name declared in plugins/*/manifest.ts. ${manifest} is missing, or no longer declares name: \"ai-spend\" -- production would silently drop the plugin's routes."
160+
exit 1
161+
fi
162+
163+
echo "Staged ${count} TypeScript files from the plugin; manifest present and named correctly."
164+
165+
# All three run even if an earlier one fails, so a PR sees every problem in
166+
# one go. eslint is scoped to the plugin: core files are already linted by
167+
# the code quality workflow.
168+
- name: Typecheck, lint and validate dependencies
169+
if: steps.resolve.outputs.has_token == 'true'
170+
working-directory: apps/opik-frontend
171+
run: |
172+
set -uo pipefail
173+
failed=0
174+
175+
echo "::group::typecheck"
176+
npm run typecheck || failed=1
177+
echo "::endgroup::"
178+
179+
echo "::group::eslint (plugin sources)"
180+
npx eslint src/plugins/ai-spend --max-warnings=0 || failed=1
181+
echo "::endgroup::"
182+
183+
echo "::group::dependency-cruiser"
184+
npm run deps:validate || failed=1
185+
echo "::endgroup::"
186+
187+
if [ "${failed}" -ne 0 ]; then
188+
echo "::error title=Frontend checks fail with the ai-spend plugin staged::Reproduce locally: symlink or copy a sibling opik-plugin-ai-spend checkout's src/ into apps/opik-frontend/src/plugins/ai-spend, then from apps/opik-frontend run: npm run typecheck && npx eslint src/plugins/ai-spend --max-warnings=0 && npm run deps:validate. (bash scripts/dev-runner.sh --lint-fe is close but not equivalent -- it lints the whole src tree with --fix, plus stylelint, none of which this check runs.) Keep the shared surface backward compatible, or land the matching plugin change first and add 'ai-spend-plugin-ref: <branch>' to this PR body."
189+
exit 1
190+
fi

.github/workflows/lint_helm_chart.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
uses: actions/checkout@v7
4444

4545
- name: Install Helm ${{ matrix.helm-version }}
46-
uses: azure/setup-helm@v4.3.1
46+
uses: azure/setup-helm@v5.0.1
4747
with:
4848
version: ${{ matrix.helm-version }}
4949

@@ -69,7 +69,7 @@ jobs:
6969
uses: actions/checkout@v7
7070

7171
- name: Install Helm
72-
uses: azure/setup-helm@v4.3.1
72+
uses: azure/setup-helm@v5.0.1
7373
with:
7474
version: v3.21.0
7575

@@ -102,7 +102,7 @@ jobs:
102102
uses: actions/checkout@v7
103103

104104
- name: Render with Helm 3.x
105-
uses: azure/setup-helm@v4.3.1
105+
uses: azure/setup-helm@v5.0.1
106106
with:
107107
version: v3.21.0
108108

@@ -119,7 +119,7 @@ jobs:
119119
cd -
120120
121121
- name: Render with Helm 4.x
122-
uses: azure/setup-helm@v4.3.1
122+
uses: azure/setup-helm@v5.0.1
123123
with:
124124
version: v4.2.0
125125

.github/workflows/publish_helm_chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- name: Install Helm
3535
# azure/setup-helm v4.3.1 pinned to commit SHA 1a275c3b69536ee54be43f2070a358922e12c8d4
3636
# Source: https://github.com/Azure/setup-helm/releases/tag/v4.3.1
37-
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
37+
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310
3838
with:
3939
version: v3.19.4
4040

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ jobs:
228228
# Same action + inputs as update_helm_readme.yaml, keeping CI and the
229229
# local pre-commit hook in agreement.
230230
- name: Regenerate Helm chart README
231-
uses: losisin/helm-docs-github-action@v1
231+
uses: losisin/helm-docs-github-action@v2
232232
with:
233233
chart-search-root: deployment/helm_chart/opik
234234
git-push: false

.github/workflows/update_helm_readme.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
# If the PR has the "update readme" label, generate and commit
2525
- name: Generate and commit helm docs
2626
if: contains(github.event.pull_request.labels.*.name, 'update readme')
27-
uses: losisin/helm-docs-github-action@v1
27+
uses: losisin/helm-docs-github-action@v2
2828
with:
2929
chart-search-root: deployment/helm_chart/opik
3030
git-push: true
@@ -35,7 +35,7 @@ jobs:
3535
# If the PR does NOT have the label, just validate that docs are up-to-date
3636
- name: Validate helm docs are up-to-date
3737
if: "!contains(github.event.pull_request.labels.*.name, 'update readme')"
38-
uses: losisin/helm-docs-github-action@v1
38+
uses: losisin/helm-docs-github-action@v2
3939
with:
4040
chart-search-root: deployment/helm_chart/opik
4141
git-push: false

apps/opik-backend/config.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,20 @@ databaseAnalyticsDataModel:
158158
# wrong in either direction and the backend fails readiness at startup with a message naming the flag and the
159159
# observed engine, rather than serving traffic whose trace deletes are guaranteed to fail.
160160
tracesDistributedWrapEnabled: ${ANALYTICS_DB_DATA_MODEL_TRACES_DISTRIBUTED_WRAP_ENABLED:-false}
161+
# Default: false
162+
# Description: Enables partition-aware PRUNING of trace deletes - it does NOT create or activate any partitioning.
163+
# With it on, a trace DELETE bounds itself to the weekly partitions its own ids resolve to instead of being planned
164+
# against every part of the table. Turning it on therefore ASSERTS a schema fact rather than causing one: that the
165+
# live mutation target already IS the weekly partitioned successor, id_at as DateTime64(0,'UTC') under
166+
# PARTITION BY toYYYYMMDD(toDate32(id_at) - toIntervalDay(toDayOfWeek(id_at, 1))). Installing that schema is the
167+
# EXCHANGE step of the cutover, never this flag. Purely an optimisation: false keeps the unbounded mutation, which
168+
# is always correct and merely slower. A third flag on purpose - the partitioning appears at the EXCHANGE, and
169+
# neither sibling marks it:
170+
# traceColumnsNonNullable must be rolled out BEFORE the EXCHANGE, tracesDistributedWrapEnabled flips at the wrap,
171+
# which may be deferred long after it. Leave false at deploy time; set true once the EXCHANGE is confirmed, and back
172+
# to false BEFORE a rollback promotes the original `traces` (legacy `traces` has no PARTITION BY and a 32-bit
173+
# DateTime id_at that overflows past 2106, so the predicate would silently match zero rows for a far-future id).
174+
tracesWeeklyPartitionPruningEnabled: ${ANALYTICS_DB_DATA_MODEL_TRACES_WEEKLY_PARTITION_PRUNING_ENABLED:-false}
161175

162176
# Description: UUIDv7 ingestion validation. Rejects writes whose `id` embeds a timestamp outside the
163177
# window, protecting data quality.

0 commit comments

Comments
 (0)