Skip to content

feat: add bounded issue-to-PR workflows - #29

Merged
kodiakhq[bot] merged 7 commits into
mainfrom
claude/issue-11-implementation-vy5b5t
Aug 13, 2026
Merged

feat: add bounded issue-to-PR workflows#29
kodiakhq[bot] merged 7 commits into
mainfrom
claude/issue-11-implementation-vy5b5t

Conversation

@RedStar071

@RedStar071RedStar071 commented Aug 12, 2026

Copy link
Copy Markdown
Member

Deliver the v0.4 milestone: a scoped, labeled GitHub issue can become an investigated, implemented, verified, review-ready pull request without widening the runtime's authority.

  • shared: add the issue trigger, IssueRef, and acceptance criteria to the decision, result, and evidence contracts; render criteria in reports
  • config: add the issues policy (enabled, requireLabel, branchPrefix) with branch-prefix validation; issue work is opt-in twice
  • models: let the model record verifiable acceptance criteria and treat issue text as an untrusted change request
  • agent: bound model-authored criteria before they become evidence and require an isolated runner for issue-triggered fixes when configured
  • github: parse issues webhooks behind the required label, build runtime input with observe as the default mode, and publish verified changes through the Git data API on a fresh branch that is never force-updated; prepareIssuePullRequest is the single publication gate and refuses any run that is not completed, accepted, and verified, or that proposes a high-impact change
  • server: ingest issues events behind repository policy, and compose the publication from stored evidence through a read-only runner; a failed publication reports its reason instead of failing the run

Verification: aube run check:repo, oxfmt --check, type-aware oxlint and tsc on every changed package, and 333 vitest tests across shared, config, models, agent, github, runner, cli, auth, and server all pass locally.

Closes#11

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

Summary

Why

Verification

  • aube run check:repo
  • aube run lint:ci
  • aube run typecheck
  • aube test
  • aube run build

Safety and compatibility

  • I added or updated deterministic tests for changed behavior.
  • I preserved observe mode as read-only, or explained the policy change above.
  • Runtime commands and target-repository writes remain inside the runner boundary.
  • I did not expose secrets, tokens, personal data, or untrusted output in logs.
  • I updated documentation and Agent Skills when workflows or boundaries changed.

Reviewer notes


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Confidence Score: 5/5

No blocking failure remains.

No accepted blocking findings remain after executable checks exercised the previously reported publication, repository-binding, delivery-claim, and remote-origin paths.

T-Rex T-Rex Logs

What T-Rex did

  • Ran a focused server publication regression using a focused test command and observed two tests pass with exit code 0; the first test captured invalid UTF-8 bytes and a deletion in the verified snapshot, mutated the live checkout, and the GitHub blob request contained the original exact base64 payload while the tree showed the deletion with sha: null; the second test bound the checkout to donor/library and caused openIssuePullRequest to refuse publication with no GitHub requests; a broader regression command covering apps/server and router tests produced 48 passing tests with exit code 0.
  • Ran the focused webhook idempotency regression, exercising 32 concurrent claims with an atomic store, 32 adversarial concurrent claims via the fallback arbitration path, a replay through a fresh persistent-store instance, and production route injection; all four checks passed, and existing delivery-claim and router tests passed 53 checks, with the server typecheck and production route build completing successfully.
  • Created an executable probe that builds temporary Git repositories and exercises LocalRunner.originRepository against real HTTPS and SCP origin metadata; attacker origins returned null while github.com origins returned the expected acme/app identity; the focused runner suite passed all 46 tests.
  • Observed that pnpm commands were captured as the before condition and failed because the repository is configured for aube; after switching to direct installed-tool invocations, the focused regression passed 4/4, existing server regressions passed 53/53, and the TypeScript typecheck and production route build completed successfully.
  • Implemented the remote-host-binding probe and captured non-GitHub runtime output, GitHub-origin comparison runtime output, and a runner-origin regression test run; the artifacts include the probe source and the corresponding before/after logs and the runner-origin test log.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (7): Last reviewed commit: "fix(server): arbitrate fallback delivery..." | Re-trigger Greptile

