Skip to content

Integration batch 2026-10-30: #3697 #3737 #3616 #3595 #3723 #3607 - #3741

Closed
trissim wants to merge 123 commits into
mainfrom
batch/integ-20261030
Closed

trissim wants to merge 123 commits into
mainfrom
batch/integ-20261030

Conversation

@trissim

@trissim trissim commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

One integration run for every agent-comms PR in flight, built from origin/main 238db61+ (d6084cb). It runs CI once instead of six queue runs, and conflicts are resolved here instead of sent back.

PR Head What Merge
#3697 1f68dcd install-speed: CheckoutHistory.merge_base reads branch-only commits (heartbeat probe was 234–307 s of every install) + ratchet fixes clean
#3737 abb0d90 installer: owners given back through a context, not a None probe; WAL pinned instead of truncated clean
#3616 7a344c6 export: text/other formats render decoded Messages; wire parse-back deleted (19,410 claim-notice crashes) clean
#3595 efb40c5 command binding: PendingCommandBinding.command field deleted; the context derives its command clean
#3723 f14659d (debt-src fork fix) clean
#3607 a6eb302 frame baseline: shared _joined stored-record reader conflict in messages.py stored_records: batch side was main's unchanged body, #3607's _joined delegation taken

Members' own auto-merge is off while batched. A member that fails its verdict or this batch's checks is dropped and the batch is rebuilt without it the same tick.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu

trissim and others added 25 commits October 30, 2026 15:42
…sons

#3735 made every deal open with the trigger that caused it, and gave PiRedeal.deal_from a
required trigger. This branch predated that: `agent-comms-prime --to` raised TypeError at
prime.py:39, and a session /prime fell back to LostContext and opened with "Dealt because
this session just started", the false reason #3735 removed.

- rule_deal.py: PrimedDeal joins the DealTrigger family; its reason names /prime and the
  variant.
- skill.py: DeckStart.dealt takes the trigger it opens with. Each StartReason passes its own
  (StartReason.deal, Resume.deal, widened), and primed() passes PrimedDeal for the variant.
- prime.py: prime_threads hands deal_from the same PrimedDeal.
- tests: the import conflict with main is resolved, keeping both sides; one test checks
  every variant's reason names /prime and is never the started reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
Install 040380a8 (2026-10-30, main d977b8d) stopped every owner, then
something raised; the give-back start refused with "Stopped owner session
has not retired yet" and that refusal was the only line printed. The real
failure survived only as __context__, which nothing reports, so the
install's cause was lost.

OwnersStopped.given_back_on registers the restart as an exit hook that
sees the in-flight failure: a refused restart during a failing install
raises OwnersNotRestarted naming both, caused by the install's failure.
Both owners_stopped declarations use it; the copied callback is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
PendingCommandBinding carried a command field and a __post_init__ that refused a
command not inheriting the context (IMPL-10): the context's own class already
declares which command inherits it. The binding now holds only the context, and
CommandContext.command() reads the one CliCommand family member inheriting it.
new gets NewThreadContext so each context has exactly one declared command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…ire parse-back

Text export crashed on every claim-notice row: WireExportFormat.stored_row
parsed the SQL-built public wire back through Message.from_wire, and
ClaimNoticeKind decodes that as a ClaimMessage needing claim_transition,
which the public envelope never carries. On a copy of the live bus 19,410
claim-notice rows failed this way (first at seq 1561).

