Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions .verification/viewed-object-repair/author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import json
from pathlib import Path
root=Path.cwd(); ops=[]
def patch(f,t,o,n): ops.append(dict(operation='patch_target',file_path=str(root/f),target_qualname=t,replacements=[dict(old_source=o,new_source=n)]))
def insert(f,t,s): ops.append(dict(operation='insert_before_target',file_path=str(root/f),target_qualname=t,source=s))
def imp(f,s): ops.append(dict(operation='ensure_import',file_path=str(root/f),import_source=s))
f='src/toad/forms/editors.py'
imp(f,'from ui_theme.scheme import MutedColour')
insert(f,'ValueEditor.control_mounted',''' @property
def previewing(self) -> bool:
"""The raw field inherits; its resolved value is only a preview."""
return self.field.state.parameters[self.field.path.value] is None and self.field.value is not None

def paint_value(self) -> None:
self.paint()
self.styles.color = self.app.colours.colour(MutedColour) if self.previewing else None
self.styles.text_style = "dim" if self.previewing else ""

''')
patch(f,'ValueEditor.control_mounted','self.call_after_refresh(self.paint)','self.call_after_refresh(self.paint_value)')
insert(f,'LineEditor.control_arguments',''' def current_text(self) -> str:
return "" if self.previewing else self.value_text(self.field.value)

''')
patch(f,'LineEditor.control_arguments',''' "value": self.value_text(self.field.value),''',''' "value": self.current_text(),
"placeholder": self.value_text(self.field.value) if self.previewing else self.field.placeholder,''')
patch(f,'LineEditor.finish','self.value == self.value_text(self.field.value)','self.value == self.current_text()')
patch(f,'LineEditor.paint',''' self.value = self.value_text(self.field.value)''',''' self.placeholder = self.value_text(self.field.value) if self.previewing else self.field.placeholder
self.value = self.current_text()''')
patch(f,'SelectEditor.control_arguments',''' listed = any(value == choice for _, choice in options)''',''' listed = not self.previewing and any(value == choice for _, choice in options)''')
patch(f,'SelectEditor.control_arguments',''' "prompt": self.field.placeholder if value is None else str(value),''',''' "prompt": next((label for label, choice in options if choice == value),
self.field.placeholder if value is None else str(value)),''')
patch(f,'SelectEditor.paint',''' self.value = value if self.lists(value) else Select.NULL''',''' self.value = value if not self.previewing and self.lists(value) else Select.NULL''')
f='src/toad/forms/form_view.py'
patch(f,'FormView.values_changed','editor.paint()','editor.paint_value()')
f='src/toad/object_configuration.py'
insert(f,'ObjectSettingField.edit',''' def reset(self) -> None:
"""The writer resets its actual parameter to that parameter's signature default."""
state = self.state if self.allows_override else self.state.defaults
state.reset_parameter(self.path.value)
if state is self.state.defaults:
self.state.global_settings.save_sync()

''')
f='src/toad/forms/object_configuration.py'
patch(f,'InheritSettingButton', '''class InheritSettingButton(ActingButton):
def __init__(self, field):
super().__init__("Override here")
self.field = field

async def act(self):
if self.field.state.parameters[self.field.path.value] is None:
self.field.edit(self.field.value)
else:
self.field.state.reset_parameter(self.field.path.value)''','''class ResetSettingButton(ActingButton):
"""Reset uses the parameter's own signature, including lazy None defaults."""
def __init__(self, field):
super().__init__("Reset")
self.field = field

async def act(self):
self.field.reset()''')
patch(f,'ObjectValueView.__init__','self.inherit = InheritSettingButton(field)','self.reset = ResetSettingButton(field)')
patch(f,'ObjectValueView.compose','yield self.inherit','yield self.reset')
patch(f,'ObjectValueView.mark', ''' self.inherit.display = local
self.inherit.label = "Use global default" if explicit else "Override here"''',''' if self.editor.is_mounted:
self.editor.paint_value()''')
Path('.verification/viewed-object-repair/preview.plan.json').write_text(json.dumps({'recipes':[{'recipe_id':'paint-inherited-previews-and-reset-the-original-parameter','operations':ops}]},indent=2))
64 changes: 64 additions & 0 deletions .verification/viewed-object-repair/consumer.plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"recipes": [
{
"recipe_id": "exercise-the-original-view-menu-and-original-writers",
"operations": [
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " assert not field_view.inherit.display",
"new_source": " assert field_view.reset.label.plain == 'Reset' "
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " assert state.fields.ui.column_width == 83\n state.field('ui.column_width').edit(91)",
"new_source": " assert state.fields.ui.column_width == 83\n width = next(part for part in menu.query(ObjectValueView)\n if part.field.path.value == 'ui.column_width')\n await ui.until(lambda: width.editor.placeholder == '83', why='inherited width preview')\n assert width.editor.value == '' and width.editor.previewing\n width.editor.value = '83'\n width.editor.finish()\n assert state.parameters['ui.column_width'] == 83\n assert not width.editor.previewing\n state.field('ui.column_width').edit(91)"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " state.reset_parameter('ui.column_width')\n assert state.fields.ui.column_width == 85",
"new_source": " await width.reset.act()\n assert state.parameters['ui.column_width'] is None\n assert state.fields.ui.column_width == 85\n await ui.until(lambda: width.editor.placeholder == '85', why='reset restores lazy preview')\n assert width.editor.value == '' and width.editor.previewing"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " workspace.thread('panel-owner')\n await workspace.bind(native, 'panel-owner')",
"new_source": " peer = workspace.thread('panel-owner')\n from agent_comms.team.pi_rule_gate import PiRedeal\n deal = PiRedeal.of(workspace.comms, peer)\n deal.start()\n await workspace.bind(native, 'panel-owner')"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " relationships.widget._visible()\n settings_entry",
"new_source": " relationships.widget._visible()\n from toad.widgets.session_thread_panels import SessionPanel\n assert set(SessionPanel.members_with(SessionPanel)) == {\n type(owner) for owner in native_bar._panel_owners}\n from agent_comms.cli_verbs.configure_rule_gate import ThreadRuleGateCliCommand\n from toad.configured_view import ActionProperties\n await ui.until(lambda: any(isinstance(entry.widget, ActionProperties)\n and entry.widget.definition.declaration is ThreadRuleGateCliCommand\n for entry in native_menu.entries), why='original rule-gate configuration')\n gate_entry = next(entry for entry in native_menu.entries\n if isinstance(entry.widget, ActionProperties)\n and entry.widget.definition.declaration is ThreadRuleGateCliCommand)\n native_menu.picker.value = gate_entry\n await ui.until(lambda: gate_entry.widget.is_mounted and bool(gate_entry.widget.form.values),\n why='original backend rule-gate form')\n from agent_comms.team.rule_deal import RuleGateSettings\n from dataclasses import fields\n assert set(gate_entry.widget.form.values) == {field.name for field in fields(RuleGateSettings)}\n from toad.widgets.comms_command_dialog import CommandPreparation\n await ui.until(lambda: not CommandPreparation.running_on(gate_entry.widget), why='gate choices loaded')\n gate_entry.widget.form.values['read_batch'].editor.value = '7'\n await gate_entry.widget.confirm()\n await ui.until(lambda: deal.current().read_batch == 7, why='original gate writer saves settings')\n dm = await ui.open_direct('panel-owner', actor=workspace.viewer)\n dm_view = app.workspace_sessions.require(dm)\n dm_bar = await ui.revealed(dm_view.thread_sidebar)\n dm_menu = dm_bar.query_one(PanelMenu)\n dm_relationships = next(entry for entry in dm_menu.entries\n if isinstance(entry.widget, ThreadCommsSidebar))\n dm_menu.picker.value = dm_relationships\n await ui.until(lambda: dm_relationships.widget.is_mounted, why='DM original relationship panel')\n assert dm_relationships.widget.thread_identity.thread_incarnation() == peer.incarnation\n assert dm_view.thread_identity.thread_name() == workspace.viewer\n await ui.select_tab(original)\n settings_entry"
}
]
}
]
}
]
}
16 changes: 16 additions & 0 deletions .verification/viewed-object-repair/cycle-import.plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"recipes": [
{
"recipe_id": "remove-presentation-dependency-from-conversation-values",
"operations": [
{
"operation": "remove_import_bindings",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/conversation_kind.py",
"bound_names": [
"ThreadIdentity"
]
}
]
}
]
}
58 changes: 58 additions & 0 deletions .verification/viewed-object-repair/cycle.plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"recipes": [
{
"recipe_id": "keep-conversation-subjects-below-panel-presentation",
"operations": [
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/conversation_kind.py",
"target_qualname": "ConversationKind.sidebar_identities",
"replacements": [
{
"old_source": "def sidebar_identities(self, root: str):",
"new_source": "def sidebar_threads(self):"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/conversation_kind.py",
"target_qualname": "DmConversation.sidebar_identities",
"replacements": [
{
"old_source": " def sidebar_identities(self, root: str):\n return (ThreadIdentity(self.peer, root),)",
"new_source": " def sidebar_threads(self):\n return (self.peer,)"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/screens/comms.py",
"target_qualname": "CommsScreen.make_thread_sidebar",
"replacements": [
{
"old_source": "self.conversation.sidebar_identities(self.wire_root)",
"new_source": "self.conversation.sidebar_threads()"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/session_thread_sidebar.py",
"target_qualname": "ConversationThreadSidebar.__init__",
"replacements": [
{
"old_source": " def __init__(self, screen, identities):\n self.identities = identities",
"new_source": " def __init__(self, screen, threads):\n self.identities = tuple(ThreadIdentity(thread, screen.wire_root) for thread in threads)"
}
]
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/session_thread_sidebar.py",
"import_source": "from toad.thread_identity import ThreadIdentity"
}
]
}
]
}
15 changes: 15 additions & 0 deletions .verification/viewed-object-repair/cycle_author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import json
from pathlib import Path
r=Path.cwd();ops=[]
def p(f,t,a,b):ops.append(dict(operation='patch_target',file_path=str(r/f),target_qualname=t,replacements=[dict(old_source=a,new_source=b)]))
def i(f,s):ops.append(dict(operation='ensure_import',file_path=str(r/f),import_source=s))
p('src/toad/conversation_kind.py','ConversationKind.sidebar_identities','def sidebar_identities(self, root: str):','def sidebar_threads(self):')
p('src/toad/conversation_kind.py','DmConversation.sidebar_identities',''' def sidebar_identities(self, root: str):
return (ThreadIdentity(self.peer, root),)''',''' def sidebar_threads(self):
return (self.peer,)''')
p('src/toad/screens/comms.py','CommsScreen.make_thread_sidebar','self.conversation.sidebar_identities(self.wire_root)','self.conversation.sidebar_threads()')
p('src/toad/widgets/session_thread_sidebar.py','ConversationThreadSidebar.__init__',''' def __init__(self, screen, identities):
self.identities = identities''',''' def __init__(self, screen, threads):
self.identities = tuple(ThreadIdentity(thread, screen.wire_root) for thread in threads)''')
i('src/toad/widgets/session_thread_sidebar.py','from toad.thread_identity import ThreadIdentity')
Path('.verification/viewed-object-repair/cycle.plan.json').write_text(json.dumps({'recipes':[{'recipe_id':'keep-conversation-subjects-below-panel-presentation','operations':ops}]},indent=2))
24 changes: 24 additions & 0 deletions .verification/viewed-object-repair/delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# P219 source checkpoint

Original viewed-object consumer passed 1/1 in 13.50s, exit 0:
/home/ts/.cache/agent-scratch/codex-latency/viewed-object-repair/consumer-4.log

It checks lazy inherited placeholder text, typing the same inherited value as an explicit override, upstream changes preserving the override, Reset returning to raw None and the current inherited preview, global-field saves, separate channel/file identities, shared context editor state, actual changing ACP advertisements, every original native SessionPanel member, a real rule-gate form and its original backend write, DM peer birth versus actor identity, and hidden-panel observation lifecycle.

## Applied owners

- ConfigurationCommand membership stays on the existing Core configuration commands. ConfigureCliCommand now uses the original named target/action contracts and its unchanged writer; ThreadConfiguredResult uses the target-edit result contract.
- CommandForm owns preparation and submission in modal and sidebar presentations. Both use ThreadAction.submit. Native constraints stay on the original command decoder rather than being copied onto the encoded text draft.
- ThreadDetailsPanel shares the existing diagnostics/relationship declarations with DM views. ThreadIdentityScope keeps the panel subject separate from the sender; current/retired references retain peer identity. Native context/project/plan owners remain intact.
- ValueEditor derives preview styling from original raw/resolved values; no override flag or second resolved store. Reset uses ObjectState.reset_parameter on the original writer. The Override here switch is deleted.

## Red history retained

consumer.log: helper could not move fds above the shell's 1024 limit; no UI proof.
consumer-2.log: preview style used an invalid empty flag; newly declared peer then missed by a registry read after the app observer started. Store failure reported to claude-laptop as message b65fcca1edb0. The peer fixture is now declared before opening the app.
consumer-3.log: numeric native constraints were incorrectly applied to editor text; rule-gate write refused. Fixed at the shared encoded-editor boundary, preserving original command decoding/validation.
consumer-4.log: passed.

Cold Toad/Core import and MRO passed; original panel family lists all five members and its two shared thread-details members. Native plans and apply logs retained. Existing unrelated guarded annotations remain unchanged; the touched lazy CommandDialog import was promoted to a module import with cold import proof.

No installed or physical-success claim at this checkpoint. No total CPU claim. No subagent, profiling, broad suite or provider request.
Loading
Loading