Skip to content

CI: run Linux jobs on Jog runners - #20381

Closed
rawphp wants to merge 311 commits into
pingdotgg:mainfrom
original-solutions:ci/jog-runners
Closed

rawphp wants to merge 311 commits into
pingdotgg:mainfrom
original-solutions:ci/jog-runners

Conversation

@rawphp

@rawphp rawphp commented Oct 16, 2026

Copy link
Copy Markdown

Switches GitHub-hosted Linux jobs (ubuntu-latest / ubuntu-24.04) to runs-on: jog, matching livepane/replymate/do-work.io/original-solutions-site.

Changed jobs:

  • factory-ci.yml: check, lint
  • factory-sync.yml: prepare, publish
  • pr-size.yml: prepare-config, sync-label-definitions, label
  • pr-vouch.yml: collect-targets, label
  • desktop-macos-preview-publish.yml: resolve, cleanup
  • issue-labels.yml: sync
  • thread-transfer-report.yml: publish
  • cursor-hygiene-webhook.yml: forward
  • release.yml: publish_cli

Blacksmith runners (incl. blacksmith-*-ubuntu-2404), macOS and Windows jobs are unchanged.

tomkaczocha and others added 30 commits October 15, 2026 21:17
One check script, run by a factory-ci workflow and by the factory gate
…ker exports

A whitespace run followed by other text made the `[...]+$` trim backtrack
quadratically on untrusted session output (200k spaces ran past a minute).
Trim with index loops over the same Rust White_Space set instead.

DONE_MARKER, NEEDS_INFO_LINE and STUCK_LINE had no importer, which fails
knip:check; they are module-private until a caller needs them.
…rrupt and drain tests

- spawn's synchronous throws (a NUL byte in env or args) now fail with
  RunSpawnError instead of dying
- RunSpawnError keeps the command only in cause; its attributes are shell and cwd
- the env allowlist and defaults are no longer exported (knip)
- RunResult.exitCode doc: a timed-out command can still exit 0, check timedOut first
- the post-run kill comment says a process that left the group escapes
- tests: an interrupted run kills the group, a stray outside the group does not
  hold run past the drain wait, a tail cut inside a UTF-8 character
- design.md Shape diagram: gate commands go through node:child_process in
  factory/process.ts, not ProcessRunner
…ough a pull request

Red: factory/scripts/sync.sh does not exist yet, so every case fails on
reading it. Covers the tag choice by version order, the up-to-date exit,
a clean merge that records UPSTREAM and merges the pull request, a route
tree conflict that regenerates, another conflict that aborts and files or
comments on an issue, and failing checks that open a draft and an issue.

Issue: #4
…h a pull request

sync.sh picks the newest v*-nightly.* tag by version order, stops with
"up to date" when factory/UPSTREAM names it, and otherwise merges it on
sync/<tag> with --no-ff, regenerating the route tree with
regenerate-routes.sh when only that file conflicts. Any other conflict
aborts and files or comments on `Sync to <tag> conflicts`. Green checks
push, open `sync: <tag>` and merge it; red checks open it as a draft and
file `Sync to <tag> fails checks` with the failing step's last 200 lines.
factory-sync.yml runs it daily at 03:17 UTC and on dispatch.

The test's gh stub answers `issue list` by title so the comment-or-create
decision is covered; the conflicts body may mention the route tree in its
hint, so the test checks the list line only.

Issue: #4
status is polled per session, so it now reads the runs and assistant
messages through getThreadRecords instead of loading the whole thread
projection. Adds tests for blank project and provider instance ids,
thread read errors and project store failures failing as sessions errors.
…n a failed merge or push

Red: a merge that fails without a conflict falls through as a route tree
conflict, a refused push dies without saying why, a tag with a quote is
accepted, vp i and check.sh see GH_TOKEN, and failing checks exit 0.

Issue: #4
…token from upstream code

A merge that failed without unmerged paths was taken for a route tree
conflict and went on to commit the UPSTREAM bump alone; it now prints
git's output and exits 1. A refused push says which branch and tag. The
tag must match the nightly pattern before it reaches gh, git or jq.
vp i, the generator and check.sh run without GH_TOKEN; the workflow
stops persisting the checkout token and routes git push through gh's
credential helper instead. Failing checks exit 1 after filing the issue,
so the scheduled run is red on both failure paths.

Issue: #4
…dirty builds

- build.sh smoke-tests the archive in its stage dir and moves it to release/ only
  after the smoke passes, so a failed smoke leaves no archive install.sh would take.
  T3FAC_SMOKE_TIMEOUT sets the deadline (60 s).
- Uncommitted changes to tracked files add `.dirty` to the version, so a rebuild of
  the same commit never replaces the clean build on install.
- install.sh and rollback.sh source factory/scripts/lib/t3fac.sh for the install
  root, the LaunchAgent label and plist, and restart_job. T3FAC_UNLOAD_WAIT sets the
  unload wait (10 s).
- Tests: the whole of build.sh with stubbed vp and cargo (pass, early exit, no 200,
  no "factory started"), a dangling `previous`, and a job that never unloads.
Adapter: find a project, launch a thread and read its status in-process
… every directory

Review round 1 of PR 35.

- An append first reads the lines written since its last one, by any handle, so a
  `finished` or `gate_command` line another handle wrote counts (f14), and Ledger.open
  reads through the fd it appends to, closing the gap between the read and the open.
- A write starts with a newline whenever the file does not end in one, so another
  handle's cut-off line cannot swallow this handle's event (f4).
- Ledger.create and MachineLog.open sync the file's directory, the data dir and its
  parent every time, so a retry after a failed sync still makes them durable (f13, f7).
- A cause attempt that is not a u32 is left out, so the cause still reads back (f3).
- The RunEvent doc names the fields that hold text sent elsewhere (f2).
- Tests: open counts a whole last line left without its newline (f5); gate attempts
  outside u32 do not count (f6).
- An issue number above 2^53 is written digit for digit (f1).
- Shared limits in one module, a reason on every diagnostics directive, no barrel,
  no re-export shims, enum arrays as union types (f10, f11, f12).
…ed changes

Two builds of one commit with different uncommitted edits used to share the
`.dirty` version, so installing the second deleted the first. The suffix is now
`.dirty.<8 hex>` from `git diff HEAD --binary`, so only identical contents share a
name.
FactoryPaths keeps the adapter's shape from main (the service and its layer in
factory/t3/paths.ts) and gains machineConfigPath, which the config loader reads.
factory/paths.ts goes.
…fy/delete conflicts abort

Red: the gh stub now prints every open issue as number and title rows,
so the comment-or-create decision is the script's own match; a fuzzy
search hit listed first must not win. The modify/delete case passes
already and pins --diff-filter=U.

Issue: #4
… in jq

The tag no longer reaches a jq program, and the exact-title match is the
script's own, so a fuzzy search hit cannot receive the comment. The
token comments say what env -u does and does not do.

Issue: #4
Config: the factory's machine config and a repo's factory block
…finished

Review round 2 of PR 35.

- A finished line cut off just before its newline was not seen by a live handle's
  catch-up, which only reads whole lines; the next append's leading newline then
  completed it and landed after it. An append now ends a cut-off last line first,
  as a reopen does, then catches up, so that line counts and the append is refused
  (f15).
- openForAppend returns the file alone, and its doc names O_RDWR and why read
  access is needed (f16).
Cases for the stream of thread ids whose latest run changed status, and the
real-orchestration harness extracted from sessions.contract.test.ts into
contract.testkit.ts so both contract tests share it.

Fails now: events.ts does not exist yet, so events.test.ts, events.contract.test.ts
and sessions.contract.test.ts (through the testkit) fail to import it.

Issue: #7
Callers depend on the FactoryProcess tag, so their tests can swap in a
fake layer instead of starting real processes. The two process-group
tests now use withTempDir and waitForDeath, so a failed assertion no
longer leaks the temp dir, and their wall-clock bound is 5 s instead of
1 s; the grandchild death check still proves the kill.
…r goes through the io seam

Review round 3 of PR 35.

- LedgerError is a Data.TaggedError tagged `LedgerError`, so an Effect caller can
  catch it with Effect.catchTags and branch on `kind`. The messages stay softfac's;
  an Io error keeps the file system's error as its `cause` (f9).
- The newline that ends a cut-off last line is written and synced through AppendIo,
  so a test can make it fail: the append then throws Io and writes no event, and the
  next append repairs the line (f17).
Unit tests for send, archive and removeWorktree, and a contract test that
sends a second message, archives and removes the worktree against T3's real
orchestration layers.

Fails now: FactorySessions has no send, archive or removeWorktree, and
Sessions.layer does not yet take ThreadManagementService, GitVcsDriver or
FileSystem. 21 tests red.

Issue: #6
Run commands with a cleared environment, a time limit and a bounded output tail
…ter open repairs it

Review round 4 of PR 35: covers the repair at open with a write that throws and one
that writes nothing (f18).
FactoryEvents.runStatusChanges emits a thread's id each time its latest run
changes status, built on EventSinkV2.stream from the live position, with no
history replayed. The latest-run selection is shared with `status` through an
exported latestRun in sessions.ts. The contract test now drives one thread (the
replay transcript serves a single turn) and checks the live path and no replay.

Issue: #7
send dispatches message.dispatch with automatic delivery through
ThreadManagementService. archive reads the thread, dispatches thread.archive
under a fresh command id per attempt, and counts an archived or unknown thread
as done. removeWorktree runs git worktree remove --force from the worktree,
finishes a 'Directory not empty' leftover after a wait, and keeps the branch.

Tests: fixes to the test harness only (typed ids, a tagged dispatch error, the
removal test's temp directory, the findProject layer's new dependencies).

Issue: #6
transition threw a plain Error, so an Effect caller saw a stale or duplicate
webhook's event as an untyped defect. It now returns a Result whose failure is
a tagged InvalidTransition, as softfac's transition returns Result.
Follow-up to f9 of PR 35, as asked: the single tagged LedgerError becomes six
Schema.TaggedError classes (InvalidRunIdError, LedgerAlreadyExistsError,
LedgerAlreadyFinishedError, LedgerNotFoundError, LedgerUnknownEventError,
LedgerIoError), so an Effect caller picks them apart with Effect.catchTags instead
of branching on a `kind`. Messages are built from each class's attributes and stay
softfac's; LedgerIoError keeps softfac's `<path>: <file system error>` text, pinned
by a test, with the error itself as its `cause`. The ioError and invalid mappers
are gone.
… with a second launch

F1: assert thread A's run ends completed (terminal event and sessions.status), not any terminal status.
F2: replace the 1 s negative timeout with a consumer started before launch B that must emit B's id, not A's.

Issue: #7
tomkaczocha and others added 23 commits October 16, 2026 22:14
End of a run: merge, close, abandon and stop by hand
… provider

Red: the testkit's layerRuntime only takes a transcript URL, so building the
e2e transcripts in memory fails to decode (Path.fromFileUrl, Invalid URL), and
factoryRuntime has no gateRemoteBase option yet to point the gate at the
file:// remote. Both cases fail before the first pass.

Issue: #21
… and a file:// gate remote

layerRuntime takes a transcript as ndjson text as well as a fixture URL, and
factoryRuntime takes a test-only gateRemoteBase for the gate's fetch. The e2e
test now passes: ready, triage, building, pr-open, with the ledger in
softfac's order and the thread archived; and a gate that fails once is sent
back into the same session and passes the second time.

Issue: #21
…own clone

Red: factory/config.example.yml does not exist yet, so loadMachineConfig
reports no config and the test fails.

Issue: #21
Watches original-solutions/t3code-factory from the clone
~/EA/projects/t3code-factory-fac, with the fork's own gh login directory.

Issue: #21
The plist sets GH_CONFIG_DIR to ~/.config/t3fac/gh, so the server, the gate and
its agent sessions act as the factory's own login, and appends the directory
the vp that the gate runs lives in to PATH.

Issue: #21
Moves the hand-back and move-back steps from the README into
factory/docs/handover.md, with the build, install, config, clone and project,
Rust factory removal, restart and first-run check that lead up to them.

Issue: #21
Only factory/t3/ may import T3 packages; the test took ThreadId from
@t3tools/contracts only to brand a string it never used as one.

Issue: #21
The hand-back and move-back runbook now has the factory that lets go of the repo restart before the other one takes it, so both never watch it at once. Also drops an unused type in the e2e test, a repeated heading in the runbook, and notes that gh_config_dir must match the plist's GH_CONFIG_DIR.
Handover: the fork's factory is ready to build this repo
…tory-config

fix(factory): build.sh smoke test passes on a clean build
The tests need forward, activitySince, the new Seen fields, the two
message builders and the forward actions of applyActions, none of which
exist yet: they do not compile and fail until the next commit.

Issue: #22
forward sends the instructors' new comments and their edit of the issue
body into a building run's session, once each, under softfac's message
wording, command ids and forward-wait steps. The pass runs it between
watch and advance and holds the gate in a pass where it sent something.
activitySince reads the activity from GitHub.

Issue: #22
…d.sh

PR #72 changed build.sh to look for "no factory config" in the smoke
server's log but left the test's fake server logging "factory started"
and expecting the old failure message, so the factory suite was red on
main. The gate for this branch runs that suite.

Issue: #22
Fails: a running, reminded or paused run with a pending gate send does not
start the gate, a pending send does not win over the gate waiting for a sent
comment, and a ledger read error for the pending check is not recorded.

Issue: #22
Port softfac's dropped-comment notice into `forward`: after the sends, each
comment `activitySince` drops gets one comment on the issue in softfac's fixed
words and a `comment-dropped <id>` step, and a comment told about as dropped
is never forwarded later (f10).

Look up the editors of edited comments in one GraphQL call per 100 ids
instead of one per comment (f5). Rename `GatePayload` to `ActionPayload`,
since forwards carry their message on it too (f7). Pin the live
`hasPendingGateSend` wiring (f3) and a failed pending-send read for a
finished session (f4) with tests.

Fixes f3, f4, f5, f7, f10.
Forward instructor comments and edits into a running session
@rawphp

rawphp commented Oct 16, 2026

Copy link
Copy Markdown
Author

Opened against the wrong repo by mistake, sorry.

@rawphp rawphp closed this Oct 16, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $26.42, which exceeds your per-review limit of $15.00.

The top 3 files driving up this estimate:

File Diff Size Estimate
apps/server/src/factory/tracker/github.ts 68.43KB $2.74
apps/server/src/factory/pass.ts 52.55KB $2.10
apps/server/src/factory/runner/building.ts 49.08KB $1.96

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Oct 16, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This change adds a substantial production factory capability, authenticated server integration, automated publishing/synchronization workflows, and installation infrastructure alongside the runner edits. It also introduces product defaults and static-analysis diagnostic suppressions, so the breadth and operational impact require human review.

Needs human approval because:

  • Per-review cost limit exceeded (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings, or comment @macroscope-app review this PR to bypass the limit and review now. You can add or adjust custom eligibility rules. Learn more.

@zainmitchell

Copy link
Copy Markdown

Factory catalog cross-reference — 2026-10-26. Prior-work history: this PR is cataloged for its work on Linux CI runner configuration in the public original-solutions factory, acknowledged in our catalog. No code from that effort was copied into this derivative. This historical cross-reference requests no reopening and implies neither quality rejection nor an installation dependency.

Factory Ideas · Pinned fork source/guide · Source release. Version-pinned community experimental source preview; full lifecycle acceptance remains open. No upstream endorsement or current-PR-head test acceptance is claimed.

Prepared with GPT-6.1 Sol through Codex in T3 Code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants