Skip to content

fix(mobile): bump app version to 1.0.4 - #4794

Open
iscekic wants to merge 33 commits into
mainfrom
chore/mobile-version-1.0.4
Open

fix(mobile): bump app version to 1.0.4#4794
iscekic wants to merge 33 commits into
mainfrom
chore/mobile-version-1.0.4

Conversation

@iscekic

@iscekic iscekic commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Bumps mobile app version to 1.0.4.


Workflow final report (gate-mobile-version-0ad2)

COMPLETE

PR: #4794
Head: 3c1fda3

What changed

  • Merged origin/main into chore/mobile-version-1.0.4; resolved the sole apps/mobile/app.config.ts conflict as main's full file with version: '1.0.4'.
  • Merged origin/mobile-e2e-ste cleanly, as required.
  • Addressed one valid Kilobot finding in merged seed tooling: synthetic GitHub user IDs now derive from the target UUID, avoiding normalized-email collisions.
  • Rejected and resolved one Kilobot harness comment: repeated port release already ignores a missing claim and has no observable failure.

Validation

  • pnpm exec oxfmt --check apps/mobile/app.config.ts passed.
  • Implementer ran focused formatting and lint for dev/seed/app/github-integration-copy.ts; both passed.
  • git diff --check passed.
  • PR checks are green after rerunning two cancelled infrastructure workflows: CI and kilo-app CI.
  • Kilobot's latest summary says No Issues Found and recommends merge.
  • Final gate command returned GATE OK (mechanical items) with mergeability MERGEABLE, clean state, zero unresolved threads, assignee iscekic, and label human-ready.

E2E

  • Skipped: this is a build-time version constant plus required merge/harness integration; no runtime behavior changed.

Assumptions used

  • PR intent remains mobile version 1.0.4.
  • The required ordered merge of main then mobile-e2e-ste is intentional.
  • No self-approval or PR merge was performed.

Kilobot / CI history

  • Kilobot was absent after the first post-merge head, so one allowed empty retrigger commit was pushed.
  • The first Kilobot review identified two comments; one accepted and fixed, one rejected with a technical reply. The latest-head re-review found no issues.
  • The CI and kilo-app CI workflows were cancelled without failed logs; each was rerun once and completed green.

Reviewer note: This PR temporarily contained changes from #4960 to unblock e2e. Those changes are removed. #4960 lands the e2e harness.

@iscekic iscekic self-assigned this Jul 27, 2026
@kilo-code-bot

kilo-code-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The latest commits reverted every shared e2e-harness file, so the net PR diff against main is now a single line — the mobile app version bump 1.0.31.0.4 — with no remaining defects.

Verification performed in this pass
  • Incremental diff f79b0bd5..db17e64c covers four files (dev/local/mobile-android.ts, dev/local/mobile-simulator.ts, dev/local/tmux.ts, and the deletion of dev/seed/app/github-integration-copy.ts); every hunk restores the base content that PR refactor(mobile-e2e): simplified runbook, scripted stub setup, load-tolerant flows #4960 owns.
  • Confirmed the revert is exact: git diff --name-only origin/main db17e64c and gh pr diff 4794 --name-only both report only apps/mobile/app.config.ts, so no partial revert or leftover harness edit remains on the branch.
  • Merge base is still b9ebddce, matching baseRefOid, so the single-file net diff is not an artifact of a stale base.
  • apps/mobile/app.config.ts net change is version: '1.0.3'version: '1.0.4' only; the file declares no ios.buildNumber, android.versionCode, or runtimeVersion that would need a matching bump.
  • Searched apps/mobile/ and dev/ for residual 1.0.3 references; none exist, so no test or config is pinned to the old version.
  • Behaviors removed by the revert (exact-match = tmux targeting, the atomic claim writer, the bootstatus timeout, the claim-rollback shutdown, the emulator GPU relaunch policy, and the seed integration-copy tool) all return to base state rather than to a hybrid, so none of the previously reviewed dev-tooling logic is left half-applied here.
  • All eight existing inline threads are outdated (line: null) and target paths no longer in the changed-file set (dev/seed/app/github-integration-copy.ts, apps/mobile/e2e/github-stub.sh, dev/local/mobile-workflow.test.ts); nothing carries forward.
