# Restricted-check permission reproduction

This is a real T3 server and web client driven by e2e, with a **synthetic GitHub HTTP transport**, not a genuinely restricted PAT. The transport preserves PR metadata and aggregate status, returns GitHub's field-level FORBIDDEN error for check contexts, and accepts the aggregate-only retry. No app implementation was changed.

Browser: Chromium, 1280×800, light theme. Each commit used its own fresh T3 home with automatic seeding disabled. The project was created through `t3.project` with a synthetic GitHub remote. The same driver opened PR 7 and revealed Checks on both commits. Captures were accepted after two identical PNGs 500 ms apart. Recordings show the same navigation from loading to the final panel; initial setup is trimmed.

## Run

Place the scenario beside the repository's `scripts/scenarios/t3.ts`. Apply `harness-env.patch` to let e2e pass the fixture environment to the real app process. On a checkout with dependencies installed:

```sh
export PROOF_SCRATCH="$(mktemp -d)"
mkdir -p "$PROOF_SCRATCH/gh-config"
printf 'http_unix_socket: %s/forge.sock\n' "$PROOF_SCRATCH" > "$PROOF_SCRATCH/gh-config/config.yml"
node ./forge.mjs &
forge_pid=$!
export GH_CONFIG_DIR="$PROOF_SCRATCH/gh-config"
export GH_TOKEN=synthetic-permission-fixture
export T3CODE_DEV_SEED=0
# From scripts/, repeat against each commit's separate checkout:
T3_SCENARIO_APP_DIR="$APP_CHECKOUT" node_modules/.bin/e2e run scenarios/restricted-check-details.e2e.ts --target web
kill "$forge_pid"
```

The fixture never forwards requests to GitHub. `GH_TOKEN` above is a dummy fixture value. `APP_CHECKOUT` is the commit's own installed checkout. The scenario harness comes from current main. No stored review guide is seeded; the guide read checks whether resolving its current PR head succeeds.

AI-assisted; verified with the tests and tools listed above.

## Watch and guide runtime evidence

The additional runtime captures call the real server's MCP endpoint using a temporary local client session, revoked after each call. `mcp-call.mjs` uses the same authentication and MCP helpers as the shipped thread CLI. It takes a harness checkout, the isolated T3 home, tool name, and JSON arguments. Make the owning server package's dependencies available beside the script before running it. Use one harness checkout consistently to avoid loading two copies of Effect's secret wrappers.

`seed-watch.mjs` creates a synthetic git project, starts a replay turn through the real CLI, then invokes `watch_pull_request`. Run it once per separately running app/home. `event-capture.mjs <home> <side> <commit> <output>` reads that isolated server's persisted domain events read-only and captures just PR snapshots, watch state, and monitor messages. It subscribes to filesystem changes instead of polling. It excludes provider settings and conversation metadata.

With both watches running, change `control.json` beside the forge script to introduce an aggregate failure, then a conflict, comment, and review:

```json
{"state":"FAILURE","conflict":true,"comment":"<current ISO timestamp>","review":"<current ISO timestamp>"}
```

Only individual check-node reads are refused; aggregate check counts and metadata remain readable. Let the real two-minute watch sweeps run. The base's repeated failed detail reads eventually stop its watch; the head delivers monitor messages. The transcript includes actual event times, so it also records the earlier head-only aggregate pass/fail observation before the base watch was created. The matched visual comparison uses the same independent fresh seed and driver on both commits.

`read_pull_request_guide` is called with the synthetic PR URL on each running server. Neither side has a stored guide; success means resolving the PR and current head rather than generating a guide.
