Skip to content

tests: faster dev loop + hpack dep dedup; misc hasql fixes#411

Merged
tonyalaribe merged 5 commits into
masterfrom
telemetry-derive-row-instances
Jun 4, 2026
Merged

tests: faster dev loop + hpack dep dedup; misc hasql fixes#411
tonyalaribe merged 5 commits into
masterfrom
telemetry-derive-row-instances

Conversation

@tonyalaribe

Copy link
Copy Markdown
Contributor

Summary

  • make live-test-dev: lib + integration tests as one GHCi target via a new test-dev test-suite, with --match filtering. Compiles src/ + test/integration/ together so iteration on test code skips the library re-link step.
  • hpack-includes/lib-deps.yaml: single source of truth for library dependencies, referenced from both library and tests.test-dev via !include. Eliminates the manual dep mirror (which had already drifted — vector-split was missing from test-dev, breaking the build after rebase). hpack 0.38 doesn't splice list-position !includes, so a handful of test-only deps (hspec, uuid-quasi, ki, pg-transact, aeson-pretty, process) also live in the shared file; the library declares them unused, silenced by the existing repo-wide -Wno-error=unused-packages.
  • Follow-up fixes on top of the hasql-interpolate migration that landed in hasql-interpolate + record-dot migration: derived ENUM/CITEXT decoders #409 / Ingestion/derive bulk insert cap #410: bigint COUNT decoded as Int64 in BackgroundJobs.hs; doctest pin on length otelColumns; minor DeriveUtils adjustments.

Test plan

  • hpack regenerates cleanly
  • cabal repl monoscope (ghcid): All good, 109 modules
  • cabal build test-dev: exit 0, 157 modules compiled and linked
  • make live-test-dev on a real spec (e.g. TEST_MATCH=/MonitoringSpec/ make live-test-dev)
  • CI green on the integration / unit / doctest jobs

… misc fixes

Squashed from 19 commits on telemetry-derive-row-instances. Backup branch:
telemetry-derive-row-instances-backup.
Move the library dependency list into hpack-includes/lib-deps.yaml and
reference it from both 'library' and 'tests.test-dev' via !include.
Eliminates the manual mirror that drifted (vector-split was missing from
test-dev, breaking live-test-dev after rebase).

hpack 0.38 does not splice list-position !include, so test-only deps
(hspec, uuid-quasi, ki, pg-transact, aeson-pretty, process) also live in
the shared file; the library declares them unused, silenced by the
existing -Wno-error=unused-packages.

Document make live-test-dev + the include-file pattern in CLAUDE.md
(local-only; CLAUDE.md is gitignored in this repo).
@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review

The core ideas here — lib-deps.yaml as a single source of truth, the test-dev combined target for faster iteration, and the tmux pane-pinning rework — are all solid. A few things worth fixing before merge:


Bug: base16-bytestring duplicated in lib-deps.yaml

hpack-includes/lib-deps.yaml lists base16-bytestring twice: once near line 27 and again at line 137 (just before minio-hs). This is a carry-over from the same dup in the old package.yaml. hpack silently deduplicates at resolve time so it won't break the build, but the YAML is confusing and contradicts the stated goal of deduplication.

- - base16-bytestring   # remove the line 137 occurrence
  - minio-hs

Incomplete IntInt64 fix

The PR correctly fixes jobStats/stuckJobs at lines 700–701, but the same Int/bigint mismatch exists in several nearby sections that weren't touched:

Line Annotation SQL
656 [(ProjectId, Text, Int)] COUNT(*)::bigint
677 [(ProjectId, Text, Int)] COUNT(*)::bigint
757 [(ProjectId, Text, Text, Int, Int)] ::bigint AS reported, ::bigint AS ingested

These will decode fine on 64-bit Linux (where Int is 64 bits) but the decoder contract is technically violated — hasql's int8 decoder returns Int64, not Int. Worth fixing in this PR since you're already in this file for the same reason.


live-test-dev missing from .PHONY

The new target isn't in the .PHONY declaration (line 244). If a file named live-test-dev ever exists in the repo root, make will silently skip running the recipe.

-.PHONY: ... tmux-pin-here tmux-unpin ...
+.PHONY: ... live-test-dev tmux-pin-here tmux-unpin ...

Minor: TEST_MATCH is unquoted in the match flag

--test ':main $(if $(TEST_MATCH),--match=$(TEST_MATCH))'

If TEST_MATCH contains spaces or glob characters the shell will mis-parse it. --match="$(TEST_MATCH)" (inner double-quotes) would be safer, since the whole string is already inside single quotes for ghcid:

--test ':main $(if $(TEST_MATCH),--match="$(TEST_MATCH)")'

Observation: test-only deps in the library

