The three carried API bugs, resolved โ
- Outcome: one is real and now filed, two are not real in the current tree. No issue was filed for those two.
- Why this exists: the three were surfaced by the API mutation runs around 2026-08-21 and carried on the daily agenda on 08-21, 08-23, 08-24, 08-27 and 08-28 without ever being written down. They existed only in a cut-section paragraph, which is how a real bug becomes folklore.
- Checked: 2026-08-28, against the tree at
fix/merchant-portal-988.
1. A ban check that ignores expiry: REAL, filed โ
services/api/auth/src/routes/adminUsers.js:170 reads the raw flag. โ
if (d.banned) stats.banned++, where every other ban read in the codebase goes throughisActivelyBanned(userData).- Filed as the admin Banned stat counts expired bans, because it reads the raw flag instead of isActivelyBanned (#995), with a second instance of the same shape in the admin portal's
bansService.js. - Not fixed here. Auth and moderation was a hard stop for the session that found it, so the deliverable was a precise location.
What makes it durable rather than a transient drift. โ
- Temp bans are lifted LAZILY, by
checkLoginBanwhen the banned user next tries to sign in. A user who never returns keepsbanned: trueand an elapsedbanExpiresAtforever, so the miscount grows rather than settling.
2. A printable-ASCII-only sanitiser: NOT REAL in this tree โ
Every sanitiser in the services is a DENY-list, not an ASCII allow-list. โ
sanitizeDisplayName(services/api/lanterns/src/services/lantern.service.js:103) strips C0 controls and DEL, the zero-width family, and the bidi overrides. Nothing else.- Its two mirrors (
syncPublicProfile.js,backfill-public-profiles.mjs) carry a byte-identical character set. - The other sanitisers in the services (
sanitizeTitlein assistant,sanitizeMetadatain forge,sanitizeTierFiltersin venues) are also deny-lists or key filters.
Verified by running it, not by reading it. โ
| Input | Output |
|---|---|
Josรฉ รlvarez | unchanged |
ๅผ ไผ | unchanged |
็ฐไธญๅคช้ | unchanged |
๊น๋ฏผ์ค | unchanged |
Ana ๐ | unchanged |
Zoรซ, รnal | unchanged |
| a name containing a zero-width space | the zero-width space removed, which is the point of it |
- The current character set has been in place since
dc70fda3(2026-06-11), which predates the mutation runs.
3. A lantern uniqueness guard cleared unconditionally: NOT REAL in this tree โ
The clear is conditional, and the code says why. โ
services/api/lanterns/src/services/lantern.service.js:452reads the guard and deletes it only whenguardSnap.data()?.lanternId === lanternId, with a comment naming the failure mode: a guard naming a newer lantern must not be deleted by an extinguish of an older one.- The other site that touches the guard,
schedule.service.js:370, SETS it inside a transaction that first checksactiveLanternGuardHeld, which is the invariant rather than a violation of it. - The condition entered at
ddcb98a3(2026-08-17), which also predates the mutation runs.
What this means for the agenda โ
- The row can be retired. One issue exists, two are verified absent, and the evidence for each is above rather than in a session transcript.
- Both "not real" findings predate the runs that reported them, so the likeliest reading is that the mutation-run summary was imprecise rather than that something was quietly fixed. Worth knowing before trusting a future summary from the same source without a location.
One thing found while looking, not filed โ
services/api/assistant has no ban check at all. โ
grep -rc "isActivelyBanned" services/api/assistant/srcreturns zero matches, while every other service re-fetches the user and checks it. The service does have arequireAdmin.- First noted in the operator's agenda on 2026-08-21 as "pre-existing and out of today's scope, needs its own issue", and it still has none.
- Not filed here because it was outside what this session was asked to file, and a security gap deserves its own deliberate write-up rather than a rider. Surfaced so it is not lost a second time.