Skip to content

Keep queue inspections and control failures bound to their source - #1389

Open
trissim wants to merge 18 commits into
mainfrom
work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad
Open

trissim wants to merge 18 commits into
mainfrom
work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad

Conversation

@trissim

@trissim trissim commented Oct 31, 2026 •

Copy link
Copy Markdown

P1090 — original input, session and draft ownership

18 composed commits; 112 files, +3932/-2392 against main 7b36ed6be51993471150eb475fc378c640d96fdb. Head edaf58682186f842dc3f910fade03ffbf2b81a62; pushed and remote-verified; tracked source clean. Latest launch/login increment: 5 files, +40/-29. Prior request-owner increment: 3 files, +9/-12. Prior transcript-owner increment: 4 files, +39/-22. Prior current-output increment: 6 files, +58/-52. Previous submission-provider increment: 7 files, +105/-97. Prior source-qualified session-agent increment: 10 files, +174/-77. Prior accepted capability increment: 9 files, +84/-32. Prior configuration correction: 10 files, +92/-78. The rebase preserves main's remote Core page/revision requests and deletion of the old history-view/NamedViewer route, while retaining the original queue-source fences. The login-contract commit changes 3 files, +15/-3; the publication-envelope correction changes 3 files, +6/-5. The original 43-commit authored history remains on archive/p1090-composed-before-main-20261102-a44f0eec4; composition/rebase is not discarded work.

Status: source work continues. Core companion #3848 merged at e9ae7997e and was installed. This Toad PR has not been observed merged or installed. The saved P1090 delivery claim names predecessor a638bdbc1; the attempted head amendment was refused because the order is already marked merged by its Core half. That record is not approval of this head.

Latest increment: acquire launch and login at their actual owners

Before: Agent forwarded an optional OS command through a duplicate SessionAgent declaration; process launch and terminal login interpreted its absence differently.

After: ConfiguredAgentProcess.from_definition acquires the launch. Missing commands still record the exact startup failure and return the original process object; strings, including empty strings, construct the same configured process. Process reuse and admission conjuncts, membership/terminal/task order, env/cwd/route and retirement remain. The original Platform selector and exact-before-wildcard lookup are unchanged.

The complete map found terminal login too. Command.for_login acquires its catalogue command: missing OR empty commands still raise the identical ValueError. SDK name, arguments/quoting and bootstrap default remain. Conversation retains its captured actor, modal/action/env/cwd, subsequent wait/reconnect/authentication and finally cleanup. Agent's diagnostic repr yields the same selected scalar. The Agent.command facade and duplicate SessionAgent declaration are deleted; stored fields and MROs remain, with no wrapper or compatibility alias.

Map28:10 modules,49 classes,95 consumer leads; extension29:five modules including actual SDK/catalog/modal,301 classes. Proof29: 298 common bodies/signatures, four explicit rewrites, two transferred factory bodies, unchanged field/MRO declarations and eight neighboring owner files. Cold33 passed both fresh orders,4.903s/4.651s, on Coree068/lock8b07, with resolved factory metadata, original Command constructor shape and native concreteness. No pytest/local gate/application run occurred.

Artifacts: delivery-owned/launch-owner-28-before.json, launch-auth-29-before.json, launch-owner-29-{proof,published}.json, cold-import-owner-33/. Assumed: production ACP factory/platform binding, no external command-property overrides; ordinary SDK fields and frozen Command construction. Command allocation now precedes modal/action argument evaluation, and the actual catalog factory imports the declared SDK earlier. Main7b36 was unchanged; no rebase occurred. Both SessionAgent session-ID declarations and wider findings remain. Exact edaf subsequently failed NRA in run 41617695617, job125855164889; suite125855167038 skipped. Remaining growth is SessionAgent NoneAbsence +2 (was+3), its session-ID getter/setter at59/63. Wider introduced absence sites and recipient failure collector remain. Full original log: delivery-owned/launch-owner-29-gate.log. Commander independently source-qualified only this increment in pi-commander/review-1389-edaf/increment-review.md (message59133); no application run. This is not whole-head acceptance, merge/install or application delivery.

Prior increment: require the original request at the execution owner

The live public Agent.send_prompt(prompt, request=None) API still accepts ordinary text and explicitly supplied requests. Its existing QueuePromptRequest fallback now normalizes that optional input once at this public boundary. AgentController.submit requires a PromptRequest, and NativeSubmissionExecution sends its already-captured request directly to that controller. The unused SessionAgent sender declaration and its two imports are removed. The generic AgentBase contract and every public caller remain unchanged; no new sender facade, alias or compatibility entry point is introduced.

Rendered prompt text and request.user_text remain separate values. An explicitly supplied request is not copied or regenerated: input ID, origin, control mode and defer-display choice survive. Ordinary text still creates exactly one QueuePromptRequest before ClientSessionRequest captures binding/disposition. Agent.controller has one production assignment in Agent.init; PermissionRequest.controller is a different owner, not another writer of that field. Shielded operation, authority/scope/project capture, prompt-in-flight accounting, ACK/result/paint and writer/waiter bodies are unchanged.

Map27: 18 modules,159 classes,118 consumer leads. Proof27: 109 body/signature comparisons, three explicit rewrites,18 public text callers, two controller callers and ten unchanged neighboring/fixture files. The first source-check attempt wrongly combined the two same-spelled controller fields; its failed log is preserved, and the corrected trace scopes them to their actual owners. Cold32 passed both fresh orders,4.767s/4.664s, on Coree06802a54/lock8b07, including required request metadata, unchanged public default and native concreteness. The only later source difference was an EOF blank-line deletion. No pytest, local gate or application execution occurred.

Artifacts: delivery-owned/prompt-owner-27-{before,proof,published}.json, prompt-owner-27-proof-failed-01.log, cold-import-owner-32/. Assumed: the production ACP factory, not a plugin overriding the public text facade; default request minting is frozen construction and a fresh identifier, not a callback into controller selection. Native shared-session admission, cancellation and retirement paths remain unchanged. Three SessionAgent command/session-ID declarations and wider findings still need repair. Exact b61e131 subsequently failed NRA in run 41611577722, job125834512475; suite125834514560 was skipped. Its original log is saved as delivery-owned/prompt-owner-27-gate.log; this is not application acceptance.

Previous hosted status:718c5f109

Exact718c5f109 failed NRA in run 41606589596, job125817828582; suite125817830256 skipped. SessionAgent NoneAbsence +4 remained; conversation_submission's two import-growth entries were gone. The wider introduced absence sites and recipient failure collector were still reported. Full output: delivery-owned/transcript-owner-26-gate.log. This does not establish the outcome for b61e131.

Prior increment: transcript/window operations stay with their real owner

The actual ConversationSessionBinding retains its transcript: TranscriptPresentation declaration and now owns the unchanged native Window query descriptor formerly declared on its event subclass. ConversationSubmissions declares three resource operations rather than mirroring transcript/window fields: canonical refresh, bound-transcript visibility, and mailbox binding. Their implementations live on the existing rich view. No type erasure, rich eager import into the submission contract, parallel manager or compatibility entry point replaces the dependencies.

Mailbox completion still strongly retains BOTH the original source and original view. A source-owned lambda looks up self.external_transcript_changed(owner) at completion, not from a replaced current scope. The view callback first jumps the native window and then invokes that captured source operation. The original scope/owner/submission/DmConversation/callback binding is established before preparation. Detached views still short-circuit before reading their bound transcript. The actual transcript constructor, independent document/history/editor/undo and writer/waiter lifetimes, mailbox precedence and queue-service callback-capture code are unchanged.

Map26 extends the retained map with 13 modules,105 classes,229 consumer leads. Proof26 compares 462 bodies/signatures, with three explicit outer-body transfers and the nested callback move, exact predicate/canonical request/binding expressions, unchanged class base lists and actual transcript/native-getter declarations. The native query descriptor has no declaration-owner or __set_name__ state. Callback qualname and extra method frames change; this is not an identical-instruction-count claim.

Cold30 completed its imports but failed my new metadata assertion: typing.Callable[[], NoneType] and collections.abc.Callable[[], None] are different annotation objects. I corrected the check to preserve nominal input/result identities and verify the callable origin, zero arguments and void return. Failed30 remains saved. Cold31 passed both fresh orders,4.728s/4.686s, on Core3a5153f94/lock8b07, including native concreteness, inherited Window identity/type/selector and resolved operation contracts. Imports preceded the clean rebase onto7b36; all four edited source hashes are identical afterward. No pytest/local gate or application execution occurred.

Artifacts: delivery-owned/transcript-owner-26-{before,proof,published}.json, their logs, cold-import-owner-{30,31}/. Assumed: the admitted production declarations and no live reflection contract on the private callback's qualname. SessionAgent's four nullable declarations and wider findings remain open. This increment is not whole-head source acceptance, hosted clearance, merge, installation or application delivery. Its exact hosted failure was subsequently observed and is recorded above; the new b61e131 NRA failure and skipped suite are recorded in the current increment above.

Previous hosted status:3b4afcc

Exact head 3b4afcc048ee103c89d5224f3715472adb0c7c9c failed the NRA gate in run 41598805134; suite skipped. Recorded growth is now SessionAgent NoneAbsence +4 and conversation_submission TypeCheckingImport +2; the two shell growth entries are gone. Introduced absence sites across the wider change and the recipient-failure collector remain reported. Full original output is delivery-owned/shell-output-25-gate.log. This is not whole-head clearance.

Prior increment: current shell output owns absence

Before: the current output was ShellTerminalOutput | None; command start, focus, resize, input formatting and data acquisition repeated presence decisions outside the model.

After: CurrentShellOutput supplies the current-output contract; frozen NoCurrentShellOutput inherits its absent answers. ShellTerminalOutput(ShellOutput, CurrentShellOutput) retains its existing ANSI model and borrowed-terminal projection and supplies the present answers. The existing finalized bit remains model state; this change does not claim removal of every lifecycle flag or of the independently optional borrowed view.

The fresh-output producer still constructs the original TerminalState with the same write callback and current dimensions, assigns current output before appending it to the output list, and only runs when a model is absent or finalized. Paste framing uses the same requested-paste/ANSI-mode condition and bytes. Focus, model resize, finalization, projection and detach/retire/join/clear ordering preserve their documented cases. Declared psutil==7.2.2 now imports at module scope rather than inside every busy observation.

Two legacy ShellTerminal message types and their handler had no producers. Actual menu and key controls both call interrupt_shell() directly, with unchanged bodies. Deleting the two types, their handler and three imports removes 26 lines. Four obsolete submission_queue imports are also deleted. The queue failure collector itself is unchanged.

Map25 extends the retained source map with 10 modules,44 classes,101 consumer leads. Proof25 compares 250 bodies and signatures, with 11 explicit transformations, original constructor/paste expressions, current-output cases and unchanged live interrupt entry points. Cold29 on Core0ac4aca41 passed both fresh import orders in 5.139s/4.798s, including output MRO/concreteness and existing constructor/field metadata. No pytest, local gate or application execution occurred. This is an increment, not whole-head acceptance.

Artifacts: delivery-owned/shell-output-25-{before,proof,published}.json, map/proof/publication logs and cold-import-owner-29/. Assumed: declared psutil is installed (a broken dependency now fails earlier); the closed source/tests/tools producer map defines deletion scope for these frontend messages. Fresh main was unchanged; no rebase occurred. At3b4, SessionAgent's nullable interfaces, the two transcript/window resource dependencies and wider hosted/application delivery remained open; the transcript operation repair is documented above.

Previous hosted failure:0680

At 0680c75eff6ae4beedf3e1267f5a5353f9943cb4, run 41591774227 failed the NRA gate; suite skipped. Recorded growth: shell_source FunctionLocalImport +1; SessionAgent NoneAbsence +4; shell_source NoneAbsence +1; conversation_submission TypeCheckingImport +2. Introduced absence sites and the per-recipient failure collector are additional unresolved findings. Full output and source disposition are saved in delivery-owned/submission-provider-24-gate.{log,rc} and submission-provider-24-gate-disposition.md. Source/import correspondence below does not override this failure or establish whole application delivery.

Previous increment: submission providers and one receiver

The submission view now requires ShellOperationalSource, not concrete Shell. The existing operational parent owns is_busy and send_input with their original bodies; its abstract write signature matches the original concrete operation. Shell process, output, echo/paste handling, acquisition and retirement remain independent and unchanged.

BusSubmissionSource owns the captured Comms reference and MessageDestination field. WireSource inherits this data, retains its narrower ConversationKind declaration and all remaining fields. Flattened field declarations, order, positional/keyword constructor shape and identity hashing remain the same. Delivery no longer names rich WireSource. The redundant owner argument is gone from all three declarations and the sole repository caller: that caller always passed its receiver as owner. Both implementations now use self; the page-source capture and original-source checks are unchanged.

QueueSource's entire class AST is unchanged and colocated with its reciprocal submission contract; callers import it from its declaration. This is a dependency-layout correction, not a claimed removal of implementation debt. MailboxSessionSources retains its BusQueueSource/OperationalSessionSources precedence and captured callback evaluation order.

The retained NRA map covers 21 modules /169 classes /298 consumer leads. Proof24 compares 433 function bodies, including ten QueueSource methods and two shell methods moved to their providers (plus the nested children function). Three explicit body adjustments remove the duplicate receiver; the new abstract write contract matches the existing implementation. Publication writer/waiter lifetime, ACK/result/paint/draft/undo distinctions and original request/source/recipient fences are unchanged.

Cold27 failed both imports when I incorrectly made the data facet depend on richer ConversationKind. The corrected parent uses the existing MessageDestination family; WireSource retains its narrower declaration. Cold28 on Core0ac4aca41 passed both fresh orders in 4.907s /4.922s, including Shell/Agent/Conversation/MainScreen concreteness, inherited shell method identity, field order/hash/constructor reflection and resolved submission contract types. No app run, pytest or local NRA gate occurred. Original failed27 stays saved. TranscriptPresentation and HistoryWindow remain two explicit type-only resource dependencies; whole delivery is open.

Artifacts under delivery-owned/: submission-provider-24-{before,proof,published}.json, map/publish logs, cold-import-owner-{27,28}/. Assumed: the closed repository bind_bus_submission call map defines duplicate-receiver deletion scope; no obsolete constructor or import alias is retained. Physical/candidate acceptance remains separate.

Prior source-qualified increment: operational session-agent ownership

Resource consumers now hold the nominal SessionAgent parent, not concrete ACP Agent. The parent declares the actual controller, session, process, permission, queue, configuration and publication operations; Agent(AgentBase, SessionAgent) supplies them. The contract constructs no resources and merges no lifetimes. ClientSessionRequest, controller and notification signatures retain their existing type-only boundary while naming this parent. No object/Any cast, lazy import, compatibility alias or eager concrete-Agent import replaces the old dependency.

OperationalAgentPresentation(..., declared_name=None) owns the native presentation implementation. The original ACPAgentPresentation member remains as an empty subclass, preserving its identity; callers can require the operational capability rather than that leaf.

Cold25 failed both orders before app startup. The complete source trace found that LocalTurnBinding ignores its agent parameter and ManagedTurnBinding only stored it without any reader in the family. The only factories are AgentPresentation's TURN_BINDING(...) and ManagedTurnBinding(...); all were updated to argumentless construction, with no compatibility parameter. The binding.agent hit in tests/support/ui.py belongs to the separate AgentAttached family. This deletion removes the false turn→agent dependency rather than moving an import to hide it.

Source proof23 compares 344 function bodies, with four explicit adjustments (the moved field annotation and deleted unused turn inputs) and 14 presentation methods moved intact to their provider except the documented factory argument deletion. Its owner-attribute map is covered by the declared contract. Captured-binding/disposition checks, late-response handling, task tracking, gather-before-detach, controller cleanup and shared-process retirement bodies remain unchanged. In particular a refused remote close still discards only that session in finally, retains the error and leaves siblings on their shared transport.

Cold26 on Core0ac4aca41 passed two fresh import orders in 4.890s / 4.851s, including native Agent, Conversation and MainScreen concreteness plus resolved contract field types. These are exact checkpoint source bytes, not an app pass. No pytest/local NRA gate ran. Failed25 remains saved. Artifacts under delivery-owned/: agent-lifecycle-{21,22}-before.json, session-agent-23-{proof,published}.json, cold-import-owner-{25,26}/. Whole-head hosted/application acceptance remains open; conversation_submission's remaining dependencies still need repair.

Assumed: the closed repository turn-binding family and its two mapped factories define this unused-input deletion scope; no external constructor compatibility is retained. Native producers still construct the same independent resources in the same order. Required combined app/session/permission/terminal and physical verification is not replaced by this source proof.

Prior accepted increment: connection view capabilities

Before: ACP Agent named concrete MainScreen and Conversation through two guarded imports. Its inherited reconnect fallback actually needs source attachment, so erasing that argument because the native override ignores it would lose behavior.

After:

StatusView(ToadNode, Widget): actual feedback getter + thread_status reactive
  DeliveryFailureView(StatusView)
  CompactionView(StatusView): abstract compact_context -> Worker[None]
Conversation(..., CompactionView, SurfaceTarget, ...)
SessionStartTarget: abstract attach_started(plan)
MainScreen(..., SessionStartTarget, metaclass=NativeNodeMeta)
AgentConnection.reconnect_session -> source.attach_started(plan)

The original attachment body now belongs to MainScreen.attach_started; native reconnect still calls its session. Shared status declarations moved, not copied; observed thread activity stays on its distinct ThreadStatusOwner. SurfaceTarget retains the actual view's nominal identity without pretending to own the binding's permission/terminal resources. The two no-native surface defaults moved from NoAgentConnection to the family base; actual native overrides and pointer-identity checks are unchanged. No object/Any erasure, concrete eager import, cast or compatibility alias was added.

Source correspondence against caec records 418 unchanged function bodies, the explicit fallback move, the two docstring-only defaults and exact moved field ASTs. Controller, permission controller, session entry, session presentation and observed activity files are byte-identical. Artifacts: delivery-owned/agent-view-20-{before,proof,published}.json and the map/publication logs under /home/ts/.cache/agent-scratch/pi-toad-errors/.

Cold24 on Core3a1f856 executed two fresh import orders including MainScreen: 4.794s / 4.711s, both successful; both Conversation and MainScreen remain concrete. The final source differs from that import input only by an import-group blank line in delivery_failure_view.py; executable ASTs are unchanged. Saved commands, actual package paths and MRO are in delivery-owned/cold-import-owner-24/. No pytest or local NRA gate was run. This is not candidate application acceptance. The last hosted result still belongs to caec (six guarded-import growth categories, suite skipped); this new head's hosted result is not yet recorded.

Assumed: existing bindings continue to receive actual Conversation identities, and the original MainScreen remains the startup source; those producer/consumer paths are retained. Fresh application submission/draft/eviction/shared-close/compaction/native-image evidence remains required for the complete PR.

Required behavior

An input retains its original request, session, source and recipient across every await. Replacement thread births and superseded bindings cannot receive it. Cancellation of a UI waiter does not cancel or replay an uncertain physical write. ACK, returned result, painted output and editor intent are separate facts. Independent draft/document/history/undo survives eviction, and rejecting one session's close preserves its sibling's shared transport.

Before / after structure

Before: optional controller/session probes, duplicated submission/error paths, mutable current-view lookup across awaits, a raw SDK destination mixed with history/resume spelling, and acknowledgement tied to the current editor.

After:

AgentConnection -> AgentBase -> ACP Agent
  default capabilities             AgentInitialization / InitializedAgent
                                   SessionBinding / BoundSessionBinding
                                   CoordinationAttachment / CoordinatedThread
                                   AgentSession owns close/cancel/reconnect

ConversationSessionBinding(..., ConversationSubmissions, ...)
  -> ConversationEvents -> Conversation -> CommsChatView
InputSubmission -> QueueSource.begin_submission -> SubmissionExecution
     captures request/source/session before preparation and sending
     physical writer remains separate from cancelled waiter

MailboxSessionSources(BusQueueSource, OperationalSessionSources)
Conversation(..., SessionLoginTarget, ...)

The inherited defaults and concrete members supply behavior; overlapping BUS/operational capabilities compose through the MRO. No parallel manager, compatibility alias, fallback decoder or second queue replaces them.

Original identities and publication

Core ThreadManagement.set_project receives the original ThreadIncarnation, rejects replacement before path work and preserves require_original_project. Toad's immutable CoordinatedThread retains the decoded publication, root and birth. Metadata/rename replacement is not a new birth.

ClientSessionRequest captures binding and disposition before awaits. SessionBinding.from_sdk decodes the acquired ACP destination once; BoundSessionBinding owns its AcpSessionId and output. An unbound required-session request refuses. Initialization/authentication remain connection-wide.

SessionBinding.publication now supplies the bound/unbound publication identity instead of optional session-ID arguments at callers. CommsUpdateConsumer captures request authority before decoding metadata; source claims and assistant/round commits use that binding's output, not a later mutable controller session. Existing retirement and original-source checks remain.

Canonical history and DB resume spelling remain distinct. AgentSession.new persists the original SDK response.session_id; nominal live authority remains on the binding. This fixes the strict DB refusal without casts, schema weakening or another decoder. Normal/control prompts retain SDK list[ContentBlock]; the common control carrier is [text_block(" ")] on AgentController.

Submission, ACK, cancellation and local editing

ConversationSessionBinding inherits ConversationSubmissions, composing queue, turn completion, posting and failure presentation. Its pending list is initialized at the original construction point; no per-view helper stores a route back to the view. Each SubmissionExecution still owns its captured request, worker and outcome through preparation, send and feedback, including cancellation before startup. Closing joins the waiter before pruning; unresolved submissions retain their views.

PreparationRuntime retains the physical Task[Message] independently of the waiter and joins it at application close. A definite Message or CommittedMessageError.record settles the original transaction. An unresolved outcome remains UNKNOWN and is never replayed.

contains_message, acknowledged_by, settle_acknowledged and SentAwaitingSource separate acknowledgement, result and paint from editor intent. Early ACK survives response failure; late ACK cannot overwrite a newer draft. SessionViewState retains document/history/undo. Captured action/mode preserves the separately shipped Neovim send-now behavior.

Queue and view capability owners

QueueSource owns send-now availability. Native additionally requires its deferred-input state; BUS preserves its own MRO lookup. SubmitNowAction, queued matching and immediate matching consume the same admission owner. MessagePrompt inherits shared control refresh, specializing only its no-goal separator.

Queue evidence retains FrozenRecipient identities, not names. Captured service callbacks validate the original source and transcript root. A retired source refuses rather than resolving a replacement route. No BUS message-withdrawal backend is invented as a prerequisite for these controls.

FailurePresentation, CommitRequirement, MessageDestination, ThreadInterest, ConversationEvents and shared NativeNodeMeta declare the actual consumer capabilities instead of asking unrelated consumers to import the entire rich implementation.

Latest correction: login presentation

CoordinationAttachment.prepare_login previously depended on the whole Conversation type for prune_window(0, 0) and output.boundary(). SessionLoginTarget declares those requirements, and Conversation inherits it. The ordinary and coordinated method bodies are AST-identical to their predecessors: ordinary login clears transient output; coordinated login preserves saved history. No session/source/recipient/draft identity was merged or deleted to reduce a gate count.

Publication admission keeps its original envelope

The view now passes the intact CommsUpdated to AgentConnection.accepts_publication, rather than extracting an optional ID and declaring that field shape again in both connection signatures. The concrete ACP owner still checks message.publisher is self and self.session_id == update.session_id. The non-ACP default still refuses. This retains the emission-time event and its legitimate bound/unbound distinction; it does not invent a new event schema or remove either identity fence.

Mode configuration is read from its existing owner

The four current_mode/available_modes properties on AgentConnection and ACP Agent are deleted (16 lines). AgentConfiguration.mode.selected/choices already owns those exact answers. All traced production consumers and the SDK journey assertions now read that declaration directly. The empty unbound advertisement still gives no selected mode and no choices; native advertisements retain the original option objects. Selection now calls the configuration owner directly, as described below; all native request and response fences remain. Textual App.current_mode is a different identity and is untouched.

Queue sources consume an inherited view contract

QueueView(ToadNode, metaclass=NativeNodeMeta) declares the actual source-bound queue capabilities; Conversation inherits it instead of separately naming ToadNode. QueueSource, native/BUS policies and WireSource use this contract, deleting submission_queue.py's guarded dependency on the complete Conversation implementation.

Native readiness/model/original-thread admission remains the same short-circuit expression, now on the view that owns those fields. Native busy/queue-support checks and BUS MRO precedence remain unchanged. Mailbox service capture still constructs partial with the original bound transcript-scope method before obtaining the default observation callback. The view exposes that bound method as a property; it does not defer looking up a mutable current scope until invocation. A preliminary unpublished hook would have made that mistake; the source trace caught it and it was corrected before this commit.

The eight-module NRA before-map, receiver-normalized AST comparisons and unchanged session_scope.py bytes preserve the default observation callback, transcript membership, native admission and original root/source checks. Cold import18 passed both authorized orders with concrete Conversation. These proofs do not substitute for the affected queue application journey.

Compaction carries its existing declared request intact

CompactCommand now stores a CompactRequest; parsing performs the same strip-or-None normalization and constructs that request once. AgentConnection, ACP Agent, Conversation and AgentController pass the object intact instead of unpacking and restating optional instructions across seven method signatures. The Core request declaration and wire schema are unchanged. Default/no-native refusals and the valid-request authority capture/operation/confirmation ordering remain unchanged.

Intentional invalid-input behavior change: overlong instructions now raise from command parsing instead of later from the controller worker. This is not claimed to preserve invalid-input timing or the earlier progress flash. No validation was removed or weakened. The same request constructor still enforces its existing 2000-character normalized limit.

The eight-module before-map and eight method-body comparisons are retained in compaction-request-11-before.json and compaction-request-11/preservation.json. The correction is five files,+20/-16. The owned Textual checkout was advanced to9e36a681 before rebasing onto current Toad main; no borrowed checkout or installed package was edited. Cold19 passed both authorized import orders with concrete Conversation,3.715s/3.857s. This is source/import evidence, not compaction application acceptance; the existing turn-publication control does not exercise the new command-request path.

Submission lifetime is inherited

The per-view helper is gone. ConversationSessionBinding inherits ConversationSubmissions(QueueView, PromptTurnTarget, InputPresentation, DeliveryFailureView); concrete Conversation supplies its leaf hooks and CommsChatView inherits the same lifetime. Transactions and physical publication tasks remain independent. Prompt and queue inspection keep their captured capability references, not a forwarding helper. close_submissions avoids confusing widget lifetime with submission-worker joining.

Command execution moved intact from the catalog to the concrete view; InputPresentation owns the shared abstract posting signature. Actual src/tests/tools callers were migrated without compatibility aliases. New component annotation dependencies remain explicit source-gate work; this is not a claim that the whole gate is green.

The retained before-map has28 modules/225 original classes/153 caller lines. Authored receiver-collapse correspondence checks1,421 functions/methods and four explicit moves; this is not an automatically proved DSL fold or application proof. Prompt document/undo source, original bound callback property and BUS/native base order remain unchanged. Cold21 checks the final source-owning parent placement. Cold20 passed an earlier leaf placement and is not final qualification.

Caller correction after review

Spacing found two tests still calling the deleted catalog executor. Both now call the view's execute_command, with their behavioral assertions unchanged and unused imports removed. Whole-family search additionally found stale helper .view access in Send Now eligibility and the prompt separator. Send Now uses its existing submission capability directly; the regular prompt queries the actual Conversation owning its goal bar. MessagePrompt keeps its no-goal specialization.

HistoryNotifications now declares its existing visibility/target hooks on the native node parent rather than relying on an undeclared method or a cast. Original nine-module/73-class NRA map and both final-parent import orders are saved. These are five changed files, +15/-7; no pytest or local gate ran. The inspected f2c hosted result failed eight categories; the earlier ff3 notification-target type error was gone. The caec hosted gate is now inspected: six guarded-import categories remain; the prior absence and raw-ID growths are gone. The suite was skipped.

Physical01 failed to display its unsent marker and did not reach undo. Subsequent installed-source trace finds the driver issue: Escape in idle Normal leaves the editor; history does not forward printable input in modal mode. Its focus records change to false. This failed driver epoch is not a certificate of product input loss. The separate ordinary export Input defect was subsequently repaired by Textual#232 and #233. A distinct fresh installed physical03 on Core6673220f / Toadc700d077 / Textualdca5859a passed intact h/l typing, real Left/Right movement and Cancel, with exit0 and normal retirement. Failed02 remains unchanged. That installed baseline is not this unmerged Toad candidate and does not settle composer/Neovim, undo or eviction.

Configuration selection has one execution owner

The three ACP Agent setters and four AgentConnection/NoAgentConnection setters are removed. Their actual consumers call ConfigurationSetting.select through configuration.model, .mode and .thinking. The connection family owns only its distinct refusal wording. Source correspondence confirms the original ClientSessionRequest, both authority checks, SDK option/session/value, failure translation and response publication are unchanged. model_info is unchanged too. No aliases or replacement forwarding object were added.

The picker test no longer overrides Toad's Agent.set_model. Its existing external ACP-peer mechanism now supplies catalogue and set-config responses over the SDK, and assertions observe the received requests. The catalogue has one declaration shared with its UI assertions. Unbound/native refusal controls and the updated SDK journey controls are authored, not executed under the standing restriction.

Explicit wording change: an unavailable generic configuration event now also uses its connection's refusal; on an unbound connection that is No agent is bound yet, rather than missing-advertisement wording. Native missing-advertisement feedback and prior model/mode unbound feedback remain the same.

Before-map: 25 modules, 128 classes, 118 caller lines. configuration-source-proof-18.json records final source hashes and correspondence. Both authorized cold23 import orders passed on the candidate with concrete Conversation (4.788s/4.774s, Core6673220f); this is not qualification against later Core builds or an application pass. No pytest or local NRA gate ran.

What was deleted

  • conversation_comms_handlers.py: 188 lines removed; existing behavior is inherited through the conversation family.
  • Unused InputDecision.begin_submission and its accepted/refused overrides, plus duplicate guarded imports: the cleanup checkpoint changed 4 files, +6/-27.
  • Competing mailbox/operational/BUS/failure submission decisions, nullable controller-access decisions and duplicate initialization checks.
  • MessagePrompt's no-op turn refresh; it inherits the actual controls.
  • Old submit_blocks path, duplicate OS literal, duplicate metaclass and the ThreadRead re-export path. All traced callers use their owning declarations.
  • Dead observed_thread() after the complete caller search; original root/birth assertions remain.

Evidence — separate epochs, not one blanket green run

Artifacts are under /home/ts/.cache/agent-scratch/pi-toad-errors/delivery-owned/. Prior PR text is retained in toad-a827-current-14.json; earlier bodies, failed roots and original inputs remain intact.

