Chapter 3 of 15

Making Architectural Decisions Under Uncertainty

Some decisions had to be load-bearing immediately; most could stay provisional. I was making these choices before I had perfect evidence, so the goal was not to predict the final stack. It was to identify which boundaries would be painful to move later and which decisions could safely remain provisional.

  • What needed to be built immediately
  • What could remain provisional
  • How you distinguished product assumptions from engineering facts

The situation

Early architecture choices (workspace model, tool boundary, provider abstraction) had to be made before user demand had fully proven the product. In Making Architectural Decisions Under Uncertainty, I wanted to capture the real operating situation rather than describe the problem in abstract terms. What mattered to me was the moment the existing approach stopped being sufficient in normal use, because that was usually the point where the next architectural requirement became obvious.

The naive solution

Try to design the complete, final system up front: every stack, every provider, every deployment target. The naive option was attractive precisely because it was faster and easier to explain. I could have pushed further in that direction and probably improved the demo, but it would have optimised the visible symptom rather than the underlying system constraint.

The hidden constraint

Committing early to specifics like a single framework or deployment provider would have been expensive to reverse and cheap to defer. This constraint was easy to miss early because it did not show up in the first successful run. It appeared once the workflow had to survive repetition, failure, another user, another provider, or a return visit, which is why I now look for these second-order requirements much earlier.

The decision

Separate "facts that constrain everything downstream" (tool boundary, tenant isolation, provider-neutral orchestration) from "choices that can stay provisional" (which frameworks, which cloud storage provider). I treated this as an architectural or product decision rather than a prompt tweak. The aim was to create a boundary I could reason about later, instead of relying on model behaviour to remain consistent as providers, templates, and user requests changed.

The implementation

Built a provider-neutral agent runner and a provider-neutral deployment state machine first, then plugged in specific model providers (OpenAI, Anthropic, Gemini) and a specific storage backend (Cloudflare R2) behind those seams. I also tried to make the implementation concrete enough that the decision could be inspected in code and runtime behaviour. That meant explicit state, explicit policy, and observable transitions rather than a collection of hidden assumptions spread across prompts and handlers.

The tradeoff

More upfront abstraction work than hard-coding a single provider, in exchange for not re-architecting when the second provider was added. I did not treat the decision as free. In most cases I was deliberately accepting more engineering, state management, or operational complexity in exchange for a smaller failure surface and a product that could survive realistic use.

The evidence

Adding Laravel and TanStack as two different workspace templates did not require changing the orchestration or execution layers. I use this evidence as a practical signal, not as a claim that the architecture is universally correct. The useful question was whether the new design changed what the system could reliably do under the conditions that had previously broken it.

The reusable lesson

Invest early design effort in the boundaries that are expensive to move later (security, tenancy, tool contracts); leave vendor and framework specifics behind an interface until real usage tells you which one matters. The part I would carry into another build is the decision rule behind the implementation, not the exact technology choice. Vendors and frameworks will change; the underlying question about state, control, isolation, feedback, or user trust is much more reusable.

The consultant's questions

  • Which of today's architecture decisions would be expensive to reverse in six months?
  • Which decisions are you treating as final that are actually still guesses?
  • What assumption in this part of the system would become dangerous if usage or tenant count increased?
  • What evidence would tell me this decision needs to be revisited rather than defended indefinitely?