Deliver the v0.4 milestone: a scoped, labeled GitHub issue can become an
investigated, implemented, verified, review-ready pull request without
widening the runtime's authority.
- shared: add the issue trigger, IssueRef, and acceptance criteria to the
decision, result, and evidence contracts; render criteria in reports
- config: add the issues policy (enabled, requireLabel, branchPrefix) with
branch-prefix validation; issue work is opt-in twice
- models: let the model record verifiable acceptance criteria and treat
issue text as an untrusted change request
- agent: bound model-authored criteria before they become evidence and
require an isolated runner for issue-triggered fixes when configured
- github: parse issues webhooks behind the required label, build runtime
input with observe as the default mode, and publish verified changes
through the Git data API on a fresh branch that is never force-updated;
prepareIssuePullRequest is the single publication gate and refuses any
run that is not completed, accepted, and verified, or that proposes a
high-impact change
- server: ingest issues events behind repository policy, and compose the
publication from stored evidence through a read-only runner; a failed
publication reports its reason instead of failing the run
Verification: aube run check:repo, oxfmt --check, type-aware oxlint and
tsc on every changed package, and 333 vitest tests across shared, config,
models, agent, github, runner, cli, auth, and server all pass locally.
Closes#11
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4XhMKBtf98NZZmETE1XR4
Comment threadapps/server/src/router.ts Outdated
Comment threadapps/server/src/router.ts Outdated
Comment threadapps/server/src/router.ts
Before an issue task is trusted, the runtime already decides from
repository evidence whether the issue reports a real problem. Make that
triage visible where the work was requested, in the style of Pullfrog:
a finished run posts one comment on the issue with its verdict —
confirmed with the cited evidence and acceptance criteria, not confirmed
with every rejection reason, or inconclusive for a human to decide.
- config: add issues.validationComment (default true); the comment is
report-only and never changes what a run may write
- github: prepareIssueValidationComment composes the verdict from the
persisted evidence bundle alone, so it can never claim more than the
run proved; a run that failed before reaching a verdict gets no
comment; items are collapsed and bounded, credentials redacted; the
new GitHubIssueComments adapter can only create a comment — no path
to label, edit, or close an issue
- server: publishIssueValidation supplies stored evidence and posts the
composed comment; ingestWebhook reports the outcome per issue event,
and a failed post is a reported reason, never a failed run
Verification: check:repo, oxfmt --check, type-aware oxlint and tsc on
config, github, and server, and 349 vitest tests across all packages
pass locally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4XhMKBtf98NZZmETE1XR4
Comment threadapps/server/src/router.ts Outdated
Comment threadapps/server/src/router.ts Outdated
Comment threadapps/server/src/router.ts
…apshot, and delivery key
Address three review findings on the issue-to-PR flow:
- Bind issue events and publication to the checkout's trusted origin
repository via a new RepositoryBoundary.originRepository, rejecting
events whose claimed repository does not match the checkout.
- Publish pull requests from an immutable snapshot of the verified
changed files captured under the run lease, instead of re-reading
the mutable checkout at publication time.
- Deduplicate webhook deliveries with an atomic delivery-key claim
(delivery GUID or payload digest) so redeliveries return the
recorded outcome instead of starting a second task.
Comment threadpackages/runner/src/boundary.ts Outdated
Comment threadapps/server/src/router.ts
The checkout identity parser now refuses any remote whose host is not github.com, so an
owner/repo path on an attacker-controlled host can no longer approve publication to the GitHub
repository of the same name. Issue delivery claims gain a durable, atomically claimed store
shared across restarts and instances: the claim is persisted before the run starts, the recorded
outcome replays to redeliveries, and a transport failure releases the claim so a retry can
proceed.
Comment threadapps/server/src/router.ts
Comment threadapps/server/server/utils/store.ts
Comment threadapps/server/src/control-plane.ts Outdated
Comment threadapps/server/src/router.ts Outdated
…y claims
Verified snapshots are now captured through a new byte-safe Runner.readBytes
and stored as base64, and publication creates base64 blobs through the Git
data API instead of the text-only inline tree content field, so a verified
binary change lands with exactly the bytes the run verified.
Delivery claims on drivers without a conditional write no longer trust a bare
read-then-write: every contender writes a random arbitration token and only
the writer whose token survives the read-back owns the delivery, so two
instances that both observed the key absent resolve to a single owner.
The production Nitro server gains POST /webhooks/github, which injects the
shared taskStore and durable deliveryClaimStore into ingestWebhook and fails
closed (503, nothing ingested) until GITHUB_WEBHOOK_SECRET and
AGENT_ZERO_CHECKOUT_PATH are configured.
Comment threadapps/server/src/control-plane.ts Outdated
@kodiakhq
kodiakhqBot merged commit 9463e85 into mainAug 13, 2026
14 checks passed
@kodiakhq
kodiakhqBot deleted the claude/issue-11-implementation-vy5b5t branch August 13, 2026 00:13
RedStar071 pushed a commit that referenced this pull request Aug 13, 2026
Merge origin/main (PR #29, "add bounded issue-to-PR workflows") into
this branch. #29 landed after this branch forked and built a new
GitHub-issue-to-PR feature directly on the old packages/github APIs —
the exact package this branch renamed to packages/source-control and
restructured into provider-neutral adapters, so a textual merge alone
could not reconcile the two.
Resolution: ported comments.ts, issues.ts, and pulls.ts into
packages/source-control/src/providers/github-{comments,issues,pulls}.ts
unchanged in behavior, re-exported from the package's public surface,
and rewired apps/server/src/router.ts so ingestWebhook dispatches
GitHub `issues` events to the ported pipeline ahead of the
provider-neutral review-event path (issue-to-PR remains GitHub-only;
it has no equivalent on the other providers yet). WebhookRequest keeps
its provider-neutral `{ body, headers }` shape; the issue workflow
reads its delivery id from `X-GitHub-Delivery` via the newly exported
`readHeader` helper instead of a GitHub-specific request field.
WebhookOutcome now carries two `accepted` variants (review vs. issue),
distinguished structurally as `'changeRequest' in outcome` /
`'issue' in outcome`, matching the pattern main's own tests already
used for `'pullRequest' in outcome`.
Also updated: apps/server/server/routes/webhooks/github.post.ts to
build a headers-record request and pass `providers: [...]` instead of
a bare secret; SKILL.md, docs/architecture.md, and README's remaining
`packages/github` mentions; router.test.ts's issue-webhook suite
rebuilt against the header-based request shape.
Verification: 161 packages/source-control tests, 97 apps/server tests,
and the full suite for agent/config/models/runner/shared/cli/auth
(188 tests) pass; typecheck and oxlint type-aware lint are clean for
every touched package; oxfmt is clean repo-wide; check:repo passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJQxEwqaaP4aMG4E7yeaky
Sign up for freeto 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.

feat: v0.4 add bounded issue-to-PR workflows

2 participants

@RedStar071@claude