The comment in lib-deps.yaml is clear and the -Wno-error=unused-packages suppression is already repo-wide, so this is understood to be a hpack 0.38 workaround. One alternative for the record: ki is already in the library as ki-effectful (which re-exports the structured concurrency primitives), so the bare ki entry might be droppable from the extras list depending on what test/integration/ actually imports.

@tonyalaribe tonyalaribe force-pushed the telemetry-derive-row-instances branch from 2364483 to cf8db3f Compare June 4, 2026 13:32
@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review

Overall this is a solid DX/infra PR. A few concrete things worth addressing:


BackgroundJobs.hsIntInt64 (bug fix ✓)

Correct fix. hasql's decoder for bigint (int8) requires Int64, not Int; the previous code would fail at decode time when the result exceeded maxBound :: Int32 on 64-bit GHC or silently truncate values.


BackgroundJobs.hs — minor succinctness nit

-- current
stuck = fromMaybe 0 $ listToMaybe stuckJobs

-- with `extra` (already in deps)
stuck = headDef 0 stuckJobs

headDef from Data.List.Extra removes the listToMaybe/fromMaybe dance.


package.yaml / generated .cabal — duplicate -threaded

test-dev's ghc-options in package.yaml includes -threaded, but it's already present in the global ghc-options. hpack concatenates them, so the generated cabal ends up with -threaded twice. Harmless, but removing -threaded from the test-dev-specific options would clean it up.


lib-deps.yaml — test-only deps leaking into library

The comment explains the hpack 0.38 limitation, and -Wno-error=unused-packages silences it. That said, it's worth noting these six packages (hspec, uuid-quasi, ki, pg-transact, aeson-pretty, process) now appear in the library's build graph and affect cabal outdated, cabal check, and lock-file diffs. If hpack ever gains proper list-position !include support, extracting them to a separate test-only-deps.yaml would be the right clean-up.


Makefiletmux set-option -g @build-pane scope

Using -g (global) means the pinned pane ID is shared across all windows and sessions in tmux. If someone runs make tmux-pin-here from two project windows concurrently, the second pin silently clobbers the first. -w (window-scoped) would be more conservative here.


DeriveUtils.hs — doc comments ✓

The new Haddock lines for WrappedEnum and WrappedEnumShow clearly distinguish the TEXT-column decoder path from the PG-ENUM path. Good addition.


Telemetry.hs doctest ✓

length otelColumns pin updated from 89 → 88. Correct maintenance after the column removal in #409/#410.

… Makefile fixes

- hpack-includes/lib-deps.yaml: remove the second base16-bytestring entry
  (was a carry-over from the old package.yaml).
- BackgroundJobs.hs: same Int -> Int64 fix as 66a565a applied to the three
  remaining COUNT(*)::bigint sites (issueCounts, alertCounts, usage audit rows).
- Makefile: add live-test-dev to .PHONY; quote TEST_MATCH in the --match arg
  so values with spaces / glob chars don't get shell-mangled.
@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

See review below

- BackgroundJobs.stuck: headDef 0 instead of fromMaybe 0 . listToMaybe
  (from Data.List.Extra, already in deps).
- test-dev ghc-options: drop -threaded (already in global ghc-options;
  hpack was concatenating to a duplicate flag).
- Makefile @build-pane: -w (window-scoped) instead of -g (global). Two
  project windows pinning concurrently no longer clobber each other.

(Reviewer also noted hspec/uuid-quasi/ki/pg-transact/aeson-pretty/process
leak into the library's build graph via lib-deps.yaml; that's the
hpack-0.38 list-splice limit and can be revisited if/when hpack ships
proper support — left as-is for now.)
@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

Code Review - PR 411

Overview: Adds a test-dev GHCi target (src/ + test/integration/ as one unit), consolidates lib deps into hpack-includes/lib-deps.yaml, fixes Int->Int64 for COUNT()::bigint, updates doctest pin, adds haddock to DeriveUtils.

Bug - proto-lens-protoc missing from package.yaml test-dev build-tools: package.yaml lists only hspec-discover:hspec-discover, but the generated cabal has both hspec-discover and proto-lens-protoc. Since test-dev compiles all Proto modules via generated-other-modules, the next hpack run would drop proto-lens-protoc and break the build. Add it explicitly or confirm it comes from a global build-tools stanza.

Generated Cabal: Duplicate Flags: test-dev ghc-options contain both -fwrite-ide-info and -fno-write-ide-info, and -threaded twice. Global options prepend before stanza overrides. Last occurrence wins so it is functional, but noisy.

