Skip to content

Collab#2

Closed
david-tobi-peter wants to merge 5 commits into
masterfrom
collab
Closed

Collab#2
david-tobi-peter wants to merge 5 commits into
masterfrom
collab

Conversation

@david-tobi-peter

Copy link
Copy Markdown
Contributor

No description provided.

Comment thread src/Types.hs
deriving (Generic)
deriving
(PET.Entity)
via (PET.GenericEntity '[PET.TableName "create_project", PET.PrimaryKey "id", PET.FieldModifiers '[PET.StripPrefix "pj", PET.CamelToSnake]] CreateProject)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you have this? There's no create project table.
Instead, you can have a DTO record (Data Transfer Object) for the form, and then convert that into the Project record

-- worked with postgresql-simple as seen in the doc but keeps throwing a type error

createProjectHandler :: CreateProject -> PgT.DBT IO (Maybe (Text, Text, Text)) -> Servant.Handler CreateProject
createProjectHandler project = executeMany q options

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're creating a single Project you don't need execute many

@david-tobi-peter
david-tobi-peter deleted the collab branch January 27, 2022 21:19
This was referenced Dec 24, 2025
@claude claude Bot mentioned this pull request Feb 27, 2026
tonyalaribe added a commit that referenced this pull request May 2, 2026
- docs/cli.md CI/Automation example said `jq '.items | length'` —
  inconsistent with the agentic-workflow section above and broken since
  normalizeList moved everything to `.data`.
- emitFirstEventId now uses `arr V.!? 0` instead of `head (toList arr)`
  — same V.take optimisation as takeFirstEvent, no intermediate list
  allocation.

Bug #2 from the review (renderEventsTable in runEventsContext receiving
raw `val`) is intentional: the table renderer reads `cols`/`logsData`
out of the raw envelope to produce a dense table; the JSON path uses
the named-field `enriched` form. Passing `enriched` to the table
renderer would render an empty table because the normalised shape
doesn't carry `cols`/`logsData`. The split is by design — table mode is
column-oriented, JSON mode is record-oriented.
tonyalaribe added a commit that referenced this pull request May 2, 2026
…ge, dead code

3. normalizeDecoded now emits `null` for missing fields (row shorter
   than colIdxMap) instead of silently coercing to "". Agents can now
   tell "field present but empty" from "field missing".
4. Comment on the --debug setEnv site explaining the single-shot, pre-
   thread-spawn placement (so future readers know it's not a race).
6. emitCompletion lifts to IO once at the entry instead of per-branch.
7. CLIBinarySpec helpCases extended with `facets`, `schema`, `services
   list`, `events {search,context,tail}`, `metrics {query,chart}`,
   `auth login`, `completion` — every top-level subcommand now has a
   --help smoke test.
8. dashboardGetH/dashboardTabGetH: replace appCtx.config.hostUrl with
   bw.config.hostUrl now that mkPageCtx threads config through; appCtx
   binding stays because appCtx.env.apiKeyEncryptionSecretKey isn't on
   bw. dashboardTabContentGetH untouched — no mkPageCtx, no bw.

Style:
- Drop dead extractNumericRows from Pkg.CLIFormat (no callers since the
  metrics path moved to MetricsData).
- Export validateDurationFor so the doctest examples (which reference it)
  resolve at doctest runtime.

Re #2 (parseServiceFacets via FromJSON) and #10 (double blank lines):
already landed in commit 2a54bd0.

Re #5 (renderParams allowlist): keeping the comment-only enforcement.
The CLI doesn't put credentials in query params today (Bearer + project
go via headers), and a type-level distinction would touch every API
helper for a hypothetical leak. The doc note is sufficient guard for
contributor review.
tonyalaribe added a commit that referenced this pull request May 2, 2026
* refactor: extract mkPageCtx page-handler bootstrap

