Skip to content

Make fresh Flow runs self-initializing - #223

Merged
bigboateng merged 4 commits into
mainfrom
fix/fresh-flow-self-initialization
Aug 16, 2026
Merged

Make fresh Flow runs self-initializing#223
bigboateng merged 4 commits into
mainfrom
fix/fresh-flow-self-initialization

Conversation

@bigboateng

Copy link
Copy Markdown
Contributor

Problem

A fresh repository Flow requested product delegation before installation had established the exact control bundle. Generated skills also entered through a path that expected initialization to have happened separately.

Change

  • resolve and commit installation prerequisites before projecting product delegation;
  • derive deterministic initialization inputs from the selected repository and executing runtime;
  • reject conflicting host restatements;
  • enter delegated generated skills through the canonical Flow continuation;
  • preserve exact delegation and provider-authority boundaries.

Verification

  • python3 .github/scripts/run_go_tests.py — 489 tests passed
  • go test ./cmd/boatstack-helper ./flow/softwaredelivery
  • go build ./...
  • go vet ./...
  • python3 -m unittest discover -s .github/tests -p 'test_*.py' -v — 54 tests passed, one expected failure
  • release-note validation and preflight
  • Boatstack local fixed-point review — READY

Release note: release-notes/2026-08-16-canonical-flow-initialization.md

@cursor

cursor Bot commented Aug 16, 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.92

The fresh-run path itself composes correctly, but changing checksum-bound generated skills without a compatible migration path makes existing delegated Flow repositories fail validation before they can update. Model-level verification is not required before addressing this concrete migration defect.

Comment on lines +66 to +68
if entry.Delegation != nil {
startCommand = fmt.Sprintf("boatstack flow run --repo . --flow %s --entry %s --repository-authority --host %s --format json", compiled.Document.Program.ID, entry.ID, host)
}

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.

[P1] Provide an upgrade path for existing generated Flow artifacts

Invariant: a candidate runtime must accept or atomically migrate artifacts produced by the admitted runtime before requiring candidate-generated projections. A repository with a delegated Flow compiled at the base revision has control-program.compiler.4 artifacts and skill digests containing the old boatstack next command. Running the head candidate regenerates different skill bytes here while retaining the same compiler version, so CheckArtifact returns CONTROL_PROGRAM_STALE before resolution or installation.update; recompiling with head first conversely makes the active base runtime reject the repository. This patch therefore blocks the governed runtime-update path for existing delegated Flow repositories. Add a regression test that creates the fixture with the actual base generator, then verifies the head runtime can perform the update/migration without an unmanaged incompatible intermediate state.

Confidence: 0.94

@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.99

The new prerequisite ordering has two concrete liveness failures: the normal generated command cannot authorize initialization, and an authority-bearing invocation installs an uncommitted bundle that later fails workspace admission. Model-level verification is recommended before merge, particularly to check that every new pre-delegation prerequisite has an actionable authority path and that installation effects compose with revision-bound workspace transitions.

Comment thread boatstack/cmd/boatstack-helper/flow_runtime.go Outdated
Comment thread boatstack/cmd/boatstack-helper/flow_runtime.go
@bigboateng

Copy link
Copy Markdown
Contributor Author

Review cycle 1 is settled at d58ee1c. Both P1 threads were fixed, answered individually, and resolved. The canonical local Boatstack review is READY; affected Go suites and the exact fake-provider product-delivery Flow pass. This head is now frozen for the next independent review cycle.

@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 new revision guarantee is bypassable through the public kernel/SDK path and remains vulnerable to a helper-to-effect TOCTOU race. This is a concrete boundary defect, so model-level verification is not required before fixing it; afterward, model-level verification is not specifically recommended.

Comment thread boatstack/cmd/boatstack-helper/control_bundle.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 commit boundary can shadow mandatory recovery, rejects valid idempotent replays, and remains vulnerable to revision drift between its final check and effect execution. Model-level verification is recommended before merge, particularly to ask whether any other pending-journal or maintenance states are shadowed by the new pre-resolution suspension.

Comment on lines +201 to +204
if options.transitionID == "" || !installationAuthority {
acceptedBundleRevision, err = requireCommittedAcceptedFlowBundle(ctx, repository, options, bundle.Source, bundleFingerprint)
if err != nil {
return commandOptions{}, err

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.

[P1] Allow interrupted installation to reach recovery before enforcing commit

Invariant: a pending transaction must reach its prescribed recovery transition without requiring the transaction's partial effects to be committed. If installation.initialize installs its target pin, generated bundle, and final state mutation but the process stops before journal commit, the state fingerprint matches the dirty target bundle while a pending journal requires recovery. Restarting the Flow enters this unconditional guard, VerifyControlBundleRevision fails, and returns CONTROL_BUNDLE_COMMIT_REQUIRED before the controller can observe the journal and select recovery.resume or recovery.rollback; every retry repeats the suspension. This patch introduces that pre-resolution guard, forcing users to commit unverified, rollbackable effects or leaving recovery blocked. A regression test should interrupt initialization after PreparedEffect.Execute but before journal commit, restart the same Flow, and assert that recovery is selected without a commit suspension and rollback can restore the bundle.

Confidence: 0.98

Comment on lines +124 to +132
if request.ControlBundleRevision != "" {
layout, _, layoutErr := k.resolver.ResolveLayout(ctx, invocation)
if layoutErr != nil {
response.Error = layoutErr.Error()
return response, layoutErr
}
if revisionErr := boatstackruntime.VerifyCurrentControlBundleRevision(ctx, layout.RepositoryRoot, request.ControlBundleRevision, request.ControlBundle.Source); revisionErr != nil {
response.Error = revisionErr.Error()
return response, revisionErr

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.

[P2] Check idempotency receipts before rejecting revision drift

Invariant: replaying an already committed idempotent request must return the committed fact without re-admitting current repository authority. Apply a revision-bound transition at commit A, advance HEAD to commit B while retaining identical bundle files, then resend the exact request with its idempotency key and ControlBundleRevision=A. This new controller-level check rejects the request before Engine.Apply can find and replay the receipt, producing a false failure despite no effect being required. The observable result is an ambiguous failed retry of a successfully committed transition. A regression test should commit a transition, create an empty Git commit, resend the identical request, and assert Replayed=true, the same receipt, and zero new effects.

Confidence: 0.96

Comment on lines +519 to +525
// Prepare is the final side-effect-free plant preflight. Run it after the
// locked observation but before receipt binding or transaction state so a
// changed external boundary leaves no managed mutation to recover.
prepared, err := e.effects.Prepare(ctx, admission, transition)
if err != nil {
return result, err
}

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.

[P1] Close the race between final revision verification and effect execution

Invariant: if the admitted control-bundle revision changes before the first transition effect, the transition must perform zero effects. The added revision check runs during Prepare, but after it succeeds the engine writes journal state and later calls PreparedEffect.Execute; neither the repository ref nor Git writers are locked across that interval. A concurrent commit/reset can therefore move HEAD from admitted revision A to B after preparation, after which a state-only or program effect executes and can commit a receipt whose admission binds A even though the effect ran at B. This patch introduces the exact-revision claim without making its final check atomic with execution. A regression test should wrap a prepared effect so that it moves HEAD immediately before delegating Execute, then assert refusal with no journal, state mutation, command, or receipt.

Confidence: 0.93

@bigboateng
bigboateng merged commit 6485491 into main Aug 16, 2026
18 checks passed
@bigboateng
bigboateng deleted the fix/fresh-flow-self-initialization branch August 16, 2026 17:22
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