Skip to content

Commit f7a9499

Browse files
authored
Bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks (#431) (#436)
* docs(orchestration): bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks - Bridge safety rule now reads: the child writes code and may commit checkpoints on the branch the host names; never push, never rebase or rewrite history, never decide scope, never issue a verdict, never spawn a bridge; the host keeps push, review, flowctl done, task state, and any history rewrite (usage template, orchestration guide, running-lean pointer, CLAUDE.md/AGENTS.md routing blocks, Codex mirror regenerated) - Usage guide states the host's on-return obligation (record base, review the commit range, run the gates on that diff, host-owned squash-or-keep) and carries a brief template for long bridged tasks with no timebox - Sandbox fallback named from a live probe: codex 0.153.4 workspace-write keeps .git/ read-only (index.lock: Read-only file system); danger-full-access in the asserted repo root permits the commit, else one run per scope unit with the host committing between - Changelog entry credits @DanielKillenberger (#431) Task: fn-244-bridged-implementer-may-commit.1 Claude-Session: https://claude.ai/code/session_01JFYv5JtK8HAsshpWRAT5YL * chore(flow): task receipt fn-244-bridged-implementer-may-commit.1 Claude-Session: https://claude.ai/code/session_01JFYv5JtK8HAsshpWRAT5YL * chore(flow): record completion-review skip for fn-244 Claude-Session: https://claude.ai/code/session_01JFYv5JtK8HAsshpWRAT5YL
1 parent bb3554f commit f7a9499

13 files changed

Lines changed: 255 additions & 18 deletions
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"branch_name": "fn-244-bridged-implementer-may-commit",
3+
"completion_review_status": "not_required",
4+
"completion_reviewed_at": "2026-09-14T07:48:56.149778Z",
5+
"created_at": "2026-09-14T07:20:44.619982Z",
6+
"default_impl": null,
7+
"default_review": null,
8+
"default_sync": null,
9+
"depends_on_epics": [],
10+
"id": "fn-244-bridged-implementer-may-commit",
11+
"impl_review_rounds": {
12+
"fn-244-bridged-implementer-may-commit.1": 0
13+
},
14+
"next_task": 1,
15+
"no_plan": true,
16+
"plan_review_rounds": 0,
17+
"plan_review_status": "unknown",
18+
"plan_reviewed_at": null,
19+
"ready": true,
20+
"review_attempts": [
21+
{
22+
"artifact_sha256": "ef090d804c5087056482382894adb7446c6e4c099973e6d1c2ab8428c08a5bc4",
23+
"backend": "codex",
24+
"base_sha": "bb3554f6854c9f5ee7dc02bdebf77c0d33722a4a",
25+
"counter_kind": "impl",
26+
"effort": "high",
27+
"failure_class": null,
28+
"finalized": {
29+
"digest": "complete",
30+
"receipt": "complete",
31+
"status": "not_applicable"
32+
},
33+
"findings_digest": {
34+
"backend": "codex",
35+
"digest_truncated": false,
36+
"items": [],
37+
"reviewKind": "implementation"
38+
},
39+
"forced": false,
40+
"hash_epoch": 0,
41+
"head_sha": "15792ae478d5a9fa8b8d1d60c10f55a0c0fa08a9",
42+
"head_sha_observed": true,
43+
"kind": "impl",
44+
"model": "gpt-6-astra",
45+
"outcome": "verdict",
46+
"output_bytes": 2068,
47+
"output_sha256": "a1692e8a49a8a2e2cdf8cb6003fdd3da91f3b261f203cab41f3059ba21ed186b",
48+
"reservation_id": "578d584fe3804f3cb5d300ea2a077f69",
49+
"round_consumed": true,
50+
"scope": "impl:fn-244-bridged-implementer-may-commit.1",
51+
"superseded_by": null,
52+
"task": "fn-244-bridged-implementer-may-commit.1",
53+
"timestamp": "2026-09-14T07:45:38.574556Z",
54+
"verdict": "SHIP"
55+
}
56+
],
57+
"review_hash_epoch": {
58+
"impl:fn-244-bridged-implementer-may-commit.1": 1
59+
},
60+
"review_pending_rounds": {},
61+
"review_reservations": {},
62+
"review_transport_failures": {
63+
"impl:fn-244-bridged-implementer-may-commit.1": 0
64+
},
65+
"spec_path": ".flow/specs/fn-244-bridged-implementer-may-commit.md",
66+
"status": "open",
67+
"title": "Bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks (#431)",
68+
"tracker": {
69+
"baseHashFlow": null,
70+
"baseHashTracker": null,
71+
"depRelations": [],
72+
"id": null,
73+
"identifier": null,
74+
"lastSyncedAt": null,
75+
"mergeBaseFlow": null,
76+
"mergeBaseTracker": null,
77+
"url": null
78+
},
79+
"updated_at": "2026-09-14T07:48:56.149786Z"
80+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks (#431)
2+
3+
## Conversation Evidence
4+
5+
Source: GitHub issue gmickel/flow-next#431 (reporter: DanielKillenberger), routed by the user through `/flow-next:flow`, plus one user answer in this session.
6+
7+
1. [issue] "The bridge recipe in `flowctl usage` ... says the bridged child never commits and the host keeps git. For a one-task spec implemented through a `codex exec` bridge, that rule leaves the host two bad options: one multi-hour run that ends in a single giant uncommitted diff, or host-inserted returns between the spec's steps so the host can commit checkpoints."
8+
2. [issue] "Because the child may not commit, the host committed after each return. The first host session added a 'stop cleanly if you run out of room' line ... the implementer took that as licence to return partial after 30 to 45 minutes. Result: 19 dispatches for one task, each with a fresh context and a re-brief."
9+
3. [issue] "with an in-host worker the worker commits per task and returns once; with a bridge the child cannot commit, so a long task either has no checkpoints or has host-inserted turns."
10+
4. [issue] Option 1: "Let the bridged child commit checkpoints on its branch, with the host still owning review, `flowctl done`, push and any history rewrite. The safety rule could keep 'never push, never rebase, never decide scope, never issue a verdict' and drop 'never commit'. The host reviews the commit range on return, which is what the in-host worker path already does."
11+
5. [issue] Option 2: "document the checkpoint pattern for long bridged tasks: one run per spec step or per commit-sized unit, host commits between, with a template brief that does not carry a timebox and says 'return only when this scope is done or blocked'."
12+
6. [issue] Environment: "flow-next 5.2.1, Claude Code host, Codex CLI 0.153.4 as the bridge; implementer on the Codex bridge, reviewer host-native, `review.backend none`."
13+
7. [user] "i feel like relax commit rule + brief template seems safe here right, any model is intelligent enough to do a commit."
14+
8. [user] (selected option) Relax commit rule + brief template: let the bridged child commit checkpoints on its branch; keep never push / rebase / scope / verdict / nested bridge; host reviews the commit range on return; add the timebox-free brief template.
15+
16+
Strategic context (STRATEGY.md): approach "the artifact is the contract"; design principle "remember the bitter lesson: do not build scaffolding around a model's current weaknesses". Active tracks: Ralph autonomous mode (flow --auto + land), Cross-platform parity, Self-improving through normal work.
17+
18+
## Goal & Context
19+
<!-- scope: business -->
20+
<!-- Goal & Context: 60% [paraphrase], 20% [user], 20% [inferred] -->
21+
22+
The headless bridge recipes (the `## Orchestration & model steering` section of the usage guide, mirrored into the orchestration guide and the site) carry a safety rule: the bridged child writes code, the host keeps git, judgment, and the verdict, and the child never commits. A user running a one-task `--no-plan` spec through a `codex exec` implementer hit the cost of that rule: with no checkpoints allowed, the host had to insert returns between the spec's steps and commit each one, and a timebox line added to make that possible taught the implementer to return partial. One task took 19 dispatches with a re-brief each time (evidence 1-3).
23+
24+
The in-host worker already commits per task and returns once, and the host reviews its commit range. A bridged child gains nothing from being forbidden to commit; the guard the rule actually needs is against push, history rewrite, scope drift, self-issued verdicts, and nested bridges. The maintainer's call (evidence 7-8): relax the commit clause, keep the rest, and document a brief shape for long bridged tasks that carries no timebox. This is a prose-only change to the bridge route, consistent with the recorded decision that bridge safety lives in prose rather than a hook.
25+
26+
## Architecture & Data Models
27+
<!-- scope: technical -->
28+
29+
No code or config change. The deliverable is the revised bridge safety rule and a brief template, applied to every surface that currently states the rule: the usage guide template and its Codex mirror (kept identical by the sync script), the orchestration guide and its Codex mirror, the running-lean guide's pointer sentence, the repo's own instruction files' routing block, the changelog, and the site's work page, model-routing guide, cookbook entry, and landing-page card. Reach pages do not restate the rule and need no change unless a per-harness note about commit permission in a sandbox is warranted.
30+
31+
The rule's new shape: the bridged child writes code and may commit checkpoints on the branch the host names; the host keeps push, history rewrite, scope, review, verdict, task state, and `flowctl done`. On return the host reviews the child's commit range from the recorded base, exactly as it does for the in-host worker.
32+
33+
## API Contracts
34+
<!-- scope: technical -->
35+
36+
Prose contract only. The brief template for a long bridged task states, at minimum: the branch to commit on and the commit convention; that the child commits a checkpoint per completed scope unit (a spec step or a commit-sized unit); that the child never pushes, never rebases or amends, never changes scope, never issues a verdict, never spawns a bridge; and the return condition "return only when this scope is done or blocked", with no timebox and no "stop cleanly if you run out of room" clause. The host's return handling names the base commit, the commit-range review, the gates, and the host-owned squash or rewrite decision.
37+
38+
## Edge Cases & Constraints
39+
<!-- scope: technical -->
40+
41+
- A bridge invoked under a read-only or workspace-write sandbox that denies `git commit`: the brief's fallback is the one-run-per-scope-unit pattern with the host committing between runs; the child records that it could not commit in its digest rather than silently returning a dirty tree. [inferred]
42+
- The child's commits are on the host-chosen branch only; any commit landing elsewhere is a host review finding on return. [inferred]
43+
- The usage template and its Codex mirror must stay byte-identical; the sync script regenerates the mirror. [inferred]
44+
- The recorded decision that bridge safety is prose-only stands: no hook, guard, or flowctl subcommand is added to enforce the new rule. [paraphrase]
45+
46+
## Acceptance Criteria
47+
<!-- scope: both -->
48+
49+
- **R1:** The bridge safety rule in the usage guide (the `## Orchestration & model steering` section) and its Codex mirror reads: the bridged child writes code and may commit checkpoints on the branch the host names; the child never pushes, never rebases or rewrites history, never decides scope, never issues a review verdict, and never spawns a bridge of its own; the host keeps push, review, `flowctl done`, task state, and any history rewrite. Errors: no error surface beyond the template-mirror parity check. [user]
50+
- **R2:** The same rule replaces every other copy that says the child never commits: the orchestration guide and its Codex mirror, the running-lean pointer sentence, and the repo's own instruction-file routing block. No surface in the plugin still states "never commits" for a bridged child. Errors: none beyond a grep for the old wording returning empty. [paraphrase]
51+
- **R3:** The usage guide's bridge section states the host's on-return obligation: record the base commit before dispatch, review the child's commit range on return, run the gates on that diff, and decide squash or keep as the host. Errors: none. [paraphrase]
52+
- **R4:** The usage guide carries a brief template for long bridged tasks: branch and commit convention, checkpoint unit (per spec step or commit-sized unit), the five never clauses from R1, and the return condition "return only when this scope is done or blocked", with an explicit note that a timebox or "stop cleanly if you run out of room" line invites partial returns and must not be included. Errors: none. [paraphrase]
53+
- **R5:** The brief template names the fallback for a sandbox that denies commits: one run per scope unit with the host committing between runs, and the child reporting the denied commit in its digest. Errors: none. [inferred]
54+
- **R6:** The changelog entry for this change credits the reporter of issue #431 and states the old rule, the new rule, and why. Errors: none. [inferred]
55+
- **R7:** The flow-next.dev pages that restate the rule (work page, model-routing guide, cookbook entry, landing-page card) are updated to the new wording in the downstream release walk, and the issue receives a reply pointing at the shipped change. Errors: none. [inferred]
56+
57+
## Boundaries
58+
<!-- scope: business -->
59+
60+
- No hook, guard, or flowctl subcommand enforces the new rule; bridge safety stays prose-only. [paraphrase]
61+
- The child still never pushes, never rebases or amends, never decides scope, never issues a verdict, and never spawns a bridge. [user]
62+
- No change to the in-host worker, `flowctl done`, review backends, or the thin-wrapper recipe beyond the sentence that names the rule. [inferred]
63+
- No packaged delegation, no `work.delegate*` revival, no per-bridge config key. [inferred]
64+
65+
## Decision Context
66+
<!-- scope: both — conditionally substructured -->
67+
68+
### Motivation
69+
<!-- scope: business -->
70+
71+
The commit prohibition protected against an unbounded second agent, but the bound that matters is push, rewrite, scope, and verdict; a local commit is reversible and reviewable. Forbidding it forced host-inserted turns and a timebox, which is scaffolding around a workflow gap rather than a capability gap, and the field report shows it multiplied dispatches nineteen-fold. Allowing checkpoint commits makes the bridge path match the in-host worker path the host already reviews. [paraphrase]
72+
73+
### Implementation Tradeoffs
74+
<!-- scope: technical -->
75+
76+
Option 2 alone (document one-run-per-step, host commits between) was rejected as the primary shape because it keeps the re-brief cost that caused the report; it survives only as the sandbox fallback in R5. Adding a mechanical guard was rejected per the standing decision that prose-routed bridges have no hook-level git guard. [paraphrase]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"assignee": null,
3+
"claim_note": "",
4+
"claimed_at": null,
5+
"created_at": "2026-09-14T07:32:54.558519Z",
6+
"depends_on": [],
7+
"id": "fn-244-bridged-implementer-may-commit.1",
8+
"implicit_owner": true,
9+
"priority": null,
10+
"spec": "fn-244-bridged-implementer-may-commit",
11+
"spec_path": ".flow/tasks/fn-244-bridged-implementer-may-commit.1.md",
12+
"status": "todo",
13+
"title": "Implement Bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks (#431)",
14+
"updated_at": "2026-09-14T07:32:54.558519Z"
15+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
satisfies: [R1, R2, R3, R4, R5, R6, R7]
3+
---
4+
# fn-244-bridged-implementer-may-commit.1 Implement Bridged implementer may commit checkpoints; timebox-free brief for long bridged tasks (#431)
5+
6+
## Description
7+
TBD
8+
9+
## Acceptance
10+
Every R-ID in the parent spec's ## Acceptance Criteria is satisfied; judge this task against the spec's criteria directly.
11+
12+
## Done summary
13+
Relaxed the bridge safety rule so a bridged implementer may commit checkpoints on the branch the host names (never push, rebase or rewrite history, decide scope, issue a verdict, or spawn a bridge; the host keeps push, review, `flowctl done`, task state, and any history rewrite), stated the host's on-return obligation (record base, review `<base>..HEAD`, run the gates on that diff, host-owned squash-or-keep), and added a timebox-free brief template for long bridged tasks with the sandbox-denied fallback. Applied to the usage template and its Codex mirror (regenerated via sync-codex.sh, idempotent), the orchestration guide (bridge route, host-model paragraph, field-pattern table, "What stays fixed"), the running-lean pointer, this repo's CLAUDE.md/AGENTS.md routing blocks, and a CHANGELOG Unreleased entry crediting @DanielKillenberger (#431).
14+
15+
Verified live rather than asserted: codex 0.153.4 `--sandbox workspace-write` keeps `.git/` read-only (`git commit` fails with `index.lock: Read-only file system`, exit 128); `--sandbox danger-full-access` commits. The usage recipe names that flag for a checkpointing child in the asserted repo root, else the one-run-per-scope-unit fallback.
16+
17+
baseline: green (python3 scripts/run_tests_parallel.py suite_rc=0, 4991 ran; uvx ruff@0.16.0 check . clean)
18+
verify: green at HEAD (same commands; receipt .flow/tmp/green-receipts/15792ae4-unittest.json)
19+
20+
R-ID coverage: R1-R6 satisfied in commit 15792ae4. R7 (flow-next.dev work page, model-routing guide, cookbook entry, landing-page card; reply on #431) is deferred to the downstream release walk in ~/work/flow-next.dev per the spec.
21+
22+
Follow-ups (not built): `plugins/flow-next/docs/release-history.md` 4.0.0 line still describes the old rule as history; the release walk may append an entry for this change once the version is known. The spec's "byte-identical mirror" edge case is inexact: the Codex mirror carries the pre-existing `/flow-next:x` -> `$flow-next-x` transform (12 diff lines at both base and HEAD); the edit carried through identically.
23+
24+
stage: impl-review - ran (codex fan-out, 3 draws gpt-6-astra:high, all SHIP, 0 findings; receipt /tmp/impl-review-receipt-6a743e80ce39-fn-244-bridged-implementer-may-commit.1.json)
25+
## Evidence
26+
- Commits: 15792ae478d5a9fa8b8d1d60c10f55a0c0fa08a9
27+
- Tests: python3 scripts/run_tests_parallel.py (baseline: green, suite_rc=0, 4991 ran; verify at HEAD: green, suite_rc=0, 4991 ran, receipt .flow/tmp/green-receipts/15792ae4-unittest.json), uvx ruff@0.16.0 check . (baseline green; verify green), ./scripts/sync-codex.sh x2 (idempotent, rc=0 both), live probe: codex exec 0.153.4 --sandbox workspace-write denies git commit (index.lock: Read-only file system, exit 128); --sandbox danger-full-access commits (exit 0)
28+
- PRs:

AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ the session model with one notice. Host review is the exception: preserve its
4747
fresh-context, tool-enforced read-only, cross-family requirement and fail closed
4848
if unavailable. Reviews through other backends retain their existing contracts.
4949
Escalate an inadequate cheaper implementation within the authorized scope.
50-
Unattended bridge calls use the thin-wrapper recipe in `flowctl usage`; the host
51-
keeps git, judgment, and verdict ownership.
50+
Unattended bridge calls use the thin-wrapper recipe in `flowctl usage`; the
51+
bridged child may commit checkpoints on the named branch, and the host keeps
52+
push, history rewrite, review, task state, and verdict ownership.
5253
<!-- flow-next:model-routing:end -->

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Flow-Next changed shape with 5.0.0. One command, `/flow-next:flow`, reads whatev
66

77
## Unreleased
88

9+
### Changed
10+
11+
- **A bridged implementer may commit checkpoints on its branch.** The bridge safety rule in `flowctl usage`, the orchestration guide, the running-lean pointer, and this repo's routing block used to say the bridged child never commits and the host keeps git. For a one-task spec run through a `codex exec` bridge that left two bad shapes: one multi-hour run ending in a single uncommitted diff, or host-inserted returns between the spec's steps so the host could commit, with a timebox line that taught the implementer to return partial (one task took 19 dispatches). The rule now reads: the child writes code and may commit checkpoints on the branch the host names; it still never pushes, never rebases or rewrites history, never decides scope, never issues a review verdict, and never spawns a bridge; the host keeps push, review, `flowctl done`, task state, and any history rewrite, and reviews the child's commit range from the recorded base on return, exactly as it does for the in-host worker. A local commit is reversible and reviewable; the bounds that matter are push, rewrite, scope, and verdict. The usage guide gains a timebox-free brief template for long bridged tasks (return only when the scope is done or blocked) and names the sandbox fallback: codex's `workspace-write` keeps `.git/` read-only, so a checkpointing child runs `danger-full-access` in the asserted repo root, or the host commits between one-run-per-scope-unit dispatches. Prose-only; no hook or flowctl guard is added. Thanks to @DanielKillenberger for the report (#431).
12+
913
## [flow-next 5.3.0] - 2026-09-14
1014

1115
Teams whose specs depend on each other stop waiting on merges. A dependent spec used to sit until its parent's pull request landed, so every layer of a dependency chain cost one human merge before the next could start and the build loop idled in between. Now the dependent spec builds as soon as its parent is built, its pull request shows only its own layer, GitHub links the layers into one of its [stacked pull requests](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs) (in public preview since 2026-07-30, [announcement](https://github.blog/changelog/2026-07-30-stacked-pull-requests-are-now-in-public-preview/)), and land drains the chain from the bottom without a hand rebase. Off GitHub, or when the preview is unavailable on a repository, the same chain works as plain dependent PRs; only the stack map and GitHub's own retarget are GitHub-only. Nothing is configured: the dependency graph a plan already records is the only input, and a spec with no dependencies behaves exactly as before.

0 commit comments

Comments
 (0)