Test-Only Deps Leaking into Library: lib-deps.yaml adds hspec/uuid-quasi/ki/pg-transact/aeson-pretty/process to the shared file, silenced by -Wno-error=unused-packages. Accepted given the hpack 0.38 limitation, but it permanently degrades -Wunused-packages signal on the library. Consider a separate hpack-includes/test-dev-extras.yaml with two !include lines in the tests: test-dev: dependencies block — the splice limitation may only affect the library: stanza.

Makefile - tmux Option Namespace: tmux set-option -g @build-pane is machine-global across all sessions. Namespacing as @monoscope-build-pane avoids clobbering other projects.

Positive: lib-deps.yaml dep consolidation is clean and fixes the vector-split drift; tmux_run pane-id tracking is more robust than grepping command names; Int->Int64 for COUNT bigint is correct; doctest pin and haddock additions are good.

@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

Code Review

Overview

Clean dev-loop improvement: the combined lib+test GHCi target (test-dev) and !include-based dep dedup solve real friction points. The IntInt64 fix for COUNT(*)::bigint is a genuine correctness fix that was silently wrong.


Correctness / Bugs

IntInt64 (BackgroundJobs.hs) Correct fix. PostgreSQL COUNT(*)::bigint is always 64-bit; Int happens to be 64-bit on most 64-bit hosts but is not guaranteed by the Haskell standard. The explicit Int64 is right.

headDef 0 stuckJobs (line 703) Good use of Data.List.Extra.headDef over fromMaybe 0 $ listToMaybe — already in-scope via the existing extra import.


Biggest Concern: Test-only Deps Leaked into Library

hpack-includes/lib-deps.yaml includes at the bottom:

# === extras shared with test-dev ===
- hspec
- uuid-quasi
- ki
- pg-transact
- aeson-pretty
- process

These are now declared as explicit library build-depends in the generated monoscope.cabal. The -Wno-error=unused-packages silences GHC, but:

  • Accidental import risk: process, pg-transact, hspec etc. are now importable in production modules with no warning. One stray import would compile silently.
  • ki is redundant: ki-effectful already transitively brings in ki. Adding it explicitly buys nothing and makes it importable directly in prod code.
  • process is a non-trivial dep — the library almost certainly does not need shell process spawning in prod paths.

Suggestion: Keep the shared file as just the pure lib deps and list the 6 test-only extras inline in the test-dev stanza of package.yaml. Still far less duplication than before, and the test-only extras stay test-only:

# package.yaml, test-dev.dependencies:
dependencies: !include hpack-includes/lib-deps.yaml
  # test-only extras:
  - hspec
  - uuid-quasi
  - ki
  - pg-transact
  - aeson-pretty
  - process

This is exactly what the existing integration-tests section already does (lib-include + inline extras) — just move those 6 lines out of lib-deps.yaml back into the test-dev stanza.


Makefile

Tmux pane pinning — Using tmux set-option -wv @build-pane is more robust than grepping for command names. tmux-pin-here / tmux-unpin are a nice ergonomic addition.

TEST_MATCH quoting: The variable is embedded as --match="$(TEST_MATCH)" inside a single-quoted --test string. Shell metacharacters are inert here, but a value containing a literal " would break the inner quoting. Low severity (dev-only), but single-quoting the inner match avoids the edge case.

-osuf dyn_o -hisuf dyn_hi note: These options let ghcid reuse .dyn_o artifacts cabal already wrote. Worth noting in the comment that the first run on a clean checkout still does a full build.


DeriveUtils.hs

The two doc comments on WrappedEnum / WrappedEnumShow are a useful navigability improvement. Minor: 'Just "schema.type"' in the haddock will be interpreted by Haddock as a type-reference link attempt rather than a code span — @Just "schema.type"@ is more consistent.


Summary

Area Assessment
Int64 correctness fix Ship it
headDef cleanup Cleaner
!include dep dedup approach Good idea, implementation has the leak issue
Tmux improvements Better
Test-only deps in library Address before merge
live-test-dev target Useful

The core idea is solid. The main thing worth addressing before merge is keeping the 6 test-only extras out of the library's dep graph — they are importable in prod code with no warning once they are in build-depends.

@claude

claude Bot commented Jun 4, 2026

Copy link
Copy Markdown

Code Review

Overall this is a clean, well-motivated PR. The lib-deps.yaml single-source-of-truth approach, the test-dev unified GHCi target, and the tmux pane-pinning rework are all good ideas.


Factual correction to the existing review comment

The previous review flags four issues — all four are already addressed in this diff:

  • issueCounts/alertCounts/rows Int→Int64 "not fixed" — all are fixed (BackgroundJobs.hs hunks at lines 653, 674, and 754)
  • live-test-dev "missing from .PHONY" — it is present in the updated .PHONY line
  • TEST_MATCH "unquoted" — the diff already uses --match="$(TEST_MATCH)" with inner double-quotes
  • base16-bytestring "duplicated in lib-deps.yaml" — appears exactly once; the duplicate was in the old package.yaml and was cleaned up

Genuine observations

BackgroundJobs.hs — headDef

headDef 0 stuckJobs is a nice simplification over fromMaybe 0 $ listToMaybe. Import from Data.List.Extra alongside the existing chunksOf/groupBy is correct.

lib-deps.yaml — test-only deps leaking into library stanza

The workaround (hspec, uuid-quasi, ki, pg-transact, aeson-pretty, process appearing in the library's declared deps) is documented and silenced by -Wno-error=unused-packages. Fine for an application. One small suggestion: extend the comment to say where a new test-only dep should go, so the next contributor doesn't add it in the wrong place and reintroduce drift.

package.yaml test-dev — proto-lens-protoc absent from build-tools

The generated monoscope.cabal has proto-lens-protoc:proto-lens-protoc in test-dev's build-tool-depends, but it is not listed in the test-dev stanza of package.yaml. If hpack infers it from generated-other-modules that is fine, but worth confirming — if that inference ever stops, the cabal will silently drop the tool dep and proto codegen breaks.

Makefile — log file gitignored?

tee build-test-dev.log creates a new log file. Make sure build-test-dev.log is in .gitignore alongside build.log.


Summary

The Int→Int64 fixes are correct and complete across all affected queries, dep deduplication via !include is the right call, and the Makefile improvements are solid. Main things to confirm before merge: hpack's proto-lens-protoc inference for test-dev, and the .gitignore entry for the new log file.

@tonyalaribe tonyalaribe merged commit 5bac013 into master Jun 4, 2026
9 checks passed
@tonyalaribe tonyalaribe deleted the telemetry-derive-row-instances branch June 4, 2026 14:14
tonyalaribe added a commit that referenced this pull request Jun 4, 2026
After merging master (which added the test-dev stanza in #411), the
auto-generated other-modules list was missing Pkg.Metrics — the stanza
was hpack-generated before this branch's new module existed.
tonyalaribe added a commit that referenced this pull request Jun 4, 2026
…ncy, redactJSON early-exit (#412)

* ingestion: OTel histograms for decode + write phase

Initialises a global MeterProvider in Start.startApp (nested inside the
existing TracerProvider bracket so shutdown order is meter→tracer, both
flushing pending exports via shutdown*Provider). Picks up the same
OTEL_EXPORTER_OTLP_ENDPOINT / headers as traces by default, with the
usual per-signal overrides.

Adds Pkg.Metrics with two top-level NOINLINE instruments
(monoscope.ingest.decode.duration, monoscope.ingest.write.duration, ms)
plus a `timed` helper that brackets the action so latency is recorded
on exception too — useful for the dual-write where a timeout is still
latency we want in the distribution.

ProcessMessage.processMessages now records the decode phase manually
and wraps insertAndHandOff in `timed`.

* Auto-format code with fourmolu

* ingestion: per-partition Kafka group concurrency

Group records by (topic, partition) instead of just topic and process
groups via pooledForConcurrentlyN with a new kafkaGroupConcurrency knob
(default 4). Each tpsFor still yields exactly one TP, so a failed group
only stalls its own partition's commits.

Bound stays well under the hasql pool (shared with web): the failure
mode to avoid is AcquisitionTimeout → Hasql.isTransientException → no
commit → redelivery storm. Single committer (the poll thread) — no
concurrent commitPartitionsOffsets.

* ingestion: symmetric Metrics.timed for decode + write, redactJSON elem idiom

Wraps the decode block in Metrics.timed (replacing manual getMonotonicTime
+ recordMs) so both phases use the same bracket-on-exception path. Drops
the GHC.Clock import.

redactJSON: switches `any T.null ps` to `"" \`elem\` ps` — equivalent but
reads as "have we consumed all path segments?" which matches intent.

Removes TODO.md — belongs in PR/issue tracker, not the repo.

* hpack: pick up Pkg.Metrics in test-dev other-modules

After merging master (which added the test-dev stanza in #411), the
auto-generated other-modules list was missing Pkg.Metrics — the stanza
was hpack-generated before this branch's new module existed.

* queue: use HashMap consistently for byTP + tpsFor, drop Data.Map import

The rest of Pkg/Queue.hs uses HM throughout; (Text, Int32) and Int32
keys are both Hashable, so HashMap is a drop-in. tpsFor's group is
always single-partition, so the map has size 1 — ordering doesn't
matter.

* queue: revert HashMap swap, KP.PartitionId has no Hashable instance

The previous 79bd1bc assumed crPartition was Int32 (Hashable), but
it's KP.PartitionId (Ord-only). Data.Map.Strict was load-bearing, not
an inconsistency. Comment added to prevent the next reviewer from
trying the same swap.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant