ReferenceOperatorsarchitecture.decide

architecture.decide

Generated by docs/scripts/generate-docs.mjs from operators/architecture-decide/operator.md and operators/architecture-decide/operator.json. Edit the source, not this page.

Binding

FieldValue
idarchitecture.decide
domainarchitecture
resources.profilesol-fresh
resources.requires
policy.webSearch
policy.grammarBound
policy.imageGeneration

Job

Decide one architecture with its tech stack, system boundaries, and data ownership, and prove it against the observed current state, the rejected alternatives, verified compatibility, and an independent critique.

Observe before proposing

Nothing is proposed before the current state has been observed at the frozen head of @workspaces/be and written to response/data/current-state.json with its own fingerprint. A proposal written before the observation describes a system simpler than the real one, and every later comparison inherits that simplification. An observation taken at another head is worse: it looks rigorous while describing code that no longer exists.

Incumbency is not authority

The inventory says what the system runs today; that is the most useful and the most dangerous context this operator receives. An existing framework, datastore, broker, or deployment shape enters the decision in exactly two roles: as a measurable constraint the target must satisfy, or as observed evidence about behaviour already proved. It never enters as a reason by itself. A component justified because it is already there is rejected outright.

Prove, do not assume

An alternative is counted only when it is materially different, different in ownership or mechanism, not in wording, and assessed on exactly the trade-off axes the person named. Every retained component carries a verified verdict with evidence across runtime version, deployable unit, communication failure, datastore ownership, and backup and restore; a verdict that skipped an axis is a partial check wearing a complete label. Every boundary answers the data question: it owns at least one store or states that it owns none; a store names one owning boundary that writes it, and a second writer exists only with an explicit shared-write justification.

The decision names every write it commits to

A boundary that owns a store says nothing about who writes it, when, or under which transaction, so the decision closes that gap itself: response/data/stack-model.json carries one operations entry per write this architecture commits to, and ## Operations of the receipt restates the same rows. Each entry names its transport, its writer, the stores it touches, its transaction boundary, its idempotency kind, the migrations it ships, and the coverage-matrix dimensions of the business head it implements. That list is the frozen contract backend.source.apply fills: the implementation restates those operations unchanged and may add none, so an operation nobody declared here cannot be written anywhere. Declaring a write is not the same as choosing an implementation, which is why the writer is the one file path this operator names.

The critique is a nested exchange

After the selected alternative is deepened, the branch pauses: it emits response/response.json with status waiting and awaiting { exchange: critique, kind: independent-critique }. The orchestrator writes critique/request/request.json with only response/data/stack-model.json as input, never the author’s rationale, and runs a fresh agent on this operator’s own profile with no inherited turns. That agent writes only critique/response/. When its response is done the paused agent resumes at the confirmation step. Other branches of the same step keep running throughout.

Boundary

Context is read-only. The operator writes only response/ of its own branch: response.md, data/current-state.json, data/stack-model.json, the alternatives page when more than one alternative was asked for, and response.json; the critique agent writes only critique/response/. It does not mutate routed source, publish business authority, start or reconfigure runtime services, name implementation files in the handoff, or claim that an implementation, a quality gate, or a UAT run has passed.

When the model Input is present it is the authority for this run and the published head is lineage only, because a decision taken against yesterday’s promise is a decision against the wrong promise. When it is absent the published head is the authority.

Context

AliasBindRequired
@workspaces/bethe routed backend checkout read at the frozen head; the inventory comes from its manifests and deployment filesyes
@worktrees/businesses/<featureId>the published business head, the promise the architecture must keep; evidence when the session carries a model Inputyes
@knowledge/patternsreusable shapes the scope may bind; a shape, never a selectionno

Inputs

KindFromRequired
architecture-decisiona prior run of architecture.decide on the same or an adjacent boundary; lineage that may be contradicted, never ignoredno
modelbusiness.decide; the head that branch modelled, when it has not been published yetno

Requirements

