Skip to content

fix(pipeline): clean foreign-owner PR bodies and refuse PRs approved with intent-conformance findings - #4

Merged
dmealing merged 5 commits into
localfrom
fm/nm-upstream-pr-body
Oct 3, 2026
Merged

dmealing merged 5 commits into
localfrom
fm/nm-upstream-pr-body

Conversation

@dmealing

@dmealing dmealing commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Intent

Make the gate stop writing bad pull request descriptions for repositories we don't own.

Context: the gate pasted a stale task intent verbatim into kunchenguid/firstmate#6488's description, plus a "🚨 High ... needs maintainer decision" risk line and an unresolved review error, and still opened the PR. kunchenguid/axi#230's description got internal history, a stray directive line and local evidence file paths (~/.no-mistakes/evidence/...) the maintainer cannot open.

What Changed

  • Foreign-owner PRs — a configured fork whose owner differs from the parent repository's (isForeignOwnerPR) — now omit the ## Intent section (prBodyIntent, shared by both intent paths) and every local-file evidence reference the maintainer cannot open (testingSummaryOptions.omitLocalPaths); an artifact with only a local path is dropped, while inline evidence text, links, and attachments stay. Same-owner PR bodies are unchanged.
  • The review prompt's intent-conformance clause now requires category: intent-conformance on contradiction findings (added to the review findings schema and types.FindingCategoryIntentConformance), and the PR step fails instead of opening or updating the PR while the completed review still holds one (refuseUnresolvedIntentConformance) — the branch stays pushed.
  • Documented the refusal and foreign-owner body rules in docs/src/content/docs/reference/pipeline-steps.md, moved the PR-body and intent-mismatch notes into the owning skill files, and added regressions in internal/pipeline/steps/pr_upstream_test.go.

Validation Notes

  • Lint was verified locally with go1.25 (make lint: generated-skill drift check plus go vet ./..., clean on the PR head). The gate's lint step could not run because the gate service's Go toolchain is too old to parse go 1.25.0 in go.mod.
  • TestRebaseStep_NonConflictFailureWithRebaseMetadataReturnsError and TestRebaseStep_FixModeNonConflictFailureReturnsError fail on origin/local too and are not caused by this change (it touches no rebase code). They fail on hosts whose global git config sets rebase.autostash=true, because the tests do not isolate git config; they pass with that setting neutralized.

Risk Assessment

✅ Low: Well-bounded change: deterministic omissions sit at single choke points with byte-identical same-owner behavior pinned by tests, the PR refusal is fail-closed, keyed on a structured category that survives the findings wire, and verified against both normal and daemon-recovery approval paths; the only finding is an adjacent pre-existing link gap noted as informational.

Testing

No scenario was driven against the live running product, so all six are untested. What was done is unit-level: the branch's scenario tests and temporary evidence probes called the real buildPRContent/Execute code with a real git repo and run DB, but the forge boundary was the repo's fake gh, so every PR body, diff, refusal message, and 'pr create' call exists only as rendered output or a recorded stub invocation. The full go test -race ./... regression suite ran twice: under the real host environment it failed only TestRebaseStep_FixModeNonConflictFailureReturnsError and TestRebaseStep_NonConflictFailureWithRebaseMetadataReturnsError, which were proven environmental (host ~/.gitconfig sets rebase.autostash=true; both pass 3/3 with the config neutralized; the branch diff touches no rebase files); the second run's only failure was TestCIStep_CommitAndPush_GitCommandsUseStandardCredentialEnv, an artifact of the synthetic GIT_CONFIG_GLOBAL, and it passes under the real environment of run 1. No LLM API calls were made. A live drive of any scenario requires a full gate run whose agent steps bill metered LLM spend (needing Doug's pre-approval with a dollar figure) plus an authorized publish to a real repository; neither was authorized, so none was attempted.

  • Live validation: ⚠️ inconclusive - 0 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Foreign-owner PR body omits the run's task-intent section and every local evidence path a maintainer cannot open, while keeping What Changed, Testing, openable evidence, and the live attestation marke… ⏸️ untested no The prior payload did not establish a live result: it drove only the branch's scenario tests and temporary probes through PRStep rendering with the repo's fake gh stub. A live drive would publish a re…
Same-owner PR body is unchanged: it keeps the Intent section and local evidence paths, byte-identical with and without a same-owner fork ⏸️ untested no The prior payload did not establish a live result: byte-identity was asserted on strings rendered in-process behind the fake gh stub, and no real PR was opened or updated against an owned repository,…
PR step refuses to open or update a pull request while the completed review still holds an intent-conformance finding, naming the finding IDs and issuing no forge PR-create call ⏸️ untested no The prior payload did not establish a live result: the refusal and the absent create call were observed only in-process via Execute with the fake gh log. No live run demonstrated a real forge receivin…
PR step still opens the PR when review findings carry no intent-conformance category (no over-blocking of ordinary review warnings) ⏸️ untested no The prior payload did not establish a live result: the recorded 'pr create' was a fake gh invocation inside a unit-level Execute, not a real pull request opened on a forge by the running product.
Review contract carries the intent-conformance category: the emitted review prompt asks for it and the review findings schema accepts it ⏸️ untested no The prior payload did not establish a live result: the prompt text and schema enum were asserted as delivered artifacts from the emitted files, and no real reviewer agent ever ran, so the end-to-end c…
Adversarial: PR step fails closed when the completed review's findings JSON is unreadable instead of publishing a PR with unknown conformance state ⏸️ untested no The prior payload did not establish a live result: the fail-closed path was exercised in-process against malformed fixture findings with the fake gh stub, not against the running product publishing to…
Evidence: Foreign-owner PR body (rendered in-process by PRStep code)

Source: Foreign-owner PR body (rendered in-process by PRStep code) (local file: ~/.no-mistakes/evidence/01M416CSGV9W8P8HPQDCFPZM5Y/pr-body-foreign-owner.md)

Title: fix: tidy

## What Changed

- tidy

## Testing

Evidence was collected.

\<details>
<summary>Evidence: Server log</summary>

`` `text
embedded evidence file body
`` `
</details>

## Pipeline
...
Evidence: Diff: what a foreign maintainer no longer receives

# Lines the same-owner body carries that the foreign-owner body drops - stale task intent the maintainer never saw - ## Intent - - Evidence: Local only log (local file: <code>~/.no-mistakes/evidence/.../missing.bin</code>)

# Lines the same-owner body carries that the foreign-owner body drops
- stale task intent the maintainer never saw
- ## Intent
- 
- - Evidence: Local only log (local file: <code>~/.no-mistakes/evidence/01M416CSGV9W8P8HPQDCFPZM5Y/probe-run-evidence/missing.bin</code>)
Evidence: Same-owner PR body (unchanged behavior)

Source: Same-owner PR body (unchanged behavior) (local file: ~/.no-mistakes/evidence/01M416CSGV9W8P8HPQDCFPZM5Y/pr-body-same-owner.md)

Title: fix: tidy

## Intent

stale task intent the maintainer never saw

## What Changed
...
- Evidence: Local only log (local file: <code>~/.no-mistakes/evidence/.../missing.bin</code>)
Evidence: Refusal message: unresolved intent-conformance finding

refusing to open or update the pull request: review was approved with unresolved intent-conformance finding(s) review-1 - the change does not match the run's intent; fix the change or rerun with a corrected --intent (the branch stays pushed)

refusing to open or update the pull request: review was approved with unresolved intent-conformance finding(s) review-1 - the change does not match the run's intent; fix the change or rerun with a corrected --intent (the branch stays pushed)
Evidence: Refusal message: unreadable review findings (fail closed)

read review findings before opening a pull request: invalid character 'n' looking for beginning of object key string

read review findings before opening a pull request: invalid character 'n' looking for beginning of object key string
Evidence: Scenario test run (go test -race -v)

--- PASS: TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence, TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence, TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved, TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding, TestReviewIntentConformanceCategoryIsRequestedAndAccepted

=== RUN   TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence
=== PAUSE TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence
=== RUN   TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence
=== PAUSE TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence
=== RUN   TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved
=== PAUSE TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved
=== RUN   TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding
=== PAUSE TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding
=== RUN   TestReviewIntentConformanceCategoryIsRequestedAndAccepted
=== PAUSE TestReviewIntentConformanceCategoryIsRequestedAndAccepted
=== CONT  TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence
=== CONT  TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved
=== CONT  TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding
=== CONT  TestReviewIntentConformanceCategoryIsRequestedAndAccepted
=== CONT  TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence
=== RUN   TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_0
=== PAUSE TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_0
=== RUN   TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_0
=== PAUSE TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_0
=== RUN   TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_60000
--- PASS: TestReviewIntentConformanceCategoryIsRequestedAndAccepted (0.00s)
=== PAUSE TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_60000
=== RUN   TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_60000
=== CONT  TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_0
=== PAUSE TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_60000
=== CONT  TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_60000
=== CONT  TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_60000
=== CONT  TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_0
--- PASS: TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding (0.39s)
--- PASS: TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence (0.00s)
    --- PASS: TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_0 (0.38s)
    --- PASS: TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence/limit_60000 (0.39s)
--- PASS: TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved (0.39s)
--- PASS: TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence (0.00s)
    --- PASS: TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_0 (0.39s)
    --- PASS: TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence/limit_60000 (0.41s)
PASS
ok  	github.com/kunchenguid/no-mistakes/internal/pipeline/steps	3.569s
Evidence: Full regression suite, real host env

exit=1; only failures: TestRebaseStep_NonConflictFailureWithRebaseMetadataReturnsError, TestRebaseStep_FixModeNonConflictFailureReturnsError (host rebase.autostash=true)

ok  	github.com/kunchenguid/no-mistakes	2.511s
ok  	github.com/kunchenguid/no-mistakes/cmd/fakeagent	1.053s
?   	github.com/kunchenguid/no-mistakes/cmd/genskill	[no test files]
ok  	github.com/kunchenguid/no-mistakes/cmd/no-mistakes	1.020s
ok  	github.com/kunchenguid/no-mistakes/cmd/publish-channels	1.021s
ok  	github.com/kunchenguid/no-mistakes/cmd/recordfixture	3.459s
ok  	github.com/kunchenguid/no-mistakes/internal/agent	38.158s
ok  	github.com/kunchenguid/no-mistakes/internal/agentcfg	1.014s
ok  	github.com/kunchenguid/no-mistakes/internal/bitbucket	1.030s
ok  	github.com/kunchenguid/no-mistakes/internal/branchsync	23.585s
?   	github.com/kunchenguid/no-mistakes/internal/buildinfo	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/cimonitor	1.011s
ok  	github.com/kunchenguid/no-mistakes/internal/cli	111.103s
ok  	github.com/kunchenguid/no-mistakes/internal/config	1.221s
ok  	github.com/kunchenguid/no-mistakes/internal/conventional	1.016s
ok  	github.com/kunchenguid/no-mistakes/internal/custody	1.151s
ok  	github.com/kunchenguid/no-mistakes/internal/daemon	112.280s
ok  	github.com/kunchenguid/no-mistakes/internal/db	49.239s
?   	github.com/kunchenguid/no-mistakes/internal/e2e	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/e2edaemon	20.364s
ok  	github.com/kunchenguid/no-mistakes/internal/eval	53.366s
ok  	github.com/kunchenguid/no-mistakes/internal/evidence	1.754s
ok  	github.com/kunchenguid/no-mistakes/internal/forgecontext	1.063s
ok  	github.com/kunchenguid/no-mistakes/internal/gate	20.183s
ok  	github.com/kunchenguid/no-mistakes/internal/gatecontext	3.743s
ok  	github.com/kunchenguid/no-mistakes/internal/gateguidance	1.021s
ok  	github.com/kunchenguid/no-mistakes/internal/git	2.323s
ok  	github.com/kunchenguid/no-mistakes/internal/intent	2.789s
ok  	github.com/kunchenguid/no-mistakes/internal/ipc	1.394s
?   	github.com/kunchenguid/no-mistakes/internal/lifecycle	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/logstore	4.336s
ok  	github.com/kunchenguid/no-mistakes/internal/paths	1.040s
ok  	github.com/kunchenguid/no-mistakes/internal/pipeline	63.969s
?   	github.com/kunchenguid/no-mistakes/internal/pipeline/fakecli	[no test files]
2026/10/03 12:00:54 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:00:54 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:01:03 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:01:03 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:01:03 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:01:03 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:01:04 WARN failed to fetch CI logs err="job log expired"
2026/10/03 12:01:08 WARN failed to persist uncertified pipeline range run_id=run-1 error="upsert uncertified pipeline range: constraint failed: FOREIGN KEY constraint failed (787)"
2026/10/03 12:01:08 WARN failed to persist uncertified pipeline range run_id=run-1 error="upsert uncertified pipeline range: constraint failed: FOREIGN KEY constraint failed (787)"
2026/10/03 12:01:09 WARN failed to persist uncertified pipeline range run_id=run-1 error="upsert uncertified pipeline range: constraint failed: FOREIGN KEY constraint failed (787)"
2026/10/03 12:01:15 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z35JEXG60D3GY37VGMNP commit_email=test@test.com local_user=doug
2026/10/03 12:01:15 INFO intent: attached run_id=01M417Z35JEXG60D3GY37VGMNP agent=claude score=1
2026/10/03 12:01:16 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z3R82757SR0D81MATJ83 commit_email=test@test.com local_user=doug
2026/10/03 12:01:16 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z425RHAB8JBW2MN7C2S1 commit_email=test@test.com local_user=doug
2026/10/03 12:01:16 INFO intent: attached run_id=01M417Z425RHAB8JBW2MN7C2S1 agent=claude score=1
2026/10/03 12:01:17 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z4BR0N65ZAZ9G60SD6VV commit_email=test@test.com local_user=doug
2026/10/03 12:01:17 INFO intent: attached run_id=01M417Z4BR0N65ZAZ9G60SD6VV agent=claude score=1
2026/10/03 12:01:17 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z4NX2P0Z8RT0ZKPVQFH4 commit_email=test@test.com local_user=doug
2026/10/03 12:01:17 INFO intent: attached run_id=01M417Z4NX2P0Z8RT0ZKPVQFH4 agent=claude score=1
2026/10/03 12:01:17 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z500ES5FN85EMBT4KCQH commit_email=test@test.com local_user=doug
2026/10/03 12:01:17 INFO intent: attached run_id=01M417Z500ES5FN85EMBT4KCQH agent=claude score=1
2026/10/03 12:01:18 WARN intent: head commit author looks different from local user; intent may not reflect this commit run_id=01M417Z5AAJ4TPGRP5Q6Z108T8 commit_email=test@test.com local_user=doug
2026/10/03 12:01:18 INFO intent: attached run_id=01M417Z5AAJ4TPGRP5Q6Z108T8 agent=claude score=1
2026/10/03 12:01:18 INFO intent: attached run_id=01M417Z5KZ4BR6J128Y6G4PRA3 agent=claude score=0.9
2026/10/03 12:01:18 INFO intent: attached run_id=01M417Z5XFV8623DMV2CRJAG6P agent=claude score=0.9
2026/10/03 12:01:50 INFO intent: attached run_id=01M417Z6ZFEWV18VRDBZK7R48J agent=claude score=0.92
2026/10/03 12:01:51 WARN panic during intent extraction run_id=01M41805XRAVEQR48R8TTCF88Z panic=boom
2026/10/03 12:02:09 INFO auto-fixing step step=review attempt=1 max=3
2026/10/03 12:02:09 INFO auto-fixing step step=review attempt=2 max=3
2026/10/03 12:02:10 INFO auto-fixing step step=review attempt=1 max=3
2026/10/03 12:02:10 INFO step fix requested, re-executing step=review
2026/10/03 12:02:13 INFO auto-fixing step step=review attempt=1 max=2
2026/10/03 12:02:13 INFO auto-fixing step step=review attempt=2 max=2
2026/10/03 12:02:21 WARN tightened agent PR title type from="Improve pipeline header UX" to="fix: Improve pipeline header UX"
2026/10/03 12:02:21 WARN agent returned nested JSON in PR body, unwrapping
2026/10/03 12:02:21 WARN agent returned nested JSON in PR body, unwrapping
2026/10/03 12:02:22 WARN agent returned nested JSON in PR body, unwrapping
2026/10/03 12:02:22 WARN agent failed for PR content, using fallback error="agent timed out after 20ms; agent produced no output at all in 20ms and never reported a subprocess start"
2026/10/03 12:02:23 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:23 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:23 WARN agent failed for PR content, using fallback error="simulated agent failure"
--- FAIL: TestRebaseStep_NonConflictFailureWithRebaseMetadataReturnsError (0.84s)
    rebase_test.go:420: expected error for non-conflict rebase failure
