Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d5e6772
feat(product-events): derive product events from annotated spans
Makisuo Sep 1, 2026
c51c20b
fix(product-events): close two data-loss paths found in review
Makisuo Sep 1, 2026
4f5d457
fix(cli): commit the regenerated local-schema projectRevision header
Makisuo Sep 1, 2026
36291f8
Merge remote-tracking branch 'origin/main' into HEAD
Makisuo Sep 1, 2026
5175315
fix(domain): regenerate the anticipated-error identifier list
Makisuo Sep 1, 2026
be27da6
fix(lint): clear the three effect-lint errors carried in from main
Makisuo Sep 1, 2026
224e489
Merge origin/main, dropping this branch's carried lint fixes
Makisuo Sep 1, 2026
9270bf6
Merge origin/main: renumber to migration 0025 / local schema v15
Makisuo Sep 2, 2026
3e20ad7
Merge origin/main: renumber to migration 0026 / local schema v16
Makisuo Sep 2, 2026
054366a
Merge origin/main: renumber to migration 0027 / local schema v17
Makisuo Sep 3, 2026
06f5255
fix(tinybird): add the product_events FORWARD_QUERY the deploy needs
Makisuo Sep 3, 2026
95db702
Merge origin/main: regenerate the Tinybird manifest for both sides
Makisuo Sep 4, 2026
cde217a
Merge origin/main: regenerate the ClickHouse schema artifacts
Makisuo Sep 4, 2026
1a8ab01
Merge origin/main: query-catalog unification and dual-write removal
Makisuo Sep 4, 2026
c6dd7d9
fix(knip): declare bench suites as apps/api entry points
Makisuo Sep 4, 2026
5e3820b
Merge origin/main: take main's knip comment for the bench-suites entry
Makisuo Sep 5, 2026
2317121
Merge origin/main: renumber to migration 0028 / local schema v18
Makisuo Sep 5, 2026
4fa4ef1
fix(product-events): align the local backfill projection, guard the r…
Makisuo Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion apps/api/src/routes/internal/query-engine.http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ import {
ProductEventsFunnelResponse,
ProductEventsFunnelBreakdownResponse,
ProductEventNamesResponse,
ProductEventsForTraceResponse,
ProductEventTraceSamplesResponse,
CommitSha,
FingerprintHash,
ServiceName,
Expand Down Expand Up @@ -2072,6 +2074,43 @@ export const HttpQueryEngineLive = HttpApiBuilder.group(MapleInternalApi, "query
})
}),
)
// Both directions of the trace ↔ product-event link.
.handle("productEventsForTrace", ({ payload }) =>
Effect.gen(function* () {
const tenant = yield* CurrentTenant.Context
const rows = yield* runQuery(Queries.productEventsForTrace, tenant, payload)
return new ProductEventsForTraceResponse({
data: rows.map((row) => ({
timestamp: String(row.timestamp),
eventName: String(row.eventName),
spanId: String(row.spanId),
serviceName: String(row.serviceName),
userId: String(row.userId),
groupId: String(row.groupId),
visitorId: String(row.visitorId),
sessionId: String(row.sessionId),
// Already decoded as Record<string, string> by the derived row schema.
attributes: row.attributes,
})),
})
}),
)
.handle("productEventTraceSamples", ({ payload }) =>
Effect.gen(function* () {
const tenant = yield* CurrentTenant.Context
const rows = yield* runQuery(Queries.productEventTraceSamples, tenant, payload)
return new ProductEventTraceSamplesResponse({
data: rows.map((row) => ({
traceId: String(row.traceId),
spanId: String(row.spanId),
timestamp: String(row.timestamp),
serviceName: String(row.serviceName),
userId: String(row.userId),
visitorId: String(row.visitorId),
})),
})
}),
)
.handle("executeRawSql", ({ payload }) =>
Effect.gen(function* () {
const tenant = yield* CurrentTenant.Context
Expand Down Expand Up @@ -2099,7 +2138,9 @@ export const HttpQueryEngineLive = HttpApiBuilder.group(MapleInternalApi, "query
context: "rawSql",
}).pipe(
// Every statement is audited, however it ended: a refused one as `denied`.
Effect.tap((executed) => audit({ _tag: "rows", rowCount: executed.rowCount })),
Effect.tap((executed) =>
audit({ _tag: "rows", rowCount: executed.rowCount }),
),
Effect.tapError((error) =>
audit(
error._tag === "@maple/http/errors/RawSqlValidationError"
Expand Down
20 changes: 18 additions & 2 deletions apps/cli/src/server/local-schema-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ export const LOCAL_SCHEMA_HISTORY: ReadonlyArray<LocalSchemaHistoryEntry> = Obje
projectRevision: "ed74788ef292834069e0ea6ee3b22d68fc604fb66cb54d2d551db67ce8d20b3a",
}),
Object.freeze({
// TODO(v17): what changed, whether any part is rewritten or any row
// moves, and what this edge does NOT backfill.
// v17: `audit_log` table added (ClickHouse migration 0027). Purely
// additive — nothing is rewritten, no row moves, nothing is backfilled.
//
// projectRevision is carried forward deliberately — it is a hardcoded
// constant that no longer tracks the generator's header, and the identity
Expand All @@ -194,4 +194,20 @@ export const LOCAL_SCHEMA_HISTORY: ReadonlyArray<LocalSchemaHistoryEntry> = Obje
manifestDigest: "f19b88567770ee1b67f77d5734de61adbfd3ba907ce8ae28ce65a4da4e544533",
projectRevision: "ed74788ef292834069e0ea6ee3b22d68fc604fb66cb54d2d551db67ce8d20b3a",
}),
Object.freeze({
// v18: `product_events` gains `TraceId`/`SpanId` plus a bloom filter, and
// `product_events_traces_mv` projects annotated spans in (ClickHouse
// migration 0028). Metadata-only ALTERs plus a view swap — no part is
// rewritten and no row moves. The trace half IS backfilled from whatever
// `traces` still retains; annotated spans older than that are not.
//
// projectRevision is carried forward deliberately — it is a hardcoded
// constant that no longer tracks the generator's header, and the identity
// this gate compares is the fingerprint/digest pair.
version: 18,
fingerprint: "09ee43045937c44e",
digest: "09ee43045937c44e89cf65001569497fb2e2d5b3356a8ddc2d81e0a8551bf1b2",
manifestDigest: "2a7d05f4fb19422404264521f06ea9ca2f2106cdce2165899f00433215aca8b0",
projectRevision: "ed74788ef292834069e0ea6ee3b22d68fc604fb66cb54d2d551db67ce8d20b3a",
}),
] as const)
2 changes: 1 addition & 1 deletion apps/cli/src/server/local-schema-version.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Increment this value for every structural change to the generated local
// schema. The compatibility manifest and migration registry must be updated in
// the same change before a new value can ship.
export const LOCAL_SCHEMA_VERSION = 17 as const
export const LOCAL_SCHEMA_VERSION = 18 as const
2 changes: 2 additions & 0 deletions apps/cli/src/server/local-store-migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { v13ToV14AiTraceIndexModule } from "./local-store-migrations/v13-to-v14-
import { v14ToV15CommitShaVcsRevisionModule } from "./local-store-migrations/v14-to-v15-commit-sha-vcs-revision"
import { v15ToV16AiTraceIndexFilterColumnsModule } from "./local-store-migrations/v15-to-v16-ai-trace-index-filter-columns"
import { v16ToV17AuditLogModule } from "./local-store-migrations/v16-to-v17-audit-log"
import { v17ToV18ProductEventsFromTracesModule } from "./local-store-migrations/v17-to-v18-product-events-from-traces"
import type {
AnyLocalStoreMigrationModule,
LocalStoreMigration,
Expand Down Expand Up @@ -127,6 +128,7 @@ export const localStoreMigrations: ReadonlyArray<AnyLocalStoreMigrationModule> =
v14ToV15CommitShaVcsRevisionModule,
v15ToV16AiTraceIndexFilterColumnsModule,
v16ToV17AuditLogModule,
v17ToV18ProductEventsFromTracesModule,
]

export const validateMigrationRegistry = (
Expand Down
Loading
Loading