Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
ef93154
feat(mq): give every tenant a queue of its own
taitelee Sep 24, 2026
3022b92
feat(config): choose each layer's implementation at boot
EricAndrechek Sep 25, 2026
fde17ba
docs(config): say coord.backend is reserved; sync the boot-config lists
EricAndrechek Sep 25, 2026
431084e
fix(cache): snapshot versions at lookup; tenant token on every key
EricAndrechek Sep 25, 2026
f129d57
docs(config): no backend has a sub-block yet; index backends.go in AG…
EricAndrechek Sep 25, 2026
67df317
perf(cache): flat version index, pruned per tenant
EricAndrechek Sep 25, 2026
ed8022b
docs(cache): name the cache prune hook; pin LocalCache as a pruner
EricAndrechek Sep 25, 2026
50b7e0c
feat(cache): Redis-compatible shared cache backend
EricAndrechek Sep 25, 2026
e346426
fix(cache): count only transport failures against the breaker
EricAndrechek Sep 25, 2026
d2a87ab
fix(cache): replace token and value keys of the wrong type
EricAndrechek Sep 25, 2026
d67a46a
test(cov): keep the unreachable Redis backend out of the e2e gate
EricAndrechek Sep 25, 2026
44cec4d
Merge remote-tracking branch 'origin/feat/boot-backends' into feat/ca…
EricAndrechek Sep 25, 2026
85803f0
Merge remote-tracking branch 'origin/feat/cache-flat-versions' into f…
EricAndrechek Sep 25, 2026
c068084
feat(config): cache.backend=redis selects the shared cache
EricAndrechek Sep 25, 2026
13c6cb3
fix(cache): review round — e2e gate, trust boundary, #386, addr spaces
EricAndrechek Sep 25, 2026
1134d5c
fix(pipes): run write pipes every call, uncached and uncoalesced
EricAndrechek Sep 25, 2026
74a7bf4
fix(pipes): no-store on write pipes; reconcile the mutation-path docs
EricAndrechek Sep 25, 2026
7bb8c27
docs(pipes): name the operator as a write pipe's author; no-store in …
EricAndrechek Sep 25, 2026
264d71b
Merge remote-tracking branch 'origin/main' into feat/cache-snapshot
EricAndrechek Sep 25, 2026
ce14795
refactor(keyenc): one escaping for subject and cache key tokens
EricAndrechek Sep 25, 2026
51db11c
docs(keyenc): name only the keys built from it today
EricAndrechek Sep 25, 2026
27f7608
docs(architecture): keyenc is not yet every composite key's escaping
EricAndrechek Sep 25, 2026
ca16db5
Merge origin/feat/cache-snapshot into feat/cache-flat-versions
EricAndrechek Sep 25, 2026
673f461
Merge remote-tracking branch 'origin/main' into refactor/keyenc
EricAndrechek Sep 25, 2026
2c31eff
refactor(keyenc): keep '-', join keys, count dead letters per table
EricAndrechek Sep 25, 2026
011fb93
Merge branch 'refactor/keyenc' into feat/cache-snapshot
EricAndrechek Sep 25, 2026
999e92c
docs(keyenc): pin the %2D compatibility to builds since #612
EricAndrechek Sep 25, 2026
cc516d8
refactor(cache): namespaces carry raw names; the cache escapes its keys
EricAndrechek Sep 25, 2026
4552f91
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 25, 2026
79ab364
test(mq): cover a byte left unescaped in the lenient-token case
EricAndrechek Sep 25, 2026
40d817d
refactor(cache): the Redis codec escapes the raw names it keys
EricAndrechek Sep 25, 2026
d03178b
Merge branch 'refactor/keyenc' into feat/cache-snapshot
EricAndrechek Sep 25, 2026
c004690
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 25, 2026
972a53d
docs(cache): one name for keyenc's cache keys; the entry key's lead f…
EricAndrechek Sep 26, 2026
3d2a8fb
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 26, 2026
1e70d64
docs(cache): the Redis token-key layout is a protocol between builds
EricAndrechek Sep 26, 2026
dbd3681
docs(cache): InvalidateTenant drops pipe results; a pipe passes no deps
EricAndrechek Sep 26, 2026
a7c86d5
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 26, 2026
e6a824a
docs(cache): a token-key layout change needs both layouts read and bu…
EricAndrechek Sep 26, 2026
674e0e2
docs(changelog): #382 never reached pipes; entry keys gained the tena…
EricAndrechek Sep 26, 2026
8541758
Merge remote-tracking branch 'origin/main' into feat/cache-snapshot
EricAndrechek Sep 26, 2026
ee51e84
test(app): assert the wired cache is a pruner before swapping it
EricAndrechek Sep 26, 2026
fcf1e89
Merge main (5004cd23) into feat/cache-redis-wiring
EricAndrechek Sep 26, 2026
e9204e6
Merge main (5004cd23) into feat/cache-snapshot
EricAndrechek Sep 26, 2026
55eb103
fix(cache): take the snapshot before choosing the tenant's pool
EricAndrechek Sep 26, 2026
19720fb
fix(api): classify writes the way ClickHouse lexes them
EricAndrechek Sep 26, 2026
9a4888a
fix(config): cache.redis defaults in defaults(); 0 never compresses
EricAndrechek Sep 26, 2026
6fa1ae6
fix(cache): give the two-instance test its roles; redis is the shared…
EricAndrechek Sep 26, 2026
712b1db
fix(config): refuse cache.redis.mode=sentinel until #656
EricAndrechek Sep 26, 2026
a7ef71f
fix(config): refuse a URL-style cache.redis address without echoing it
EricAndrechek Sep 26, 2026
de27b60
fix(config): cap cache.redis.dial_timeout at 2s
EricAndrechek Sep 26, 2026
972ff30
docs(cache): only a move to another address or database bumps a tenant
EricAndrechek Sep 26, 2026
8189783
test(cache): the local backend's insert-invalidates lifecycle, end to…
EricAndrechek Sep 26, 2026
5e84762
fix(ingest): log an invalidation that did not land at WARN
EricAndrechek Sep 26, 2026
0696702
fix(cache): owed bumps hold lookups; refused writes open the breaker
EricAndrechek Sep 26, 2026
c6df13a
fix(cache): bound a cluster client's topology read like a dial
EricAndrechek Sep 26, 2026
b861bdb
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 26, 2026
3c19a85
test(cache): count Redis values so the zero-snapshot case runs
EricAndrechek Sep 26, 2026
4c9d951
Merge origin/feat/cache-snapshot into fix/mutation-pipes-uncached
EricAndrechek Sep 26, 2026
05a536d
fix(api): step over heredocs when classifying writes
EricAndrechek Sep 26, 2026
0880685
fix(api): a failed write pipe is never retryable
EricAndrechek Sep 26, 2026
ef59d85
Merge remote-tracking branch 'origin/feat/cache-snapshot' into feat/c…
EricAndrechek Sep 26, 2026
0c31dc5
fix(api): lex //, curly quotes and _-led words as ClickHouse does
EricAndrechek Sep 26, 2026
c427697
fix(cache): replace connections so a failover reaches the new primary
EricAndrechek Sep 26, 2026
4df73f9
docs(cache): clarify which bumps a no-index tenant absorbs
EricAndrechek Sep 26, 2026
95575f2
docs(cache): CHANGELOG says #262 is part-fixed, not fixed
EricAndrechek Sep 26, 2026
9b8ed1a
docs(pipes): a proxy's 5xx is retried too, so a write can run twice
EricAndrechek Sep 26, 2026
4752811
docs(cache): cache.backend exists; Redis key shapes; failover wording
EricAndrechek Sep 26, 2026
1f24da5
docs(cache): a reconnect must fit in the operation timeout
EricAndrechek Sep 26, 2026
98f4a12
fix(api): match a statement's leading bareword whole
EricAndrechek Sep 26, 2026
e0d7018
Merge feat/cache-flat-versions (#621) into feat/cache-redis (#626)
EricAndrechek Sep 26, 2026
d60615b
Merge the new #626 and #621 heads into feat/cache-redis-wiring
EricAndrechek Sep 26, 2026
5b31ce6
fix(config): cap cache.redis timeout and dial_timeout at 1s
EricAndrechek Sep 26, 2026
41ebc66
fix(cache): review round 1 — one standalone address, e2e stack docs, …
EricAndrechek Sep 26, 2026
64f09e8
docs(dev): list Redis among the cache backend's integration servers
EricAndrechek Sep 26, 2026
558bb23
fix(cache): pin the no-index bump test and fix a "query key" mixup
EricAndrechek Sep 26, 2026
1febf32
docs(cache): fix entry-vs-caller query key terms and cachetest coverage
EricAndrechek Sep 26, 2026
5a72724
fix(cache): review round 2 — stale docs claims, redisConfig field pin
EricAndrechek Sep 26, 2026
568f2dd
docs(cache): version_manager.go's own doc carries the query-key/entry…
EricAndrechek Sep 26, 2026
277b5b1
Merge remote-tracking branch 'origin/feat/cache-snapshot' into feat/c…
EricAndrechek Sep 26, 2026
f724033
fix(api): classify a WITH-led statement by INSERT INTO alone
EricAndrechek Sep 26, 2026
e8f65ac
docs(pipes): what a write pipe skips, bounds and costs
EricAndrechek Sep 26, 2026
bf56403
fix(cache): trip on rejected credentials; give the probe a dial budget
EricAndrechek Sep 26, 2026
470cf75
Merge origin/feat/cache-snapshot into fix/mutation-pipes-uncached
EricAndrechek Sep 26, 2026
f64ce77
Merge branch 'feat/cache-snapshot' into feat/cache-redis
EricAndrechek Sep 26, 2026
a10ba14
docs(agents): list mutationtest in the file structure
EricAndrechek Sep 26, 2026
c42b6db
docs(cache): fix the one query-key/entry-key spot the terminology pas…
EricAndrechek Sep 26, 2026
11a1fc6
Merge feat/cache-flat-versions (#621) into feat/cache-redis (#626)
EricAndrechek Sep 26, 2026
f1ab891
Merge the new #626 and #621 heads into feat/cache-redis-wiring
EricAndrechek Sep 26, 2026
ce0da48
docs(cache): match configuration.mdx and deployment.md to #626's fixes
EricAndrechek Sep 26, 2026
0eea1cb
fix(cache): close the breaker only on a probe write within Timeout
EricAndrechek Sep 26, 2026
e2366d7
fix(api): see a write behind a .-led number or an EXECUTE AS prefix
EricAndrechek Sep 26, 2026
1058677
Merge the new #626 head (0eea1cbc) into feat/cache-redis-wiring
EricAndrechek Sep 26, 2026
d0af402
docs(api): name write pipes as a mutation path, not a second route
EricAndrechek Sep 26, 2026
ecd21c0
docs(cache): match deployment.md to #626's probe-fix (0eea1cbc)
EricAndrechek Sep 26, 2026
b3068ab
test(cache): pin the failover test to one connection
EricAndrechek Sep 26, 2026
822aecb
fix(cache): log the breaker opening once, at WARN
EricAndrechek Sep 26, 2026
aad9b1e
docs(cache): say every breaker opening logs, a failed probe's included
EricAndrechek Sep 26, 2026
0281ca3
docs(cache): correct the Close bound, deferred count and probe wording
EricAndrechek Sep 26, 2026
28d4537
Merge the new #626 head (aad9b1e5) into feat/cache-redis-wiring
EricAndrechek Sep 26, 2026
13418e9
Merge #621 (feat/cache-flat-versions) into feat/cache-snapshot
EricAndrechek Sep 26, 2026
088a4b1
Merge #634 (fix/mutation-pipes-uncached) into feat/cache-snapshot
EricAndrechek Sep 26, 2026
2db5027
Merge #626 and #630 (feat/cache-redis) into feat/cache-snapshot
EricAndrechek Sep 26, 2026
212ad13
fix(cache): log a failed probe's reopening at DEBUG, not WARN
EricAndrechek Sep 26, 2026
a7cd351
fix(cache): log a reopening at its own level when its cause changed
EricAndrechek Sep 26, 2026
71477cb
test(e2e): a write pipe inserts on every call over the shared cache
EricAndrechek Sep 26, 2026
79d550e
docs(deployment): write pipes no longer cached; name #394 instead
EricAndrechek Sep 26, 2026
99dc945
test(e2e): a failed write pipe answers not retryable
EricAndrechek Sep 26, 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
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Break one of these knowingly or not at all.

2. **A dedicated `coverage` job applies the consolidated gate, polling — not `needs`-ing — the suites.** Each suite (`unit`, `integration`, `e2e`) runs with `COV_DEFER=1` and uploads a `coverage-<suite>` fragment; the `coverage` job runs `make cov` (merge + every threshold gate) over all three — exactly like local `make ci`'s final step. Keeping it a separate job (not folded into e2e's tail) decouples the gate result from the e2e suite's pass/fail. Crucially it is `needs: changes` **only, not the suites**: a `needs` edge is a *scheduling* barrier — GitHub won't pick up a runner, check out, restore caches, or `pnpm install` until the needed jobs finish — so needing the suites would serialize this job's ~50s of setup onto the critical path after the last suite, for nothing (the setup doesn't depend on their results). Instead it starts at run creation, runs its setup in parallel with the suites, and blocks only at the merge by polling for the three fragments with [`scripts/ci/wait-artifact.sh`](../../scripts/ci/wait-artifact.sh) (fails fast if a producer concluded without producing). Tail on the critical path: ~10s, not ~50s. **The aggregator and `docs-deploy` must keep `coverage` *and* every suite in their `needs`** — the suites directly (a suite failure must red the gate even though `coverage` no longer needs them), and `coverage` (else a coverage-gate failure wouldn't block merge or a prod deploy).

3. **e2e builds its own inputs and mirrors local `make test-e2e`.** It compiles the SDK dist + cover binary itself (`make -j test-e2e`, warm per-suffix cache) rather than waiting on a builder job, and runs the suite exactly as a developer does — one orchestrator, one ClickHouse testcontainer, sequential files. The ClickHouse image pulls in the background while caches restore (also in the integration job).
3. **e2e builds its own inputs and mirrors local `make test-e2e`.** It compiles the SDK dist + cover binary itself (`make -j test-e2e`, warm per-suffix cache) rather than waiting on a builder job, and runs the suite exactly as a developer does — one orchestrator, one ClickHouse and one Redis testcontainer, sequential files. The ClickHouse image pulls in the background while caches restore (also in the integration job).

4. **One change classifier, split into a pure core + a CI wrapper.** The pure allowlist — file list on stdin ⇒ `code`/`docs` — lives in [`scripts/classify-paths.sh`](../../scripts/classify-paths.sh), dependency-free and unit-tested by [`scripts/classify-paths.test.sh`](../../scripts/classify-paths.test.sh) (`make test-classify-paths`, a `verify` leaf) so the allowlists can't silently regress. The `changes` job runs the thin wrapper [`scripts/ci/classify-changes.sh`](../../scripts/ci/classify-changes.sh), which adds the CI-only policy (API file-list fetch + fail-closed: pushes, dispatches, API hiccups ⇒ `code=true`) on top. Keeping the core pure means the local git hooks can share it (`git diff --name-only | scripts/classify-paths.sh`). The `code`/`docs` outputs gate the suites and docs jobs — gate on these, never on workflow-level `paths:` filters, which would orphan the required check (invariant 1).

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ jobs:
with:
go-cache-suffix: "-e2e-cov"
# `-j` builds the prereqs (build-ts ∥ build-cover) concurrently,
# then runs the orchestrator: ClickHouse testcontainer + the cover
# binary + the SDK vitest suite.
# then runs the orchestrator: ClickHouse and Redis testcontainers +
# the cover binary + the SDK vitest suite.
- name: Build SDK dist + cover binary, run E2E suite
run: make -j "$(nproc)" test-e2e COV_DEFER=1
- name: Upload coverage fragment
Expand Down
11 changes: 11 additions & 0 deletions .testcoverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,14 @@ exclude:
- ^internal/settings/
- ^cmd/wavehouse/validate\.go$
- ^cmd/wavehouse/bootstrap\.go$
# The in-process cache backend: the e2e stack runs cache.backend=redis
# (#613), so the binary carries LocalCache and its version index but e2e
# never reaches them. The unit suite and the integration suite's main
# app (cache.backend=local) cover them; the merged total still counts them.
- ^internal/cache/(local|version_manager)\.go$
# What e2e's Redis never makes it run: the cache.redis block's rejection
# paths (boot adopts a valid fixture, as with internal/settings above)
# and the retry of invalidations the server did not take, which needs an
# outage. The unit and integration suites cover both.
- ^internal/config/cache_redis\.go$
- ^internal/cache/pending\.go$
Loading
Loading