business.decide
Generated by docs/scripts/generate-docs.mjs from operators/business-decide/operator.md and operators/business-decide/operator.json. Edit the source, not this page.
Binding
| Field | Value |
|---|---|
id | business.decide |
domain | business |
resources.profile | sol-fresh |
resources.requires | — |
policy.webSearch | — |
policy.grammarBound | — |
policy.imageGeneration | — |
Job
Decide and publish one evidence-backed business promise as durable backend-owned authority, frozen behind a complete promise-to-enforcement coverage matrix, or reconcile that published head against the source that was actually delivered.
Two modes, one head
mode decides which half of this operator runs. Under model the promise is modelled and the
coverage matrix is frozen: steps 4, 5 and 6 run and the branch writes
response/data/coverage-matrix.json. Under reconcile nothing is modelled again; step 7 compares the
head that was already published against the source a backend run delivered, and the Input
backend-source-application is required in that mode, because a reconciliation with no delivered source
is an opinion about code nobody read. The Inputs table marks it optional because the requirement is
conditional, and validate.mjs refuses a reconcile branch whose request does not bind it. Both
modes end at the same place: one head under @worktrees/businesses/<featureId> and one
response/data/model.json that says exactly what that head now holds.
A first run starts from the person’s promise
A feature that no source implements yet has no fact claim by construction. On a first run under mode
model, the promise the person stated in promise is recorded as the one intent claim, bound to
request/request.json#requirements.promise instead of a source line, and the model is built from it;
EVIDENCE_MISSING applies to a fact claim without a file behind it, never to the intent of a promise
that is being decided for the first time. Every enforcing row of the coverage matrix still rests on a
fact claim, so a greenfield head publishes with its enforcing rows open, which is what pending means.
Separate the claim before modelling it
Modelling begins by separating every observation into fact, intent, example, unknown, or
contradiction, and that separation is written to response/data/claims.json before anything is
modelled from it. The separation exists to make one substitution impossible: an example, a
screenshot, or an owner’s intent illustrates a promise, and only an observed fact in routed source
proves that the promise is enforced. A coverage row that asserts enforcement therefore cites at least
one fact claim, and every fact claim binds the observed source head. A claim that cites a source
nobody bound is invalid input rather than a warning, because an unbound citation cannot be told apart
from an invented one. Two claims that disagree about the same behaviour are never averaged into a
middle reading; the contradiction stops the invocation and returns to its owner.
No promise without coverage
A promise is publishable only when every dimension the request declared carries exactly one
disposition, and every consumer and lifecycle branch the operator discovered is disposed by name.
dimensions defaults to the dimensions of the previous head, which is why it is required on a first
run: the first publication is the one that decides what the promise is even accountable for. That
rule exists because “full access” was modelled, implemented, and published while its course,
community, blog, AI, mock-interview, legacy-sale, quota, settlement, renewal, cancellation, and
recovery consumers had never all been proved. The promise was true in the offer and false at the
guard. Four prohibitions carry the repair, and each is enforced rather than advised. A discovered
consumer with no matrix row is CONSUMER_UNPROVEN. A mandatory dimension, meaning actor and
eligibility, offer entry, read entry, purchase side effect, settlement, idempotency, entitlement
consumer, and denial, can never be marked not applicable when it was declared. A dimension whose
branch was observed in source can never be marked not applicable either, because it was found, so it
applies. A preserve or replace disposition without a negative proof is rejected, since positive proof
alone shows the promise is granted and never that it is denied when it should be.
The dispositions and what each one must carry
preserve keeps the existing enforcement and carries owner, source, positive proof, negative proof,
and one fact claim. replace changes the enforcement and carries the same substance for the new
path. retire closes a path on purpose and carries owner, source, proof the path is closed, and one
fact claim. defer postpones a branch to a named owner, carries a deferral reference, and carries no
proof at all, because proof for work that has not happened is the most convincing kind of false pass.
not-applicable states the branch cannot occur and carries nothing: no owner, no source, no proof, no
consumer, no claim. defer is a disposition, so a deferred branch does not block publication; what
blocks publication is silence.
One flat authority root
One feature owns exactly one head directory, <businesses root>/features/<featureId>, whose
model.json is the head, and step 8 takes an exclusive lease on that alias before it writes. Two
branches of the same step may not publish the same feature. features/ is the only segment between
the root and a feature: a project segment inserted below the root starts a second authority tree that
later readers never find, so any head that is not exactly features/<featureId> is refused. The head
is classified absent, fresh, or stale against the frozen evidence and the frozen source head, and
that classification decides which lifecycle transition is legal. Rejection preserves lineage by
naming the previous head rather than erasing it, and implemented is never published on the strength
of a plan: delivered source is compared against the frozen matrix first, under reconcile.
Boundary
Context is read-only apart from the one feature head. The operator writes only response/ of its own
branch, response.md, response/data/claims.json, response/data/coverage-matrix.json under mode
model, response/data/model.json and response.json, plus the one feature head under
@worktrees/businesses/<featureId>. It never publishes a promise while a discovered consumer or
lifecycle branch carries no disposition, promotes an example, a screenshot, or an intent claim into
product truth, invents an actor, entitlement, quota, payment, settlement, or lifecycle behaviour the
evidence does not state, advances a head through a transition the lifecycle does not allow, or writes
a head below a project segment under the businesses root. It does not modify product source,
architecture authority, frontend authority, or backend implementation, and it never claims that an
implementation, a quality gate, or a UAT run has passed.
Context
| Alias | Bind | Required |
|---|---|---|
@worktrees/businesses/<featureId> | the promise head and its lifecycle state, by content address from the registry; the one place this operator writes outside its branch | yes |
@workspaces/be | the routed backend checkout read at the frozen head; every fact claim cites it by path, line range, and head | yes |
Inputs
| Kind | From | Required |
|---|---|---|
architecture-decision | architecture.decide; architecture evidence, never a source of business behaviour | no |
backend-source-application | backend.source.apply; the delivered source a reconciliation reads, required under mode reconcile and refused otherwise | no |
Requirements
| Field | Type | Default | Ask |
|---|---|---|---|
featureId | id | — | The one feature the promise belongs to |
mode | choice | model | model decides and publishes the promise; reconcile compares the published head against delivered source |
promise | prompt | the promise the previous head states | The promise in the person’s words; required on a first run, when no head exists yet, and recorded as the intent claim bound to request/request.json#requirements.promise |
targetState | choice | — | pending, in-progress, implemented or rejected for the published head |
dimensions | list | the dimensions of the previous head | The coverage surface this promise is accountable for; required on a first run, because no previous head declares it |
approval | id | null | The owner approval the transition needs, supplied on resume after APPROVAL_REQUIRED |
resume | token | null | The blocked branch’s token when re-entering after a stop |
Steps
| # | Step | Params | Reads | Writes | Stops with |
|---|---|---|---|---|---|
| 1 | Validate the gate and resume | resume, mode | request/request.json, @workspaces/be at the frozen head | — | INVALID_INPUT, SOURCE_DRIFT, NO_PROGRESS |
| 2 | Normalize the evidence into claims | — | @workspaces/be, every observation with its role, path, line range and head, input architecture-decision when present as evidence only, @tools/git | response/data/claims.json | EVIDENCE_MISSING, CONTRADICTION_UNRESOLVED |
| 3 | Check the published head and the transition authority | featureId, targetState, approval | @worktrees/businesses/<featureId>: the current head, its state and its frozen evidence | — | LIFECYCLE_TRANSITION_INVALID, AUTHORITY_CONFLICT, APPROVAL_REQUIRED |
| 4 | Model the promise, its actor and its eligibility, under mode model: fact claims carry every enforcing row, the intent claim carries the promise itself | promise | response/data/claims.json, @workspaces/be at the frozen head, @tools/websearch | — | EVIDENCE_MISSING |
| 5 | Freeze the coverage matrix, under mode model | dimensions | response/data/claims.json, @workspaces/be and the surface it discovers | response/data/coverage-matrix.json | COVERAGE_INCOMPLETE, CONSUMER_UNPROVEN |
| 6 | Dispose legacy coexistence, under mode model | — | response/data/coverage-matrix.json: the legacy create, read and settle rows and their proof | — | CONTRADICTION_UNRESOLVED |
| 7 | Reconcile against delivered source, under mode reconcile | — | input backend-source-application, @workspaces/be at the frozen head, the coverage matrix frozen at the published head | — | RECONCILIATION_DISCREPANCY |
| 8 | Publish one head under an exclusive lease | — | response/data/claims.json, @worktrees/businesses/<featureId> at the previous head | @worktrees/businesses/<featureId> as the new model.json head, response/data/model.json, @tools/sourcewrite | SOURCE_DRIFT |
| 9 | Emit | — | everything above | response/response.md, response/response.json | — |
Legacy create, read, and settle each take their own row when they are declared: a new sale path may retire legacy creation only while already-purchased rights stay readable and pending legacy settlement still completes, and the retirement carries proof that the creation path is closed. The matrix is content addressed and its fingerprint travels in the binding, so backend implementation, quality integration, and UAT can prove they consumed the same matrix rather than a paraphrase of it. A resume begins again at step 1, reuses only unchanged fingerprinted observations, and consumes the exact delta; republished evidence arrives as a new evidence fingerprint, because the same fingerprint cannot yield a different answer.
Outputs
| Kind | File | Type | Required |
|---|---|---|---|
business-promise-authority | response/response.md | md | yes |
claims | response/data/claims.json | data | yes |
coverage-matrix | response/data/coverage-matrix.json | data | no |
model | response/data/model.json | data | yes |
Stops
| Code | Disposition |
|---|---|
INVALID_INPUT | terminate |
SOURCE_DRIFT | terminate |
NO_PROGRESS | terminate |
EVIDENCE_MISSING | terminate |
CONTRADICTION_UNRESOLVED | terminate |
LIFECYCLE_TRANSITION_INVALID | terminate |
AUTHORITY_CONFLICT | terminate |
APPROVAL_REQUIRED | terminate |
COVERAGE_INCOMPLETE | terminate |
CONSUMER_UNPROVEN | terminate |
RECONCILIATION_DISCREPANCY | terminate |
Next
| When | Operator |
|---|---|
| the promise is published and a frontend surface must carry it | frontend.direction.decide |
| the promise is published and a backend contract must carry it | backend.source.apply |
| the promise needs boundaries and data ownership decided before it can be enforced | architecture.decide |
| the head is reconciled against the delivered source and the delivery may be published | git.publish |