Evidence Actual result and limit
Original census 85 files / 17,016,557 bytes; 13 protocol logs / 72 tracebacks. Already-main repairs were identified as already fixed, not claimed as new work.
Combined04 Core 9/9 passed, 38.55s. Toad 23 collected / 22 passed before aggregate 300s INT. Not all green.
Remaining05 Separate final handoff/SDK selection: 2/2 passed, 44.88s, rc0.
BUS presentation06 / binding07 Separate 2/2 passes, 33.79s / 33.98s. Not broader source typing or installed acceptance.
Session-binding08 9/9 passed, 84.54s; scoped typing 0 errors / 3 files.
Title-policy03 5/5 passed, 68.03s, including original project/rename/replacement assertions and original SDK resume persistence. The earlier strict `str
Publication11 Failed before collection: wrong Textual checkout lacked DeclaredKey. Corrected by allocating the owned current dependency, not editing live packages.
Publication12 Failed before collection: Core's pytest-only --integration-lease argument was unsupported by Toad's collector. Parent lease ownership remained required.
Publication13 14 collected / 14 passed, rc0; pytest 164.05s, process 167.591s. Exact unchanged sources: Toad a827ea60c, Core 592aa58583c2, Textual 06317bf1. Captured binding/output, recorded history, recipient fencing, stream boundaries and superseded replies. Not installed journey evidence.
Cold import15 Both authorized fresh orders returned rc0 (3.791s / 3.812s), including concrete Conversation assertion. This checks the new login import/MRO boundary, not the application journey.
Login source07 NRA class/base/hash map plus AST equality of both prepare_login effect bodies. Fetch/rebase/push/remote identity verified at d9c36262475d.
Publication envelope08 NRA class/base/hash/admission map and explicit preservation of publisher/session fences. Fetch/rebase/push/remote verified at 2c6980adf406. Cold import16 completed both orders rc0, 3.404s/3.452s.
Mode projection09 Seven-module NRA before-map, complete src/tests/tools caller search, unchanged configuration-owner bytes, migrated assertions and inspected six-file diff. Fetch/rebase/push/remote verified at 9b7eb0d4392e. The affected SDK journey has not run for this correction; its path is tests/textual/test_acp_client_requests.py.
Queue view10 5 files,+75/-31; eight production-module before-map, source-preservation checks passed, push/remote verified at 9eec1006d31e. Cold import18: both orders rc0,3.451s/3.232s. Cold17's earlier pass predates the final bound-method correction and is retained, not treated as final qualification.
Compaction request11 Published848f54c0b5b8,5files,+20/-16; eight method-body substitutions and unchanged Core declaration verified. Cold19 both orders rc0,3.715s/3.857s. Invalid argument validation intentionally occurs earlier; no application run claimed.
Last inspected hosted gate Exact current head caec50b1a901, run 41575993766: NRA failed; suite skipped. Six guarded-import categories remain: ACP Agent +2, AgentProcess +1, AgentSession +1, CoordinationAttachment +1, AgentPresentation +1, ConversationSubmissions +5. AgentConnection absence growth is now0 and raw-ID annotations fall3→0 against main. No current-head green gate or application acceptance is claimed.
Submission inheritance12 Publishedff3e49de4804,22files,+211/-184;1,421 source-body correspondences/four explicit moves. Cold21 both orders rc0,3.743s/3.391s, concrete Conversation. New head's hosted gate not inspected; no candidate application run. Installed-baseline physical01 failed in the observation driver and remains preserved separately.
Configuration owner17 Publishedcaec50b1a901,10files,+92/-78; seven product setters and the fake picker override removed. Native selection request/response tail unchanged; both cold23 orders passed on Core6673220f. New external-peer/refusal controls remain unexecuted.
Ordinary Input physical03 Textual#233 merge dca5859a installed with Core6673220f/Toadc700d077; fresh literal text, real arrows and Cancel passed, exit0 and normal private-root/terminal/display retirement. Not the unmerged1389 candidate or composer acceptance. Report: /home/ts/.cache/agent-scratch/pi-toad-errors/printable-input-physical-03/result.md.
Historical native-image 3 executed / 2 passed / 1 failed, 109.29s. Original image tool was refused before image I/O; no transport-loss conclusion or replay.

No local NRA gate or full suite was run. Cold imports and source equality do not certify behavior beyond their stated paths. The completed publication selection is not rerun merely for reassurance after rebasing.

Remaining delivery

  1. Finish the remaining declaration-owner findings and inspect the hosted gate on the actual final head.
  2. Obtain exact-source acceptance and land the compatible Toad half; use the existing shared installer, not a competing deployment lane.
  3. Observe the real submission/project/draft/undo/queue/shared-close journey and fresh answered communication.
  4. Native-image and isolated physical acceptance remain unfinished until actually observed.

Assumed

  • Actual acquired SDK schemas and Python3.14; raw external inputs remain foreign until the existing decoder boundary.
  • Original request/source/birth, frozen recipient, ACP destination, history/resume key, writer/waiter, ACK/result/paint and draft intent remain different facts.
  • Source traces cover the current concrete consumers, not arbitrary external subclasses.
  • Test epochs, source acceptance, merge, install, communication, native-image and physical observation are distinct evidence states.
  • Protected user processes, original sessions, failed roots, archives and UNKNOWN inputs stay intact and unreplayed.

Copilot AI balanced review requested due to automatic review settings October 31, 2026 20:31

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.

@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 6 times, most recently from c7923c6 to 7517cad Compare November 1, 2026 18:56
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 2 times, most recently from 8d7fd15 to 4580932 Compare November 1, 2026 22:22
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 2 times, most recently from 17712cb to ec73e7a Compare November 2, 2026 01:57
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 3 times, most recently from 3269e2c to e052cb7 Compare November 2, 2026 08:20
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 7 times, most recently from 33bf010 to e39cc59 Compare November 2, 2026 15:01
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

debt-src at edaf586 blocks on 13 lines:

grew NoneAbsence:src/toad/acp/session_agent.py +2
found NoneAbsence:src/toad/acp/session_agent.py at src/toad/acp/session_agent.py:63 src/toad/acp/session_agent.py:59
introduced BroadSwallow:src/toad/submission_queue.py at lines [121]
introduced NoneAbsence:src/toad/acp/agent.py at lines [115, 164, 207, 212, 216]
introduced NoneAbsence:src/toad/acp/agent_controller.py at lines [60, 62, 67, 144]
introduced NoneAbsence:src/toad/acp/agent_process.py at lines [38, 40, 41, 275, 287, 288, 288, 289, 293, 324, 325]
introduced NoneAbsence:src/toad/acp/agent_session.py at lines [64, 66, 69, 141, 329]
introduced NoneAbsence:src/toad/acp/client_session.py at lines [30]
introduced NoneAbsence:src/toad/acp/session_agent.py at lines [59, 63]
introduced NoneAbsence:src/toad/agent_presentation.py at lines [30]
introduced NoneAbsence:src/toad/conversation_submission.py at lines [403]
introduced NoneAbsence:src/toad/core/events.py at lines [96]
introduced NoneAbsence:src/toad/widgets/conversation.py at lines [903, 1517, 1541, 1684, 1769]
Warn-only, never blocks (54)
src/toad/acp/agent_controller.py: LintFindings +2
src/toad/acp/agent_process.py: LintFindings +1
src/toad/acp/comms_updates.py: LintFindings +1
src/toad/acp/coordination_attachment.py: LintFindings +1
src/toad/acp/session_agent.py: LintFindings +1
src/toad/acp/thread_read.py: LintFindings +1
src/toad/acp/tool_source.py: LintFindings +1
src/toad/agent_binding.py: LintFindings +1
src/toad/conversation_turn.py: LintFindings +1
src/toad/input_decision.py: LintFindings +1
src/toad/textual_colours.py: LintFindings +1
src/toad/transcript_preparation.py: LintFindings +1
src/toad/transcript_read_scope.py: LintFindings +5
src/toad/wire_history.py: LintFindings +1
src/toad/acp/coordination_attachment.py: Unformatted +1
src/toad/acp/initialization.py: Unformatted +1
src/toad/acp/session_agent.py: Unformatted +1
src/toad/acp/session_disposition.py: Unformatted +1
src/toad/acp/thread_read.py: Unformatted +1
src/toad/acp/tool_source.py: Unformatted +1
src/toad/agent.py: Unformatted +1
src/toad/failure_presentation.py: Unformatted +1
src/toad/message_destination.py: Unformatted +1
src/toad/native_node_meta.py: Unformatted +1
src/toad/queue_capability.py: Unformatted +1
src/toad/shell_output.py: Unformatted +1
src/toad/transcript_read_scope.py: Unformatted +1
found LintFindings:src/toad/acp/agent_controller.py at src/toad/acp/agent_controller.py:41 (I001 [*] Import block is un-sorted or un-formatted) src/toad/acp/agent_controller.py:294 (SIM102 Use a single `if` statement instead of nested `if` statements)
found LintFindings:src/toad/acp/agent_process.py at src/toad/acp/agent_process.py:2 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/acp/comms_updates.py at src/toad/acp/comms_updates.py:3 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/acp/coordination_attachment.py at src/toad/acp/coordination_attachment.py:2 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/acp/session_agent.py at src/toad/acp/session_agent.py:6 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/acp/thread_read.py at src/toad/acp/thread_read.py:2 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/acp/tool_source.py at src/toad/acp/tool_source.py:2 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/agent_binding.py at src/toad/agent_binding.py:33 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/conversation_turn.py at src/toad/conversation_turn.py:3 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/input_decision.py at src/toad/input_decision.py:2 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/textual_colours.py at src/toad/textual_colours.py:11 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/transcript_preparation.py at src/toad/transcript_preparation.py:3 (I001 [*] Import block is un-sorted or un-formatted)
found LintFindings:src/toad/transcript_read_scope.py at src/toad/transcript_read_scope.py:2 (I001 [*] Import block is un-sorted or un-formatted) src/toad/transcript_read_scope.py:15 (B008 Do not perform function call `LatestPage` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable) src/toad/transcript_read_scope.py:15 (B008 Do not perform function call `AtFrontier` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable) src/toad/transcript_read_scope.py:16 (B008 Do not perform function call `LivePageSource` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable) src/toad/transcript_read_scope.py:21 (B008 Do not perform function call `LatestPage` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable)
found LintFindings:src/toad/wire_history.py at src/toad/wire_history.py:13 (F401 [*] `functools.partial` imported but unused) src/toad/wire_history.py:68 (F401 [*] `toad.widgets.conversation.Conversation` imported but unused)
found Unformatted:src/toad/acp/coordination_attachment.py at src/toad/acp/coordination_attachment.py:1 (Black would reformat this file)
found Unformatted:src/toad/acp/initialization.py at src/toad/acp/initialization.py:1 (Black would reformat this file)
found Unformatted:src/toad/acp/session_agent.py at src/toad/acp/session_agent.py:1 (Black would reformat this file)
found Unformatted:src/toad/acp/session_disposition.py at src/toad/acp/session_disposition.py:1 (Black would reformat this file)
found Unformatted:src/toad/acp/thread_read.py at src/toad/acp/thread_read.py:1 (Black would reformat this file)
found Unformatted:src/toad/acp/tool_source.py at src/toad/acp/tool_source.py:1 (Black would reformat this file)
found Unformatted:src/toad/agent.py at src/toad/agent.py:1 (Black would reformat this file)
found Unformatted:src/toad/failure_presentation.py at src/toad/failure_presentation.py:1 (Black would reformat this file)
found Unformatted:src/toad/message_destination.py at src/toad/message_destination.py:1 (Black would reformat this file)
found Unformatted:src/toad/native_node_meta.py at src/toad/native_node_meta.py:1 (Black would reformat this file)
found Unformatted:src/toad/queue_capability.py at src/toad/queue_capability.py:1 (Black would reformat this file)
found Unformatted:src/toad/shell_output.py at src/toad/shell_output.py:1 (Black would reformat this file)
found Unformatted:src/toad/transcript_read_scope.py at src/toad/transcript_read_scope.py:1 (Black would reformat this file)

@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch from 86fb945 to b6984d2 Compare November 2, 2026 16:38
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch 6 times, most recently from f2c2c5d to caec50b Compare November 3, 2026 04:05
@trissim
trissim force-pushed the work/pi-toad-errors--7425ce3d67d94062967e2f4208730b62--toad branch from 3b4afcc to 718c5f1 Compare November 3, 2026 08:52
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