Files Reviewed (1 file)
  • apps/mobile/app.config.ts - 0 issues

Assumptions: review was static and read-only — no tests were executed and CI status at HEAD was not read. The version constant is assumed to be consumed by EAS build metadata only, with build numbers auto-incremented outside this file; the reverted dev-tooling changes are assumed to land via #4960 as the PR description states.

Previous Review Summaries (6 snapshots, latest commit f79b0bd)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit f79b0bd)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The branch was force-pushed to f79b0bd5 with byte-identical content to the previously reviewed 2b3f4e2c (empty tree diff, only commit metadata changed), and a re-verification of all five net-changed files against main found no unresolved issues.

Verification performed in this pass
  • git diff 2b3f4e2c..f79b0bd5 is empty; the rewrite preserved trees exactly, so no new code was introduced.
  • Net PR diff vs base b9ebddc remains limited to five files; the reverted apps/mobile/e2e/** and dev/local/mobile-workflow.test.ts changes appear only inside the per-commit patch series and are not part of the merged diff.
  • dev/local/mobile-simulator.ts: writeClaimAtomic preserves the previous flag: 'wx' semantics via linkSync (still throws EEXIST, still handled by the candidate-skip branch at the claim loop), temp files (<udid>.json.tmp.<pid>) are ignored by the release-all scan which filters on .json, and the temp file is always removed in finally.
  • dev/local/mobile-simulator.ts: the new shutdown rollback path only fires when bootedByClaim is true and keeps the claim when the shutdown throws, so an abandoned claim cannot leave a booted device adoptable; bootstatus is now bounded at 15 minutes and a timeout surfaces through result.signal/result.error into the existing catch that powers the device down.
  • dev/local/mobile-android.ts: the single automatic relaunch matches the documented GPU policy (did not reach sys.boot_completed=1 retries the same GPU, everything else falls back to swiftshader_indirect), the already exists guard is re-thrown without teardown, and both teardown failures preserve the original error.
  • dev/local/tmux.ts and dev/local/mobile-android.ts tmux targets consistently use =<session> for exact-name matching.
  • dev/seed/app/github-integration-copy.ts: local-database guard, synthetic-id (^[89]\d{12}$) protection on both the pre-check and the setWhere of the upsert, donor exclusion of synthetic rows, live GitHub token probe, and Buffer public key are all consistent with packages/encryption/src/keyed-envelope.ts (publicKeyPem: string | Buffer).
  • apps/mobile/app.config.ts: version bump 1.0.31.0.4 only.
  • All eight existing inline threads are outdated (line: null) and already answered by the author; no defect from them reproduces in the current diff.
Files Reviewed (5 files)
  • apps/mobile/app.config.ts - 0 issues
  • dev/local/mobile-android.ts - 0 issues
  • dev/local/mobile-simulator.ts - 0 issues
  • dev/local/tmux.ts - 0 issues
  • dev/seed/app/github-integration-copy.ts - 0 issues

Assumptions: review was static and read-only — no tests were executed and CI status at HEAD was not read; local-only dev tooling under dev/local/** and dev/seed/** is assumed to never run against production credentials, which the USE_PRODUCTION_DB/loopback guard enforces for the seed script.

Previous review (commit 2b3f4e2)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of 135c1d4..2b3f4e2c found no remaining issues: the only change restores dev/local/mobile-workflow.test.ts to its base content, so its assertions again match the reverted apps/mobile/e2e harness and both previously reported CRITICAL test-assertion mismatches are resolved.

Verification performed in this pass
  • dev/local/mobile-workflow.test.ts:19 now asserts launchTimeout = ctx.platform === 'android' ? 420000 : 30000, matching apps/mobile/e2e/flows/open-app.js:30.
  • dev/local/mobile-workflow.test.ts:119 now asserts timeout: ctx.platform === 'android' ? 300000 : 15000, matching apps/mobile/e2e/flows/settle-app.js:16.
  • The removed Date.now() >= deadline) throw assertion no longer applies, since the reverted open-app.js has no sliced-wait deadline.
  • The extracted timeout list assertion [3000, 5000, 5000, 5000, 5000, 15000] still matches settle-app.js (the platform-aware first wait is not a numeric literal and is excluded by the regex).
  • dev/local/mobile-workflow.test.ts is now byte-identical to base b9ebddc, so it no longer appears in the PR diff.
  • Remaining PR diff vs base is limited to apps/mobile/app.config.ts, dev/local/mobile-android.ts, dev/local/mobile-simulator.ts, dev/local/tmux.ts, and dev/seed/app/github-integration-copy.ts; earlier comments on those paths have been addressed or were declined by the author with rationale.
Files Reviewed (1 file in this increment)
  • dev/local/mobile-workflow.test.ts (reverted to base) - 0 issues

Note: assertion/flow consistency was determined statically (read-only review; no tests were executed). CI status at HEAD was not read.

Previous review (commit 135c1d4)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The apps/mobile/e2e revert in 135c1d4 left dev/local/mobile-workflow.test.ts asserting the reverted-away flow implementation, so two assertions now fail and pnpm test (test:dev-local) breaks.

Overview

Severity Count
CRITICAL 2
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
dev/local/mobile-workflow.test.ts 17-21 Asserts launchBudget = ... : 120000 and Date.now() >= deadline) throw, but the reverted apps/mobile/e2e/flows/open-app.js has launchTimeout = ... : 30000 and no sliced-wait deadline
dev/local/mobile-workflow.test.ts 120-122 Asserts timeout: ctx.platform === 'android' ? 300000 : 120000, but the reverted apps/mobile/e2e/flows/settle-app.js:16 is back to 300000 : 15000
Verified in this pass (3c1fda3..135c1d4)
  • apps/mobile/e2e/ is now byte-identical to the base tree (b9ebddc), so the harness revert itself is clean and those paths no longer appear in the PR diff.
  • dev/local/appium-wrapper.test.ts is unchanged from base, so its appium.sh / record.sh / wdio/ports.js expectations stay consistent with the reverted harness.
  • dev/local/mobile-workflow.test.ts was not reverted with the harness; its settle-app.js timeout list ([3000, 5000, 5000, 5000, 5000, 15000]) and the mobile-android.ts content assertions still hold, but the two platform-budget assertions above do not.
  • Note (not raised inline, unchanged line): the new dev/seed/app/github-integration-copy.ts help text still points at github-stub.sh, which no longer exists in this branch after the revert and only lands in refactor(mobile-e2e): simplified runbook, scripted stub setup, load-tolerant flows #4960.
Files Reviewed (10 files)
  • dev/local/mobile-workflow.test.ts - 2 issues
  • apps/mobile/e2e/AGENTS.md
  • apps/mobile/e2e/appium.sh
  • apps/mobile/e2e/flows/open-app.js
  • apps/mobile/e2e/flows/settle-app.js
  • apps/mobile/e2e/github-stub.sh (deleted)
  • apps/mobile/e2e/login.sh
  • apps/mobile/e2e/logout.sh
  • apps/mobile/e2e/record.sh
  • apps/mobile/e2e/remote-cli.sh

Note: incremental review of 3c1fda3..135c1d4; test failures were determined statically (read-only review, no test execution). CI status at HEAD could not be read.

Fix these issues in Kilo Cloud

Previous review (commit 3c1fda3)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The only change since the previous review (5db9a3c) re-keys the synthetic github_user_id in dev/seed/app/github-integration-copy.ts from the normalized email to target.id, which resolves the previously flagged cross-account collision; no new issues were found.

Verified in this pass
  • dev/seed/app/github-integration-copy.ts:352 now hashes target.id (the kilocode_users primary key), so plus-tagged and case-variant accounts that normalize to the same address can no longer produce the same 8-prefixed id and can no longer violate the non-arbiter unique index UQ_user_github_app_tokens_github_user_app.
  • Determinism per target is preserved, so re-running the copy still updates the same row in place, and the comment above the hash ("deterministic per target") remains accurate.
  • normalizedEmail is still used by the normalized_email lookup fallback (line 151), so the change leaves no unused binding.
  • The 8 prefix plus 12 decimal digits still satisfies both isSyntheticGithubUserId (/^[89]\d{12}$/) and the setWhere guard regex, and cannot collide with the stub seed's 9 prefix.
  • The previously flagged apps/mobile/e2e/github-stub.sh suggestion was answered by the author and that file is unchanged in this increment, so it is not carried forward.
Files Reviewed (1 file)
  • dev/seed/app/github-integration-copy.ts

Note: incremental review of 5db9a3c..3c1fda3 only; runtime behaviour was not executed (read-only review).

Previous review (commit 5db9a3c)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The PR grew from a version bump into the mobile E2E harness; the highest-risk item is dev/seed/app/github-integration-copy.ts, whose synthetic github_user_id is derived from the normalized email and can collide across two distinct accounts, producing an unhandled Postgres unique-key violation.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
dev/seed/app/github-integration-copy.ts 352 Synthetic github_user_id hashes the normalized email, so plus-tagged / case-variant accounts collide and the upsert hits the non-arbiter unique index UQ_user_github_app_tokens_github_user_app as a raw 23505

SUGGESTION

File Line Issue
apps/mobile/e2e/github-stub.sh 82 release_port leaves STUB_PORT set, so the machine-global port claim is rmdir'd twice and the EXIT trap can delete a peer worktree's live claim
Verified and not flagged
  • encryptKeyedEnvelope accepts a PEM Buffer for publicKeyPem, matching the production helper — the asymmetry with decodePem is intentional.
  • setWhere on onConflictDoUpdate plus .returning() is valid in drizzle-orm 0.45.2 and is already used the same way in apps/web/src/lib/integrations/platforms/github/user-authorization.ts; the zero-row guard is correct.
  • new Date('2026-04-29 01:16:12.945+00') parses in V8 and matches the pattern packages/db/AGENTS.md prescribes for mode: 'string' timestamps.
  • git-token-service gates refresh solely on the access-token 5-minute buffer, so the dummy refresh_token_expires_at and the documented "~30 usable minutes then revoked" lifetime are accurate.
  • writeClaimAtomic temp names are invisible to releaseWorktreeSimulators' .json scan and to the .lock path; the finally unlink is correct for both the rename and the link (exclusive) paths.
  • mobile-android.ts emulator-start never launches a third time, rethrows on the already exists guard before any teardown, and always tears down after a failed second attempt.
  • execWithOutput's new spawnSync timeout always throws, so bootSimulator's catch still powers the device back off.
  • record.sh's new lock sits after the frame subcommand's exit, so record.sh frame … cannot deadlock, and "$0" "$DEVICE" "$@" reconstructs argv exactly.
  • appium.sh hierarchy ${2:-$(mktemp …)} resolves to the optional out.xml after the leading shift; grep -c exiting 1 on an empty file is discarded as a command-substitution argument.
Files Reviewed (15 files)
  • dev/seed/app/github-integration-copy.ts - 1 issue
  • apps/mobile/e2e/github-stub.sh - 1 issue
  • apps/mobile/e2e/appium.sh
  • apps/mobile/e2e/AGENTS.md
  • apps/mobile/e2e/flows/open-app.js
  • apps/mobile/e2e/flows/settle-app.js
  • apps/mobile/e2e/login.sh
  • apps/mobile/e2e/logout.sh
  • apps/mobile/e2e/record.sh
  • apps/mobile/e2e/remote-cli.sh
  • apps/mobile/app.config.ts
  • dev/local/mobile-android.ts
  • dev/local/mobile-simulator.ts
  • dev/local/mobile-workflow.test.ts
  • dev/local/tmux.ts

Note: the previous review covered only apps/mobile/app.config.ts; the branch has since merged origin/main and origin/mobile-e2e-ste, so the other 14 files were reviewed here for the first time. Runtime behaviour was not executed (read-only review).

Fix these issues in Kilo Cloud

Previous review (commit 6fe409c)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Simple, isolated version bump in apps/mobile/app.config.ts (1.0.3 -> 1.0.4) with no logic or security concerns.

Files Reviewed (1 files)
  • apps/mobile/app.config.ts

Reviewed by claude-opus-5 · Input: 32 · Output: 4.9K · Cached: 924K

Review guidance: REVIEW.md from base branch main

@iscekic
iscekic enabled auto-merge (squash) July 27, 2026 12:22
@iscekic
iscekic requested a review from jeanduplessis July 27, 2026 12:22
@iscekic
iscekic disabled auto-merge July 27, 2026 12:22
@iscekic iscekic added the human-ready The PR is ready for human review. label Aug 1, 2026
iscekic added 22 commits August 2, 2026 00:16
…olerant flows

- rewrite e2e/AGENTS.md in simplified technical English: task-structured,
  scripts own the mechanics, 410 -> ~215 lines
- new e2e/github-stub.sh: PR-review stub server + env line + token seed
  as one reversible command pair; failed starts clean up after themselves
- emulator-start --wait retries a failed launch once itself (boot-envelope
  timeout keeps the GPU, other failures switch to software rendering);
  the runbook's manual GPU decision table is gone
- appium.sh hierarchy writes to a file and prints the path; a raw XML dump
  into an agent session is large enough to kill it silently
- raise iOS cold-launch/settle budgets to 120s (timed out under parallel
  dual-bundle load); document ANR-under-load handling
- simulator claims record originalDeviceName and bootedByClaim intent in
  the initial write, so a lost post-boot rewrite can no longer leak a
  renamed or still-booted device on release
- emulator-start retry: rethrow the already-exists guard (a retry would
  tear down a live emulator) and keep attempt 1's error when the interim
  teardown itself fails
- github-stub: curl transport failures now route through seed_fail, so a
  failed start still rolls back the session and env line
- github-stub: guard against a .env.local without a trailing newline
  before appending, so the marker line can never merge into (and later
  delete) an existing variable
- tmux targets use exact-match (=name): bare -t prefix-matches, so a sibling
  worktree whose slug extends ours could be probed or killed in its place
- simulator claims write atomically (temp + rename/link): in-place truncation
  let an unlocked reader see a partial file, judge it corrupt, and delete a
  live claim
- a claim abandoned after its boot (rename failure) now powers the device
  off, or keeps the claim when even that fails
- simctl bootstatus is bounded (15 min) so a wedged CoreSimulator cannot
  block a claim forever
- emulator-start tears down after a failed second attempt too
- github-stub start claims its port machine-globally and verifies its own
  session survived, so two worktrees cannot share one stub silently; stop
  releases the claim
- appium: driver install re-checks inside the install lock; server startup
  verifies port ownership before adopting a listener; stop escalates to
  SIGKILL instead of orphaning a live server
- record.sh serializes start/stop per device with the shared process lock
- open-app consumes its launch budget in 30s slices so an ANR dialog is
  answered promptly instead of after the full wait
- login.sh matches the recipient literally, not as a regex
- hierarchy mktemp template puts Xs last (BSD mktemp leaves embedded Xs
  literal, making every bare call after the first fail)
- AGENTS.md: per-platform mixed fixtures, pull-and-grep for ADB dumps,
  stub-stop token residue note
- mobile-workflow tests updated for the raised launch/settle budgets
- appium: the recorded-server fast path now verifies the recorded pid owns
  the listener before adopting (a recycled pid plus a sibling's server on
  the same port answered /status and got adopted)
- github-stub: seeding extracted into seed_token; new 'seed <email>'
  subcommand adds a token row for a second signed-in account (the other
  platform's verifier) without touching the running stub
- github-stub: the port claim covers only the choose-to-bind window and an
  EXIT trap releases it, so an interrupted start cannot leak claims and
  erode the port range
- github-stub: githubUserId carries the pid — concurrent seeds in the same
  second cannot collide on the unique github_user_id
- AGENTS.md: the ADB dump example creates its own mktemp file instead of
  assuming $SCRATCH
devSeedUserGithubToken can answer 200 with success:false (row not
upserted); the status code alone reported a seed that never landed.
A process that survives even SIGKILL kept its state file removed and the
stop reported success; the caller then released device claims over a live
server. stop now fails and keeps the state in that case.
- claim_port reaps an orphaned port claim (older than 120s with nothing
  listening) and the start path traps INT/TERM/HUP besides EXIT, so a
  killed start can no longer shrink the port pool permanently
- githubUserId derives deterministically from the account email: the
  upsert's setWhere only updates a matching row, so the fresh random id
  made every re-seed of an already-seeded account report success:false
  and tear the stub down with a misleading hint
- lsof ownership probes tolerate no-match exits; pipefail otherwise killed
  appium.sh before the fresh-start fallback could run
…ling

- appium startup adopts a port only on proven ownership (listener pid equals
  ours); an empty lsof keeps polling instead of adopting a vanished or
  foreign server
- github-stub signal traps exit instead of continuing a start that just
  released its port claim
- success:false with 200 and no error means an account seeded under an older
  random id — keep that usable row instead of tearing the stub down
success:false can come from an older random-id seed or from a real GitHub
connection on the dev account; the keep-message now says so instead of
implying only legacy seeds, and notes the stub accepts any token.
…lback

- a kept token row is verified to be the stub's (getUserAuthorization
  githubLogin == kilo-stub-user); a real GitHub connection row fails with a
  drop-the-row hint — under the stub its refresh bypasses
  GITHUB_API_BASE_URL, hits real github.com, and revokes itself
- start rolls back everything (session, env line, state, port claim) via one
  EXIT trap when it dies before the final state write, so an aborted start
  no longer blocks the next one behind 'session already runs'
- appium ownership checks degrade to pid+status when lsof is missing or
  cannot attribute the socket, instead of killing healthy servers across 50
  port blocks
- the row probe checks HTTP status and error envelope before advising: a
  failed probe reports 'could not determine the existing row' instead of
  confidently telling the operator to delete a row it never examined; a
  kept row must also be connected (a revoked stub row gets the drop hint)
- start's rollback undoes only what this run did (session-created and
  env-added flags), so a start losing the session-creation race cannot kill
  the winner's session, env line, or state
- the recorded-server reuse path applies the same blind-lsof rule as the
  start loop: adopt on pid+status after three blind probes instead of
  orphaning a healthy server and consuming a port block per invocation
- drop dead SEED_FAIL_MODE and the stale random-id comment
- github-stub creates its session under a pid-unique name armed before the
  create and renames to claim the canonical one: a signal at any instant
  tears down only our own session, and a lost rename race touches nothing
  but our port claim; the env-added flag arms before the append for the
  same reason
- the appium reuse probe rechecks pid liveness and /status on every pass,
  so a server dying mid-probe is cleaned up (stop_server) instead of
  adopted; a foreign listener still only drops our state
…windows

Concurrent stub commands raced over the session name, env line, and state
dir; each guard narrowed the window without closing it. The shared
process-lock (the appium.sh pattern) removes the class: one stub command per
worktree at a time, so the entry check is authoritative, the rollback flags
only order against signals, and the unique-name rename dance goes away.
Both row branches run after the account answered the seed call, so the
sign-in hint contradicted what the script had just proved.
- every network call under the stub lock carries --max-time 30, so a hung
  local API cannot hold the lock to its 300s wait bound; status runs
  unlocked (read-only) and answers during a long start
- a failed session create (a survivor of a SIGKILLed lock wrapper got there
  first) resets the created flag before exiting, so cleanup cannot touch
  the survivor's session
- align the env-append comment with the lock (the rename step it cited is
  gone)
pnpm dev:seed app:github-integration-copy <email> finds the newest real
integration in the shared dev database (fakes excluded: kilo-stub* logins
and far-future expiries — a real refresh token expires within months),
decrypts it with git-token-service's local dev key, re-encrypts for the
target account under a synthetic github_user_id (the pair index is unique),
and upserts. Scenarios that need a real integration (cloud agents) run
against the copy; with no valid donor the command fails with an explicit
BLOCKED message, and the runbook tells verifiers to report VERIFICATION
BLOCKED rather than fake or silently skip. Verified against the dev db:
copy mechanics end to end, and the blocked path on a database holding only
seeded rows.
- donor filter excludes 13-digit synthetic github_user_ids (stub seeds and
  earlier copies): revocation lands only on the real row, so a surviving
  copy could hand out dead credentials as a fresh success
- app:github-integration-copy --remove <email> deletes the account's token
  row, so an account can return to stub use; runbook and usage text now
  require separate accounts for stub and integration scenarios
- verified live: remove clears the copied row and is idempotent
One instruction per sentence in the integration and stub sections; no rule
changed meaning.
- the donor's access token is checked against api.github.com before the
  copy: database metadata cannot prove a rotated or GitHub-revoked token
  dead, so silent dead-credential copies reported success
- the copy row carries a dummy, already-expired refresh token: GitHub
  refresh tokens rotate on use, so a refreshing copy would kill the donor's
  stored refresh token and poison every later copy
- usage and runbook text updated to the access-token-only contract
The copy relocates real credentials, so every destructive path is now
guarded and every shared-grant hazard is stated:

- assertLocalDatabaseTarget: USE_PRODUCTION_DB=true and non-loopback hosts
  are refused, making the dev-only claim enforceable (verified live)
- --remove deletes only a synthetic row (copy or stub seed) and names what
  it removed; a real connection is refused with instructions
- a copy refuses to overwrite a real connection on the target account
- donor lookup also matches google_user_email (normalized_email is nullable)
- usage and runbook state the real blast radius: the copy shares the donor's
  OAuth grant, so disconnect on a copied account revokes the DONOR's
  authorization and no re-copy repairs it — disconnect scenarios are blocked
  on copied accounts; commit attribution carries a synthetic id
- stub status reports 'starting' when a session has no state yet, instead of
  claiming up for a stub that is not usable
- lock-bounded curls raised to 120s (30s was the budget this PR already
  found too small under full parallel load)
- a failed tmux create distinguishes a concurrent session from a tmux error
A dead database dumped a driver AggregateError stack trace, and a dead
network read as 'no valid donor'. Both now fail with one line naming the
command that fixes them, so an agent does not spend a round guessing at
ECONNREFUSED output or chasing a false BLOCKED. Verified live with postgres
stopped.
- the synthetic-only rule is re-asserted in the upsert's setWhere, so a real
  OAuth callback landing between the pre-check and the write cannot be
  overwritten; zero updated rows reports that explicitly (postgres predicate
  verified against synthetic and real id shapes)
- donors need >10 minutes of access-token life (twice git-token-service's
  5-minute refresh buffer): a token inside the buffer passes the live probe,
  then triggers a refresh the copy cannot perform
- the target lookup tries the exact sign-in email before the normalized
  fallback, since normalized_email is not unique
iscekic added 6 commits August 2, 2026 05:06
…dget

- the 'can never refresh' claim was wrong: git-token-service gates refresh on
  the ACCESS token's expiry, so the dummy refresh token IS sent and the copy
  ends up revoked. Docs, usage text and the runbook now describe that end
  state, the tool reports usableUntil, and donors need 35 minutes of access
  life so a copy is usable for at least 30
- --remove reports what actually went away (.returning()), so a row replaced
  mid-command cannot read as removed
- stub lock --wait raised to 900s, above the ~8 minute worst-case hold the
  120s per-call budgets allow, so a queued stop or seed waits instead of
  failing
- drop the now-unused 'or' import
The 35-minute SQL margin is measured before up to ten 15-second GitHub
probes, so a copy could return with less than the promised 30 usable
minutes. The selected donor is now re-checked against the clock after its
probe, and one helper owns the usable-until arithmetic the filter, the
check, and the report all share.
A campaign verifier died with no sentinel right after a doctor --json dump
(the whole environment, PATH included). The runbook now states the general
rule — bound anything that can print a lot — and names --json diagnostics
alongside the Appium and hierarchy cases it already covered.
…1.0.4

# Conflicts:
#	apps/mobile/app.config.ts
Comment thread dev/seed/app/github-integration-copy.ts Outdated
Comment thread apps/mobile/e2e/github-stub.sh Outdated
Comment thread dev/local/mobile-workflow.test.ts Outdated
Comment thread dev/local/mobile-workflow.test.ts Outdated
iscekic added 2 commits August 2, 2026 15:27
The e2e harness changes belong to #4960.
The assertions pin apps/mobile/e2e content that #4960 owns.
@iscekic
iscekic force-pushed the chore/mobile-version-1.0.4 branch from 2b3f4e2 to f79b0bd Compare August 2, 2026 13:28
PR #4960 carries these changes and merges first. This branch keeps no copy.

- dev/local/mobile-android.ts
- dev/local/mobile-simulator.ts
- dev/local/tmux.ts
- dev/seed/app/github-integration-copy.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants