Fix stale references in backend expert agents and module-conventions skill (#83658)
- backend-module-conventions: the retire-a-changeset precedent cited a nonexistent id (v59.2026-07-10T22:29:18). Point at the two real precedents and describe both placements they show (same file, same release vs. a later release retiring an older one). Drop the last em-dash. - modules-backend-expert: description path is .clj-kondo/config/modules/config.edn. - platform-backend-expert: run kondo hook tests through bin/test-agent (they are on the dev classpath) instead of raw clj -X:dev:test, which CLAUDE.md says not to use. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: modules-backend-expert
|
||||
description: "Metabase backend expert for module structure: `config/modules/config.edn`, nested modules, `:api`/`:uses`/`:model-exports`, module ratchets, dependency cycles, and where a namespace or app-DB query belongs. Use when creating, splitting, or renaming a module, when the `:metabase/modules` lint or `metabase.core.modules-test` fails, or when choosing `.core` vs `.db` vs internal placement. Not for the feature inside a module (use the domain expert)."
|
||||
description: "Metabase backend expert for module structure: `.clj-kondo/config/modules/config.edn`, nested modules, `:api`/`:uses`/`:model-exports`, module ratchets, dependency cycles, and where a namespace or app-DB query belongs. Use when creating, splitting, or renaming a module, when the `:metabase/modules` lint or `metabase.core.modules-test` fails, or when choosing `.core` vs `.db` vs internal placement. Not for the feature inside a module (use the domain expert)."
|
||||
model: opus
|
||||
memory: project
|
||||
skills:
|
||||
|
||||
@@ -49,7 +49,7 @@ All OSS, under `src/metabase/` unless noted.
|
||||
## How to work
|
||||
|
||||
1. Migrations: follow the "Add app-DB migrations as one file per change" section of the `backend-module-conventions` skill (file layout, IDs, backports, scoped preconditions). Copy the shape of a recent file in the newest dir. Run `bin/lint-migrations-file.sh`. Test with the `test-migrations` macro (`metabase.app-db.schema-migrations-test.impl`); `metabase.app-db.schema-migrations-test` and `metabase.app-db.custom-migrations-test` have examples.
|
||||
2. Guards and lint: run `metabase.app-db.value-guard-test`, `metabase.app-db.query-test`, and `hooks.metabase.toucan.db-ns-test` (run kondo hook tests with `clj -X:dev:test:test/kondo`). A hook change alters lint output for every module, so run `./bin/mage kondo-ratchets` after it.
|
||||
2. Guards and lint: run `metabase.app-db.value-guard-test`, `metabase.app-db.query-test`, and `hooks.metabase.toucan.db-ns-test` (kondo hook tests are on the dev classpath, so `./bin/test-agent :only '[hooks.metabase.toucan.db-ns-test]'` works; `:only '[".clj-kondo/test"]'` runs all of them). A hook change alters lint output for every module, so run `./bin/mage kondo-ratchets` after it.
|
||||
3. Middleware and server: read the stack in `metabase.server.handler`, then the one middleware. Tests live in `test/metabase/server/` (`handler-test`, `streaming-response-test`, `middleware/`).
|
||||
4. API framework: run `metabase.api.macros-test` and `metabase.api.open-api-test`. A change to `defendpoint` touches every endpoint, so also load a few `*.api` namespaces.
|
||||
5. Settings: run `metabase.settings.models.setting-test`. Check the env-var override and visibility, not only the DB path.
|
||||
|
||||
@@ -65,7 +65,7 @@ The docstring of `metabase.app-db.value-guard` explains what the guard refuses w
|
||||
|
||||
- Starting with v60, each change is its own file at `resources/migrations/<NNN>/<yyyyMMdd>_<snake_name>.yaml`. `NNN` is the earliest release the change ships in. New work goes in the newest directory. Don't add to `001_update_migrations.yaml`; its footer describes the legacy format.
|
||||
- Changeset IDs are `v<NN>.<unique suffix>`, where `NN` matches the directory. The suffix can be a timestamp from `(dev/migration-timestamp)` or any unique string. IDs are not ordered within a directory.
|
||||
- Don't edit a shipped changeset. Add a new one. (Liquibase does recompute checksums and some edits are technically harmless, but the line between "cosmetic" and "ran instances now diverge from fresh installs" is easy to misjudge — just add a new changeset.) Never delete a shipped changeset either: instances keep the row in `DATABASECHANGELOG` forever; removing the id makes Liquibase log "not rolled back" and any replacement that recreates the same object fails with a duplicate-object error. To retire one when you must, append a NEW same-version-id changeset to the SAME yaml file that does `DELETE FROM DATABASECHANGELOG WHERE id IN (...)` the retired ids. Precedent: `059_update_migrations.yaml::v59.2026-07-10T22:29:18`.
|
||||
- Don't edit a shipped changeset. Add a new one. (Liquibase does recompute checksums and some edits are technically harmless, but the line between "cosmetic" and "ran instances now diverge from fresh installs" is easy to misjudge, so just add a new changeset.) Never delete a shipped changeset either: instances keep the row in `DATABASECHANGELOG` forever; removing the id makes Liquibase log "not rolled back" and any replacement that recreates the same object fails with a duplicate-object error. To retire one when you must, add a NEW changeset that does `DELETE FROM DATABASECHANGELOG WHERE id IN (...)` the retired ids. Put it in the same file as the retired changeset when it ships in the same release (`063/20260714_field_fk_target_field_id_fk.yaml::v63.2026-07-22T12:00:00`), or in the current release's file when it retires an older release's changeset (`059_update_migrations.yaml::v59.2026-01-09T11:30:00` retires `v58.2026-01-09T12:00:00`).
|
||||
- To backport, copy the changesets into the older directory with `v<older>` IDs. Guard each copy with `preConditions: onFail: MARK_RAN` plus `not: changeSetExecuted` that points at the newer ID, so databases that already ran it skip it. `resources/migrations/064/20260911_glossary_entity_id.yaml` shows the pattern.
|
||||
- Give every `indexExists`, `primaryKeyExists`, and `uniqueConstraintExists` precondition a `tableName`, and every `foreignKeyConstraintExists` a `foreignKeyTableName`. Without it, Liquibase snapshots the whole schema, which takes seconds per check.
|
||||
- Prefer SQL changesets. A custom migration (`metabase.app-db.custom-migrations`, `define-migration` / `define-reversible-migration`) must use table names, never `:model/*` or other application code. Application code changes later, and then the migration breaks. Decrypt encrypted columns such as `metabase_database.details` and `setting.value` before reading them.
|
||||
|
||||
Reference in New Issue
Block a user