Files
stack/agents/sage/work/window-plan/repin-1024-draft1.md

15 KiB

10-24 window: re-pin 4429a104f to 7247d80c7 (rows 190, 199, 210, 234 and on, row 196 last), with 3i-3j (draft 1)

Sage, 2026-10-21, draft 1, for mos-1145 under DECISIONS Q173. Mos checks this file at its commit before P0. Any change to this file or to NEW after that check means Mos checks it again (mos-0849/0850). The step layout follows repin-4429a104f.md. Where a step is unchanged, I name it and say what differs. Draft 0 is repin-1024-draft0.md, and the working notes are in repin-1024-draft1-prep.md.

Who, and what nobody does

  • Q3 below names the operator: Darkwing if they're free, otherwise me. Mos verifies each step's output before the next one, and runs rehearse (P3).
  • Jason has no step. Q173 covers a re-pin of this test system with a migration, a backup first and a STATE report after. Nothing is pruned.
  • Nobody acts as Jason. No --by jason, no human shell or tmux pane, and every bus read and write carries --tester. bus.tester stays as it is. If it isn't true, stop at P1.
  • No pi (P19 #383). No Save in the human Console, no mosaic name.
  • Outside reach doesn't change. There's no --sso and no --send. Both go on together in the Q175 phase 2 window, which runs after this window is verified, when Jason starts it (mos-1195, mos-1197). The proof pair stays unset. The tunnel still forwards 7332 only (P4 and W10).
  • One Console flag does change. Row 196 retires the tester's TCP port. The live Console runs --tester-port 7333, and NEW refuses that flag. So W5 converts it explicitly with --tester-socket, and the tester listener becomes the 0600 socket $DATA/console/tester.sock. Only 127.0.0.1 could reach port 7333, so nobody outside gains or loses reach. Mos ruled this Q173 work in mos-1211 item 2. The socket is narrower than loopback TCP, and Mos's acceptance in mos-1015 (on sage-1359) already accepted losing browser access to 7333. DECISIONS has no Jason ruling on 7333 (mos-1214 item 2).
  • Under mos-1198, .53 and .54 take no copy carrying 196 until row 253 lands. This window is dragon-lin only.

Names

  • OLD, live: 4429a104f6d65ccf165f6c83b5d1dce3147dfde0, schema 3i, pointer pm: true, activation 20261020T220206Z-4429a104f6d6. The Console runs --port 7332 --public-host mosaic.woltje.com --auth-header X-authentik-username --allow-user jason.woltje --tester-port 7333, read from status at 19:38Z. P1 re-reads all of these on the day. I don't copy them from this file.
  • NEW: 7247d80c7af7ffa70fc61557406bf491cdf3bfc7, the row 196 landing, the latest code landing when this draft was cut (mos-1161). It is 135 commits past OLD (git rev-list --count 4429a104f..7247d80c7). The commit after it, c3d88840c, is doc-only and doesn't move NEW. If 244 or 251 land before P0, NEW stays here unless Mos rules otherwise (Q1).
  • 194 hasn't landed, so P3 has no lifecycle step (mos-1161).
  • REPO, P, WIN=agents/sage/work/window-repin-7247d80c7/ and SNAP are as in repin-4429a104f.md, with the sha checks at P0 and before S1, S2 and any D3.

What NEW carries over OLD

This is draft 0's table, rows 201 through 234 plus PRD 1.7 and 1.8, unchanged, together with these rows from git log --first-parent c771a36f4..7247d80c7, limited to packages, scripts, roles, contracts, adapters, skills, tools, migrations and the package files:

Row Commit Live effect to check
240 c515273db Installer I4: root host check, pins and the boot unit. This window doesn't run them.
228 86249ac55 ZAI_API_KEY joins the session env allowlist. The live config sets no ZAI key, so the env doesn't change. P3 checks this.
238 d49b1f2bd sso-config takes --instance. Default instance with --sso off, so no effect.
212 ee7b2f137 New package, packages/library. The live business has no library entry.
195 b65014647 scripts/case1-accept.sh, root only. Not run.
213 361ba2387 Creative roles, persona file and block, launch-settings, bundle.mjs. P3 checks that the chief's and the pm's bundles are unchanged apart from the new code path, and gets one pm reply.
231 29ce1e360 Library reader fixes. No live library.
235 b1fece6f0 Machine grant row b. The live business has no hosts. P3: bus start runs the grant reconcile and sweep, they change nothing, and the log lines are shown.
221, 247 300766450, 856c1826b Persona import script and follow-up. Not run. yaml 2.9 joins package-lock, and W0's npm ci covers it.
245, 248, 249 6d5545d44, 8a04f4aa4, 9de5a57ab case1-accept F9, test stubs, and hostLineLeft on a grant whose install never returned. No grants are live. The look-alike count below covers hostLineLeft.
197 a36523713 Test lane fixture. No live effect.
66 2c38325ec Managed sessions run the unslop check. COPY_PATHS adds tools/unslop-hook, and P3 checks the copy has it. W12 is the live check.
243 6096b051b Tests only.
215 e54e05463 Library entry kind, consumer skips, M9 and the bare mirror. M9 refuses an organization write that changes projects, so P3 checks that the chief's and the pm's usual organization writes don't touch it.
250 1b6158ce2 Conversation shim and K12 test. No live effect on its own.
222 0b33f5e9d library.sync verb, a 60 s timer per library entry, and the askpass helper in COPY_PATHS. No library entry, so the timer starts nothing. P3: the copy has packages/library/bin/askpass with its mode, and bus start logs no library: line.
PRD 1.9, 1.10 f48725cfc, add0f1aae packages/tasks/requirements.json is in the copy. W9: the pm's requirements read answers version 1.10 with 70 ids.
196 7247d80c7 The human boundary. See the next section.

Row 196 in this window

What the code does (scripts/stack-release.sh:791-845, docs/TOOLS.md "Console tester listener"):

  • An inherited --tester-port with no --tester-socket refuses tester-transport-migration before anything stops. So --tester-socket goes on W3 and W5, and the plan's drop line must read --tester-port 7333 (replaced by private Unix socket).
  • Before the stop, activate checks the socket path: $DATA/console/tester.sock must fit 107 bytes, and console/ must be absent or a directory with no symlink, owned by the instance's uid, with no group or other bits. A failure refuses tester-socket-path before the stop. P1 reads ls -ld $DATA/console (expected absent).
  • Activate preflights the pinned root-owned system Python, records its identity, and checks the bus's fresh start receipt. Each bus start appends one line to $DATA/bus/peercred-starts.jsonl. P3's rehearsal must show the preflight passing on dragon-lin, and W9 reads the one new receipt line.
  • rehearse starts NEW's Console with --tester-socket under its scratch data root when the copy carries the socket marker (stack-release.sh:2153-2155). It doesn't run activate's path check from line 815, so that check first runs live at W3. P1's ls -ld $DATA/console plus the path length are its only preview. If the rehearsal Console fails to start on the socket, P3 stops and the log goes to Mos.
  • Direct browser access to the tester is gone, with Mos's acceptance in mos-1015. W10's browser check on 127.0.0.1:7333 becomes node packages/cli/src/tester-http.mjs GET /api/config and GET /api/bus/agents, run from the NEW copy against the live data root. Each must answer 200 with the same tester flags OLD's 7333 gave. mosaic ... --tester still uses broker.sock.

Rollback is where 196 matters most. Without --sso, rollback takes the Console flags from the pointer, and after W5 the pointer carries --tester-socket. OLD's Console doesn't support the socket. So rollback to OLD drops the tester listener, the plan prints --tester-socket (tester disabled; no TCP fallback), and port 7333 doesn't come back. The test client then has no tester listener until a new activate. Q4 asks Mos how to handle that.

Schema and backups

  • SCHEMA_VERSION is 3i at OLD and 3j at NEW (packages/bus/src/store.mjs:17). The only step is packages/bus/src/migrations/3i-3j.sql (row 234, tables hosts and host_grants). Nothing after c771a36f4 changes schema.sql or adds a step. --plan must say migration: 3i -> 3j.
  • Restore guard, recounted at NEW (T46, packages/cli/tests/stack-release.test.mjs:913). COUNTED is the same 11 tables (stack-release.sh:404). The untimed list has six: host_grants, hosts, meta, message_threads, sqlite_sequence and task_comment_cursors. Each write to hosts or host_grants goes with a grant.* event, which is counted. A D3 snapshot still covers them, as draft 0 says.
  • W5 takes the stopped store backup every activate takes (SHA256SUMS, SCHEMA 3i, STAMP) plus the rollback set. Before --migrate writes, I check that SCHEMA reads 3i and record the backup's SHA256SUMS hash. W0b copies the business file, as last time.
  • Grant look-alikes (row 234 A22b, gizmoduck-0107): P3, and again just before W5, on the backup copy. Count the action.allowed events whose body.action or body.operation starts with grant., or whose body has hostLineLeft. Expect 0. Any nonzero count stops the window until I've read those rows.
  • Rollback after the migration isn't the plain rollback. OLD is 3i and the store is 3j, so going back needs --restore <W5 activation>, which loses the events written after W5. Mos decides any restore past W5.

Before the window (nothing stopped)

# Who Step
P0 Mos The $P sha check, and this file's commit.
P1 Sage status: pointer, activation, schema 3i, Console flags, unit flags match. The business file sha256 and business-check.mjs LOAD_OK for OLD now and NEW after W0. ls -ld $DATA/console (expected absent). bus.tester is true.
W0 Sage scripts/stack-copy.sh copy $NEW in a gap between gate runs. The package-lock diff is empty. The copy has tools/unslop-hook and packages/library/bin/askpass, with the mode NEW's tree gives it.
P2 Sage console-check.sh $NEW on a stub Console on a scratch port, once without and once with --tester-socket under a scratch data root. CONSOLE_PASS both. Render the Console unit for NEW from REPO's webui-service.sh and diff it against the live unit. The only difference allowed is --tester-port 7333 becoming --tester-socket. Diff the bus unit too. It must match apart from the copy path.
P3 Mos stack-release.sh rehearse $NEW mosaic-stack --backup <latest live activation> --port <scratch> with --migrate on the backup copy. It must show the 3j step, row counts before and after, the interpreter preflight passing, a receipt line, the grant reconcile and sweep changing nothing, no library: line, no publish or land decision open (rows 241, 242), the look-alike count 0, and one pm reply. As in mos-1107, Mos also starts NEW's Console by hand with the pointer's flags, with --tester-socket in place of --tester-port, and reads healthz, /api/config and the two tester-http reads.
P4 Sage The tunnel read.
P5 Sage The four service scripts are held at NEW (git diff --quiet $NEW HEAD -- on them, and empty porcelain). If 244 or 251 lands and touches one of them, P5 fails and the window waits for Mos.
P6 Sage The 7332 matrix (a)-(g) on OLD, saved as $WIN/matrix-old.txt, plus the two tester reads on 7333 with curl, for W10 to compare against.

The window

# Who Step
W0b Sage The business file copy.
W1 Sage Idle check, the start stamp from date -u, then S1 with $SNAP --held. Open pm tasks from row 42: pm finishes or parks them before W5, or I record which piece crosses the window.
W2 Sage status: pointer on OLD, pm: true, 3i, unit flags match.
W3 Sage stack-release.sh activate $NEW mosaic-stack --pm --migrate --tester-socket --plan. It must show OLD to NEW, migration: 3i -> 3j, the backup line, the drop line for --tester-port 7333, and a Console line with OLD's other flags exactly: no --send, no --sso, no proof pair. Any other difference stops here.
W4 Sage The unit reads, as in the 177-185 plan.
W5 Sage, on Mos's go The same command without --plan. Exit 0, result ok, and every gate check passes, pm_launched included. Record the activation id, the backup path, STAMP and the backup SHA256SUMS sha256. Then status.
W9 Sage, after Mos verifies W5 The 177-185 W9 list, plus: the webui journal since the W5 stamp (with UTC) has no Sign-in: line; /proc/<Console pid>/cwd names the NEW copy; $DATA/console/tester.sock is 0600 in a 0700 console/; peercred-starts.jsonl gained one line for this start; the bus journal has the grant reconcile and sweep lines and no library: line; the pm's requirements read gives 1.10 with 70 ids.
W10 Sage The matrix again, as $WIN/matrix-new.txt, identical to matrix-old.txt apart from the lines the pin changes, each one named. The two tester reads through tester-http.mjs match P6's. Port 7333 has no listener (ss -ltn). Then P4 again. A write without a signed-in session must still be refused. That's Console POST through the main port, with no session. This is the check mos-1195 asks for before phase 2 is done, so I run it here too, as a baseline.
W11 Sage STATE report in $WIN/STATE.md, posted on P19 386, 412 and 435 (J2, mos-1215), and on the Gitea issues for 190, 199, 210, 234 and 196.
W12 Sage, after W11 Row 66's live check (Vikunja #454). One Claude Code managed session with a prompt that draws a known tell, then the operator note on the RESULT, the next-turn notice and the unslop.jsonl counts. Backup first (Q173). Pi isn't run (#383).

Stop conditions and rollback

The same as the 177-185 plan. Two failures in one window: stop and report (mos-0823).

Rollback before W5 writes is rollback --plan, then the real run. After the migration it needs --restore <W5 activation>, with Mos deciding. Both drop the tester listener (see Row 196 above). Keep every copy. Prune nothing.

Questions for the plan check, answered (mos-1214 item 3)

  • Q1: NEW stays 7247d80c7 unless a landing fixes something this window needs.
  • Q2: mos-1211 item 2 rules the --tester-port 7333 to --tester-socket change Q173 work.
  • Q3: Darkwing operates if free, and I check. Otherwise I operate.
  • Q4: after a rollback, the tester listener stays off for the window's length, and the tester goes through broker.sock. A same-copy re-activation of OLD with --tester-port 7333 goes to Mos only if a rollback holds past the window day.

What Sage ran for this plan

Read only, 2026-10-21 between 20:40Z and 21:20Z: the path-limited first-parent log c771a36f4..7247d80c7, git rev-list --count, SCHEMA_VERSION at both ends, git diff --name-only on the schema and migrations, stack-release.sh lines 40-47, 125-158, 404, 791-845, 886-919 and 2140-2157, T46 in stack-release.test.mjs:913, packages/cli/src/tester-http.mjs, and TOOLS.md:1274-1310 on the tester listener. Nothing ran against live. OLD's values come from the 19:38Z status read, and P1 reads them again.