Skip to content

Commit e85f9b3

Browse files
authored
Merge pull request #112 from codeacme17/codex/issue-dev-loop
fix: recover issue loop control plane
2 parents 9eea053 + 62b9d60 commit e85f9b3

18 files changed

Lines changed: 616 additions & 163 deletions

.github/workflows/issue-dev-loop-evidence.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ jobs:
148148
docker run --rm --network none \
149149
--mount "type=volume,src=${candidate_volume},dst=/work" \
150150
"${image}" \
151-
pnpm verify 2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/pnpm-verify.log"
151+
sh -ceu 'git config --global --add safe.directory /work; pnpm verify' \
152+
2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/pnpm-verify.log"
152153
candidate_exit_code="${PIPESTATUS[0]}"
153154
set -e
154155
baseline_status=blocked
@@ -158,7 +159,8 @@ jobs:
158159
docker run --rm --network none \
159160
--mount "type=volume,src=${baseline_volume},dst=/work" \
160161
"${image}" \
161-
pnpm test 2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/owner-merged-baseline-tests.log"
162+
sh -ceu 'git config --global --add safe.directory /work; pnpm test' \
163+
2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/owner-merged-baseline-tests.log"
162164
baseline_exit_code="${PIPESTATUS[0]}"
163165
set -e
164166
if [[ "${baseline_exit_code}" == "0" ]]; then

loops/issue-dev-loop/LOOP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ The recorded implementation commit is the product-code boundary. Later commits m
8383

8484
### 5. Verify before publication
8585

86-
Run relevant checks and `pnpm verify`. For UI behavior, capture before/after screenshots under `screen-shots/<run-id>` at meaningful desktop and mobile viewports and include interaction or accessibility evidence where applicable. Bind `before` to the frozen base and `after` to the latest `$implement` commit; never put the containing commit's not-yet-known hash inside its own files. Commit sanitized screenshots and run metadata to the issue branch. The low-privilege `pull_request` evidence workflow checks out the exact candidate head, resolves its frozen run base, proves that base remains an ancestor of live `dev`, and separately checks out the immutable owner-merged base without persisted credentials. It installs candidate and baseline dependencies with lifecycle scripts disabled into distinct Docker volumes. Candidate `pnpm verify` and the actual frozen owner-merged baseline `pnpm test` run in separate no-network containers that receive no GitHub token and cannot mount any host checkout. Before accepting the artifact, the installed control plane independently rejects any exact-head change to the workflow or trusted control/verification plane. The manifest binds candidate head, workflow-run SHA, frozen owner-merged base SHA, and the live PR base SHA that selected the workflow.
86+
Run relevant checks and `pnpm verify`. For UI behavior, capture before/after screenshots under `screen-shots/<run-id>` at meaningful desktop and mobile viewports and include interaction or accessibility evidence where applicable. Bind `before` to the frozen base and `after` to the latest `$implement` commit; never put the containing commit's not-yet-known hash inside its own files. Commit sanitized screenshots and run metadata to the issue branch. The Draft PR body must render at least one representative before/after pair with Markdown image syntax, using `raw.githubusercontent.com` URLs pinned to the exact recorded head; links to an index or manifest alone are not UI evidence. The low-privilege `pull_request` evidence workflow checks out the exact candidate head, resolves its frozen run base, proves that base remains an ancestor of live `dev`, and separately checks out the immutable owner-merged base without persisted credentials. It installs candidate and baseline dependencies with lifecycle scripts disabled into distinct Docker volumes. Candidate `pnpm verify` and the actual frozen owner-merged baseline `pnpm test` run in separate no-network containers that receive no GitHub token and cannot mount any host checkout. Before accepting the artifact, the installed control plane independently rejects any exact-head change to the workflow or trusted control/verification plane. The manifest binds candidate head, workflow-run SHA, frozen owner-merged base SHA, and the live PR base SHA that selected the workflow.
8787

8888
### 6. Create the draft PR
8989

90-
Push the issue branch and create a draft PR targeting `dev`. Immediately bind it to the run with `record-pr`; later evidence and review gates accept only that PR and head. The PR must include the issue, run ID, base/head SHAs, risk, changes, evidence links, screenshots, known limitations, and explicit owner-only merge language. In `Verification`, bind every manifest check to its own result using the exact line `- \`<exact command>\`: passed (exit code 0)`; a summary-level pass statement is not sufficient.
90+
Push the issue branch and create a draft PR targeting `dev`. Immediately bind it to the run with `record-pr`; later evidence and review gates accept only that PR and head. The PR must include the issue, run ID, base/head SHAs, risk, changes, evidence links, rendered before/after screenshots for UI work, known limitations, and explicit owner-only merge language. In `Verification`, bind every manifest check to its own result using the exact line `- \`<exact command>\`: passed (exit code 0)`; a summary-level pass statement is not sufficient.
9191

9292
### 7. Independent review
9393

loops/issue-dev-loop/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ Require `$implement` to write a unique `logs/runs/<run-id>/implementation-result
3737

3838
## Publish a draft PR
3939

40-
Push only the issue branch and create a **draft** PR targeting `dev` using `templates/pr-body.md`; preserve its machine-readable run marker and owner-only merge statement. Bind it immediately with `loopctl.mjs record-pr --run-id <id> --pr-url <url> --head-sha <full-sha>`. Include the issue, risk assessment, test results, evidence manifest, screenshots, known limitations, run ID, and exact head SHA. Never target `main` from an issue branch.
40+
Push only the issue branch and create a **draft** PR targeting `dev` using `templates/pr-body.md`; preserve its machine-readable run marker and owner-only merge statement. Bind it immediately with `loopctl.mjs record-pr --run-id <id> --pr-url <url> --head-sha <full-sha>`. Include the issue, risk assessment, test results, evidence manifest, screenshots, known limitations, run ID, and exact head SHA. For UI work, render at least one representative before/after pair directly in the PR with Markdown images whose `raw.githubusercontent.com` URLs are pinned to that exact head; an index or manifest link alone is insufficient. Never target `main` from an issue branch.
4141

4242
## Run independent review
4343

4444
After the draft PR exists, spawn the project agent `echo_ui_pr_reviewer` with a fresh context. Give it only the issue snapshot, acceptance criteria, repository instructions, base SHA, head SHA, diff, CI results, and evidence manifest. Do not give it executor conversation history or rationale.
4545

46-
Publish every round through the installed wrapper with role `reviewer`; the executor identity may not author it. Every PR write must include `--repo codeacme17/echo-ui` (or use the full configured PR URL). Use `gh pr review --comment --body <body>` for a body-only review and include the exact run/cycle/round/head marker; the gate rejects body files, skipped rounds, duplicates, and publications outside the next durable cycle. When file/line findings require inline comments, use only the reviewer's gated `POST repos/codeacme17/echo-ui/pulls/<recorded-pr>/reviews` API shape with `event=COMMENT`, the exact durable head, and validated inline fields. Post findings verbatim as one review plus inline comments. Each finding needs a run-wide stable ID, severity, confidence, evidence, expected resolution, and the published GitHub inline comment ID or `null` for a body-only finding. Record the GitHub review URL for each round. Accepted repairs must start after that round was submitted, and executor replies must be posted through the automation wrapper after the corresponding `$implement` invocation finishes. One executor response comment may resolve only one finding. Follow `review/REVIEW.md` and `review/response-policy.md`.
46+
Publish every round through the installed wrapper with role `reviewer`; the executor identity may not author it. Every PR write must include `--repo codeacme17/echo-ui` (or use the full configured PR URL). Use `gh pr review --comment --body <body>` for a body-only review and include the exact run/cycle/round/head marker; the gate rejects body files, skipped rounds, duplicates, and publications outside the next durable cycle. When file/line findings require inline comments, use the installed `publish-review.mjs` command through the reviewer wrapper. Give it the recorded PR number and head, cycle and round, inline body text, and one canonical JSON object per comment; the trusted publisher validates every field and submits one exact-head `COMMENT` review. Do not construct nested `gh api` fields directly. Post findings verbatim as one review plus inline comments. Each finding needs a run-wide stable ID, severity, confidence, evidence, expected resolution, and the published GitHub inline comment ID or `null` for a body-only finding. Record the GitHub review URL for each round. Accepted repairs must start after that round was submitted, and executor replies must be posted through the automation wrapper after the corresponding `$implement` invocation finishes. One executor response comment may resolve only one finding. Follow `review/REVIEW.md` and `review/response-policy.md`.
4747

4848
The executor must classify every finding as `accepted`, `rejected`, `needs-human`, `stale`, or `already-fixed`:
4949

loops/issue-dev-loop/references/github-operations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Publish reviewer output only as a non-approving comment review:
1818
"$ECHO_UI_LOOP_CONTROL_PLANE/scripts/with-github-identity" --loop-root "$ECHO_UI_LOOP_TARGET_ROOT" reviewer -- gh pr review <number> --repo codeacme17/echo-ui --comment --body <review-body>
1919
```
2020

21-
The shell launcher removes Node preload hooks before starting the router. The router then builds a strict child environment, rejects reviewer pushes and every reviewer mutation except a comment-only review on the recorded PR, and rejects approvals, change requests, merges, executor-authored reviews, GraphQL, and administration APIs. Reviewer publication requires the next run/cycle/round marker; the gate paginates existing reviews and rejects duplicates, skipped rounds, body files, or an omitted reviewer publication. A reviewer API write is permitted only for one exact-head `event=COMMENT` review with validated inline fields. Authenticated Git disables worktree hooks, fsmonitor, external diff, textconv, proxy environment variables, repository-local HTTP/proxy/cookie/header/SSL/URL rewrites, and the `ext` transport. Remote Git is restricted to exact origin push/fetch/issue-branch discovery shapes and executes against a canonical configured-repository HTTPS URL. Automation API mutations are limited to the current issue's exact claim label, the current issue/PR or journal comments, and current-PR review-comment replies. PR bodies and comments must be inline; body files, API input files, and typed `@file` expansion are rejected. PR creation requires the durably authorized issue or published evolve request branch, explicit `--repo codeacme17/echo-ui`, `--base dev`, and `--draft`; later PR writes require the same explicit repository (or full configured PR URL), the exact durable checkpoint, the recorded live PR branch/base/head, and the phase-specific Draft/evidence/review gates. `pr edit` is limited to title/body updates and requesting `codeacme17`; non-`--undo` `pr ready` is rejected because only the owner may mark a Draft Ready. Issue pushes derive `codex/issue-<number>` from the durable checkpoint, require a clean exact local issue branch whose post-`$implement` commits contain only the current run's evidence paths, and reject local branch overrides; evolve pushes require the automation-authored request publication. Every other push shape is rejected.
21+
The shell launcher removes Node preload hooks before starting the router. The router then builds a strict child environment, rejects reviewer pushes and every reviewer mutation except a comment-only review on the recorded PR, and rejects approvals, change requests, merges, executor-authored reviews, GraphQL, and administration APIs. Reviewer publication requires the next run/cycle/round marker; the gate paginates existing reviews and rejects duplicates, skipped rounds, body files, or an omitted reviewer publication. Body-only reviews use the validated `gh pr review --comment` shape. Inline reviews must use the installed `publish-review.mjs`; it accepts only canonical comment JSON, validates the durable exact head and finding markers, and is the sole component allowed to stream a canonical `event=COMMENT` payload to GitHub. Authenticated Git disables worktree hooks, fsmonitor, external diff, textconv, proxy environment variables, repository-local HTTP/proxy/cookie/header/SSL/URL rewrites, and the `ext` transport. Remote Git is restricted to exact origin push/fetch/issue-branch discovery shapes and executes against a canonical configured-repository HTTPS URL. Automation API mutations are limited to the current issue's exact claim label, the current issue/PR or journal comments, and current-PR review-comment replies. PR bodies and comments must be inline; body files, arbitrary API input files, and typed `@file` expansion are rejected. PR creation requires the durably authorized issue or published evolve request branch, explicit `--repo codeacme17/echo-ui`, `--base dev`, and `--draft`; later PR writes require the same explicit repository (or full configured PR URL), the exact durable checkpoint, the recorded live PR branch/base/head, and the phase-specific Draft/evidence/review gates. `pr edit` is limited to title/body updates and requesting `codeacme17`; non-`--undo` `pr ready` is rejected because only the owner may mark a Draft Ready. Issue pushes derive `codex/issue-<number>` from the durable checkpoint, require a clean exact local issue branch whose post-`$implement` commits contain only the current run's evidence paths, and reject local branch overrides; evolve pushes require the automation-authored request publication. Every other push shape is rejected.
2222

2323
## Selection and claim
2424

loops/issue-dev-loop/review/REVIEW.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Do not emit formatter noise, personal style preferences, speculative concerns, u
2424

2525
## Publication
2626