Replaces 25+ inlined BWConfig + sessionAndProject + ask AuthContext
sequences across Pages/* with a single mkPageCtx helper that returns
(Session, Project, BWConfig) seeded with the always-set fields
(sessM, currProject, config). Net: -102 LoC.

* refactor: extract toastError helper for validation/error responses

Collapses the recurrent 'addErrorToast msg Nothing >> addRespHeaders payload'
shape across Pages/Projects.hs and Pages/Dashboards.hs. Net: -5 LoC plus
+5 LoC for the helper and re-export = breakeven, but eliminates a duplicated
two-line pattern at every site.

* refactor: extract withCardFrame for widget renderer card shell

Collapses the duplicated outer flex-wrapper + optional widget header +
flex-1 fill + surface-raised card shell shared between renderLogsWidget,
renderTraceTable, and renderTable into a single helper.

* refactor: derive FieldTypes/FieldCategoryEnum JSON via WrappedEnumSC

Replaces manual ToJSON/FromJSON instances and the parseFieldTypes,
parseFieldCategoryEnum, fieldTypeToText helper functions with a single
deriving-via clause that piggybacks on the existing WrappedEnumSC wrapper.
Net: -50 LoC.

* refactor: distill CLI; reuse server types (Schema, Paged, MetricsData)

Replace ad-hoc AE.Value field-name probing in the CLI with typed parsing
against the server's existing response types so wire-shape changes
surface as compile errors:

- filterSchema now takes Models.Telemetry.Schema.Schema
- normalizeList decodes via Web.ApiTypes.Paged
- metrics renderers/assertion take Pages.Charts.Types.MetricsData

Also: factor validateDurationOrDie/validateAndNormalizeKind helpers,
fold three case-of-OutputMode triplets through renderWith, derive
ServiceRow/ConfigGetJson/AuthStatusJson/TraceSummary JSON via CustomJSON.

* Auto-format code with fourmolu

* docs: add agentic-pipeline showcase to README

Show the discover -> search -> context -> triage chain with the stable
JSON envelope each command exposes, so a reader scanning the README sees
why the CLI is agent-friendly before getting to the Claude Code Skills
section.

* refactor(cli): apply hlint fixes (errors + warnings + suggestions)

Drops 2 errors and 7 warnings from `hlint cli` to 0:
- Resource.hs: `>> pure n` -> `$> n` for the apply-batch counter
- Commands.hs: `ExceptT . pure` -> `hoistEither`; manual `maybe ... Right` -> `maybeToRight`
- Config.hs: `either (const x) id` -> `fromRight x`
- UI.hs: `T.unlines` -> Relude's `unlines`
- Validate.hs: drop redundant `void`

Plus higher-impact suggestions:
- `data` -> `newtype` for ServicesCommand, ConfigGetOpts, ServicesListOpts, FormEditorName
- `fmap (fmap f) x` -> `f <<$>> x` in 6 list/schema/facets handlers
- `Set.singleton` -> Relude's `one`
- `pure ()` -> `pass` in UI event handlers
- `\_ -> action` -> `const action`
- `(\c -> Map.lookup c idxMap)` -> `(`Map.lookup` idxMap)`

Build green: `All good (8 modules)`. The two remaining hlint hints
(`Data.Set as Set` alias, `universe` import) belong in `.hlint.yaml`
rather than the code.

* fix(test): unwrap IssueL through .base.id in ErrorPatternsSpec

IssueL is a list-view wrapper around Issue (`{ base :: Issue, ... }`),
so the `id` field is reached through `.base`. Four sites in
ErrorPatternsSpec called `issue.id` directly, which type-errored after
IssueL gained its current shape. Matches the pattern used in
src/Pages/Anomalies.hs (`errL.base.id`).

* fix(cli): accept uppercase --since suffixes (1H, 24H)

The platform's TimePicker emits uppercase ("1H", "24H") — the same
strings the CLI itself injects as defaults via buildSearchParams /
runServicesList — but the validator only accepted lowercase, so a user
who copy-pasted the displayed default got rejected client-side. Fold
the suffix to lowercase before checking the whitelist; preserve
original casing in the returned value.

Add a regression test in CLIE2ESpec asserting `--since 1H` is accepted.

* fix(cli): four review nits — flag-aware duration error, single decode, doc/comment fixes

1. validateDurationOrDie now takes the flag name, so --window failures
   read "--window must match …" instead of "--since must match …".
   Three call sites updated (--since x2, --window x1).

2. aggregateServices keeps its `Map.lookup "service"` but with a comment
   pinning the contract: the server aliases resource___service___name to
   the short "service" column in colIdxMap (Pages.LogExplorer.Log.allCols).
   Added an e2e regression in CLIE2ESpec that asserts services-list still
   returns {services, count} so a column rename can't silently zero the
   output.

3. docs/cli.md agentic-incident-workflow: replace .items[] with .data[]
   in the issues-list and log-patterns-list jq pipes — they'd break
   against the now-normalised list envelope.

4. runEventsContext --summary used to walk logsData twice (once in
   normalizeEventsResponse, once in withTraceSummary). Introduce a
   `DecodedEvents` record that carries idxMap/rows/raw, decode once at
   the call site, and thread it through both functions.

* perf(cli): back services list with /api/v1/facets instead of 10k-event scan

Previously runServicesList fetched up to 10,000 events and aggregated
client-side because /api/v1/metrics returned empty for `summarize ... by`.
The facets endpoint (precomputed in apis.facet_summaries via a background
job) is one indexed lookup — sub-millisecond regardless of project size.

- Drop the events-scan fallback; switch to GET /api/v1/facets?field=resource.service.name
- ServiceRow loses the `last_seen` field (facets don't track per-value
  recency). The remaining {name, events} is what the use-case actually
  needs ("what services exist? how busy are they?").
- e2e regression in CLIE2ESpec already covers the {services, count}
  envelope; comment updated to pin the facets-backed contract.
- docs/cli.md and monoscope-skills/README.md output-shape tables drop
  last_seen.

* chore: trailing review nits — unused asks, V.take, normaliseList warning, debug-comment

Server side:
- dashboardsGetH: drop the appCtx ask; bw.config.liveReloadDashboards
  carries the flag now that mkPageCtx threads config through.
- teamAlertsGetH: drop appCtx + sess + project, all genuinely unused
  bindings.

(dashboardGetH / dashboardTabGetH / dashboardTabContentGetH /
unifiedMonitorOverviewH still bind appCtx — they read appCtx.env.* which
isn't on bw.config, so the binding is required.)

CLI:
- takeFirstEvent: V.take 1 arr instead of take 1 (toList arr); avoids the
  Vector→List→Vector round-trip.
- Resource.normalizeList split into normalizeListE returning Either, with
  Left carrying the raw payload on shape mismatch. runList now flags the
  unrecognised case via printDebug so contributors see when the server
  envelope drifts.
- Core.renderParams: comment pinning the "debug-only, NOT URL-encoded,
  redact if you ever pass auth via query params" contract.

* fix(cli): CI doc uses .data, emitFirstEventId avoids list round-trip

- docs/cli.md CI/Automation example said `jq '.items | length'` —
  inconsistent with the agentic-workflow section above and broken since
  normalizeList moved everything to `.data`.
- emitFirstEventId now uses `arr V.!? 0` instead of `head (toList arr)`
  — same V.take optimisation as takeFirstEvent, no intermediate list
  allocation.

Bug #2 from the review (renderEventsTable in runEventsContext receiving
raw `val`) is intentional: the table renderer reads `cols`/`logsData`
out of the raw envelope to produce a dense table; the JSON path uses
the named-field `enriched` form. Passing `enriched` to the table
renderer would render an empty table because the normalised shape
doesn't carry `cols`/`logsData`. The split is by design — table mode is
column-oriented, JSON mode is record-oriented.

* fix(cli): six review items — agent-mode truthy check, --first table parity, single decode, derived facets, forall pinning

3. isAgentMode no longer fires on `CI=` (empty) or `CI=false` — many dev
   shells export CI unconditionally; treat empty/"false"/"False"/"FALSE"/"0"
   as off.
4. --first parity in table mode: takeFirstRow trims the raw envelope's
   logsData to one row, so table output matches the JSON path's
   takeFirstEvent slice instead of silently dumping all rows.
5. Free-floating Haddock above DecodedEvents merged into the actual
   docstring (the orphan would have triggered a -Wmissing-signatures-ish
   warning eventually).
6. runEventsSearch now decodes once and threads DecodedEvents through
   normalizeDecoded, matching the pattern in runEventsContext. No more
   double walk of logsData on the JSON path.
7. parseServiceFacets decodes via Models.Apis.Fields.FacetValue
   (FromJSON via DAE.CustomJSON) — drops 6 lines of hand-rolled
   KM.lookup/AE.String/AE.Number unpacking and surfaces server wire
   changes at compile time.
8. withMetricsData now forwards aeson's Error message through
   printDebug so a server envelope drift is visible under --debug
   instead of vanishing into the raw-JSON fallback.

Plus: explicit `forall es a b` on apiGetJson/apiPostJson/apiPutJson/
apiPatchJson so TypeApplications at call sites
(`apiPostJson @_ @_ @AE.Value`) survive future constraint reordering by
fourmolu/hlint. Without this, alphabetical resort of
`(AE.FromJSON b, AE.ToJSON a, Environment :> es, ...)` flips the
implicit type-var order and the third `@AE.Value` lands on `es` instead
of the body type.

Run fourmolu over the touched files; #10 (double blank lines) is
auto-fixed.

* chore: round-three review nits — null instead of "", helpCases coverage, dead code

3. normalizeDecoded now emits `null` for missing fields (row shorter
   than colIdxMap) instead of silently coercing to "". Agents can now
   tell "field present but empty" from "field missing".
4. Comment on the --debug setEnv site explaining the single-shot, pre-
   thread-spawn placement (so future readers know it's not a race).
6. emitCompletion lifts to IO once at the entry instead of per-branch.
7. CLIBinarySpec helpCases extended with `facets`, `schema`, `services
   list`, `events {search,context,tail}`, `metrics {query,chart}`,
   `auth login`, `completion` — every top-level subcommand now has a
   --help smoke test.
8. dashboardGetH/dashboardTabGetH: replace appCtx.config.hostUrl with
   bw.config.hostUrl now that mkPageCtx threads config through; appCtx
   binding stays because appCtx.env.apiKeyEncryptionSecretKey isn't on
   bw. dashboardTabContentGetH untouched — no mkPageCtx, no bw.

Style:
- Drop dead extractNumericRows from Pkg.CLIFormat (no callers since the
  metrics path moved to MetricsData).
- Export validateDurationFor so the doctest examples (which reference it)
  resolve at doctest runtime.

Re #2 (parseServiceFacets via FromJSON) and #10 (double blank lines):
already landed in commit 2a54bd0.

Re #5 (renderParams allowlist): keeping the comment-only enforcement.
The CLI doesn't put credentials in query params today (Bearer + project
go via headers), and a type-level distinction would touch every API
helper for a hypothetical leak. The doc note is sufficient guard for
contributor review.

* fix(cli): trace-summary error count, KQL injection guard, small wins

Core bug:
- withTraceSummary used `cell "severity"` to count errors per trace, but
  the events colIdxMap (Pages.LogExplorer.Log.allCols) doesn't expose a
  "severity" column — only the boolean "errors" flag. Result: every
  trace summary reported error_count=0 regardless of traffic. Now reads
  cell "errors" and treats "true" as 1. Also added a defensive fallback
  for service ("service" <|> "resource.service.name") in case a future
  column-set rename hides the alias.

KQL safety:
- runEventsGet escapes `\` and `"` in opts.eventId before splicing into
  the query string. Event IDs aren't UUIDs (synthetic-… span ids,
  log_pattern integers, …) so format validation is wrong; escaping
  defends against injection regardless of shape.

Small wins:
- isAgentMode: fold suffix to lowercase once via `map toLower v` rather
  than enumerating "false"/"False"/"FALSE".
- filterSchema: `Map.take n filtered` instead of
  `Map.fromList (take n (Map.toList filtered))` (containers ≥ 0.6.3).

Doctests note:
- The earlier "doctest comment" the review flagged was already removed
  in a prior commit. Pure validators are still covered end-to-end via
  CLIE2ESpec ("--since 1xyz", "--kind banana") which exercise the real
  binary. Wiring CLI/* into the lib doctest target would need moving
  the modules into src/ — out of scope for this round.

Pushed back:
- AuthStatus method ADT: the strings "env"/"token" appear in two
  adjacent lines of one function. A two-constructor ADT + custom ToJSON
  is more boilerplate than the leak it prevents (no other consumer).
- Map merge tuple readability: a record would cost two lines and one
  data declaration to save zero compile errors. The merge fits on one
  line; leaving it.

* chore: clarify intent — `mempty` empty bodies, capFacets exhaustiveness comment

- Pages/Projects.hs: replace seven `toastError "…" ""` and three
  `addRespHeaders ""` with `mempty`. Reads as "no body" rather than
  "empty string body" — the underlying type is `Html ()` whose Monoid
  identity is the empty Html, same wire effect.
- cli/Main.hs `capFacets`: comment on the trailing wildcard clause so
  the (Just n) + non-Object fallthrough is explicitly documented vs the
  Nothing case the first clause already handles.

Re facets in CLIBinarySpec helpCases: already added in 76ebf71.

* chore: clear hlint warnings across src/

BackgroundJobs.hs: 6× displayException + 2× fromException were
resolving to Control.Exception.* (because the file did
`import Control.Exception (ErrorCall (..))` which exposed the
Control.Exception namespace to GHC's resolver and tripped
.hlint.yaml's "use Relude version" rule). Drop the unqualified
import; ErrorCall now goes through `Control.Exception qualified as CE`
so the only `Control.Exception` reference is the explicit qualifier
and unqualified displayException/fromException resolve through Relude.

Pages.Anomalies.hs:
- NE.head -> head (Relude)
- two whenJust lambdas -> point-free (toHtml composition)
- when (... `notElem` ...) -> unless (... `elem` ...)

Pages.Settings.hs: sortOn fst -> sortWith fst (no caching needed for
projection on first component).

Pages.Telemetry.hs: MapS.singleton k v -> one (k, v) (Relude polymorphic
container constructor).

Pages.LogExplorer.Log.hs: two `\j -> (j, x)` lambdas -> tuple sections
(TupleSections is part of GHC2024, already on).

Verified clean: `hlint src/BackgroundJobs.hs src/Pages/Anomalies.hs
src/Pages/Settings.hs src/Pages/Telemetry.hs src/Pages/LogExplorer/Log.hs`
reports "No hints".

* Auto-format code with fourmolu

* fix(cli): forward Paged decode error, lenient body decode, unambiguous null

3. normalizeListE now returns Either (rawValue, reason) — when an Object
   fails @PageD@ decoding the aeson Error message is captured and
   surfaced through runList's --debug log. Contributors see *what*
   shape changed instead of a generic "did not match envelope".
   normalizeList stays pure with `either fst id . normalizeListE`.

4. httpExToError now uses TE.decodeUtf8With lenientDecode for both the
   status reason and the response body. The body field of
   StatusCodeException is the truncated raw bytes (≤1024B) and may be
   gzip leftovers, HTML, or arbitrary upstream junk; strict decodeUtf8
   would throw at the error-handling boundary, masking the real HTTP
   failure with a UnicodeException.

6. isAgentMode: replace `not (null v)` with `v /= ""` to dodge the
   Prelude.null vs Relude container-null ambiguity. v is String here.

Re prior style notes:
- Double blank lines between top-level bindings: produced by fourmolu
  format pass; project convention is enforced by the formatter.
- AuthStatusJson / ConfigGetJson: kept as records — the CamelToSnake
  derivation pins the wire shape (an inline AE.object [...] silently
  drifts when fields are added).
- runConfigGet OutputMode asymmetry vs init/set: noted; init takes no
  output path (interactive form) and set has no payload to format.
  Follow-up if it surfaces in user feedback.
- normalizeList = either fst id . normalizeListE (was either id id;
  shape changed when Left started carrying the reason).
- CLI/UI.hs `currentValue = T.strip . unlines . BE.getEditContents`:
  verified — `unlines` here is the Relude re-export, which is polymorphic
  over the IsList/Foldable instance. Compiles clean.

* fix(test): unwrap IssueL through .base.issueType in AnomaliesSpec

Same pattern as the ErrorPatternsSpec fix in f0ab87d: IssueL wraps
Issue in `base`, so the issueType field lives at `c.base.issueType`,
not `c.issueType`.

* fix(test): add http-types to integration-tests build-depends

CLIE2ESpec imports Network.HTTP.Types.Status (statusCode) for the
reachability probe but http-types wasn't on the test target's deps.
The library has it (line 173), the test suite didn't inherit it.

* fix(test): drop System.Environment lookupEnv import — Relude already exports it

* fix(cli/test): try @someexception → tryAny, plus seven review nits

Build break: UnliftIO.Exception.try's forall is (m, e, a); the @someexception
TypeApplication landed on m and tripped a kind error. Switch to tryAny
(MonadUnliftIO m => m a -> m (Either SomeException a)) — same semantics,
no type-arg juggling. Drops the redundant Data.List (isInfixOf) import
along the way (Relude already has it).

Review items:
- AuthStatus: extract printStatus helper for the env/token branches —
  3 lines repeated → 1 helper.
- apiFacets: replace addUTCTime (-86400) with negate nominalDay (Data.Time
  re-export). No more 86400-second magic.
- capFacets: drop the now-redundant `Nothing` clause; the wildcard at the
  end already covers it (and `Just n` + non-Object).
- parseDurationMs: T.toLower the input via a view pattern so --watch 5M
  is treated like --watch 5m, matching validateDurationFor's case-insensitive
  suffix check.
- reqOpts: collapse the broken multi-line `& W.header "Accept" .~ [...]`
  formatter artifact into a single parenthesised line so subsequent `&`
  chain elements align under W.defaults.
- Resource.runList: route the unrecognised-envelope reason through
  printError (always-on stderr) instead of printDebug — agents
  expecting {data, pagination} need to see when the server returns
  something else.
- DecodedEvents: decode count / has_more / cursor at construction
  instead of carrying the raw KeyMap. Three lookups eliminated, intent
  is local to decodeEvents.

Re minor nits noted:
- isAgentMode/isDebugMode re-read env on each call: kept; called at
  most a handful of times per invocation, no hot path.
- Data.Char (toLower): kept the explicit import — Relude does re-export
  it but the explicit form documents which `toLower` we mean (vs
  Data.Text.toLower which operates on Text).

* fix(test): restore Data.List (isInfixOf) — Relude does not re-export it

* fix(test+ci): two CLI test failures, default e2e suite to the public demo project

CI failures:

1. CLIBinarySpec "auth status exits and shows status message" — when CI
   is set, isAgentMode auto-enables and `auth status` emits the JSON
   envelope ({authenticated, method, api_url, project}). The test
   predicate only matched plain-text "Not authenticated" / "Authenticated".
   Extend it to also accept the JSON shape ("authenticated" key).

2. CLIBinarySpec "completion --help" exited 1. The completion subparser
   declared a positional SHELL argument but didn't attach `<**> helper`,
   so `--help` got consumed as the SHELL value and fell through to the
   "unknown shell" branch. Adding helper makes optparse intercept --help
   and emit usage with exit 0.

Default e2e suite to prod demo project:

CLIE2ESpec.getE2EConfig now defaults @MONOSCOPE_API_URL@ to
https://api.monoscope.tech and @MONOSCOPE_PROJECT@ to the public demo
00000000-0000-0000-0000-000000000000. Only @MONOSCOPE_API_KEY@ has no
safe default (read keys for other projects would leak). The pendingWith
message names the missing variable specifically so it's obvious how to
unlock the suite.

Wired up in CI: pullrequest.yml's integration-tests step now reads
MONOSCOPE_API_KEY from secrets.MONOSCOPE_DEMO_API_KEY. Repo owner needs
to mint a read-only key on the demo project and store it in repo
secrets — then every PR/push runs the suite against prod. Forks (no
secret) still get the CLIBinarySpec smoke tests.

docs/cli.md updated with the new default-driven workflow.

* fix(test): assert specific merge edge instead of fragile global count

ErrorPatternsSpec test 12 ("Full LLM pipeline") asserted
`length mergedTypeErrors == 1` after merging one (childId, canonId)
pair. The query counted ALL TypeError patterns with canonical_id set
across the project, so any earlier test that merged a TypeError made
the count drift up. CI now sees 2 because some upstream change in the
LLM/notify pipeline produced an additional pre-merged pattern by the
time test 12 runs.

Switched to a behaviour-level assertion: query the specific childId's
canonical_id and require it equals canonId. This tests what
`assignErrorsToCanonical` actually does, with no dependence on the
global state earlier tests left behind.

* refactor(cli): lens-based shape ops, guards, precomputed indices

- takeFirstEvent / takeFirstRow rewritten with Data.Aeson.Lens
  (`AL.key … . AL._Array %~ V.take 1`). 14 lines of pattern-match-and-
  reinsert collapsed to two one-liners. AL is qualified to avoid
  collision with the `key` record fields on ConfigSet/GetOpts.
- foldFiltersIntoQuery: case (T.null …, T.null …) → pattern guards.
  Reads top-down instead of as a tuple-match puzzle.
- normalizeListE: AEKM.member → has (AL.key …) lens accessor; the
  branch matches on the value directly, no need to destructure
  AE.Object obj first.
- extractColIdxMap: round → floor on the Scientific. Column indices are
  already-integral non-negative ints; floor documents that intent and
  drops banker's rounding semantics that don't apply here.
- parseDurationMs: drop the bare-number-as-seconds fallback. validateDurationFor
  rejects unsuffixed values upstream, so the only paths that reach
  parseDurationMs have a recognised suffix; a typo now returns the
  5s default loudly instead of silently treating "5" as five seconds.
- runMetricsChart: validateDurationOrDie "--watch" before entering the
  forever loop, so a bad --watch string fails at flag parse rather
  than burning HTTP requests every 5s.
- withTraceSummary: precompute svcIdx / errIdx / tidIdx once instead
  of re-Map.lookup'ing the same column path per row. Saves one Map
  lookup per cell per row — measurable on large
  `events context --summary` payloads.

Build deps: cli exe gains `lens-aeson` (already in lib deps for the
server's Data.Aeson.Lens usage). hpack regenerated monoscope.cabal.

---------

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.

2 participants