Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a94d260
Verify legacy check reads, native correction and pre-execution CLI re…
trissim Oct 20, 2026
ff3f87b
Carry legacy home commander configuration through its root-record writer
trissim Oct 20, 2026
5b1dd0c
Verify commander-config relocation on a copied registered root
trissim Oct 20, 2026
d9c3f03
Preserve existing root commander facts when an old home file remains
trissim Oct 20, 2026
81c9c55
Make commander cutover precede presentation phases
trissim Oct 19, 2026
a272bf3
Make commander views wait on their source phases
trissim Oct 19, 2026
c0da9ab
Complete plan phases only through declared acceptance
trissim Oct 19, 2026
5ec3e1a
Declare every parity row and fail closed on incomplete comparisons
trissim Oct 19, 2026
0963f55
Record retired parity scratch and integrated-source checks
trissim Oct 19, 2026
392799e
Move the parity declarations out of #1928
trissim Oct 19, 2026
778cc50
Keep #1928 to plan phases and order claims
trissim Oct 19, 2026
60f6337
Keep the plan-claims report out of the tree
trissim Oct 19, 2026
984dd38
Format work_dispatch.py
trissim Oct 19, 2026
9268780
Break phase task import cycle at its shared capability owner
trissim Oct 19, 2026
ab31546
Preserve phase identity when an installed merge retains its checked o…
trissim Oct 19, 2026
21f5780
Integrate checked phase dispatch with current commander and merge owners
trissim Oct 20, 2026
e36e971
Run both ratchets and practice installs for GitHub merge groups
trissim Oct 19, 2026
9305d62
Isolate Actions jobs and authorize host checks by GitHub run identity
trissim Oct 19, 2026
3bcb88e
P714 post exact head review status from the accepted verdict owner
trissim Oct 19, 2026
130d8df
Keep head reviews in the connector-only declared tool and command family
trissim Oct 19, 2026
f382d3e
Type the two tool catalogs without erasing their callers
trissim Oct 19, 2026
2d743f3
Keep the connector catalog declaration within the existing formatting…
trissim Oct 19, 2026
0897973
P269: derive review identity and expose queue gate failures
trissim Oct 19, 2026
3c8163c
P269: verify failure propagation and reject unrelated status dispatches
trissim Oct 19, 2026
f7547d0
P269: command-owned deadlines and typed public check failures
trissim Oct 19, 2026
b10dcb5
P269: preserve tool-call verdict typing across the review dependency
trissim Oct 19, 2026
eea6c52
P269: distinguish public refusals from private installer tracebacks
trissim Oct 19, 2026
11f4964
P269: practice-install bounded retained tails through CheckRoot
trissim Oct 19, 2026
3839b76
Stop check-root owners only after population succeeds
trissim Oct 19, 2026
36bba6e
Copy normalized external events without native record reprojection
trissim Oct 19, 2026
713c44c
Let transcript declarations emit portable messages through one body gate
trissim Oct 19, 2026
96db4ff
Bind each synchronous import callback to its source event
trissim Oct 19, 2026
c4d2da5
Append normalized events directly through the writer lifetime
trissim Oct 19, 2026
bd54f5e
P269: verify recorded-clock imports against the current storage contract
trissim Oct 20, 2026
97256db
Remove the source-line budget measure
trissim Oct 19, 2026
fc23da1
Stamp declared package identities in archived format probes
trissim Oct 20, 2026
5babdb4
Resolve retained-tail senders through the registry namespace owner
trissim Oct 20, 2026
71332bf
Finish rebase import cleanup and record worker versus merger proof du…
trissim Oct 20, 2026
b0d043f
Defer carry-parent decoding until an existing carry step needs it
trissim Oct 20, 2026
a24aeb8
Keep copied initial history display-only at the protocol issuer
trissim Oct 20, 2026
19e40c2
Package the standing rules kept in commander memory
trissim Oct 20, 2026
dbce65b
Merge #1928
trissim Oct 20, 2026
0078776
Merge #2064
trissim Oct 20, 2026
23a2290
Merge #2069
trissim Oct 20, 2026
ee7bb5b
Merge #2076
trissim Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 69 additions & 32 deletions .github/workflows/debt-ratchet.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,84 @@
name: Debt ratchet
name: Merge queue

on:
pull_request:
branches: [main]
status:
merge_group:
types: [checks_requested]
workflow_dispatch:
inputs:
base:
required: true
type: string
head:
required: true
type: string
enter_queue:
description: Enqueue the already reviewed head after successful checks
type: boolean
default: false