FieldTypeDefaultAsk
objectivepromptThe objective the architecture must achieve, in the person’s words
decisionIdidslug of objectiveThe name the artifacts carry
alternativesnumber 1–41How many materially different designs to generate; more than one only when a comparison was asked for
tradeoffAxeslistcost, complexity, reversibilityThe axes every alternative is scored on and the critique attacks along
constraintslist of {id, kind, statement}kind is fixed-intent, measurable, preference, assumption or unknown; at least one fixed-intent
selectionPolicychoiceautomaticautomatic: the operator selects and records why; approval-required: the person selects
approvalidnullThe approved alternative id; required only under approval-required, supplied on resume after CHOICE_REQUIRED
resumetokennullThe blocked branch’s token when re-entering after a stop

Steps

#StepParamsReadsWritesStops with
1Validate the gate and resumeresume, approvalrequest/request.json, input architecture-decision when present, @workspaces/be at the frozen headINVALID_INPUT, SOURCE_DRIFT, NO_PROGRESS
2Observe the current state@workspaces/be at the frozen head: manifests, configuration, deployment files, @tools/gitresponse/data/current-state.jsonCURRENT_STATE_UNOBSERVED
3Bind the inventory to the business promiseresponse/data/current-state.json, input model when present, otherwise @worktrees/businesses/<featureId> at its published headBUSINESS_AUTHORITY_REQUIRED, EVIDENCE_MISSING
4Frame the decisionobjective, decisionId, constraints, tradeoffAxesrequest/request.json requirementsCONSTRAINT_CONTRADICTION
5Generate the alternativesalternativesresponse/data/current-state.json, @knowledge/patterns, @tools/websearchresponse/artifacts/<decisionId>-alternatives.html only when more than one alternative was asked for, @tools/visualizeNO_VIABLE_ALTERNATIVE
6SelectselectionPolicy, tradeoffAxes, approvalresponse/artifacts/<decisionId>-alternatives.html when presentCHOICE_REQUIRED
7Deepen the selected alternative and declare the operations it commits toconstraintsresponse/data/current-state.json, the bound business head’s coverage matrix for the dimensions each operation citesresponse/data/stack-model.json, including its operationsDATA_OWNERSHIP_UNASSIGNED, COMPATIBILITY_UNVERIFIED
8Await the critique: pause, a fresh agent attacks the selection, resume when it answerscritique/response/critique.md once the exchange is doneresponse/response.json (waiting, awaiting critique)CRITIQUE_UNRESOLVED
9Confirm or return the selectionselectionPolicycritique/response/critique.md, response/data/stack-model.jsonCHOICE_REQUIRED, NO_VIABLE_ALTERNATIVE
10Write the handoff and emiteverything aboveresponse/response.md, response/response.json

Under the defaults, step 5 produces one design and no comparison page, step 6 has nothing to choose, and the decision’s quality rests on step 8. When the only alternative fails an attack, step 9 stops with NO_VIABLE_ALTERNATIVE, not CHOICE_REQUIRED. The handoff names contracts, never implementation files, because choosing the files is the next domain’s job; the one exception is the writer of each declared operation, which this operator does name, because the implementation may not choose its own writer.

Outputs

KindFileTypeRequired
architecture-decisionresponse/response.mdmdyes
current-stateresponse/data/current-state.jsondatayes
stack-modelresponse/data/stack-model.jsondatayes
alternativesresponse/artifacts/<decisionId>-alternatives.htmlartifactno
independent-critiquecritique/response/critique.mdmdyes

response/response.md carries the ## Operations table and response/data/stack-model.json carries the matching operations array; together they are the mutation contract backend.source.apply consumes, and no other output of this operator crosses into that step.

Stops

CodeDisposition
INVALID_INPUTterminate
SOURCE_DRIFTterminate
NO_PROGRESSterminate
EVIDENCE_MISSINGterminate
CURRENT_STATE_UNOBSERVEDterminate
BUSINESS_AUTHORITY_REQUIREDterminate
CONSTRAINT_CONTRADICTIONterminate
NO_VIABLE_ALTERNATIVEterminate
CHOICE_REQUIREDfallback
COMPATIBILITY_UNVERIFIEDfallback
DATA_OWNERSHIP_UNASSIGNEDterminate
CRITIQUE_UNRESOLVEDterminate

Next

WhenOperator
the business promise must be modelled again against the decided boundariesbusiness.decide
the decision is confirmed and a backend contract changesbackend.source.apply
the decision is confirmed and a frontend surface changesfrontend.direction.decide

Source: operators/architecture-decide/operator.md.