8.8 KiB
id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
| id | title | status | wave | depends_on | plan | requirements | acceptance_criteria | system_design | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-attachment-identity | Repair PR attachment identity validation | done | 1 | plan.md |
|
|
|
Task 01: Repair PR attachment identity validation
This work order preserves the original implementation sequence. The Results section records the delivered implementation and verification.
Summary
Accept a valid fork PR when the ordinary task attachment identifies its target repository. Preserve exact identity checks for explicit bindings and fork-attached checkouts. Resolve from existing metadata so unprepared failed tasks can retry. Keep unattended GitHub review-watch execution disabled for fork or identity-incomplete PRs until a user starts the linked task.
In scope
- Add
TestResolveTaskRepoInfo_TargetAttachedForkPRWithoutContributioninexecutor_pr_base_identity_test.gobefore production edits. Use an upstream attachment, a distinct fork head, matching checkout branch, and only PR metadata. The initial run must fail with the reported repository-binding error. - Update
resolvePRBaseForLaunchandvalidPRBaseIdentitywith the three attachment forms from the design. Keep provider source identity transient. - Cover target mismatch, wrong PR number/branch, missing head identity, and empty checkout branch. Explicit contribution and comparison mismatches cannot enter the unbound target-attached path. Keep current explicit-binding fallback rules.
- Cover resolver lookup with no linked row, one exact linked row, duplicate matches, same-number foreign rows, cancellation, and provider errors.
- Add
TestTargetAttachedForkPRBasePreparationEndToEndinexecutor_pr_base_materialization_test.go, beside existing real Git materialization coverage. Use separate fork/upstream repositories with different same-named base commits. Publish the fork head under upstreamrefs/pull/N/head. Prove target base, PR head, and unchanged origin/push configuration. - Repeat resolution for an unprepared task to represent retry. Include a mixed two-repository preparation where one invalid binding blocks the whole launch.
- Keep same-repository GitHub review watches eligible for configured auto-start. Persist a manual-start marker for fork or identity-incomplete review watches, enforce it at automated launch boundaries, and prove a direct manual start remains available. Leave ordinary browser PR-link tasks unaffected.
Out of scope
New database schema or migrations, browser payload changes, contribution push authorization, automatic repair of live tasks, and PR-association lifecycle changes.
Acceptance
- The ordinary upstream-attached fixture fails before the fix and succeeds after it, with or without a completed linked association.
- Explicit binding mismatches and ambiguous identities keep their existing rejection or stored-qualified-target behavior. No unrelated base is applied.
- Real Git preparation uses the correct head and target commits. Retry and mixed-repository checks preserve cancellation, fallback, and push invariants.
Planned verification sequence
This is the original RED/GREEN sequence. The Results section records the commands and outcomes from implementation.
(cd apps/backend && go test ./internal/orchestrator/executor -run '^TestResolveTaskRepoInfo_TargetAttachedForkPRWithoutContribution$' -count=1 -v)
(cd apps/backend && go test ./internal/orchestrator/executor -run '^TestTargetAttachedForkPRBasePreparationEndToEnd$' -count=1 -v)
(cd apps/backend && go test ./internal/orchestrator/executor ./internal/backendapp ./internal/worktree -count=1)
python3 scripts/list-docs.py validate
python3 scripts/lint-spec-files.py --all
git diff --check
The first test records the expected pre-fix RED; the second proves real Git
materialization. Both tests reside in internal/orchestrator/executor. The
final package run also covers existing same-repository, explicit contribution,
resolver, and qualified-base regressions.
Files touched
apps/backend/internal/orchestrator/executor/executor_resume.goapps/backend/internal/orchestrator/executor/executor_pr_base_identity_test.goapps/backend/internal/orchestrator/executor/executor_pr_base_materialization_test.goapps/backend/internal/backendapp/pr_base_resolver_test.goapps/backend/internal/orchestrator/event_handlers_github.goapps/backend/internal/orchestrator/event_handlers_workflow.goapps/backend/internal/orchestrator/task_operations.goapps/backend/internal/orchestrator/event_handlers_github_review_test.goapps/backend/internal/task/models/models.godocs/specs/integrations/requirements/github-fork-review-start.mddocs/specs/integrations/system-design/github-fork-review-start.mddocs/decisions/2026-09-23-fork-pr-review-watch-manual-start.md
Dependencies
None.
Risks
A loose target match can bypass an explicit source binding. A linked-row requirement can reintroduce the browser association race. Tests must exercise production resolution and preparation, not only a copied predicate.
Parallelism
sequential
Inputs
- Requirement, .11 and .15-.19.
- Design clarification.
- Fork review-start requirement.
- Fork review-start design and decision.
executor_pr_base_identity_test.goandexecutor_pr_base_materialization_test.go.- Comparison target ADR.
Results
Completed. The ordinary target-attached fork regression failed before the fix with the reported repository-binding error. It passes after the change, along with wrong target/number/branch, missing head repository, empty checkout, explicit comparison/source mismatches, cancellation, retry, mixed-repository, resolver association and real Git preparation coverage.
Commands and results:
go test ./internal/orchestrator/executor -run '^TestResolveTaskRepoInfo_TargetAttachedForkPRWithoutContribution$' -count=1 -v: expected RED before production change.go test ./internal/orchestrator/executor -run '^TestTargetAttachedForkPRBasePreparationEndToEnd$' -count=1 -v: expected RED before production change; passed after the test exercised normal PR-head fetch.- Focused new executor and resolver tests: passed.
go test ./internal/orchestrator/executor ./internal/backendapp ./internal/worktree -count=1: passed.- Specification catalog, spec linter tests, all-spec lint and
git diff --check: passed.
Security follow-up results:
go test ./internal/orchestrator -run 'TestBuildReviewTaskRequest_ForkPRRequiresManualStart|TestAutoStart_ForkReviewWaitsForManualStart' -count=1: passed.go test ./internal/orchestrator ./internal/orchestrator/executor ./internal/backendapp ./internal/worktree -count=1: passed.make -C apps/backend build: passed.(cd apps/web && pnpm e2e:run --project chromium tests/task/create-task-github-url.spec.ts): 10 passed.(cd apps/web && pnpm e2e:run --project mobile-chrome tests/task/mobile-create-task-remote-repo.spec.ts): 7 passed.python3 scripts/list-docs.py validate,python3 scripts/lint-spec-files.test.py,python3 scripts/lint-spec-files.py --all, andgit diff --check: passed.- Same-repository review watches retain automatic start. Fork and identity-incomplete review watches remain available without unattended execution; workflow and central automatic-start gates enforce the marker, and direct manual start launches.
- Requirement, system design, and decision links above record the delivered security boundary. Browser PR-link launch remains unchanged.
The test fixture uses separate fork/upstream bare repositories with different
same-named main commits. It publishes the fork head under the upstream PR
ref and preserves the upstream origin and push URL during target-attached
preparation.