Skip to content

Make software-delivery state effects declarative - #208

Merged
bigboateng merged 5 commits into
mainfrom
feat/declarative-state-effects
Aug 12, 2026
Merged

Make software-delivery state effects declarative#208
bigboateng merged 5 commits into
mainfrom
feat/declarative-state-effects

Conversation

@bigboateng

Copy link
Copy Markdown
Contributor

Summary

  • declare each controllable software-delivery transition's durable state facets and state effect
  • replace transition-ID reducer dispatch with one assignment reducer and a named native-handler registry
  • carry declared facet envelopes through the journal and recovery path
  • bump the control-program schema to 4 and the program-runtime and extension protocols to 3

Boundary

StateEffect is a software-delivery domain primitive (category B), not a new kernel primitive. It uses the kernel transition vocabulary for owned facets and keeps capability and authority admission in the kernel. Repository and extension programs cannot select host-native handlers or own installation state.

Native handlers remain only where the existing effect needs cross-field validation, conditional phase derivation, collection updates, or reconciliation: runtime/configuration reconciliation, installation/catalog reconciliation, objective binding, plan approval, abandonment, workspace cleanup/reap/reconciliation, gate evidence, visual evidence, and publication observation.

Verification

  • complete sharded suite: 236 tests passed
  • go test -race ./... -count=1
  • Python repository contracts: 36 passed, 1 expected failure
  • go vet ./...
  • go build ./...
  • release-note validation and preflight
  • git diff --check

The end-to-end regression adds a transition unknown to Go, applies its declared assignment, commits durable state, and retains its receipt. A temporary Standard Flow JSON declaration also passed the same test without production Go changes and was removed afterward.

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.98

The declarative state-effect contract is bypassed on protocol-backed production paths, the journal schema bump strands interrupted cross-version updates, and assignment validation admits deterministic apply refusals. Model-level verification is recommended after fixes, focused on whether every new declarative transition reaches its reducer and whether all version-skew recovery states retain progress.

Comment thread boatstack/delivery/program_manifest.go
Comment thread boatstack/internal/softwaredelivery/protocol/journal.go
Comment thread boatstack/internal/softwaredelivery/catalog/transition.go Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.97

The new declarative-state boundary admits authority and liveness contradictions and gives semantically identical programs different identities. Model-level verification is recommended after these fixes: exhaustively check that every accepted assignment set preserves durable-state validity for all resolver-matching states, and that every native handler is bound to compatible origin, policy, facets, and capabilities.

Findings without inline diff anchors

[P2] Canonicalize unordered state-effect declarations before fingerprinting

Invariant: representation-only ordering must not change executable program identity. Preconditions are ANDed, their values are ORed, and assignments target unique fields, yet normalization skips all three new slices. Reversing two assignments, preconditions, or precondition values therefore produces identical behavior with a different program fingerprint, causing false program drift and unnecessary explicit reconciliation. This is introduced by adding state effects to the fingerprint without canonicalizing them. A regression should compile reordered equivalent manifests and assert identical fingerprints.

Confidence: 0.98

Location: boatstack/delivery/program_manifest.go:475-479 (RIGHT)

Comment thread boatstack/internal/softwaredelivery/catalog/transition.go
Comment thread boatstack/internal/softwaredelivery/catalog/state_facet.go
Comment thread boatstack/internal/softwaredelivery/catalog/transition.go

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.97

The new declarative state boundary introduces a reachable confused-deputy deletion path and makes recovery authority depend on mutable, unbound journal data. Model-level verification is recommended for whether other declaratively produced durable fields can unlock privileged native transitions or recovery cycles.

Findings without inline diff anchors

[P1] Recovery trusts an unbound journal field as state authority

Invariant: recovery may replay only the interrupted transition's kernel-admitted state-facet grant. AllowedStateFacets is canonicalized but is not included in the admission identity or checked against the admitted transition/program, yet recovery treats it as authority. Modifying a pending control-only journal to add program or installation, and modifying its staged state mutation accordingly, lets resume/rollback commit that cross-domain mutation and issue a successful recovery receipt. Previously recovery derived this envelope from kernel-owned transition rules. Add a regression test with a control-only interrupted admission and a journal claiming an added program facet; recovery must reject even when the claimed list and mutation annotations are canonical.

Confidence: 0.97

Location: boatstack/internal/softwaredelivery/effects/recovery.go:150-151 (RIGHT)

Comment thread boatstack/internal/softwaredelivery/catalog/state_effect_closure.go Outdated
@bigboateng

Copy link
Copy Markdown
Contributor Author

Fixed declaration canonicalization before fingerprinting. Preconditions, nested values, and assignments are sorted and deduplicated; reordered equivalent manifests now produce the same fingerprint.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is correct
Confidence: 0.86

No actionable patch-introduced defect was established. The declarations match prior reducer behavior, and validation closes resolver/apply, facet-ownership, fingerprint, and recovery-envelope relations. Model-level verification is recommended before merge because this broadly changes control-program state semantics; verify that no accepted declarative assignment combination can create a blocking durable state or recovery cycle.

@bigboateng
bigboateng enabled auto-merge (squash) August 12, 2026 19:36
@bigboateng
bigboateng merged commit f700c7c into main Aug 12, 2026
17 checks passed
@bigboateng
bigboateng deleted the feat/declarative-state-effects branch August 12, 2026 19:46

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex automated review

Verdict: patch is incorrect
Confidence: 0.98

The patch introduces capability under-classification, mutable recovery authority, an unsound state-effect/target compatibility check, and a concrete unrecoverable schema-upgrade crash window. Model-level verification is recommended before merge, particularly to ask whether any newly declarative transition can deterministically miss its target or enter a recovery cycle.

Findings without inline diff anchors

[P1] Do not trust the journal's mutable facet envelope during recovery

Invariant: recovery may replay only the immutable facet authority of the interrupted admitted transition. AllowedStateFacets is stored outside the admission content identity, is merely syntax-checked when read, and is then used here as recovery authority. Starting with a control-only interrupted transition, changing the pending journal's envelope to include installation (and its staged state mutation/annotation accordingly) makes recovery.resume accept and commit runtime-state changes without installation authority. Previously recovery derived the envelope from the kernel transition mapping, so this widening is introduced by the patch. The observable result is cross-domain mutation through an untrusted recovery record. A regression test should tamper a valid control-only pending journal this way and prove recovery refuses before any mutation.

Confidence: 0.98

Location: boatstack/internal/softwaredelivery/effects/recovery.go:145-151 (RIGHT)

Comment thread boatstack/internal/softwaredelivery/catalog/transition.go
Comment thread boatstack/internal/softwaredelivery/catalog/transition.go
Comment thread boatstack/internal/softwaredelivery/protocol/journal.go
@bigboateng

Copy link
Copy Markdown
Contributor Author

The remaining review-body finding is fixed in #209. Recovery no longer trusts an allowed-state-facets list stored in mutable journal JSON. It reconstructs the recovery envelope from the admitted transition identity and admission-bound required capabilities, with regression coverage for journal-field injection and authority widening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant