Commit Graph

2881 Commits

Author SHA1 Message Date
Claudio Ortolina 9c7ab5b229 Add Claude Code hooks, commands, and permissions
High priority:

- Auto-format on edit (.claude/hooks/format-elixir.sh): runs mix format
  synchronously after every Edit/Write on .ex, .exs, and .heex files.
  Ensures code is formatted before the next read or tool call.

- mix test permissions: added Bash(mix test) (bare) and Bash(mix test *)
  (with path/flags) to the allow list. Previously only Bash(mix test:*)
  was allowed, which didn't match common invocations.

- Slash commands: /precommit runs the full mix precommit pipeline and
  reports failures with fix suggestions. /oban-status queries Oban job
  state via Tidewave SQL, grouped by state and worker.

Medium priority:

- Chrome DevTools permissions: added 8 new tools (select_page,
  list_network_requests, get_network_request, list_console_messages,
  get_console_message, hover, press_key, wait_for) for debugging API
  traffic, JS hook errors, hover states, and keyboard navigation.

- Gettext extraction hook (.claude/hooks/gettext-extract.sh): runs
  mix gettext.extract --merge asynchronously after editing .heex files.
  Async because it's project-wide and doesn't need to block the next edit.

- Sobelow permission: added Bash(mix sobelow:*) to the allow list for
  independent security checks.
2026-04-12 09:54:32 +01:00
Claudio Ortolina e498dccde5 Provide sqlite3 console command
- Loads extensions
- Wraps with rlwrap for convenience
2026-04-12 07:36:07 +01:00
Claudio Ortolina ea9886a647 Update Erlang to 28.4.2 2026-04-12 07:16:14 +01:00
Claudio Ortolina 02761428c1 Format map and list query params as JSON 2026-04-11 23:57:40 +01:00
Claudio Ortolina a983698c72 Document SQLite query optimization conventions 2026-04-11 23:46:23 +01:00
Claudio Ortolina 1c8d63c4d7 Bump Docker image versions in production docs 2026-04-11 23:46:06 +01:00
Claudio Ortolina 754a71cf70 Update dependencies
igniter 0.7.8 => 0.7.9
2026-04-11 23:39:00 +01:00
Claudio Ortolina d8c84e787b Optimize ListeningStats query performance
Three independent refactors of lib/music_library/listening_stats.ex,
measured against the dev DB (104k tracks) via bench/listening_stats.exs:

| Query                           | Baseline  | After     | Speedup |
|---------------------------------|-----------|-----------|---------|
| recent_activity(tz, 100)        | 38.98 ms  | 2.87 ms   | 13.6x   |
| list_tracks(page 1, 200)        | 47.30 ms  | 4.81 ms   | 9.8x    |
| get_top_artists_by_days(7)      | 66.51 ms  | 1.02 ms   | 65x     |
| get_top_artists_by_days(30)     | 67.41 ms  | 2.84 ms   | 23.7x   |
| get_top_artists_by_days(365)    | 76.03 ms  | 25.57 ms  | 3.0x    |
| get_top_albums_by_days(7)       | 92.63 ms  | 1.61 ms   | 57.5x   |
| get_top_albums_by_days(30)      | 94.52 ms  | 3.69 ms   | 25.6x   |
| get_top_albums_by_days(365)     | 105.23 ms | 32.81 ms  | 3.2x    |
| get_top_artists(limit: 10)      | 123.96 ms | 101.68 ms | 1.22x   |
| get_top_albums(limit: 10)       | 209.64 ms | 108.23 ms | 1.94x   |

tracks_with_record_info_query/0 now uses correlated scalar subqueries
against record_releases and artist_records instead of materializing
helper subqueries on every call. The cost scales with the outer LIMIT,
not with the size of record_releases.

top_albums_base_query/0 and top_artists_base_query/0 are replaced by
aggregate_query + attach_metadata pairs. The pattern is aggregate first,
attach metadata second: GROUP BY runs against the raw track scan, then
a tiny outer SELECT attaches record_releases / artist_infos lookups for
the <= 10 result rows via correlated subqueries.

tracks_since_query/1 wraps the date-filtered inner scan with limit: -1.
SQLite cannot flatten a subquery that has a LIMIT, so it materializes
the date-bounded subset and the optimizer uses the timestamp index for
the range scan instead of the album/artist composite index. This trick
replaces SQLite's WITH ... AS MATERIALIZED (which ecto_sqlite3 doesn't
expose).

All json_extract(?, '\$.path') fragments use the canonical form rather
than the equivalent ? ->> '\$.path' shorthand. SQLite's index matcher
requires the GROUP BY expression to match the index expression
textually to use the composite index for natural ordering.

collected_releases_query/0 and wishlisted_releases_query/0 are removed
from Collection and Wishlist — they had a single internal caller that
no longer exists after the refactor.

New regression tests lock the semantics that the optimized queries
must preserve:
- count(DISTINCT scrobbled_at_uts) — 579 duplicate timestamps exist in
  the dev DB from rapid Last.fm scrobbles, so replacing with count(*)
  would silently change results
- :artist_id key in list_tracks result maps — ScrobbledTracksLive.Index
  destructures it even though the template body never references it

Closes #148
2026-04-11 23:36:32 +01:00
Claudio Ortolina d3da4e4559 Update architecture docs for embedding ownership 2026-04-11 21:48:59 +01:00
Claudio Ortolina 839566dd63 Update dependencies
igniter 0.7.7 => 0.7.8
2026-04-11 21:46:07 +01:00
Claudio Ortolina 82e4882aa9 Assert embedding enqueues in batch test 2026-04-11 21:43:00 +01:00
Claudio Ortolina ea6ecb2661 Assert embedding enqueues in artist info test 2026-04-11 21:43:00 +01:00
Claudio Ortolina 3da0865725 Drop Records embedding wrappers 2026-04-11 21:43:00 +01:00
Claudio Ortolina a608be7387 Move regenerate_artist_embeddings into Similarity 2026-04-11 21:43:00 +01:00
Claudio Ortolina 789ce04b87 Use MusicBrainz.get_all_releases in Records 2026-04-11 21:40:32 +01:00
Claudio Ortolina b7af9557c1 Add MusicBrainz.get_all_releases/1 2026-04-11 21:40:32 +01:00
Claudio Ortolina 755955df54 Update elixir to 1.20.0-rc.4 2026-04-10 23:12:51 +01:00
Claudio Ortolina 2422b6a243 Update dependencies
credo 1.7.17 => 1.7.18
2026-04-10 23:10:09 +01:00
Claudio Ortolina fcf5adde2f Add tests for QueryReporter 2026-04-10 11:10:12 +01:00
Claudio Ortolina 8826834549 Fix release status badge in grouped records on this day
The tooltip was using the group representative instead of the
actual record, causing all items in a group to show the same
badge regardless of their own selected_release_id.
2026-04-10 10:38:48 +01:00
Claudio Ortolina 90a0491924 Update architecture docs with QueryReporter 2026-04-10 10:31:21 +01:00
Claudio Ortolina 1c720c8394 Add query timing metadata to reporter output 2026-04-10 10:30:05 +01:00
Claudio Ortolina 27148c6507 Add dev query reporter and skill
Ecto telemetry reporter that captures executed SQL queries
to a log file with interpolated parameters and source
locations. Activated/deactivated at runtime via Tidewave
for LLM-driven query analysis workflows.
2026-04-10 10:27:12 +01:00
Claudio Ortolina b5686fa0f9 Allow creating a new page with chrome devtools 2026-04-10 09:14:27 +01:00
Claudio Ortolina eab5ec5ac1 Remove localhost URL from README (because port changes) 2026-04-10 07:49:42 +01:00
Claudio Ortolina 2c393db0f2 Add visual verification guidance to ui-framework skill 2026-04-10 07:45:22 +01:00
Claudio Ortolina 31ebfe41ed Allow use of Chrome Devtools for verification 2026-04-10 07:30:52 +01:00
Claudio Ortolina 3fb292ce35 Improve update-documentation skill
Add parallel analysis via subagents, skip-list for irrelevant
commits, format-matching guidance, and wider trigger description.
2026-04-09 16:27:49 +01:00
Claudio Ortolina f92a41241f Improve ui-framework skill with project conventions
Add project-specific UI checklist, component organization,
LiveView structure, toast patterns, and routing conventions
above the usage-rules managed section. Widen trigger description.
2026-04-09 16:24:35 +01:00
Claudio Ortolina 3e80de32b3 Improve update-dependencies skill
Adds context about dependency categories, major version bump
assessment, bulk vs selective update options, asset build
verification, and commit message conventions.
2026-04-09 16:18:16 +01:00
Claudio Ortolina eeb0763466 Deduplicate and consolidate project docs
Remove redundant sections from production-infrastructure.md that
duplicated architecture.md (Oban queues/plugins/cron, external API
integrations, SQLite extensions, scheduled maintenance). Absorb API
rate limits into architecture.md's integration table. Replace tool
versions table with pointer to mise.toml. Add two conventions from
project history: scoped test setup and single-path shared components.
2026-04-09 15:19:32 +01:00
Claudio Ortolina 67c01ab1fa Update architecture and infrastructure docs 2026-04-09 15:09:32 +01:00
Claudio Ortolina a8d6db69ec Update fine 0.1.5 to 0.1.6 2026-04-09 14:47:58 +01:00
Claudio Ortolina e2f376b423 Enable Fluxon private repo for dependabot 2026-04-09 10:43:04 +01:00
Claudio Ortolina 56b281c696 Ignore path-based NPM dependency in dependabot 2026-04-09 10:35:19 +01:00
Claudio Ortolina c048054956 Enable dependabot for Elixir and NPM packages 2026-04-09 10:28:47 +01:00
Claudio Ortolina c833149fa4 Use dependabot for docker image updates 2026-04-09 07:33:19 +01:00
Claudio Ortolina 431af98e72 Use precise litestream image version 2026-04-09 07:26:47 +01:00
Claudio Ortolina e34e06ee6f Add review and audit principles to conventions 2026-04-09 07:23:01 +01:00
Claudio Ortolina 6a60fe1860 Add benchmark for collection count functions 2026-04-09 07:05:06 +01:00
Claudio Ortolina 59937dadb8 Remove duplication around searching scrobbled tracks
Fixes #157
2026-04-09 06:57:24 +01:00
Claudio Ortolina 49d26e1fd0 Switch the release component to a form to enable recovery 2026-04-08 18:22:44 +01:00
Claudio Ortolina d406e98fce Use message index for chat DOM ids 2026-04-08 12:42:01 +01:00
Claudio Ortolina d691b1b432 Fix encoding of past messages in LLM request 2026-04-08 12:34:45 +01:00
Claudio Ortolina 91931e649c Remove experimental comment (approach works)
Closes #162
2026-04-08 06:52:31 +01:00
Claudio Ortolina 1cfd91278b Use correct api_cooldown for OpenAi.API tests 2026-04-07 10:07:48 +01:00
Claudio Ortolina 8734df127c Update dependencies
fine 0.1.4 => 0.1.5
2026-04-06 22:14:04 +01:00
Claudio Ortolina edc4e51d1d Optimize record set compaction
Closes #154
2026-04-06 18:38:56 +01:00
Claudio Ortolina 2609adbf84 Address Lumis api deprecation 2026-04-06 10:27:13 +01:00
Claudio Ortolina fcd9a17211 Update dependencies
fluxon 2.3.5 => 2.3.6
lumis 0.2.0 => 0.3.0 (minor)
mdex 0.12.0 => 0.12.1
2026-04-06 08:56:16 +01:00