27-
The fresh reviewer publishes each round verbatim through `reviewerGitHubLogin` as one non-approving GitHub review, adding `<!-- issue-dev-loop:<run-id>:<finding-id> -->` for deduplication and `<!-- issue-dev-loop:<run-id>:review-cycle:<cycle>:round:<round>:head:<sha> -->` to the round body. A body-only round uses the gated `gh pr review --comment --body <body>` command; body files are rejected so the identity gate can validate the marker before publication. Findings with a concrete file and line must be posted in one gated `POST repos/<configured-repo>/pulls/<recorded-pr>/reviews` call whose event is exactly `COMMENT`, commit ID is the durable recorded head, and inline path/line/side/body fields carry the finding markers; arbitrary input files and every other mutating API shape are rejected. Cross-cutting findings remain in the review body. The reviewer identity must differ from the executor and owner.
27+
The fresh reviewer publishes each round verbatim through `reviewerGitHubLogin` as one non-approving GitHub review, adding `<!-- issue-dev-loop:<run-id>:<finding-id> -->` for deduplication and `<!-- issue-dev-loop:<run-id>:review-cycle:<cycle>:round:<round>:head:<sha> -->` to the round body. A body-only round uses the gated `gh pr review --comment --body <body>` command; body files are rejected so the identity gate can validate the marker before publication. Findings with a concrete file and line must be posted with the installed `publish-review.mjs` through the reviewer wrapper. Pass `--loop-root`, `--pr`, the durable `--head`, `--cycle`, `--round`, the inline `--body`, and one `--comment` canonical JSON object for each finding. Each comment object contains only `path`, `line`, `side`, and `body`; the trusted publisher validates exact-head state, markers, paths, lines, sides, ordering, and uniqueness before submitting one `COMMENT` review with a canonical JSON payload. Do not construct nested `gh api` fields or pass arbitrary input files. Cross-cutting findings remain in the review body. The reviewer identity must differ from the executor and owner.
2828

2929
Before the final round is published, write the complete cycle result with a temporary/unassigned final `reviewUrl` and run the installed `loopctl review-digest --result <path>`. Put its returned `<!-- issue-dev-loop:<run-id>:review-result-sha256:<digest> -->` marker in the final body. After GitHub assigns the review URL, replace the temporary value and rerun `review-digest`; it must be unchanged. This canonical publication digest replaces only review URLs with a fixed placeholder and therefore avoids a URL↔digest cycle. The later recorded full-file digest still protects the final URLs and every other byte. The reviewer must not downgrade severity or omit findings.
3030

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Review the Echo UI PR diff between `<base-sha>` and `<head-sha>` as an independent, fresh-context reviewer for review cycle `<cycle>`. Use `$code-review`. Read only the supplied issue snapshot, acceptance criteria, repository instructions, diff, CI results, and evidence manifest. Follow `loops/issue-dev-loop/review/REVIEW.md`. Do not edit files or rely on executor conversation history. Publish a body-only non-approving review through `"$ECHO_UI_LOOP_CONTROL_PLANE/scripts/with-github-identity" --loop-root "$ECHO_UI_LOOP_TARGET_ROOT" reviewer -- gh pr review <number> --repo codeacme17/echo-ui --comment --body <review-body>` and include the exact run/cycle/round/head marker. Before a final round, use the installed `loopctl review-digest` procedure so the marker is computed before GitHub assigns the final review URL. If file/line findings require inline comments, use the same installed launcher with only the strict `gh api repos/codeacme17/echo-ui/pulls/<number>/reviews --method POST` COMMENT-review field shape documented by `REVIEW.md`. Never use the repository launcher for credentials, invoke the `.mjs` router directly, run raw `gh`, use `--body-file`, use `--input`, call any other mutating API, approve/request changes/merge, or alter global authentication. Return structured findings or `PASS` and the unique review URL.
1+
Review the Echo UI PR diff between `<base-sha>` and `<head-sha>` as an independent, fresh-context reviewer for review cycle `<cycle>`. Use `$code-review`. Read only the supplied issue snapshot, acceptance criteria, repository instructions, diff, CI results, and evidence manifest. Follow `loops/issue-dev-loop/review/REVIEW.md`. Do not edit files or rely on executor conversation history. Publish a body-only non-approving review through `"$ECHO_UI_LOOP_CONTROL_PLANE/scripts/with-github-identity" --loop-root "$ECHO_UI_LOOP_TARGET_ROOT" reviewer -- gh pr review <number> --repo codeacme17/echo-ui --comment --body <review-body>` and include the exact run/cycle/round/head marker. Before a final round, use the installed `loopctl review-digest` procedure so the marker is computed before GitHub assigns the final review URL. If file/line findings require inline comments, use the same installed launcher to run `node "$ECHO_UI_LOOP_CONTROL_PLANE/scripts/publish-review.mjs"` with the exact arguments documented by `REVIEW.md`; provide each comment as canonical JSON. Never use the repository launcher for credentials, invoke the `.mjs` router directly, run raw `gh`, construct nested API fields, use `--body-file`, call any other mutating API, approve/request changes/merge, or alter global authentication. Return structured findings or `PASS` and the unique review URL.

0 commit comments

Comments
 (0)