canonical input boundary

situation

an integration received structured identifiers and authored labels from several sources. early code trimmed segments, changed case, and derived keys from labels. it held until an identifier contained an unexpected delimiter and a label edit changed the resource it described.

the failure was not one wrong string method: it treated three kinds of input — structured syntax, closed external values, authored meaning — as interchangeable strings.

why

the three kinds carry different guarantees; convenient normalization destroys all three at once. once boundary code rewrites input, consumers cannot tell authored identity from derived display, and an editorial change silently becomes an identity migration. parse and validate before business logic reads input: every transformation auditable, invalid state unrepresentable past the boundary.

invariants

  • structured value is parsed before business logic reads it.
  • authored name/key stored exactly, with explicit ownership.
  • closed external value validated and exhaustively mapped.
  • malformed input → classified diagnostic, never a plausible rewrite.

decision process

candidatereasoningdecision
normalize all inputs into convenient stringshides grammar, identity, and provenance differences; later callers cannot recover them.rejected
derive a business key from display copyturns editorial change into an unreviewed identity migration.rejected
regex-rewrite a structured field before parsingcan alter valid syntax or accept malformed structure without a causal error.rejected
parse/validate once, keep named fields, map closed values explicitlymakes invalid state unrepresentable after the boundary and keeps each transformation auditable.selected

resulting design

  • boundary parser returns typed parts for structured input.
  • explicit schema validates external payloads.
  • named mapper converts validated provider members to internal members.
  • authored key is an independent required field with a unique constraint.
  • display formatting happens only at the rendered edge, never re-read as resource identity.

diagnosis is direct: parser failure asks for correction, unknown closed value asks for contract support, authored-key collision asks for a new explicit key. no repair path guesses what a rewrite meant.

verification

  1. test valid structured input with escaping/delimiters a string split would mishandle.
  2. send malformed syntax; confirm a stable correction diagnostic.
  3. send an unknown closed value; confirm the mapper fails visibly.
  4. edit display copy while retaining the authored key; resource identity must stay unchanged.
  5. search boundary and consumers for rewrite/casing APIs that could create a second canonicalization path.

good and bad

bad

return createWorkflow(requestBody as CreateWorkflowInput);

untrusted input crosses into the domain service through an assertion. malformed structure, unknown closed values, and rewritten identity all pass silently; first evidence is data whose provenance nobody can reconstruct.

good

return createWorkflow(CreateWorkflowInputSchema.parse(requestBody));

one canonical, diagnostic input boundary: invalid state unrepresentable past it, authored keys exact through display edits, each failure mode arrives with a named correction path instead of a plausible rewrite.

search pages

go to any page