2026/10/03 12:02:24 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:24 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:24 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:24 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:25 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:25 WARN failed to fetch CI logs check="PR must be raised via no-mistakes" check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:25 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:25 

... [609 bytes truncated] ...

d never reported a subprocess start"
2026/10/03 12:02:25 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:25 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
--- FAIL: TestRebaseStep_FixModeNonConflictFailureReturnsError (0.81s)
    rebase_test.go:369: expected error for non-conflict rebase failure
2026/10/03 12:02:26 WARN failed to fetch CI logs check=test check_id=check-b err="job log expired"
2026/10/03 12:02:26 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs check=flaky check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:26 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=e2e check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=greptile check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=greptile check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=greptile check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:27 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs check=e2e check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:28 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:29 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:29 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:29 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:29 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:30 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:30 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:30 WARN failed to fetch CI logs err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:30 WARN failed to fetch CI logs check=test check_id="" err="list GitHub runs for selected logs: exit status 1"
2026/10/03 12:02:30 WARN worktree head is not a verified descendant before terminalization run=01M4181B7GR3K5V1JHRGV15VEE error="git merge-base --is-ancestor 7055a562906594d439ef57ae34eee4ea18a7e064 18a084f77ee72633405174abbe8edf1f421f714b: exit status 1: "
FAIL
FAIL	github.com/kunchenguid/no-mistakes/internal/pipeline/steps	103.677s
ok  	github.com/kunchenguid/no-mistakes/internal/pipeline/steps/citest	6.356s
?   	github.com/kunchenguid/no-mistakes/internal/pipeline/steps/internal/stepstest	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/procreap	3.892s
ok  	github.com/kunchenguid/no-mistakes/internal/runenv	1.017s
ok  	github.com/kunchenguid/no-mistakes/internal/safepath	1.063s
ok  	github.com/kunchenguid/no-mistakes/internal/safeurl	1.016s
ok  	github.com/kunchenguid/no-mistakes/internal/scm	1.655s
ok  	github.com/kunchenguid/no-mistakes/internal/scm/azuredevops	12.219s
ok  	github.com/kunchenguid/no-mistakes/internal/scm/forgejo	152.238s
ok  	github.com/kunchenguid/no-mistakes/internal/scm/gitea	6.195s
ok  	github.com/kunchenguid/no-mistakes/internal/scm/github	12.286s
ok  	github.com/kunchenguid/no-mistakes/internal/scm/gitlab	5.182s
ok  	github.com/kunchenguid/no-mistakes/internal/shellenv	10.475s
ok  	github.com/kunchenguid/no-mistakes/internal/skill	1.125s
ok  	github.com/kunchenguid/no-mistakes/internal/telemetry	1.021s
?   	github.com/kunchenguid/no-mistakes/internal/testguidance	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/tui	1.498s
ok  	github.com/kunchenguid/no-mistakes/internal/types	1.019s
ok  	github.com/kunchenguid/no-mistakes/internal/update	2.423s
?   	github.com/kunchenguid/no-mistakes/internal/winproc	[no test files]
ok  	github.com/kunchenguid/no-mistakes/internal/wizard	9.464s
ok  	github.com/kunchenguid/no-mistakes/internal/worktrees	1.105s
FAIL
exit=1
Evidence: Full regression suite, neutral git config

Source: Full regression suite, neutral git config (local file: ~/.no-mistakes/evidence/01M416CSGV9W8P8HPQDCFPZM5Y/full-suite-race-neutral-config.log)

exit=1; only failure: TestCIStep_CommitAndPush_GitCommandsUseStandardCredentialEnv, an artifact of the synthetic GIT_CONFIG_GLOBAL (passes under real env)
- Outcome: ⚠️ 2 warnings across 1 run (21m44s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ℹ️ internal/pipeline/steps/prsummary.go:450 - Pre-existing, adjacent to the new foreign-owner rule: repo-relative artifact "Evidence" links are built from the parent repository URL at the run head SHA (pr.go:412 passes sctx.Repo.UpstreamURL and sctx.Run.HeadSHA into testingSummaryOptionsForGitHub), but on a fork-routed run that SHA is pushed only to the fork, so a maintainer clicking such a link on the foreign-owner PR gets a 404 until merge (and forever for untracked worktree files). The change deliberately keeps "links" for foreign owners while dropping local-path references, and this is the one kept link class that can still be unopenable. Not introduced by this diff; a remedy (build the blob base from the fork URL when fork-routed, mirroring evidence_publish.go:54-57 which already does exactly that for published evidence) extends beyond this change's stated intent.
⚠️ **Test** - 2 warnings
  • ⚠️ internal/pipeline/steps/rebase_test.go:369 - Both rebase non-conflict-failure tests fail on any host whose global git config sets rebase.autostash=true (this machine's ~/.gitconfig does): the dirty-tree rebase auto-stashes and succeeds, so the expected error never happens. Proven environmental, not caused by this branch: the branch diff touches no rebase files, and both tests pass 3/3 once GIT_CONFIG_GLOBAL is neutralized (and again under host-config-minus-autostash). Upstream CI passes because GitHub runners use git defaults. Fix: give the rebase test setup an isolated git config (temp HOME or empty GIT_CONFIG_GLOBAL) the way ci_commit_test.go already seeds a temp HOME with its own .gitconfig.
  • ⚠️ live validation verdict: inconclusive (0 of 6 scenarios were driven live against the product); untested: Foreign-owner PR body omits the run's task-intent section and every local evidence path a maintainer cannot open, while keeping What Changed, Testing, openable evidence, and the live attestation marker, Same-owner PR body is unchanged: it keeps the Intent section and local evidence paths, byte-identical with and without a same-owner fork, PR step refuses to open or update a pull request while the completed review still holds an intent-conformance finding, naming the finding IDs and issuing no forge PR-create call, PR step still opens the PR when review findings carry no intent-conformance category (no over-blocking of ordinary review warnings), Review contract carries the intent-conformance category: the emitted review prompt asks for it and the review findings schema accepts it, Adversarial: PR step fails closed when the completed review's findings JSON is unreadable instead of publishing a PR with unknown conformance state
  • Live validation: ⚠️ inconclusive - 0 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Foreign-owner PR body omits the run's task-intent section and every local evidence path a maintainer cannot open, while keeping What Changed, Testing, openable evidence, and the live attestation marke… ⏸️ untested no The prior payload did not establish a live result: it drove only the branch's scenario tests and temporary probes through PRStep rendering with the repo's fake gh stub. A live drive would publish a re…
Same-owner PR body is unchanged: it keeps the Intent section and local evidence paths, byte-identical with and without a same-owner fork ⏸️ untested no The prior payload did not establish a live result: byte-identity was asserted on strings rendered in-process behind the fake gh stub, and no real PR was opened or updated against an owned repository,…
PR step refuses to open or update a pull request while the completed review still holds an intent-conformance finding, naming the finding IDs and issuing no forge PR-create call ⏸️ untested no The prior payload did not establish a live result: the refusal and the absent create call were observed only in-process via Execute with the fake gh log. No live run demonstrated a real forge receivin…
PR step still opens the PR when review findings carry no intent-conformance category (no over-blocking of ordinary review warnings) ⏸️ untested no The prior payload did not establish a live result: the recorded 'pr create' was a fake gh invocation inside a unit-level Execute, not a real pull request opened on a forge by the running product.
Review contract carries the intent-conformance category: the emitted review prompt asks for it and the review findings schema accepts it ⏸️ untested no The prior payload did not establish a live result: the prompt text and schema enum were asserted as delivered artifacts from the emitted files, and no real reviewer agent ever ran, so the end-to-end c…
Adversarial: PR step fails closed when the completed review's findings JSON is unreadable instead of publishing a PR with unknown conformance state ⏸️ untested no The prior payload did not establish a live result: the fail-closed path was exercised in-process against malformed fixture findings with the fake gh stub, not against the running product publishing to…
  • go test -race ./internal/pipeline/steps -run 'TestPRBody_ForeignOwnerOmitsIntentAndLocalPathEvidence|TestPRBody_SameOwnerKeepsIntentAndLocalPathEvidence|TestPRStep_RefusesWhileApprovedIntentConformanceFindingIsUnresolved|TestPRStep_ProceedsWhenReviewHoldsNoIntentConformanceFinding|TestReviewIntentConformanceCategoryIsRequestedAndAccepted' -v -count=1 — all pass
  • temporary evidence probes TestProbeForeignOwnerBodies and TestProbeRefusalMessages (real buildPRContent/Execute renders written to the evidence dir; probe file removed afterwards, worktree clean at bc5251d)
  • go test -race ./... — complete regression suite, run 1 under the real host environment
  • go test -race ./... — complete regression suite, run 2 under neutralized global git config (GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM)
  • targeted reruns of the three git-config-sensitive tests under host-config-minus-autostash: rebase pair 3/3 pass, credential-env test passes under the real host env of run 1
✅ **Document** - passed

✅ No issues found.

⚠️ **Lint** - 1 warning
  • ⚠️ linter found issues (exit code 2)
✅ **Push** - passed

✅ No issues found.

… unresolved intent mismatch

When the PR targets a repository whose owner differs from the fork that
was pushed, the generated body now omits the ## Intent section and every
local-file evidence reference the maintainer cannot open. Inline evidence
text, links, and attachments stay; same-owner bodies are unchanged.

Review now tags intent-contradiction findings with the structured
category intent-conformance, and the PR step refuses to create or update
the pull request while a completed review still holds one (it was
approved, not fixed). The branch stays pushed.
@dmealing
dmealing merged commit 5c27c47 into local Oct 3, 2026
dmealing added a commit that referenced this pull request Oct 11, 2026
… 1.93 (#6)

* feat(ci): local CI mode for the local fork build (#1)

* feat(ci): add local CI mode for the local fork build

ci_mode (global-only, default local) skips the CI step on every run, enforced
by the daemon at run creation and recovery and by every run-launch request so
it holds against an older running daemon. Status and axi output explain the
skip via run.local_ci. The build stamps v1.72.0-local.1, refuses self-update,
and suppresses the update banner.

* refactor(ci): simplify local CI mode skip plumbing

Route fresh and recovered skips through one executor helper, share the
update-silence predicate, and pin the github-mode e2e journey to ci_mode: github.

* fix: regenerate skill and document local fork build

* feat(pipeline): let local CI mode own broad regression in Test (#2)

* feat(pipeline): let local CI mode own broad regression in Test

The Test step's prompts told every agent that remote CI owns broad
regression and remains mandatory before a PR is ready. Under
`ci_mode: local` no forge checks run for the change at all, so for a
repository with no `commands.test` that sentence sent the broad
regression pass nowhere: the evidence agent is the whole Test step, and
it was instructed to defer to a gate that never runs.

`testRegressionScope` now resolves the wording from the run's effective
`config.CIMode`. In `github` mode every bullet is byte-identical to
before. In `local` mode the evidence turn runs the repository's complete
regression suite after the targeted scenarios and reports a suite
failure as a finding, and no agent-facing text claims remote CI is
mandatory or will catch anything. Fix rounds stay focused in both modes,
because the evidence turn always follows a fix round inside the same
step execution, so the suite is paid once per Test step rather than once
per repair round.

Lint is deliberately left alone. Its changed-file narrowing is a scoping
preference, not a deferral: it never claims another gate will catch what
it skips, and widening it would surface pre-existing debt in untouched
files as churn on every run. Repositories that want a deterministic
repo-wide static gate set `commands.lint`, which is unchanged.

* no-mistakes(review): Sync stale broad-regression doctrine docs to ci_mode

* feat(test): test.live_evidence=false skips the evidence agent on a passing baseline

A repository whose commands.test is its whole regression and integration suite gets no value from
the live-evidence agent once that suite passes, and pays for it in wall clock: on one repository
the agent was ~19 of the test step's ~27 minutes. test.live_evidence: false skips the agent only
when commands.test ran and passed; a failing baseline still gets the agent to diagnose it.

Trusted-only, like test.instructions: a pushed branch cannot switch off validation of itself.
The resolved field is SkipLiveEvidence so a zero-value config keeps the agent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Kbw3LMGDkS8qHefoc7uGE

* fix(pipeline): clean foreign-owner PR bodies and refuse PRs approved with intent-conformance findings (#4)

* fix(pipeline): keep foreign-owner PR bodies clean and refuse PRs with unresolved intent mismatch

When the PR targets a repository whose owner differs from the fork that
was pushed, the generated body now omits the ## Intent section and every
local-file evidence reference the maintainer cannot open. Inline evidence
text, links, and attachments stay; same-owner bodies are unchanged.

Review now tags intent-contradiction findings with the structured
category intent-conformance, and the PR step refuses to create or update
the pull request while a completed review still holds one (it was
approved, not fixed). The branch stays pushed.

* test(pipeline): share the PR drafting stub across foreign-owner tests

* docs(agents): record foreign-owner PR body and intent-mismatch refusal owners

* docs(skills): move PR body and intent-mismatch notes into owning skills

* test(pipeline): reuse step-seeding helpers and parse the review schema in foreign-owner tests

* feat(daemon): fail dead runs and reap worktree-anchored orphans (#3)

A run could stay `running` forever once its executor could no longer make
progress - a deleted worktree, a wedged agent whose exit was never
observed, or a lost terminal write - indistinguishable from real work to
anything polling `axi status` (observed as a 12+ hour poll loop against a
run that had already merged). Separately, grandchildren that escape the
per-command process group (a backgrounded dev server) both leaked and
defeated `git worktree remove --force` by re-creating files mid-delete,
so the process leak and the undeletable worktree were the same bug.

- A 1-minute daemon watchdog declares an active run dead (terminal
  `failed`, error prefixed `dead run: `) when its worktree is gone, its
  recorded agent process died unobserved, a running/fixing non-CI step is
  silent past the new `step_stall_timeout` (default 1h, keyword-disable
  supported), or an active row has no live executor past a grace. Parked
  `awaiting_agent` runs and the CI monitor stay exempt by design.
- Configured `commands.*` invocations heartbeat step activity while the
  daemon waits on them: their output is captured buffered, so a healthy
  long-running test suite would otherwise look dead and be stall-killed.
- Rows inside startRun setup are tracked (`RunManager.settingUp`) so a
  long worktree checkout/fetch is never mistaken for an orphaned row.
- `axi status` reports machine-readable `liveness: ok|stalled|dead` (plus
  `liveness_reason` carrying the recovery command) on non-terminal runs,
  covering the stopped-daemon case the watchdog cannot.
- Run worktree removal goes through `removeRunWorktree`, which reaps
  processes anchored to the worktree (cwd via /proc, worktree path in
  argv via ps) before removal; Windows reaping is a documented no-op.
- The user-level skill now owns background-watcher discipline (finite
  watchers, run-id anchoring via `axi status --run <id>`, acting on
  `liveness`) alongside the new polling guidance.

Claude-Session: https://claude.ai/code/session_014VNhEaL6dpACh5TqrN8M6D

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* fix(agent): report claude token usage and cost from the result event (#5)

* fix(agent): take claude token usage from the result event

Per-message usage on assistant stream-json events is partial and repeats
across events of one message, so summing it undercounted output and
double-counted cache reads. Use the final result event's usage; keep the
assistant sum only as a fallback when the result carries no usage.

* no-mistakes(review): Capture claude result costUSD; fall back on zero usage

* test: align fork tests with v1.93 usage and PR summary signatures

* test: adapt fork tests to v1.93 gate-path and CI-mode defaults

* fix: run e2e harness in github CI mode and leave Intent publication to pr.publish_intent

* chore: stamp local build version v1.93.0-local.1

* no-mistakes(review): Fix watchdog worktree path, command heartbeat, foreign-owner Intent

* no-mistakes(review): Heartbeat base-attribution commands; clarify foreign-owner Intent docs

* no-mistakes(document): Document foreign-owner Intent rule and test.live_evidence

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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