feat(github): Cloud Action Rail commands under aether github (UX-01) - #141
Merged
Conversation
Extends the existing `aether github` tree with the Cloud Action Rail: pr list/view/prepare/create/update, checks, ci rerun, workflow dispatch, and action view. status/connect/disconnect are carried over unchanged. The boundary between the two halves is the point of the change. The account-link commands stay local. Everything new runs under Aether Cloud custody — the backend's GitHub App, a JIT token scoped to one repository, and an ActionRun that leaves a receipt. Nothing here invokes a local `gh` binary or touches the user's own GitHub session, and there is no fallback between the two: a silent fallback is how someone believes they published under one identity and actually published under another. Two tests read the module sources and assert no child_process/spawnSync/execFile reference exists, so that claim is structural rather than asserted. Approval is exact. `--approve create-draft-pr` authorizes creating a draft pull request and nothing else, so a phrase typed for one action cannot be replayed against another. `--yes` is not authority, a generic `--approve` is not authority, and neither is a trailing space or different casing. A TTY is not consent either: interactive mode still refuses until the confirmation is actually answered. Non-interactive callers get a structured AUTHORIZATION_REQUIRED plus the plan to show a human. They never get a prompt, never hang on a TTY that isn't there, and cannot confirm on the human's behalf. Values stay inert typed data. `--title --force` yields the string "--force"; nothing downstream re-parses it and nothing builds a shell string, so command substitutions, embedded newlines, quotes and Windows paths are just strings in a JSON body. Same discipline src/core/review_actions.ts applies to paths. Registry work follows the repo's existing architecture rather than side-stepping it: the shell:github manifest entry gains the new args, summary, detailed help and ownedFlags, and docs/generated/commands.md is regenerated with `npm run docs:generate` rather than hand-edited. scripts/generate-docs.ts needed the new args string allowlisted in COMMAND_PLACEHOLDERS — its markdown-injection guard rejects any bracketed token it does not recognise, which is the guard working correctly. NOTE FOR REVIEW: the specification says this lane must "preserve `aether ship` exactly" and lists its fake-gh canaries as an exit gate. `aether ship` does not exist in this repository at main 6c61ea1 — no command, no manifest entry, no docs, no such tests. That requirement is vacuously satisfied rather than met, and the gap is reported instead of papered over. The custody distinction it exists to protect is still enforced above. Tests: 56 new in test/github_action_rail.test.ts. Typecheck clean; docs drift check clean (6 outputs).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lane
UX-01— Packet B of the Control Plane P0 fanout. The Agent-side half of the GitHub Action Rail.Base:
main@6c61ea17203a181ef5c04f682e57b634f24f1bf9(verified three ways:gh api,git ls-remote,git rev-parse— and it matches the SHA the spec recorded).Cloud counterpart: AetherAI3/AETHER-CLOUD#1510 (
AR-01).What this adds
Extends the existing
aether githubtree — it does not fork it:status/connect/disconnectare carried over unchanged.The four rules, each asserted rather than documented
1. Custody is always stated. The account-link commands stay local; everything new runs under Aether Cloud custody — the backend's GitHub App, a JIT token scoped to one repository, an ActionRun that leaves a receipt. There is no fallback between the two, because a silent fallback is how someone believes they published under one identity and actually published under another. Two tests read the module sources and assert no
child_process/spawnSync/execFilereference exists, so "never shells out togh" is structural, not a promise.2. Approval is exact.
--approve create-draft-prauthorizes creating a draft PR and nothing else, so a phrase typed for one action cannot be replayed against another. Parametrized tests confirmyes,y,true,approve,CREATE-DRAFT-PRand a trailing space all fail.--yesis not authority. A TTY is not consent either — interactive mode still refuses until the confirmation is actually answered.3. Non-interactive callers get a structured refusal, never a prompt.
AUTHORIZATION_REQUIREDplus the plan to show a human. No hanging on a TTY that isn't there, and no confirming on the human's behalf.4. Values stay inert typed data.
--title --forceyields the string"--force". Nothing re-parses it and nothing builds a shell string, so command substitutions, embedded newlines, quotes and Windows paths are just strings in a JSON body — the same disciplinesrc/core/review_actions.tsapplies to paths.Registry work follows the existing architecture
The
shell:githubmanifest entry gains the newargs,summary,detailedHelpandownedFlags;docs/generated/commands.mdis regenerated withnpm run docs:generate, not hand-edited.scripts/generate-docs.tsneeded the new args string allowlisted inCOMMAND_PLACEHOLDERS— its markdown-injection guard rejects any bracketed token it does not recognise, which is the guard working correctly.⚠ A spec claim that does not hold in this repository
The spec requires this lane to "preserve
aether shipexactly" and lists its fake-gh canaries as an exit gate.aether shipdoes not exist at6c61ea17— no command, no manifest entry, no docs entry, no such tests. I checkedsrc/,test/,COMMANDS.mdanddocs/. That requirement is therefore vacuously satisfied rather than met, and I'd rather say so than let a green checkbox imply a canary ran. The custody distinction it exists to protect is enforced above regardless.Test plan
56 pass, 0 fail — including the pre-existing docs-parity and command-registry guards.
The full
npm testsuite exceeds my local run window, so CI is the authoritative check on this PR.Known limits
/cloud/actions/github/*, which lands withAR-01(#1510); until that merges these commands will get a 404 from the backend. Nothing is enabled by this PR alone.aether ghalias. The spec permits one as an exact parser alias; it is not shipped here rather than shipped half-done.action watchcurrently behaves asview— no streaming poll loop yet.checkApprovalacceptsconfirmed) but no prompt is wired; today every mutation needs the explicit--approve, which is the stricter path.READY_FOR_MERGE=true·MERGED=false·ENABLED=false— not self-merging, per the fanout handoff contract.