The format now owns how it reads the stored history. JSONL's row is the
stored wire text, so the limit still selects it in SQL. Every other format
renders Messages decoded once from their capability tables
(BusCapability.at_sequences, the same decode main's export used), through
the limit's ordinary selection. Deleted: StoredWireMessage.decode and
decode_wire, and the base format's stored_row, encoded_size and
stored_size, which registered a SQLite function that parsed every row back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…red history

CheckoutHistory.merge_base scanned every common ancestor (about 25,000 commits)
and cleared each one's parents from a 26,700-bit set, once per head. Over the
726 worktree heads on the live checkout that took 179 s.

The common set is ancestor-closed, so a best base is a tip or a parent of a
commit only one side reaches, and it is best exactly when no child is common.
merge_base now tests only those candidates against a children map inverted
once from the captured graph: 4.8 s for the same 726 heads, and identical to
git merge-base --all on 100 sampled pairs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…carry check

Install of d977b8d aborted before its backup: "Another connection holds the WAL of
bus.sqlite3". SQLiteFile.settle ran wal_checkpoint(TRUNCATE), which must wait out
every open reader, and the bus always has readers (session bridges, `sqlite3
-readonly` queries). The settle existed only for carried(): it compares stat
(size, mtime, inode), and the last close of a database checkpoints its WAL into the
file, moving bytes without changing a row (install 33, 5c2e5ba).

Only the last close checkpoints. Holding one connection open (read-only, no
transaction) keeps every other close from being last, and its own read-only close
never checkpoints, so the bytes stay where they are from the before snapshot to the
after snapshot with no checkpoint and no wait on any reader. Measured on SQLite
3.53.1: with the pin held, a writer's close and a reader's close leave the file and
WAL stats unchanged; without it, the last open/close re-touches the file even
when every frame is already backfilled, so FULL instead of TRUNCATE could not work.

- RootFile.settle -> pinned (a context): no-op for plain files; SQLiteFile holds one
  read-only connection; PrivateSnapshotFile keeps its no-op (immutable inodes).
- settle_bus_files -> pinned_bus_files returns the pins; PreparedMigration.capture
  takes them with the before snapshot and carry releases them after carried().
  live() pushes them onto its holder so a failure before the carry releases them
  before any restore replaces a store.
- Tests: the settle test now holds a reader of the latest snapshot while the pin is
  taken and through reconcile; a store test shows a pinned store's bytes survive
  the writer's and a reader's close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…ot resolve

The progress read moved from git rev-list --not --remotes onto CheckoutHistory,
which resolves each exclusion as a revision; the flag string '--remotes'
raised UnavailableCommitError, so every unit with a present checkout read as
Unreadable (test_order_closed_after_the_frame_read_does_not_fail_the_merge_read).
ProgressCheckout now owns its remote references; a retired checkout has none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
… None

debt-src grew NoneAbsence +2 at upgrade.py:488/492: the ExitStack callback decided
whether the install failed by testing its exception argument for None (IDEN-3).
given_back_on is now a context: the except arm is the failing install, the normal
exit is the succeeding one. It still restarts through give_back, so a published
runtime's pop_all keeps cancelling the restart.

- Both owners_stopped declarations wrap their body in it; the pushed callback
  and the None test are deleted.
- New test: a succeeding install's refused restart raises UpgradeRefused itself,
  and a taken-over (retired) give-back starts nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
… its name out

The gate counted three call sites passing prime.declared_name into PrimedDeal
(FamilyFlattened +3): the family's identity name carried out as a string. Prime
now owns trigger(), so callers ask the variant for its deal and the name stays
on the declaration. UnboundPrime takes the Error suffix (N818) and prime.py is
black-formatted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…mports them

BranchUpstream took WorkBranches only to reach its history and selected heads,
which made repo.py import work_branches under TYPE_CHECKING (debt-src
TypeCheckingImport +1). The reader now passes both. GitHead decodes git's
porcelain record into one mapping instead of three spelled name compares
(StringIdentity/FamilyFlattened +2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
test_pending_new_binding_offers_missing_tags_without_constructing_the_command read
tags.editor_default, which UnsuppliedTargetField does not declare (only
SuppliedTargetField owns a default); it failed on ce33201 before this branch's
binding change. The field's type is the fact; json_schema still omits the default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
…eyed dict

debt-src grew StringSubscript +1 from fields["worktree"]. Git's porcelain record
opens with worktree and HEAD in that order; the decode reads them positionally.
Checked against all 784 live agent-comms worktrees (550 attached, 234 detached).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
contexts() spelled type[CliCommand[CliResult]] twice (channel_targets.py:180, :396);
Answer already declares default=CliResult (cli_command.py:64), and the restated
default was the only reason channel_targets imported CliResult under TYPE_CHECKING.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
# Conflicts:
#	src/agent_comms/messages.py
Copilot AI balanced review requested due to automatic review settings October 30, 2026 20:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@github-actions

Copy link
Copy Markdown

debt-src at b468bdf, every finding:

grew ClientTypeErrors:batrachian-toad/src/toad/conversation_kind.py +2: this change removes or changes an agent_comms name that client file uses; run mypy on it to see which
grew ClientTypeErrors:batrachian-toad/src/toad/widgets/comms_command_dialog.py +1: this change removes or changes an agent_comms name that client file uses; run mypy on it to see which
grew ClientTypeErrors:batrachian-toad/src/toad/widgets/thread_comms.py +3: this change removes or changes an agent_comms name that client file uses; run mypy on it to see which
::warning file=src/agent_comms/bus.py::GodClassExcess +21 (warns, never blocks)
::warning file=src/agent_comms/field_codec.py::GodClassExcess +39 (warns, never blocks)
::warning file=src/agent_comms/typed_table.py::GodClassExcess +17 (warns, never blocks)
::warning file=src/agent_comms/cli_command.py::LintFindings +2 (warns, never blocks)
::warning file=src/agent_comms/cli_support/thread_creation.py::LintFindings +2 (warns, never blocks)
::warning file=src/agent_comms/exporting.py::LintFindings +6 (warns, never blocks)
::warning file=src/agent_comms/installer/upgrade.py::LintFindings +1 (warns, never blocks)
::warning file=src/agent_comms/messages.py::LintFindings +2 (warns, never blocks)
::warning file=src/agent_comms/thread_creation.py::LintFindings +1 (warns, never blocks)
::warning file=src/agent_comms/typed_table.py::LintFindings +1 (warns, never blocks)
::warning file=src/agent_comms/cli_support/thread_creation.py::Unformatted +1 (warns, never blocks)
found ClientTypeErrors:batrachian-toad/src/toad/conversation_kind.py at batrachian-toad/src/toad/conversation_kind.py:186 ("HistoryViews" has no attribute "channel_display_page"; maybe "channel_display_view"?  [attr-defined]) batrachian-toad/src/toad/conversation_kind.py:272 ("HistoryViews" has no attribute "dm_display_page"; maybe "dm_display_view"?  [attr-defined])
found ClientTypeErrors:batrachian-toad/src/toad/widgets/comms_command_dialog.py at batrachian-toad/src/toad/widgets/comms_command_dialog.py:169 ("TargetField" has no attribute "editor_default"  [attr-defined])
found ClientTypeErrors:batrachian-toad/src/toad/widgets/thread_comms.py at batrachian-toad/src/toad/widgets/thread_comms.py:49 (Item "NoThreadView" of "ThreadView | NoThreadView" has no attribute "thread"  [union-attr]) batrachian-toad/src/toad/widgets/thread_comms.py:209 (Item "NoThreadView" of "ThreadView | NoThreadView" has no attribute "thread"  [union-attr]) batrachian-toad/src/toad/widgets/thread_comms.py:221 (Item "NoThreadView" of "ThreadView | NoThreadView" has no attribute "thread"  [union-attr])
found LintFindings:src/agent_comms/cli_command.py at src/agent_comms/cli_command.py:270 (E501 Line too long (167 > 100)) src/agent_comms/cli_command.py:278 (E501 Line too long (175 > 100)) src/agent_comms/cli_command.py:284 (E501 Line too long (102 > 100)) src/agent_comms/cli_command.py:643 (E501 Line too long (104 > 100))
found LintFindings:src/agent_comms/cli_support/thread_creation.py at src/agent_comms/cli_support/thread_creation.py:31 (E501 Line too long (102 > 100)) src/agent_comms/cli_support/thread_creation.py:41 (E501 Line too long (108 > 100))
found LintFindings:src/agent_comms/exporting.py at src/agent_comms/exporting.py:3 (I001 [*] Import block is un-sorted or un-formatted) src/agent_comms/exporting.py:78 (E501 Line too long (117 > 100)) src/agent_comms/exporting.py:253 (E501 Line too long (101 > 100)) src/agent_comms/exporting.py:488 (N818 Exception name `WireExportCancelled` should be named with an Error suffix) src/agent_comms/exporting.py:573 (B008 Do not perform function call `WireExportObserver` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable) src/agent_comms/exporting.py:582 (B008 Do not perform function call `WireExportObserver` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable)
found LintFindings:src/agent_comms/installer/upgrade.py at src/agent_comms/installer/upgrade.py:1001 (SIM117 [*] Use a single `with` statement with multiple contexts instead of nested `with` statements)
found LintFindings:src/agent_comms/messages.py at src/agent_comms/messages.py:705 (E501 Line too long (101 > 100)) src/agent_comms/messages.py:1115 (E501 Line too long (102 > 100)) src/agent_comms/messages.py:1118 (E501 Line too long (114 > 100)) src/agent_comms/messages.py:1299 (E501 Line too long (101 > 100))
found LintFindings:src/agent_comms/thread_creation.py at src/agent_comms/thread_creation.py:73 (UP040 Type alias `RequiredCreationTime` uses `TypeAlias` annotation instead of the `type` keyword)
found LintFindings:src/agent_comms/typed_table.py at src/agent_comms/typed_table.py:2505 (E501 Line too long (101 > 100))
found Unformatted:src/agent_comms/cli_support/thread_creation.py at src/agent_comms/cli_support/thread_creation.py:1 (Black would reformat this file)
introduced NoneAbsence:src/agent_comms/historical_views.py at lines [597]

@trissim

trissim commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Closing this batch: #3616 and #3595 were sent back (copied decode loop; a test calling a deleted method), and #3697 is landing on its own as the install-speed hotfix. I rebuild from fresh main as members return with ok verdicts.

@trissim trissim closed this Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants