Each additional fallible step adds one level of indentation and one error rewrap. The shape of the code grows with the number of error sites, not the number of business steps.
async function createUser(nameInput: string, ageInput: string) {
const name = validateName(nameInput)
const age = parseAge(ageInput)
throw new Error(`Age validation failed: ${(ageError as Error).message}`)
throw new Error(`Name validation failed: ${(nameError as Error).message}`)
Three steps produce a pyramid. Recovery decisions are inverted (innermost first).
The logical sequence, validate name, parse age, return both, is buried under control flow.
Your turn: run the tests and see how each added rule deepens the pyramid.