Skip to content

Parent outcome

A parent outcome is the App’s recorded decision about one originating coordinator objective. The operator asks for it. Child runs, adoption signatures, and read paths do not write it.

Maturity: Implemented on a provisioned protected controller. It is not part of ordinary bmo or bmo run. An unprovisioned checkout cannot record an accepted parent outcome. A child verdict grade, a synthesis selection, and an applied Patch Proposal leave this decision untouched.

The command is:

Terminal window
bmo -D /absolute/controller-data protected-admission decide-coordinator-outcome \
--host-id HOST \
--fingerprint FINGERPRINT \
--adoption-key-id ADOPTION_KEY \
--adoption-fingerprint ADOPTION_FINGERPRINT \
--parent-run-id PARENT_RUN_ID

--timeout defaults to 2 minutes and must be positive. --data-dir (-D) must be explicit and absolute. The same database rules as protected admission apply: project configuration cannot select the database.

The controller database must already be the provisioned app database at that data directory. The command loads two public trust records and checks that the flags match them exactly:

FlagMust match
--host-idThe host ID in the root-owned protected-admission trust file.
--fingerprintThat file’s key ID.
--adoption-key-idA separately provisioned adoption key for the same host.
--adoption-fingerprintThe SHA-256 SSH fingerprint of that adoption public key.
--parent-run-idThe originating coordinator objective.

The trust files are the same root-owned paths documented for protected-admission admit. The adoption key is not the admission signing key. The command holds no private key and cannot sign adoption or admit a child.

A missing pin, a relative data directory, a non-positive timeout, or a trust mismatch returns coordinator parent outcome denied and prints no receipt.

The decision runs in one database transaction. It loads the protected delegation for that parent, the parent run row, child-coverage facts, the signed adoption bundle, and the artifact evidence that adoption names. The caller supplies the parent run ID only. The caller does not supply an accepted bit or a proof digest.

Acceptance requires an empty residual list. Any of the following leaves accepted false and disposition at bounded_residual:

ResidualCondition
root_run_not_completedThe parent run is not a completed run with a coherent start and completion time.
coordinator_objective_child_coverage_unknownRequired child coverage could not be determined.
parent_child_coverage_incompleteCoverage is known and incomplete.
signed_adoption_unavailableNo verified adoption bundle is stored.
signed_adoption_evidence_unverifiableThe stored adoption bundle does not verify.
protected_root_not_completedVersion 2 adoption names a protected root that is not completed.
parent_artifact_evidence_unverifiableArtifact evidence does not match the adoption claims and the delegation bundle.
independent_parent_predicate_unverifiableThe original predicate evidence does not verify against the frozen source and success contract.

When the residual list is empty, accepted is true and disposition is accepted.

The receipt binds the parent run, parent session, protected root, prompt digest, source revision, source content digest, success contract, public pins, child coverage, and the evidence digests used for that decision. The receipt’s own receipt_sha256 covers that body. decision_id is derived from the evidence. Repeating the command for the same decision returns the stored receipt instead of writing a second row.

ResultStatusOutput
Trust, database, or identity refusal before a decisionNon-zerocoordinator parent outcome denied or a wrapped database error. No receipt.
Decision stored with residualsNon-zeroJSON receipt, then coordinator parent outcome retains a bounded residual.
Decision stored and acceptedZeroJSON receipt with accepted: true and disposition: accepted.
Same decision id already storedSame as that stored receiptThe stored JSON. A residual receipt still returns the residual error.

A residual is durable work. It is not rewritten into acceptance by retrying the command with the same evidence. Repair the missing completion, coverage, adoption, or predicate evidence, then decide again. A changed evidence set is a different decision id.

  • It does not apply a Patch Proposal or run mutation aftercare.
  • It does not start a worker, spend provider budget, or admit a child.
  • It does not change a verdict grade.
  • It does not treat bmo synthesize disposition candidate_ready as acceptance.
  • It does not run as part of protected-admission run-synthesis. That command returns agent JSON and leaves parent completion to the obligation owner. Record the parent outcome only with decide-coordinator-outcome.

Independent verification states the same split from the evidence side. Change synthesis states it from the candidate side.

Command flags are defined in internal/cmd/protected_coordinator_parent_outcome.go. The command accepts public verification pins and refuses an implicit or relative database path and a nonpositive decision timeout. The exact command fixtures are in the maintainer evidence mapping. The residual rules are evaluateCoordinatorParentOutcomeInTx and issueCoordinatorParentOutcome in internal/app/coordinator_parent_outcome.go.

Limits:

  • This receipt exists only for a coordinator objective on a provisioned controller. A local coding session has no accepted parent outcome until that command succeeds.
  • accepted means this evidence set satisfied the residual rules. It does not extend to work outside the frozen source pin and success contract.
  • The public command cannot create the adoption signature it consumes.
  • Cold inspection of a missing or invalid stored row is not evidence of acceptance.