The standing follow-up cleanup, now three features behind (#222, #223, #241).
The blocker, and how this fixes it
SonarQube here is 9.9 Community. It has no Bearer auth, so the official MCP cannot connect, and the host URL is a CI secret — so the measures exist only on a dashboard I cannot reach. "Reduce the debt" is not actionable without numbers.
So this adds a CI step that queries the measures API with the secrets the workflow already holds and prints the result into the job log, which I can read. The scanner masks secrets in output, but measures are not secret. That unblocks every future cleanup instead of just this one.
What is actually wrong, found by reading the tree rather than the dashboard
A rejected library is still a dependency.#216 evaluated Drizzle against Tinqer and rejected Tinqer — "not for 187 sites in a production shop today". The closing comment said the spike branch carried a throwaway src/db-tinqer/ probe that "must not reach main". It reached main: the whole spike commit 664a0c3 was merged. Still there today:
backend/src/db-tinqer/probe.ts, 71 lines, imported by nothing
@tinqerjs/tinqer, @tinqerjs/pg-promise-adapter, pg-promise — three devDependencies for a library that was evaluated and turned down
condition_note did not reach main, so that half of the warning held.
Eight lint warnings, several of them SonarJS rules and therefore Sonar code smells directly:
File
Rule
db-drizzle/itemFilters.drizzle.ts:8
sonarjs/unused-import + no-unused-vars — eq imported, never used
db-drizzle/schema.ts:80
no-unused-vars — table parameter unused
middleware/customerAuth.ts:5
no-namespace — this one is a false positive, see below
routes/shippingAddresses.ts:119
sonarjs/no-ignored-exceptions + no-unused-vars
frontend/src/filters.ts:60
sonarjs/no-alphabetical-sort ×2
shippingAddresses.ts:119 is the one that is a real defect rather than tidiness: the catch rolls back and returns 500 while discarding the error entirely, so a failed default-address update is invisible in the logs. That gets logged rather than silenced.
customerAuth.ts is the standard declare global { namespace Express { ... } } augmentation. A namespace is the only way to spell that, so it gets a disable with the reason written next to it rather than a contortion.
Duplication.backfillImageReencode.ts:53 keeps its own TYPE_FOR_EXTENSION map — .jpg/.png/.webp — duplicating typeForExtension in src/uploadTypes.ts, which derives from a single record precisely so the two cannot drift. The backfill rewrites stored images, so if the two ever disagree it silently skips files it should have re-encoded.
Not in scope
src/db-drizzle/ stays. #217 is open and its job is to promote exactly those files properly — with tablesFilter, a decision on where the schema lives, and the sql.param() array rule written down. Deleting them now would be doing #217 badly and in the wrong issue. Only the unused-symbol warnings in them are fixed here; if drizzle-kit pull regenerates schema.ts, the table warning returns, which is worth #217 knowing.
Security hotspots and coverage are not addressed in this pass because I cannot see either number. Both are the next cleanup, once the CI step above has printed them once.
The standing follow-up cleanup, now three features behind (#222, #223, #241).
## The blocker, and how this fixes it
SonarQube here is 9.9 Community. It has no Bearer auth, so the official MCP cannot connect, and the host URL is a CI secret — so the measures exist only on a dashboard I cannot reach. "Reduce the debt" is not actionable without numbers.
So this adds a CI step that queries the measures API with the secrets the workflow already holds and prints the result into the job log, which I *can* read. The scanner masks secrets in output, but measures are not secret. That unblocks every future cleanup instead of just this one.
## What is actually wrong, found by reading the tree rather than the dashboard
**A rejected library is still a dependency.** #216 evaluated Drizzle against Tinqer and rejected Tinqer — "not for 187 sites in a production shop today". The closing comment said the spike branch carried a throwaway `src/db-tinqer/` probe that "must **not** reach `main`". It reached main: the whole spike commit `664a0c3` was merged. Still there today:
- `backend/src/db-tinqer/probe.ts`, 71 lines, imported by nothing
- `@tinqerjs/tinqer`, `@tinqerjs/pg-promise-adapter`, `pg-promise` — three devDependencies for a library that was evaluated and turned down
`condition_note` did *not* reach main, so that half of the warning held.
**Eight lint warnings**, several of them SonarJS rules and therefore Sonar code smells directly:
| File | Rule |
|---|---|
| `db-drizzle/itemFilters.drizzle.ts:8` | `sonarjs/unused-import` + `no-unused-vars` — `eq` imported, never used |
| `db-drizzle/schema.ts:80` | `no-unused-vars` — `table` parameter unused |
| `middleware/customerAuth.ts:5` | `no-namespace` — this one is a false positive, see below |
| `routes/shippingAddresses.ts:119` | `sonarjs/no-ignored-exceptions` + `no-unused-vars` |
| `frontend/src/filters.ts:60` | `sonarjs/no-alphabetical-sort` ×2 |
`shippingAddresses.ts:119` is the one that is a real defect rather than tidiness: the catch rolls back and returns 500 while discarding the error entirely, so a failed default-address update is invisible in the logs. That gets logged rather than silenced.
`customerAuth.ts` is the standard `declare global { namespace Express { ... } }` augmentation. A namespace is the only way to spell that, so it gets a disable with the reason written next to it rather than a contortion.
**Duplication.** `backfillImageReencode.ts:53` keeps its own `TYPE_FOR_EXTENSION` map — `.jpg`/`.png`/`.webp` — duplicating `typeForExtension` in `src/uploadTypes.ts`, which derives from a single record precisely so the two cannot drift. The backfill rewrites stored images, so if the two ever disagree it silently skips files it should have re-encoded.
## Not in scope
`src/db-drizzle/` stays. #217 is open and its job is to promote exactly those files properly — with `tablesFilter`, a decision on where the schema lives, and the `sql.param()` array rule written down. Deleting them now would be doing #217 badly and in the wrong issue. Only the unused-symbol warnings in them are fixed here; if `drizzle-kit pull` regenerates `schema.ts`, the `table` warning returns, which is worth #217 knowing.
Security hotspots and coverage are not addressed in this pass because I cannot see either number. Both are the next cleanup, once the CI step above has printed them once.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The standing follow-up cleanup, now three features behind (#222, #223, #241).
The blocker, and how this fixes it
SonarQube here is 9.9 Community. It has no Bearer auth, so the official MCP cannot connect, and the host URL is a CI secret — so the measures exist only on a dashboard I cannot reach. "Reduce the debt" is not actionable without numbers.
So this adds a CI step that queries the measures API with the secrets the workflow already holds and prints the result into the job log, which I can read. The scanner masks secrets in output, but measures are not secret. That unblocks every future cleanup instead of just this one.
What is actually wrong, found by reading the tree rather than the dashboard
A rejected library is still a dependency. #216 evaluated Drizzle against Tinqer and rejected Tinqer — "not for 187 sites in a production shop today". The closing comment said the spike branch carried a throwaway
src/db-tinqer/probe that "must not reachmain". It reached main: the whole spike commit664a0c3was merged. Still there today:backend/src/db-tinqer/probe.ts, 71 lines, imported by nothing@tinqerjs/tinqer,@tinqerjs/pg-promise-adapter,pg-promise— three devDependencies for a library that was evaluated and turned downcondition_notedid not reach main, so that half of the warning held.Eight lint warnings, several of them SonarJS rules and therefore Sonar code smells directly:
db-drizzle/itemFilters.drizzle.ts:8sonarjs/unused-import+no-unused-vars—eqimported, never useddb-drizzle/schema.ts:80no-unused-vars—tableparameter unusedmiddleware/customerAuth.ts:5no-namespace— this one is a false positive, see belowroutes/shippingAddresses.ts:119sonarjs/no-ignored-exceptions+no-unused-varsfrontend/src/filters.ts:60sonarjs/no-alphabetical-sort×2shippingAddresses.ts:119is the one that is a real defect rather than tidiness: the catch rolls back and returns 500 while discarding the error entirely, so a failed default-address update is invisible in the logs. That gets logged rather than silenced.customerAuth.tsis the standarddeclare global { namespace Express { ... } }augmentation. A namespace is the only way to spell that, so it gets a disable with the reason written next to it rather than a contortion.Duplication.
backfillImageReencode.ts:53keeps its ownTYPE_FOR_EXTENSIONmap —.jpg/.png/.webp— duplicatingtypeForExtensioninsrc/uploadTypes.ts, which derives from a single record precisely so the two cannot drift. The backfill rewrites stored images, so if the two ever disagree it silently skips files it should have re-encoded.Not in scope
src/db-drizzle/stays. #217 is open and its job is to promote exactly those files properly — withtablesFilter, a decision on where the schema lives, and thesql.param()array rule written down. Deleting them now would be doing #217 badly and in the wrong issue. Only the unused-symbol warnings in them are fixed here; ifdrizzle-kit pullregeneratesschema.ts, thetablewarning returns, which is worth #217 knowing.Security hotspots and coverage are not addressed in this pass because I cannot see either number. Both are the next cleanup, once the CI step above has printed them once.