fix(housekeeping): complete people read fidelity
This commit is contained in:
1 parent
d1382c839e
commit
7920d4f46c
8 files changed
+564
-37
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Task 11 — People workflow read models
|
||||
|
||||
Status: DONE — fix round 1
|
||||
Status: DONE — fix round 2
|
||||
|
||||
## Delivered scope
|
||||
|
||||
@@ -15,12 +15,12 @@ Status: DONE — fix round 1
|
||||
- User mail and current IP remain independently nullable fields. Each is projected only when the capability context contains the existing `PERMS.USERS_VIEW`; `PERMS.MOD_USERS_VIEW` alone receives the safe base projection with both values set to `null`, and a context with neither permission is forbidden.
|
||||
- No new ACL slug or rank threshold was introduced. Staff filtering reuses the existing `getMinStaffRank()` source.
|
||||
- The production user selection is explicit and excludes passwords, authentication tickets, secrets, and two-factor material. VPN settings intentionally exclude `vpn_api_key`.
|
||||
- Adapters fail closed. Malformed driver envelopes, invalid or non-positive identifiers, corrupt links, non-serializable DTO values, and count failures map to `DEPENDENCY_UNAVAILABLE`. Missing valid detail entities map to `NOT_FOUND`; invalid request identifiers map to `VALIDATION`. No partial-result shape is returned because no People DTO explicitly names failed sources.
|
||||
- Adapters fail closed. Malformed driver envelopes, invalid identifiers, corrupt links, non-serializable DTO values, and count failures map to `DEPENDENCY_UNAVAILABLE`. Primary/entity identifiers remain positive safe integers; zero is accepted only for the schema-declared guild `userId`/`roomId` and CFH `senderId`/`reportedId`/`roomId`/`moderatorId` sentinels. Missing valid detail entities map to `NOT_FOUND`; invalid request identifiers map to `VALIDATION`.
|
||||
- Pagination clamps page size to 100 and offset to 10,000. Deterministic primary sorting, numeric-ID tie breaking, and `LIMIT`/`OFFSET` now execute in the database; no list query fetches a prefix for locale re-sorting or second slicing.
|
||||
- Raw production adapters and `buildPeopleUserSelection` are module-private. Runtime exports expose only context-authorized query factories and singleton query surfaces.
|
||||
- Multi-account clusters use one bounded CTE/window query, cap accounts per cluster at 100, and never issue one query per IP cluster.
|
||||
- Multi-account clusters use one bounded CTE/window page query plus one independent matching-cluster count query, cap accounts per cluster at 100, and never issue one query per IP cluster.
|
||||
- User detail/edit now includes the operator's watched state and canonical permission-rank data. Support ticket reads use the existing unified inbox through a strict, fail-closed, database-paged mode that includes CMS and help-center rows while leaving the legacy tolerant mode unchanged.
|
||||
- Support desk/detail DTOs explicitly include queue counts, bounded staff, and the relevant active ban. Ticket messages/replies and staff rows are bounded.
|
||||
- The unified `/support/tickets` inbox still merges CMS and help-center rows. The ticket desk now has its own strict CMS-only page loader preserving priority, category, assignee, and message count; help summaries include reply count. Support desk/detail DTOs explicitly include queue counts, bounded staff, and the relevant active ban.
|
||||
- Active bans are filtered before sorting. Expiry `0` remains the permanent-active sentinel; expired rows cannot hide permanent or future-active bans in lists or details.
|
||||
|
||||
## Official fix round 1 findings
|
||||
@@ -35,6 +35,12 @@ Status: DONE — fix round 1
|
||||
|
||||
The two official Minor findings remain parked and unchanged as instructed.
|
||||
|
||||
## Official fix round 2 findings
|
||||
|
||||
1. **Entity-aware sentinels:** canonical guild DTOs now use the real schema names `userId` and `roomId`. Serialization permits zero only on those two guild fields and the four named CFH fields when the containing DTO has the matching canonical entity href. Generic `*Id` zero values, negatives, unsafe integers, and primary ID zero remain unavailable failures.
|
||||
2. **Support source fidelity:** `people.support.tickets` remains on strict `fetchUnifiedTicketInbox`. `people.support.ticket-desk` now dispatches to a distinct strict `website_tickets` loader with message aggregation and no help-center source. Real priority/category/assignee/message count and help reply count are present in canonical DTOs; malformed driver rows fail closed.
|
||||
3. **Multi-account total:** the page CTE and matching-cluster count run as two bounded parallel queries. Empty pages retain the correct total without prefix loading or N+1 queries.
|
||||
|
||||
## Strict TDD evidence
|
||||
|
||||
### Cycle 1 — exact route catalog
|
||||
@@ -253,27 +259,86 @@ Test Files 1 passed (1)
|
||||
Tests 1 passed | 4 skipped (5)
|
||||
```
|
||||
|
||||
## Fix round 2 strict behavioral TDD evidence
|
||||
|
||||
### Entity-aware schema sentinels
|
||||
|
||||
RED:
|
||||
|
||||
```text
|
||||
pnpm exec vitest run --coverage.enabled=false src/features/housekeeping/domains/people/queries/people-queries.test.ts -t "zero sentinels"
|
||||
Test Files 1 failed (1)
|
||||
Tests 2 failed | 19 skipped (21)
|
||||
Valid guild userId/roomId zero and CFH senderId/reportedId/moderatorId/roomId zero were rejected by generic identifier validation.
|
||||
```
|
||||
|
||||
GREEN:
|
||||
|
||||
```text
|
||||
same command
|
||||
Test Files 1 passed (1)
|
||||
Tests 2 passed | 19 skipped (21)
|
||||
```
|
||||
|
||||
### CMS-only ticket desk and help reply counts
|
||||
|
||||
RED:
|
||||
|
||||
```text
|
||||
pnpm exec vitest run --coverage.enabled=false src/features/housekeeping/domains/people/queries/people-queries.test.ts src/features/housekeeping/domains/people/queries/people-adapters-production.test.ts -t "CMS-only context loader|reply counts"
|
||||
Test Files 2 failed (2)
|
||||
Tests 2 failed | 28 skipped (30)
|
||||
The desk received a help row with synthetic normal priority; help summary omitted replyCount.
|
||||
```
|
||||
|
||||
GREEN:
|
||||
|
||||
```text
|
||||
same command
|
||||
Test Files 2 passed (2)
|
||||
Tests 2 passed | 28 skipped (30)
|
||||
```
|
||||
|
||||
### Independent multi-account total
|
||||
|
||||
RED:
|
||||
|
||||
```text
|
||||
pnpm exec vitest run --coverage.enabled=false src/features/housekeeping/domains/people/queries/people-adapters-production.test.ts -t "beyond the last page"
|
||||
Test Files 1 failed (1)
|
||||
Tests 1 failed | 8 skipped (9)
|
||||
Expected total 4 on the empty page; received 0.
|
||||
```
|
||||
|
||||
GREEN:
|
||||
|
||||
```text
|
||||
same command
|
||||
Test Files 1 passed (1)
|
||||
Tests 1 passed | 8 skipped (9)
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
pnpm exec vitest run --coverage.enabled=false src/features/housekeeping/domains/people/routes.test.ts src/features/housekeeping/domains/people/models.test.ts src/features/housekeeping/domains/people/queries/people-queries.test.ts src/features/housekeeping/domains/people/queries/people-adapters-production.test.ts
|
||||
Test Files 4 passed (4)
|
||||
Tests 35 passed (35)
|
||||
Tests 40 passed (40)
|
||||
|
||||
pnpm exec vitest run --coverage.enabled=false src/features/housekeeping/domains/people src/features/housekeeping/foundation/foundation-source-contract.test.ts src/features/housekeeping/foundation/authorization.test.ts src/features/housekeeping/foundation/capability-context.test.ts src/features/housekeeping/foundation/server-capability-context.test.ts src/features/housekeeping/foundation/contracts/contracts.test.ts
|
||||
Test Files 9 passed (9)
|
||||
Tests 81 passed (81)
|
||||
Tests 86 passed (86)
|
||||
|
||||
pnpm test:housekeeping
|
||||
Test Files 49 passed (49)
|
||||
Tests 430 passed (430)
|
||||
Tests 435 passed (435)
|
||||
|
||||
pnpm typecheck
|
||||
tsc --noEmit
|
||||
Exit 0
|
||||
|
||||
pnpm exec biome check --formatter-enabled=false <11 exact changed Task 11 TypeScript files>
|
||||
Checked 11 files. No fixes applied.
|
||||
pnpm exec biome check --formatter-enabled=false <7 exact changed Task 11 TypeScript files>
|
||||
Checked 7 files. No fixes applied.
|
||||
|
||||
git diff --check
|
||||
Exit 0
|
||||
|
||||
Reference in new issue
Block a user