Skip to content

refactor: unify Queue Name parsing and validation into a QueueName seam (#148) - #149

Open
jonbaldie wants to merge 2 commits into
mainfrom
refactor/queue-name-seam-148
Open

jonbaldie wants to merge 2 commits into
mainfrom
refactor/queue-name-seam-148

Conversation

@jonbaldie

Copy link
Copy Markdown
Owner

Summary

All Queue Name rules now live in one module, src/queue_name.ts. The HTTP handler maps the domain errors to responses in one place.

 src/
+├── queue_name.ts   # MAX_QUEUE_NAME_LENGTH, InvalidQueueNameError, QueueNameTooLongError,
+│                   # validateQueueName, decodeQueueName, parseQueueName
 ├── manager.ts      # validateQueueName(name) on every operation; re-exports the error and limit
 └── handler.ts      # queueRoute(handler, parseName) + queueNameErrorResponse
 route /dequeue|/peek|/length/:queue
-  extractQueueName(match) -> { name } | { error: Response }
-  try { ... } catch -> queueNameErrorResponse
+  queueRoute: parseQueueName(raw) -> handler(queueName, request)
+              catch InvalidQueueNameError -> 400 "Invalid queue name"
+                    QueueNameTooLongError -> 400 "Queue name too long"
 route /enqueue/:queue
+  queueRoute(..., decodeQueueName)   # only decodes here; the length rule runs in QueueManager
+                                      # after payload checks, so 413/Invalid JSON still win

Design notes:

  • decodeQueueName is exported so that enqueue keeps today's error order: 413 or "Invalid JSON" still beats "Queue name too long". Without it, the brief's "byte-identical" rule would break.
  • QueueManager now also rejects an empty name (InvalidQueueNameError) for direct callers. HTTP can't reach that case, because the route pattern needs at least one character. load() still does not validate persisted names, which is unchanged from before.
  • Housekeeping: added a CONTEXT.md glossary entry and registered the new module in the quality gate. openapi.yaml now documents the existing 400 "Invalid queue name" response.

Closes #148

Evidence

  • Before: queue-name rules were tested only through HTTP requests or QueueManager. tests/queue_name_test.ts didn't exist, and running it failed type-checking (module not found).
    After: tests/queue_name_test.ts has 19 HTTP-free unit tests. They cover undefined, "", %E0%A4%A, a%20b → a b, decoding exactly once (%2541 → %41), and 128/129 code points, both ASCII and astral.
  • Differential run: the same 144 requests went to main's handler and this branch's handler. They covered every queue route, HEAD dequeue, malformed and over-length names, and payload errors. Two of the payload errors were checked combined with over-length names: 413 and Invalid JSON. They also covered 507 capacity errors and thrown 500s. Result: 0 differences in status and body.
  • New HTTP tests pin the enqueue order:
    POST /enqueue/<129 chars>, Content-Length 99999999  -> 413 "Payload too large"
    POST /enqueue/<129 chars>, body "{"                 -> 400 "Invalid JSON"
    POST /enqueue/%E0%A4%A, oversized + bad body        -> 400 "Invalid queue name"
    
  • deno test (full suite): 387 passed, 0 failed. npm run quality:production passes.

Merge Danger

Door: two-way

A refactor with no change to the wire contract. Reverting it is a plain git revert.

Blast Radius: small

Direct QueueManager callers that pass "" now get an exception. Before, "" was accepted as a queue name. Expect a rebase conflict with #136 in enqueueHandler.

🤖 Generated with Claude Code

jonbaldie and others added 2 commits October 2, 2026 10:27
…am (#148)

Introduce src/queue_name.ts owning MAX_QUEUE_NAME_LENGTH,
InvalidQueueNameError, QueueNameTooLongError, validateQueueName and
parseQueueName. QueueManager validates through the same rules (and now
rejects empty names); the HTTP handler parses names once in a queueRoute
wrapper with a single error mapper, removing extractQueueName's
Response-returning union and per-route try/catch. Status codes and
response bodies are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#148)

Enqueue decodes the queue name up front but leaves the length rule to
QueueManager, so payload errors (413, Invalid JSON) still win over an
over-length name as on main. Pin that ordering with HTTP tests, cover
parseQueueName with astral code points, restore the enqueueErrorResponse
name to limit conflict with #136, and drop an unused re-export.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Architecture: Unify Queue Name parsing, validation, and error contracts into a QueueName domain seam

1 participant