Repository navigation
feat(fork): upstream sync job, fork-delta check, and agent guards #6
Description
Activity
Triage 2026-10-03T23:46Z: intended (fork maintenance, not a defect). Grounded in
docs/fork/maintenance.md.Already landed:
upstreampush URL isno_push,rerereis on globally, and the posture hook readsfork/prod(scripts/fork/agent-config/t3code-fork-posture.sh).Remaining: PreToolUse deny hooks, the pre-push
main/force-push check in.vite-hooks,docs/fork/patches.tsv+delta-check, thet3.upstream-synclaunchd job, and fork build versioning. No classification change needed.Status and finalized plan, 2026-10-05. Everything below was checked against the machine and the code by effect, not by reading the issue.
Status of the five items
# Item State 1 Guard hooks Not built. ~/.claude/settings.jsonhas only theSessionStartentry and no deny list..vite-hooks/tracks onlypre-commit(vp staged); thepre-pushshim in.vite-hooks/_exists, so a tracked.vite-hooks/pre-pushwill run.2 patches.tsv+delta-checkNot built. Nothing under scripts/fork/ordocs/fork/.3 Sync job Not built. No local.t3code.*sync*launchd job (main-syncis scaffold's). Drift is the exhibit:mainis 185 commits behindupstream/main, and a trial merge conflicts in 69 files (#36).4 Fork build versioning In flight, uncommitted in the primary checkout ( fork-versions.tsand test,docs/fork/versioning.md, edits tofork-deploy.ts,build-desktop-artifact.ts,app.config.ts, both vite configs,ServerEnvironment.ts). Design changed from this issue: a fork semver line from 1.0.0 with a decision ledger, not a-nohat.<sha>suffix. Known defect: upstream's newapps/mobile/fingerprint.config.jsmatches/^ {2}version: "(\d+)\./mand throws on theprocess.env...form inapp.config.ts.5 Move POSTURE_REFDone. The installed hook equals scripts/fork/agent-config/t3code-fork-posture.shand readsfork/prod. The "not tested from a T3-started session" gap is closed: this session was started by T3 and received the hook output. Codex has a session-start hook (hooksfeature is stable in codex-cli 0.160.0;session_startandpre_tool_useevents exist); not wired, no exhibit yet.Also verified done:
upstreampush URL isno_push;rerere.enabledandrerere.autoupdateare on.What changed the plan
Upstream's V2 orchestrator rewrite (#36) makes the first sync a one-off port, not a job run. It also shows the premise of the delta check: git auto-merges many fork files that now sit on deleted code, so "no conflict" would have meant nothing. Two consequences for design:
delta-checkmust follow renames (git diff -M --numstat) and compare against the new base (upstream/mainvs the merge result), notmainbefore the sync.- Guard tests in
patches.tsvare the primary signal;delta-checkis only the net for features without one.
Sync job design (final)
scripts/fork/upstream-sync.ts, run bylocal.t3code.upstream-sync(daily; launchd runs it on wake if the Mac slept). One run:- Lock.
git fetch upstream --prune. Fast-forwardmainwithgit fetch upstream main:main(refuses non-ff), push toorigin. Stop quietly if there are no new commits. - Trial-merge
upstream/maininto the currentfork/prodtip in a scratch worktree under the deploy root,rerereon. - Conflict: abort, record counts and file paths mapped to
patches.tsventries, and create or update one issue labeledupstream-sync(ids, paths, counts only; the repo is public). Notify once per upstream sha. - Clean: run each
patches.tsvguard, thendelta-check, then targeted typecheck for touched packages. If all pass, pushsync/upstream-<date>at the merge commit and send a one-line digest. If a guard fails or a fork file lost lines, file the issue instead. - It never changes
fork/prod. Landing isfast-forward fork/prod to the sync branch, done by the orchestrating session and thenfork-deploy(merged is not deployed). Auto-landing after N green days is a later option, not part of the build. - Silence means no news or a clean candidate with nothing to say; a buzz only for conflict, loss, or a failing guard.
Decisions recorded as assumptions (change by saying so): daily cadence;
sync/upstream-<date>branches pushed to the fork; no auto-land; the visual-diff step inREADME.mdwaits until the design-system gate exists.Priority of what remains
- Guard hooks (item 1). Hours of work, independent of everything, and it has real exhibits: the fork deleted by
gh repo fork --fork-name(2026-05-24) and the emptiedmainbranches (2026-08-28). ClaudePreToolUsedeny rules forgh repo delete,gh repo fork --fork-name,git push --force|-f, and-X ours|theirs; tracked.vite-hooks/pre-pushrefusingmainand non-ff pushes tofork/prod;pre-commitrefusing commits onmain. A Codexpre_tool_usemirror only when Codex runs fork work. - Commit the versioning work (item 4), after fixing the fingerprint regex. It is already written; leaving it dirty blocks any merge in the primary checkout and it conflicts with upstream on
app.config.tsandServerEnvironment.ts, so it should land before feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36. Also setT3CODE_MOBILE_UPDATES_ENABLED=0for fork mobile builds (cheap insurance against upstream's OTA channel; not verified). patches.tsv+delta-check(item 2). Needed to accept feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36 (the merge's acceptance test) and for the job. Seed from the accepted branches, using the guard test each already has; the V2 port rewrites the failing ones.- feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36, the V2 catch-up. Manual, dispatched, gated by items 2 and 3 above. Includes making
fork-deployV2-aware before the first V2 deploy (its running-turn count reads the frozenstate.sqlite). upstream-syncscript, then the launchd job (item 3). Build the script's trial-merge mode first; it doubles as the pre-flight for feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36. Turn on the daily job only after feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36 lands, otherwise it reports the same 69 conflicts every morning.- Codex session-start hook (item 5 remainder). No exhibit. Do not build.
Items 1 to 3 are independent and can run in parallel. 4 waits on 2 and 3; 5 waits on 4.
Ratified 2026-10-05 by the owner ("let's ratify it"), with one addition. The full design is now
docs/fork/upstream-sync.md(branchdocs/upstream-sync-v2, commit c8b2d29, to be merged tofork/prodwith the V2 report).Addition: weekly cadence review. Once a week, or whenever asked (
node scripts/fork/upstream-sync.ts cadence), the script gathers deterministic facts (upstream commits and files per day over 14 and 28 days, the sync run ledger, how long a clean merge survived before first conflicting) and runs one agent turn that writes the analysis and returns a newintervalHourswith a reason. The agent adjusts the frequency on its own; the script enforces the bounds (6 to 168 hours, at most 2x per review) and records the analysis inupstream-sync-decisions.mdin the deploy root. launchd wakes hourly and the script exits unless due, so the cadence is one number inupstream-sync.json, not a plist reload. An unchanged cadence is a ledger entry; a change is a one-line notification.Build order is unchanged (guards, versioning commit,
patches.tsv+delta-check, #36, then the script and job). The cadence review ships with the job.Resumed implementation here at the owner's request (2026-10-05).
On
fork/prod(b0ad7ce):- Agent and Git guards committed and installed. Claude PreToolUse rejects the destructive commands named in this issue. Git refuses main commits/pushes and non-fast-forward updates/deletion of fork/prod. A stable common-Git-directory dispatcher covers upstream branches lacking fork scripts; Vite's formatter still runs. The only main-push exception is an exact, fast-forward upstream/main mirror by the sync job.
- Finished the in-flight release versioning, preserving the mobile version literal required by upstream's fingerprint reader and disabling upstream OTA on fork mobile builds. Fixed partial-release marker placement and refused falsely stamping legacy cached artifacts.
- Patch registry and delta-check gates merged from feat/sync-gates.
On
sync/upstream-20261005(09f1496):- Integrated the above into the existing V2 candidate, preserving its completed ports.
- Built upstream-sync.ts: scratch trials, guards, rename-aware delta check with explicit allowances, touched-package typechecks, reusable candidate branches, metadata-only issue updates, and once-per-upstream notification state.
- Weekly cadence review gathers deterministic 14/28-day volume, run/landing history, and clean-merge survival; the script enforces 6–168 hours and at most a 2x change. The hourly launchd plist is prepared and passes plutil. Machine config remains enabled=false; no job was loaded.
- Fixed V2 port dependency wiring exposed by server typecheck (optional MCP model hints supplied at production composition, drain fixture supplied with its service).
Evidence: 19 existing V2 feature guards passed; 8 installed-hook regression tests passed; 37 selected release/sync checks passed (62 unrelated cases skipped); 12 affected MCP tests passed. Typechecks passed for server, web, mobile, client-runtime, contracts, and scripts. Final delta check: 33 explicitly allowed losses, zero unapproved losses. Fresh review found no remaining material blocker in the changed guards, versioning, sync runner, or MCP wiring.
Real local trial from current fork/prod against upstream 194c73f found 31 unresolved conflicts mapped to 16 features (rerere reduced the original 69); its scratch merge was aborted and removed. The trial made no pushes or issue writes. No production data was opened or changed.
Remaining: V2 client/build/cutover/deploy gates in #36, then enable/bootstrap the prepared sync job. Codex has the Git guards; its provider-specific pre_tool_use mirror is still pending. Existing unrelated dirty iOS/papercut edits were preserved. Issue stays open; nothing here claims V2 is deployed.
Merged and built at David's request.
- Fast-forwarded
fork/prodto09f14960c1and pushed it. Existing local iOS/doc edits were preserved and restored. - Built fork version 1.0.0, macOS ARM64, including matching V2 server and web bundles. The contracts build gate passed after installing the new lockfile dependencies in the dedicated build worktree.
- Verified packaged macOS metadata and package version are 1.0.0, and the bundled server chunks contain the V2 database implementation and fork version. Completed release staged under
releases/09f14960c1; ZIP retained locally. - DMG creation failed in host
hdiutilwithNo child processes/invalid plist output. ZIP packaging of the same already-built bundles succeeded. Build ran under the existing governor's 40% CPU cap, with ordinary scheduling priority to avoid background starvation.
No production deployment or live data migration was performed.
currentremains on7345a87552; the upstream-sync schedule remains disabled. Integrated client/cutover verification and a matching native mobile build are still pending. This update does not close the tracking issues.- Fast-forwarded
Problem
The fork has no automatic upstream sync and no check that a clean merge kept the fork's behavior. Syncs are by hand, and a merge that applies cleanly can silently drop a fork feature. The decisions are in
docs/fork/maintenance.md(branchdocs/fork-defect-resolution).Proposed work, smallest first
PreToolUsehook denyinggh repo delete,gh repo fork --fork-name,git push --force, and-X ours/-X theirsmerges. A pre-push check (in.vite-hooks, sincecore.hooksPathpoints there) refusingmainand force-pushes tofork/prod; refuse commits onmain.docs/fork/patches.tsv(name, branch, guard command) andscripts/fork/delta-check, which comparesgit diff --numstat main fork/prodbefore and after a trial merge and flags fork files that lost lines.t3.upstream-synclaunchd job: fetch upstream, fast-forwardmainonly, trial-merge intofork/prodin a scratch worktree, run the guard tests and delta check, and file an issue (ids only; the repo is public) on conflict or loss. It never lands anything.fork/<date>-<sha>.POSTURE_REFin~/.claude/hooks/t3code-fork-posture.shtofork/prodoncedocs/fork/lands there; check whether Codex has a start-of-session hook equivalent.Done already
rerereis enabled globally,upstreamhasno_push, and aSessionStarthook injects the posture. Tested withclaude -p. Not tested: a session started by T3 itself.Related: #5.