permissions:
contents: read

concurrency:
group: debt-ratchet-${{ github.ref }}
cancel-in-progress: true
group: merge-queue-${{ github.event.sha || github.sha }}
cancel-in-progress: false

jobs:
debt-ratchet:
name: Debt ratchet
runs-on: ubuntu-latest
dispatch-reviewed:
if: github.event_name == 'status' && github.event.state == 'success'
runs-on: [self-hosted, Linux, X64, ts-gaming, agent-comms-merge]
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
ref: ${{ github.event.pull_request.head.sha || inputs.head }}
- uses: actions/setup-python@v5
with:
python-version-file: pyproject.toml
- name: Install development dependencies
run: python -m pip install --disable-pip-version-check -e src/agent_comms/skills/refactor-audit '.[all,dev]'
- name: Compare touched production files
- name: Dispatch checks on the approved PR head, not the default-branch status event
env:
PR_BASE: ${{ github.event.pull_request.base.sha || inputs.base }}
PR_HEAD: ${{ github.event.pull_request.head.sha || inputs.head }}
run: python tools/debt_ratchet.py --root src/agent_comms --base "$PR_BASE" --head "$PR_HEAD"
- name: Run every marked surface guard
if: ${{ github.event_name == 'workflow_dispatch' }}
RUN_ID: ${{ github.run_id }}
REVIEWED_HEAD: ${{ github.event.sha }}
REVIEW_CONTEXT: ${{ github.event.context }}
run: |
set -euo pipefail
request=$(python3 -c 'import shlex, sys; print(shlex.join(sys.argv[1:]))' \
"$RUN_ID" dispatch "$REVIEWED_HEAD" "$REVIEW_CONTEXT")
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes \
-i "$AGENT_COMMS_GATE_KEY" "$AGENT_COMMS_GATE_ENDPOINT" "$request"

ratchet:
if: github.event_name != 'status'
name: debt-${{ matrix.kind }}
runs-on: [self-hosted, Linux, X64, ts-gaming, agent-comms-merge]
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
kind: [src, tools]
steps:
- name: Check the exact GitHub run through the restricted host entrypoint
env:
RUN_ID: ${{ github.run_id }}
CHECK_KIND: ${{ matrix.kind }}
run: |
set -euo pipefail
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes \
-i "$AGENT_COMMS_GATE_KEY" "$AGENT_COMMS_GATE_ENDPOINT" "$RUN_ID $CHECK_KIND"

practice-install:
if: github.event_name != 'status'
name: install-rehearsal
runs-on: [self-hosted, Linux, X64, ts-gaming, agent-comms-merge]
timeout-minutes: 60
steps:
- name: Practice install; private buses and logs never enter the runner sandbox
env:
RUN_ID: ${{ github.run_id }}
run: |
set -euo pipefail
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes \
-i "$AGENT_COMMS_GATE_KEY" "$AGENT_COMMS_GATE_ENDPOINT" "$RUN_ID install"

enqueue-approved:
if: github.event_name == 'workflow_dispatch' && inputs.enter_queue
needs: [ratchet, practice-install]
runs-on: [self-hosted, Linux, X64, ts-gaming, agent-comms-merge]
timeout-minutes: 5
steps:
- name: Enter GitHub's queue after approval and successful checks
env:
PYTEST_DISABLE_PLUGIN_AUTOLOAD: '1'
run: python -m pytest -p pytest_asyncio.plugin -o addopts='' --strict-markers -m refactor_guard -q
RUN_ID: ${{ github.run_id }}
run: |
set -euo pipefail
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes \
-i "$AGENT_COMMS_GATE_KEY" "$AGENT_COMMS_GATE_ENDPOINT" "$RUN_ID enqueue"
5 changes: 5 additions & 0 deletions .pi/APPEND_SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ You are one of several agents coordinating through agent-comms. Tristan owns pro

## Ownership, code, and delivery

- Do not merge main into feature branches. When your own branch conflicts with main, rebase it onto origin/main that turn, keep main's side where main deleted or moved code, push the owned branch, and report its new head. Do not ask again for that routine authorization. Do not make formatting-only or re-budget-only commits.
- Fresh-environment practice installs belong to the merger, on the pushed head. Workers prove the affected behavior on a copy of the bus using existing dependencies and report precisely which installation proof the merger still owes.
- Line growth is a measurement, not a defect or merge gate. Do not request a line budget. Fix duplicated authorities, type filters and strings replacing declared identities; the existing measure owner decides which findings block.
- P269 practice installation uses a retained bus tail with its production indexes, bounded to 3 GiB and measured against actual free space. It does not require a 26 GiB whole-desktop copy or GitHub configuration changes. Preserve original sessions, inputs and stores; never turn short storage into a skipped success.

- Check active owners, open PRs, and claims before starting overlapping work. Coordinate with the owner of an existing feature; do not edit their worktree or start a competing implementation. Delegate genuinely independent work when it speeds delivery.
- At the next safe checkpoint, when you find a concrete defect, check that a named owner is fixing it. If none is, take or assign ownership, provide the reproducer and acceptance check, and follow through to a tested fix or a precise blocker without duplicating work.
- Implement working end-to-end behavior rather than a dormant path. Enable features by default only when safe and authorized; preserve opt-in or default-off safeguards for trust-sensitive features. Put tested work in a draft PR promptly and keep its full working version visible. Work only in an isolated worktree; do not reset, clean, or commit in the live main checkout or change installed packages without review.
Expand Down
92 changes: 92 additions & 0 deletions docs/merge-queue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Automatic merge queue

Owner: pi-cn-load, P269, draft PR #2023. Not enabled or accepted.
The takeover preserved pi-install-gate's newer published 307e5955e, a descendant
of the ordered f0dc3df0c checkpoint, and merged current main without rewriting
history. First takeover push: fb6074f3e. P714/#1947 is merged as the review-owner
dependency, not copied into another verdict implementation.

GitHub owns queue order, proposed merge identity and failed-entry removal.
QueueCheck and RunEvent members own host execution and admission. The existing
workflow runs debt-src, debt-tools and install-rehearsal on merge_group.
No commander's merge scheduler is involved after bootstrap.

## Review and installer ownership

ReviewedHeadVerdict.context is the sole review-context declaration. Its existing
publisher and the queue reader both use it. The status event passes its context
as data; the host compares it with that declaration. No repository variable
mirrors the context. No native GitHub approval is required: the contributors all
use the same GitHub identity and cannot approve their own PRs.

The queue invokes PracticeGateCommand. PracticeCopy uses the existing CheckRoot
owner to retain the bus tail, bounded saved-session tails and their production
indexes; it does not snapshot the whole desktop bus. PracticeCopy owns the 3 GiB
cap and checks measured bytes against current free space. It never admits an
empty substitute or a skipped installation. The gate checks out the proposed
revision, then rehearse invokes target/tools/upgrade_bus.py, including --help and
the actual rehearsal. It does not invoke the live checkout's installer. GateResult/MachineResult carry
typed failure reasons back to the queue. CheckFailed carries the actual completed command and delegates its public
summary to the QueueCheck member. Ratchet summaries decode introduced_lines
and print Measure file:line. Installer summaries return the declared
UpgradeRefused message through the existing typed gate result. Raw child
stdout/stderr, successful rehearsal steps and bus data remain private.

## Isolation and lifetime

The existing runner ts-gaming-agent-comms-merge (ID 21) is registered but offline.
Labels: self-hosted, Linux, X64, ts-gaming, agent-comms-merge. Its bubblewrap
namespace exposes vendor runtime, work/log directories, system binaries and a
sealed runner home, not host homes, buses, personal tokens or desktop sockets.
The SSH key admits only the fixed host entrypoint. GitHub run identity and the
workflow path are verified before checks. No generic hosted runner reads a bus.

The host derives home/user from its environment and OS identity. There is no audit path on the wrapper's PYTHONPATH: debt_ratchet derives it
from the repository submodule itself. Host.fetch initializes/updates the pinned
submodules. No unit checkout is a dependency of production gates.
There is no shared host wrapper timeout. Ratchet members own 600 seconds,
install owns 3000, and enqueue/dispatch share their command capability's 120.
YAML ceilings are 15, 60 and 5 minutes respectively. Local development ratchets
retain the ordered timeout 300 and faulthandler.

Only explicit gate failure reasons and source annotations cross the runner
boundary. Full child diagnostics, copied state and successful rehearsal results
remain on the host. A storage or allocation refusal fails the gate; it never
turns into a skipped or successful practice install.

## Settings Tristan must change (no settings changed by this worker)

- Settings → Rules → Rulesets → Automatic merge queue (25439636): change Enforcement from Disabled to Active for main, after reviewed bootstrap code is on main.
- In that ruleset → Merge queue: Merge method Merge; maximum group/build/merge size 1; require debt-src, debt-tools and install-rehearsal from GitHub Actions.
- In that ruleset → Require a pull request before merging: set required approvals to 0; the staged rule currently incorrectly requires 1 native approval.
- Settings → Actions → Runners: reuse registered runner ts-gaming-agent-comms-merge (ID 21), with the labels above; do not register a duplicate. If it must be replaced, use New self-hosted runner → Linux → x64 with those same custom labels.

Runner registration does not start its host process. The previous owner confirms
that its restricted key was never added to authorized_keys and no runner
process/service has started. An authorized operator must install the reviewed
fixed-command, loopback-only key restriction and start the reviewed isolated
launcher from main, retaining the existing private runner credentials. Do not
launch the previous owner's queue-qualified/ scripts; those are old qualification
evidence, not installed entrypoints. No runner launch, authorized_keys edit,
queue enablement, native approval, production install or restart was performed
by this worker.

## Practice proof and later activation

The latest owner ruling replaces real-queue proof with a practice installation
on the bounded retained-tail copy. Report that command's exit code and the pushed
revision; unit checks alone are not the practice-install proof. Both source and
tools ratchets must exit zero. SourceLines reports actual growth without a
budget or blocking the merge; structural findings still block through their
owning Measure implementations.

The disabled queue, offline runner and unauthorized key are not prerequisites
for this proof. They remain untouched; later production activation requires the
operator actions above. No deliberate failing GitHub branch is claimed here.
The copy does not need room for a 26 GiB desktop snapshot. Its admission uses
actual copied bytes and actual remaining space, not a second queue policy.

Worker checkouts and receipts stay under /home/ts/wt/pi-cn-load--P269 and
/home/ts/.cache/agent-scratch/pi-cn-load, below the combined 3 GB limit. The old
runner state remains with its existing owner; its credentials have not been
copied or deleted.
2 changes: 1 addition & 1 deletion plans/commander-native-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,4 @@ Toad is a view of Core, so the commander's page is one more view over Core's ans

## Order and dependencies

The phases and what each waits for are declared once, in `src/agent_comms/plan_phases.py` (the `PlanPhase` family). An order names the phase it serves with a `Serves: <phase>` line, stored as `ProblemOrder.serves`; a phase is done when every order serving it is closed. Each rotation prints `PLAN IDLE` for every phase whose dependencies are done and that has no open order (`PlanIdle` in `src/agent_comms/standing_rules.py`).
The phases and what each waits for are declared once, in `src/agent_comms/plan_phases.py` (the `PlanPhase` family). An order names the phase it serves with a `Serves: <phase>` line, stored as `ProblemOrder.serves`. A phase is done when its explicitly declared full-phase checked task has accepted installed evidence; closing related subtasks does not complete the phase. Earlier delivered phases record their delivery on their declarations. Each rotation prints `PLAN IDLE` for every phase whose dependencies are done and that has no open order (`PlanIdle` in `src/agent_comms/standing_rules.py`).
13 changes: 4 additions & 9 deletions src/agent_comms/check_root.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from .comms import Comms
from .fresh_private_session import create_fresh_private_session
from .goals import NoGoal
from .importing import ImportLimits
from .launch_runtime import RestartEnvironment, ThreadLaunch
from .native_entries import ImportedSessionWriter, NativeEntry
from .read_basis import MemberActivityDisplayScope
Expand Down Expand Up @@ -66,8 +65,8 @@ def open(self) -> Iterator[Comms]:
root.mkdir(mode=0o700, parents=True) # Refuse an existing directory, including a symlink.
try:
copied = Comms(root)
self._populate(copied)
try:
self._populate(copied)
yield copied
finally:
for thread in copied.registry.snapshot().visible_threads(
Expand Down Expand Up @@ -142,7 +141,6 @@ def _populate(self, copied: Comms) -> None:
def _session(self, original: Thread, directory: Path, project: Path) -> str:
session = create_fresh_private_session(directory, worktree=project)
source = original.runtime.history_source(self.source.root, original.incarnation)
limits = ImportLimits(messages=self.max_records, characters=self.max_bytes)
with source.reading() as reader, session.path.open("r+") as output:
writer = ImportedSessionWriter(output, NativeEntry.read(output.readline().encode()))
output.seek(0, os.SEEK_END)
Expand All @@ -158,16 +156,13 @@ def _session(self, original: Thread, directory: Path, project: Path) -> str:
with source.projection(
source, TranscriptRoutes(self.source.root)
) as project_records:
for record, events in project_records(
for _record, events in project_records(
iter(reversed(selected)),
max_records=self.max_records,
max_bytes=self.max_bytes,
):
record.project(
lambda current, events=events: writer.import_record(
current.entry, events, limits
)
)
for event in events:
writer.append_recorded(event)
return session.session_file

def run(self, command: Sequence[str]) -> CheckRootResult:
Expand Down
4 changes: 2 additions & 2 deletions src/agent_comms/commander/judge.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from dataclasses import asdict, dataclass

from ..comms import Comms
from ..todos import AcceptedVerdict, PeerAcceptedVerdict, BluntText, OrderVerdict, SendBackVerdict, StrikeReason, Todo, Slop, Derivation, SupersededVerdict
from ..todos import AcceptedVerdict, PeerAcceptedVerdict, BluntText, ToolCallVerdict, SendBackVerdict, StrikeReason, Todo, Slop, Derivation, SupersededVerdict
from ..tools import CommsUnjudgedTool, CommsVerdictTool
from ..field_codec import FieldCodec, option
from ..tool_caller import ThreadCaller
Expand Down Expand Up @@ -146,7 +146,7 @@ class VerdictVerb(JudgeVerb, RuledVerb):
"--line", action="append", metavar="LINE", help="an exact diff line; repeat for each")

@abstractmethod
def operation(self, ctx: order.Commander, todo: Todo, edit_id: str) -> OrderVerdict: ...
def operation(self, ctx: order.Commander, todo: Todo, edit_id: str) -> ToolCallVerdict: ...

@abstractmethod
def check_edits(self, edits: list[Edit]) -> None: ...
Expand Down
13 changes: 13 additions & 0 deletions src/agent_comms/commander/rules/always-fork-subagents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: always-fork-subagents
description: "Owner rule: dispatch subagents as forks (subagent_type \"fork\"), not fresh agents, unless the brief fully teaches correct maintenance and the paper"
type: feedback
---

Always fork (Agent with `subagent_type: "fork"`) instead of starting a fresh general-purpose agent. Owner, 2026-10-18: "always fork. stop it, fork and let the fork take over", then "unless you already schooled it on correct maintenance and the paper".

**Why:** a fresh agent knows only its brief. My briefs carried the owner's rules (multiple inheritance, no back-compat) but not the paper's definition of slop and the results behind it, so a fresh agent judges shapes by dogma. A fork inherits the conversation, including that understanding (, ).

**How to apply:** default to forks for refactor and design work. A fresh agent is acceptable only when its brief teaches correct maintenance itself (slop = a restated required fact a complete mechanism derives; multiple parents derive crossings; mirrors add disagreeing states; passing tests cannot reveal outside supply) and points at `.claude/verify/PAPER-RESULTS.md`. Supersedes the older habit of fresh agents with written briefs.

**Turn limit (2026-10-18):** owner said "don't use that [turn limit] on ur subagents". Forks stop at ~200 turns and can't be given a limit; they have no definition file (docs: code.claude.com/docs/en/sub-agents.md, `maxTurns` frontmatter). For long work use the user-level agent `correct-maintainer` (`~/.claude/agents/correct-maintainer.md`, `maxTurns: 100000`, system prompt teaches the standard). Definitions load at session start only. If a fork hits the cap anyway, resume it via SendMessage right away.
15 changes: 15 additions & 0 deletions src/agent_comms/commander/rules/claude-usage-budget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: claude-usage-budget
description: Claude subagent usage is the scarce budget; keep background forks to the critical path until Pi (gpt-6.1-sol) threads work on the bus
type: feedback
---

2026-10-19: I had 7 background forks running at once: runtime, carry-order, strings, index-lock, hooks, fast-ratchet and fast-board. Owner: "don't launch too many background agents, I'm trying to move to Pi Codex threads to save on usage, so please be mindful. If it's going to take another 5 hours to get Pi GPT working in comms we can't just blow through usage."

**Why:** the move to Pi threads exists to save Claude usage. Spending Claude forks freely while that move is blocked defeats it.

**How to apply:**
- Only work on the path to working Pi threads gets a Claude fork; aim for one or two at a time.
- Everything else (perf, cleanup, slop hunts) becomes a written order queued for Pi units, not a fork.
- Briefs say "finish and report in N lines", with no exploration beyond the task.
- This tempers [[slow-is-a-defect]] and [[structural-fixes-over-pushing-through]]: dispatch still happens, but to Pi units once they work. See [[codex-units-need-dictation]].
Loading
Loading