Skip to content

Autoflow — add single-writer orchestration controller - #82

Merged
LogicDuke merged 2 commits into
mainfrom
feature/autoflow-controller-single-writer
Sep 5, 2026
Merged

Autoflow — add single-writer orchestration controller#82
LogicDuke merged 2 commits into
mainfrom
feature/autoflow-controller-single-writer

Conversation

@LogicDuke

@LogicDuke LogicDuke commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Autoflow Orchestration Controller / Single-Writer Boundary (Decision 060)

This is NOT autonomous orchestration. It establishes the single-writer boundary and a bounded startup-open path; real post-start event adapters remain separate future gates.

What this does

  • Establishes one private Autoflow write-authority owner (AutoflowOrchestrator): it privately owns the write-capable AutoflowRuntime and exposes only open() and reader(). The writer never leaks.
  • AutoflowRuntime prevents replacement of an active workflow: open() rejects with WORKFLOW_ALREADY_ACTIVE while current() is OPEN or AWAITING_HUMAN_DECISION (the active workflow is never clobbered). The pure domain openWorkflow is unchanged.
  • Reopening after CLOSED is allowed — one active workflow at a time, not one per process lifetime. No workflow history is retained (in-memory limitation).
  • Startup-open only: a bounded, process-scoped configuration seam (AGENTBRIDGE_WORKFLOW_ID, AGENTBRIDGE_WORKFLOW_BOUND_COMMIT_SHA, optional AGENTBRIDGE_WORKFLOW_PULL_REQUEST_ID; repository identity must equal the runtime identity). Absent → no workflow; partial/mismatch/malformed → fail closed.
  • Cockpit receives the reader only. Loopback pin, port, RepositoryObserver, D1/D2/D4, fixture rules, and source provenance are all unchanged.

What this deliberately does NOT do

  • No post-start production WorkflowEvent source (no autonomous HEAD_OBSERVED/HUMAN_GATE_OPENED/CLOSE_REQUESTED/invocation/review/evidence events).
  • No Git/GitHub/network observation, no provider or Policy execution authority, no merge/Ready/review-request authority.
  • No persistence/replay — a fresh runtime begins current() === null; no recovery is claimed.

Boundaries & validation

  • Six strong boundaries byte-identical: producer.ts, read-model.ts, evidence-freshness-projection.ts, autoflow-projection.ts, domain/workflow.ts, domain/workflow-transitions.ts.
  • 1857/1857 tests pass; typecheck, lint, build, git diff --check all pass.
  • Independent uncommitted-candidate validation: PASS.

Scope note

Runtime cutover to this composition is a separate gate; the live runtime (PID 23880 on 127.0.0.1:4317) remains untouched.

🤖 Generated with Claude Code

https://claude.ai/code/session_015R3Z9oKuFnRjoY981RV5sb

Summary by CodeRabbit

  • New Features

    • Added controlled workflow startup from environment configuration, including repository and commit validation.
    • Live Cockpit now displays the workflow opened during startup.
    • Added read-only workflow status access for Cockpit integrations.
  • Bug Fixes

    • Prevented multiple workflows from being active simultaneously.
    • Rejected incomplete, mismatched, or invalid startup workflow requests.
    • Preserved the active workflow when a second startup request is attempted.

Establish one private Autoflow write-authority owner (Decision 060,
AUTOFLOW ORCHESTRATION CONTROLLER / SINGLE-WRITER BOUNDARY). This is NOT
autonomous orchestration.

- AutoflowRuntime.open() enforces the single-active-workflow invariant:
  OPEN/AWAITING_HUMAN_DECISION reject with WORKFLOW_ALREADY_ACTIVE (the
  active workflow is never clobbered); CLOSED permits a new open; the
  pure domain openWorkflow is unchanged.
- AutoflowOrchestrator privately owns the write-capable runtime and
  exposes only open() and reader(); the writer never leaks.
- Bounded startup-open input seam (process-scoped env only); no
  post-start production WorkflowEvent source.
- Cockpit receives the read-only reader; loopback/D1/D2/D4/provenance
  unchanged. No Git/GitHub/network/provider/Policy authority, no
  persistence/replay. Six strong boundaries byte-identical.

Full suite 1857/1857; independent uncommitted-candidate validation PASS.
Runtime cutover is a separate gate; live PID remains untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015R3Z9oKuFnRjoY981RV5sb
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: e8f1684e-9dfc-4174-aa6e-82cf508c31bc

📥 Commits

Reviewing files that changed from the base of the PR and between 843d517 and d8b7493.

📒 Files selected for processing (8)
  • src/autoflow/orchestrator.ts
  • src/autoflow/runtime.ts
  • src/runtime/live-cockpit.ts
  • src/runtime/orchestration-input.ts
  • tests/autoflow/orchestrator.test.ts
  • tests/autoflow/runtime.test.ts
  • tests/runtime/live-composition.test.ts
  • tests/runtime/orchestration-input.test.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds AutoflowOrchestrator as the production write owner, prevents multiple active workflows, validates bounded startup environment input, and wires the read-only state reader into the live Cockpit runtime.

Changes

Autoflow startup flow

Layer / File(s) Summary
Runtime and orchestrator write boundary
src/autoflow/runtime.ts, src/autoflow/orchestrator.ts, tests/autoflow/*
The runtime rejects opens while a workflow is active and uses a private state cell for writer and reader state. The orchestrator exposes only open and reader. Tests verify active-workflow protection and capability containment.
Bounded startup configuration
src/runtime/orchestration-input.ts, tests/runtime/orchestration-input.test.ts
Startup environment variables produce one validated WorkflowBinding, or null when absent. Incomplete and repository-mismatched requests throw.
Live Cockpit startup wiring
src/runtime/live-cockpit.ts, tests/runtime/live-composition.test.ts
The live runtime opens configured workflows through the orchestrator, fails closed for non-APPLIED results, and gives Cockpit only the read-only reader. Composition tests cover snapshots, HTTP output, and restart behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to d8b74

Startup workflow opening is fail-closed and remains contained behind the orchestrator, while Cockpit receives only read access. No current merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant LiveCockpit
  participant StartupConfig
  participant AutoflowOrchestrator
  participant AutoflowRuntime
  LiveCockpit->>StartupConfig: readStartupWorkflowConfig
  StartupConfig-->>LiveCockpit: WorkflowBinding or null
  LiveCockpit->>AutoflowOrchestrator: open(binding)
  AutoflowOrchestrator->>AutoflowRuntime: open(binding)
  AutoflowRuntime-->>AutoflowOrchestrator: AutoflowOpenResult
  LiveCockpit->>AutoflowOrchestrator: reader()
  AutoflowOrchestrator-->>LiveCockpit: AutoflowStateReader
Loading

Poem

A rabbit guards the workflow gate
One open path must patiently wait
The reader sees, but cannot write
Startup bindings land just right
Cockpit wakes with state in sight

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the Autoflow single-writer orchestration controller.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/autoflow-controller-single-writer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LogicDuke
LogicDuke marked this pull request as ready for review September 5, 2026 19:11
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T20:29:17.913736Z d8b7493 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@LogicDuke

Copy link
Copy Markdown
Owner Author

@codex review

Please perform one substantive review of this PR at exact head 571b2ca8f73df18458afd96f3703f74810efdfcc (base main@843d517a3251e365e84ab0bd31eaaba74cd50f5d) against Decision 060 — AUTOFLOW ORCHESTRATION CONTROLLER / SINGLE-WRITER BOUNDARY. This is not autonomous orchestration.

Review focus (the actual 8-file diff):

  1. Single-writer containment — the write-capable AutoflowRuntime is private to AutoflowOrchestrator and never leaks (no getter, property, outward config, or closure).
  2. AutoflowRuntime.open() active-workflow guard — OPEN/AWAITING_HUMAN_DECISION reject with WORKFLOW_ALREADY_ACTIVE without clobbering #current.
  3. Reopen-after-CLOSED semantics (one active workflow at a time; no history retained).
  4. Startup-open fail-closed behavior (partial/malformed/repository-mismatch config).
  5. Malformed/partial/mismatch config handling in orchestration-input.ts.
  6. Any writer leakage to Cockpit / RepositoryObserver.
  7. Accidental construction of a second AutoflowRuntime.
  8. Any accidental production apply/post-start event source.
  9. Any external authority/capability widening (Git/GitHub/network/provider/Policy).
  10. Loopback + runtime composition preservation.
  11. Restart/persistence honesty (in-memory; current()===null on fresh start; no recovery claim).
  12. Six strong-boundary preservation (producer, read-model, evidence-freshness-projection, autoflow-projection, domain/workflow, domain/workflow-transitions).
  13. Any false-autonomy wording.
  14. Any side effect caused by the startup open.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 571b2ca8f7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/autoflow/orchestrator.ts
Comment thread src/runtime/orchestration-input.ts Outdated
Repairs two Codex P1 findings on PR #82 (Decision 060).

P1 #1 (capability containment): AutoflowRuntime.reader() closed over
`this` and dispatched through the mutable AutoflowRuntime.prototype.current,
so a downstream prototype swap could recover the write-capable runtime.
The runtime now holds a private state cell; open/apply/current read/write
that one cell, and reader() closes over the cell alone (a plain data
read, no prototype dispatch), so the writer is unrecoverable. Domain
semantics and the six strong boundaries are unchanged.

P1 #2 (fail-closed config): readStartupWorkflowConfig's presence check
ignored the optional workflow variables, so an optional-only config
(pull-request id or workflow repository id only) silently returned null
instead of failing closed. Presence now covers every workflow-open
variable; any present makes it a request, and an incomplete request
throws.

Adds an adversarial prototype-swap reader test and optional-only config
cases. Full suite 1862/1862; typecheck/lint/build/diff-check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015R3Z9oKuFnRjoY981RV5sb
@LogicDuke

Copy link
Copy Markdown
Owner Author

@codex review

Please perform one substantive re-review of this PR at exact head d8b7493604c6206aa0f18a32155d72ecf0c0205a (base main@843d517a3251e365e84ab0bd31eaaba74cd50f5d), Decision 060. This commit repairs the two prior P1 findings.

Focus:

  1. AutoflowRuntime.reader() no longer captures the write-capable runtime — it closes over a private state cell only, with no dispatch through AutoflowRuntime.prototype.current.
  2. A downstream AutoflowRuntime.prototype.current monkey-patch cannot recover a runtime receiver via reader.current().
  3. The state-cell is the single source of truth (current()/open()/apply()/reader all share the one cell); the reader remains live.
  4. Startup-open presence detection now includes every workflow-open variable; optional-only config (pull-request id / workflow repository id) fails closed; repository mismatch fails closed; the valid startup-open path still works.
  5. No writer leakage, no second runtime/state owner, no external authority/capability/persistence/event-source widening, six strong boundaries unchanged.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: d8b7493604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@LogicDuke

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Final substantive review at exact current head d8b7493604c6206aa0f18a32155d72ecf0c0205a (base main@843d517a3251e365e84ab0bd31eaaba74cd50f5d), Decision 060 — AUTOFLOW ORCHESTRATION CONTROLLER / SINGLE-WRITER BOUNDARY (not autonomous orchestration). Two prior Codex P1s (reader/writer-capture; optional-only startup config) are fixed on this head and their threads resolved; exact-head CI #265 and a Codex exact-head re-review are clean.

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="843d517a3251e365e84ab0bd31eaaba74cd50f5d"
head="d8b7493604c6206aa0f18a32155d72ecf0c0205a"

printf '%s\n' '=== checked-out HEAD ==='
git rev-parse HEAD
printf '%s\n' '=== requested commits ==='
git rev-parse "$base^{commit}"
git rev-parse "$head^{commit}"

printf '%s\n' '=== changed files ==='
git diff --name-status "$base" "$head"
printf '%s\n' '=== changed-file count ==='
git diff --name-only "$base" "$head" | wc -l

printf '%s\n' '=== complete range diff ==='
git diff --find-renames --find-copies --check "$base" "$head"
git diff --find-renames --find-copies "$base" "$head"

printf '%s\n' '=== changed-file outlines ==='
git diff --name-only "$base" "$head" | while IFS= read -r file; do
  printf '\n--- %s ---\n' "$file"
  ast-grep outline "$file" --items all || true
done

printf '%s\n' '=== targeted symbols and construction/application sites ==='
rg -n -C 4 --hidden \
  -g '!node_modules/**' -g '!dist/**' -g '!build/**' \
  'new\s+AutoflowRuntime\s*\(|new\s+AutoflowOrchestrator\s*\(|\.apply\s*\(|\.open\s*\(|\.reader\s*\(|AutoflowRuntime|AutoflowOrchestrator|orchestration-input|AGENTBRIDGE_WORKFLOW_' \
  .

printf '%s\n' '=== strong-boundary range changes ==='
git diff --name-only "$base" "$head" -- \
  '*producer.ts' \
  '*read-model.ts' \
  '*evidence-freshness-projection.ts' \
  '*autoflow-projection.ts' \
  '*domain/workflow.ts' \
  '*domain/workflow-transitions.ts'

printf '%s\n' '=== package and entrypoint candidates ==='
fd -HI '^(package\.json|.*\.(ts|tsx|js|mjs|cjs))$' . \
  -E node_modules -E dist -E build | head -n 300

Length of output: 108746


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== package scripts and entrypoint exports ==='
sed -n '1,240p' package.json
printf '%s\n' '--- src/index.ts ---'
cat -n src/index.ts

printf '%s\n' '=== live runtime composition ==='
sed -n '1,270p' src/runtime/live-cockpit.ts
printf '%s\n' '=== cockpit server loopback configuration ==='
sed -n '1,260p' src/cockpit-host/server.ts
printf '%s\n' '=== repository observer authority surface ==='
sed -n '1,260p' src/runtime/repository-observer.ts

printf '%s\n' '=== runtime and domain workflow status definitions ==='
sed -n '1,250p' src/autoflow/runtime.ts
ast-grep outline src/domain/workflow.ts --items all
ast-grep outline src/domain/workflow-transitions.ts --items all
rg -n -C 5 --glob 'src/**/*.ts' 'WORKFLOW_STATUS|status:|CLOSED|AWAITING_HUMAN_DECISION|OPEN' src/domain/workflow.ts src/domain/workflow-transitions.ts

printf '%s\n' '=== production-only Autoflow writer construction and calls ==='
rg -n -C 5 --glob 'src/**/*.ts' \
  'new\s+AutoflowRuntime\s*\(|new\s+AutoflowOrchestrator\s*\(|\b[A-Za-z_$][A-Za-z0-9_$]*\.apply\s*\(|\b[A-Za-z_$][A-Za-z0-9_$]*\.open\s*\(|\.reader\s*\(' \
  src

printf '%s\n' '=== direct imports of runtime/orchestrator in production source ==='
rg -n -C 3 --glob 'src/**/*.ts' \
  'from .*\bautoflow/(runtime|orchestrator)\.js' \
  src

printf '%s\n' '=== workflow event sources and external-capability imports in changed production files ==='
rg -n -C 3 \
  'WorkflowEvent|HEAD_OBSERVED|HUMAN_GATE_OPENED|CLOSE_REQUESTED|setInterval|setTimeout|node:child_process|node:fs|node:https|node:http|fetch\s*\(|GitHub|octokit|Policy|provider' \
  src/autoflow/orchestrator.ts src/autoflow/runtime.ts src/runtime/live-cockpit.ts src/runtime/orchestration-input.ts

printf '%s\n' '=== exact unchanged strong-boundary blob identity ==='
for path in \
  src/cockpit-snapshot/producer.ts \
  src/cockpit/read-model.ts \
  src/cockpit/evidence-freshness-projection.ts \
  src/cockpit/autoflow-projection.ts \
  src/domain/workflow.ts \
  src/domain/workflow-transitions.ts
do
  printf '%s ' "$path"
  git rev-parse "843d517a3251e365e84ab0bd31eaaba74cd50f5d:$path"
  git rev-parse "d8b7493604c6206aa0f18a32155d72ecf0c0205a:$path"
done

Length of output: 93925


@LogicDuke Review complete for exact head d8b7493604c6206aa0f18a32155d72ecf0c0205a against base 843d517a3251e365e84ab0bd31eaaba74cd50f5d.

I found no actionable issues.

The review confirmed these points:

  • Production composition constructs one AutoflowRuntime and one AutoflowOrchestrator.
  • The Cockpit receives only orchestrator.reader().
  • The reader closes over the private state cell. It does not capture the write-capable runtime or dispatch through AutoflowRuntime.prototype.current.
  • open() rejects both active statuses with WORKFLOW_ALREADY_ACTIVE without replacing the current state.
  • open() permits a new workflow after CLOSED.
  • Startup configuration fails closed for partial, optional-only, malformed, and repository-mismatched requests.
  • Production code has no post-start apply() call or WorkflowEvent source.
  • The live composition retains the loopback-only bind behavior.
  • The six required strong-boundary files are byte-identical to the base commit.
  • The implementation does not add Git, GitHub, network, provider, Policy, persistence, or recovery authority.
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@LogicDuke
LogicDuke merged commit 8455eb9 into main Sep 5, 2026
2 checks passed
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