Safe EPIC rebinding and native parent validation for active AutoForge runs
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 24/100
Research direction
Start with src/autoforge/cli.py, src/autoforge/validation.py, and src/autoforge/engine.py; trace run creation and persisted EPIC identity, then inspect the GitHub client and scheduler ownership, locking, and effect protocols referenced by the issue. Define the native-parent membership policy and safe standalone rebind boundaries before implementation. Done means the acceptance criteria are covered by offline tests, operator documentation is updated, and make check passes.
Written by the indexing model from the issue text.
Description
Artifact: implementation-ready standalone issue for AutoForge's REMOTE run identity and recovery. Triggered by the live #257 / PR #279 run; no run state or worktree is changed by creating this issue.
Scope: standalone REMOTE run startup and safe EPIC rebinding; scheduler-owned runs require explicit, conservative handling. Related: #257 (incident), #255 (correct Public Alpha EPIC), #158 (incorrect recorded EPIC), #287 (restrict UPDATE_EPIC next issue to the EPIC's children), #177/#179–#183 (scheduler ownership, native graph, locks and claims). Priority: proposed High for integrity/recovery; maintainer to triage. Not automatically a Public Alpha launch gate.
Problem and reproduced example
A standalone REMOTE run of issue #257 was created with --epic https://github.com/iceboundrock/AutoForge/issues/158, although its GitHub-native parent is #255. The run af-20261022T070620Z-8542c2 has state under .autoforge/AutoForge-issue-257, is associated with PR #279 (autoforge/257), and has an unpushed FIX candidate d1e7fd179302f9f0df3380303bd1dc30f5d30d69. The original run has been kept intact, and its merge gate must remain closed for recovery. This is not a request to edit that run's state.json or restart it.
At the inspected implementation:
src/autoforge/cli.pyrequiresrun --epic URL --issue URL, butresumeandunblockhave no target-EPIC parameter.src/autoforge/validation.py:validate_epic_and_issueverifies only that both URLs belong to the same repository, not that the issue is a native child of the selected EPIC.src/autoforge/engine.py:new_runpersistsepic_urlinAutoForgeStateat creation. Subsequent phases consume this recorded identity.UPDATE_EPICcan publish a progress comment and splice a managed roadmap section onstate.epic_url, so a wrongly recorded EPIC can result in an authorized write to the wrong issue if a run is allowed to proceed after merge.run --forcediscards/replaces existing nonterminal run state, not a supported migration. Direct JSON editing is unsafe because of persisted phase, effects, evidence and recovery protocols.
The current workaround is to retain the run, keep automatic merge disabled, stop at READY_FOR_MERGE and handle merge/EPIC reporting manually. The product needs a fail-closed prevention path and a supported migration path that preserve evidence.
Deliverables
A. Validate native parent/EPIC at run creation
- Before saving any new REMOTE run state or launching an agent, read and validate the repository identity, the target EPIC and issue, and the issue's GitHub-native parent through typed
GitHubClientreads. Require full, unambiguous read-back; never infer membership from prose, issue references, labels, roadmap text or title. - For a directly parented issue, require the parent to equal
--epic, comparing canonical repository/issue identities. Reject a mismatch with a diagnostic naming the supplied EPIC, the observed parent and the corrected invocation. - Specify and document a backward-compatible membership policy for existing sequential workflows that may use issues without a native parent, legacy task lists or explicitly supported EPIC references. Do not silently accept a mismatch. If a legacy exception is supported, it must be explicit, unambiguous, evidenced on GitHub and tested. Decide whether nested child issues are accepted for standalone runs or refused; do not accidentally change scheduler's direct-child contract.
- If parent lookup is unavailable, ambiguous or access-denied, fail closed before state creation; distinguish unsupported API/credential from
no parentandwrong parent. Validate open/closed state and issue repository under the same verified identity rules. - Use this checked binding for
run --dry-runand ordinaryrun; dry-run must not persist data, create worktrees, launch providers or perform GitHub writes. Recheck mutable GitHub facts under the controller lock before committing the initial state to avoid a TOCTOU gap. - Reuse the authoritative native graph/snapshot semantics of #179 where appropriate, and coordinate with #287 without duplicating its
UPDATE_EPICnext-issue restrictions. Consider independent issue-parent changes after a run starts: never silently retarget a recorded run.
B. Safe operator-controlled EPIC rebinding for an existing run
Design and implement an explicit operation (illustrative UX; exact CLI shape to be decided and documented):
autoforge rebind-epic \
--from https://github.com/iceboundrock/AutoForge/issues/158 \
--to https://github.com/iceboundrock/AutoForge/issues/255 \
--reason "Correct run binding for issue #257" \
--dry-run
The operation must have all of the following properties:
- Explicit authority. Require operator intention, expected previous EPIC, new EPIC and a nonempty reason; tie the change to the existing state directory and exact current issue/run identity. Refuse stale expected-old values. Rebind only the EPIC identity, never the issue, PR, repository or code.
- Read-only preview.
--dry-rundisplays old/new EPIC, observed native parent/membership, current phase, pending EPIC-scoped effects, worktree/PR identity and exact refusal/recovery actions. It makes no state, log, filesystem or GitHub writes. - Safe phases and locks. Work under the existing L0 controller authority plus applicable L2/L1 locks per ADR 0008. Refuse if a controller/worker holds the run, if scheduler ownership/claims cannot be reconciled, or if the run is in a phase in which migration would cross a persisted external-effect boundary. Explicitly define permissible phases (e.g., a quiescent BLOCKED run or READY_FOR_MERGE, with no conflicting EPIC-scoped effects) rather than treating all phases as safe.
- Effect and recovery integrity. Inspect effect records (including K8 progress/roadmap), acceptance/operator actions, phase observations, persisted completion context, retries and replan transaction, launch/read context, and any immutable recorded identity or digest. Refuse unresolved, planned, sent or uncertain effects tied to the old EPIC unless a provably safe, tested migration rule exists. Never rewrite a sent GitHub effect, relabel ownership or erase evidence. Prefer refusal to speculative migration.
- Scheduler namespaces. A scheduler-owned issue's binding/claim/generation and the scheduler's graph are authoritative. Refuse automatic transfer between EPICs while a claim, active invocation, unsettled namespace, or scheduler journal exists. If support cannot be made provably safe in this issue, explicitly scope rebinding to standalone runs and document a separate scheduler migration workflow; do not bypass the scheduler root or ownership checks.
- Atomic, recoverable state update. With locks held, verify preconditions, preserve a bounded auditable record or snapshot of the prior state, commit the new binding with the existing atomic state persistence protocol, and record old/new URLs, issue/run identity, operator reason and decision in the run log. Crash/interruption must leave one valid, unambiguous binding. A repeat with the same target must be idempotent and visibly report already-applied; a conflicting repeat must refuse.
- No lifecycle reset. Preserve run ID, current issue and PR, branch, reviewed HEAD/base/merge-base, local worktree and unpushed FIX candidate, review findings, review/fix rounds, replan counters, loop/step budgets, validation evidence, configuration fingerprint, effect journal and operator approvals. Do not use
run --force, hard reset, force push or reinitialize the run. - Future steps use the new EPIC safely. The next prompt/read context and any eventual
UPDATE_EPICmust be bound to the verified new parent; old EPIC read context must not be silently reused. If cached context cannot be safely invalidated without losing evidence, refuse the migration and explain why. Verify no write to the former EPIC occurs after a successful rebind. - No hidden merge escalation. Rebinding must not change
safety.allow_merge, grant--allow-merge, enter MERGE, or automatically publish/merge anything. For the concrete #257 example, rebinding (if supported) must preserve the unpushedd1e7fd1worktree and the current review/effect protocol.
C. Operator documentation and diagnostics
- Document corrected
run --epic ... --issue ...examples, mismatch errors, dry-run, safe phases, refusals, rollback/recovery and the manual fallback when rebinding is not safe. - Make
statusexpose the persisted EPIC unambiguously; consider a read-only warning if the current native parent differs, but do not silently repair it. - State the distinction between a GitHub native parent, a run's persisted
epic_url, and scheduler ownership; changing an issue's parent on GitHub must not mutate an existing run automatically.
Acceptance criteria
- Starting a standalone run with #257 and incorrect EPIC #158 refuses before writing state or launching an agent; the observed native parent #255 is named in the error.
- A correctly parented issue is accepted; explicit legacy/no-parent and nested-parent policies are documented and tested; API unavailable/403/404/malformed/truncated parent evidence refuses safely without inventing a parent.
- Fresh-run dry-run and real start agree on binding validation and do not leave a TOCTOU window before persistence.
- A documented rebind dry-run of a quiescent, eligible existing standalone run explains the proposed change without changing a byte of state/log/journal/worktree or GitHub.
- Applying an eligible rebind atomically changes only the intended durable EPIC binding and the explicitly defined audit metadata; it preserves PR/review/fix/effect identity and the unpushed candidate; repeat is idempotent.
- Rebind refuses for active controller/worker, unsatisfied scheduler claims, uncertain or existing EPIC-target writes, stale expected-old EPIC, incomplete GitHub evidence, unsafe lifecycle phase and incompatible stored context, with actionable diagnostics and unchanged state.
- Fault-injection tests cover crash/interruption at each persistence boundary, idempotent retry and concurrent
resume/scheduler admission; no half-migrated state, duplicate publication or write to the wrong EPIC. - A resumed run after a successful permitted rebind reads the new EPIC and never sends progress/roadmap writes to the old one; no implicit merge enablement or counter reset.
- Offline tests cover #257/#158 → #255 regression, parent drift, missing/nested parents, aliases/URLs, genuine denial vs no parent, pending K8/K9/operator actions, REVIEW/FIX/BLOCKED/READY_FOR_MERGE/UPDATE_EPIC boundary conditions and scheduler-owned namespaces.
- Update relevant
docs/usage.md, workflow/operator guidance and CLI help;make checkpasses in a proper Git checkout.
Out of scope
- Modifying the currently BLOCKED #257 run, its worktree/candidate or PR #279 as part of implementing this issue.
- Automatic repair on
resume,unblockorstatus. - Changing the scheduler claim protocol, merge gate or
UPDATE_EPICnext-issue eligibility (#287 owns the latter). - Broadening authority to migrate issue ownership or to rewrite previously published GitHub objects.
Delivery: ship a reviewed implementation with offline proofs and a documented recovery path. Prefer a conservative first release restricted to standalone runs over an unsafe general EPIC migration operation.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- Avg merge
- 5h 51m
- Merged PRs (30d)
- 66
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from iceboundrock/AutoForge
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
iceboundrock/AutoForge#304 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 45/100
iceboundrock/AutoForge#329 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 75/100
iceboundrock/AutoForge#328 ·
Maintainers usually reply within 1 day
-
A create whose text gh's JSON sanitizer rewrites is recorded as a conflict on the controller's own object (found on PR #314)Possibly taken @iceboundrock claimed this today. Openbug
Difficulty 4/5 3-5 days Newbie friendliness 20/100
iceboundrock/AutoForge#327 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 20/100
iceboundrock/AutoForge#326 ·
Maintainers usually reply within 1 day
All issues in iceboundrock/AutoForge
Similar issues
-
The changelog workflow excludes otelbot but not dependabot, so every Dependabot pull request fails the changelog checkPossibly taken @ocelotl claimed this today. Open
Difficulty 1/5 Under an hour Newbie friendliness 82/100
open-telemetry/opentelemetry-python#5825 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
cuga-project/cuga-agent#1020 ·
Maintainers usually reply within 2 days
-
Difficulty 1/5 Under an hour Newbie friendliness 70/100
microsoft/playwright#43640 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
stac-utils/stac-fastapi-elasticsearch-opensearch#965 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day