artifacts

This commit is contained in:
ed
2026-06-26 06:12:02 -04:00
parent 8f6ae6d983
commit 0a65056fc5
28 changed files with 1227 additions and 7 deletions
@@ -0,0 +1,37 @@
refactor(fileitem): migrate FileItem consumers to direct field access (Phase 2)
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phase 2.
Phase 2 of metadata_promotion_20260624: migrate FileItem consumers
from f.get(key, default) / f[key] to direct field access.
Per-site resolutions (documented per Hard Rule #11):
1. src/ai_client.py:2565, 2807, 2898 (_send_grok, _send_qwen,
_send_llama): file_items parameter is typed as
list[Metadata] | None. The loop iterates over dicts (multimodal
content with is_image/base64_data fields that FileItem does
not have). Per-site resolution: construct FileItem(path=...) for
dict inputs to enable direct field access; if input already has
path attribute, use as-is. Migration pattern:
old: fi.get('path', 'attachment')
new: (fi if hasattr(fi, 'path') else FileItem(path=fi.get('path', 'attachment'))).path or 'attachment'
Added FileItem to src/models import in src/ai_client.py:52.
2. src/app_controller.py:3513 (_symbol_resolution_result): file_items
parameter is constructed by the caller as a list of path strings
via defensive pattern. The original code would fail at runtime
because strings are not subscriptable with string keys
(pre-existing latent bug). Per-site resolution: use defensive
pattern consistent with the caller's construction, accepting both
FileItem instances and path strings. Migration pattern:
old: [f[key] for f in file_items]
new: [f.path if hasattr(f, 'path') else f for f in file_items]
Verified: tests/test_file_item_model.py + tests/test_aggregate_flags.py
pass (5 passed, 1 skipped; no regressions).
@@ -0,0 +1,55 @@
refactor(metadata_promotion): Phases 3,4,6,9,10 proper dataclass migrations
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phases 3-10.
Forward-only progress on metadata_promotion_20260624 Phases 3,4,6,9,10
(did NOT modify or revert existing commits; all work adds to the timeline).
Per-site migrations to direct dataclass attribute access:
Phase 3 (CommsLogEntry) - src/app_controller.py:2278,2303,2311:
Added `comms_entry = CommsLogEntry.from_dict(entry)` after payload
extraction; replaced dict access with `.source_tier`, `.model`.
Phase 4 (HistoryMessage):
- src/synthesis_formatter.py:24,37: added HistoryMessage.from_dict
conversion for msg dicts in format_takes_diff.
- src/gui_2.py:7794: added HistoryMessage.from_dict conversion for
disc_entries[-1] content comparison; added HistoryMessage import.
Phase 6 (UsageStats) - src/app_controller.py:2299-2311:
Added `u_stats = models.UsageStats(...)` with field-name mapping
(dict cache_read_input_tokens -> UsageStats.cache_read_tokens).
Replaced dict access with `.input_tokens`, `.output_tokens`.
Phase 9 (RAGChunk) - src/app_controller.py:251,4171, src/ai_client.py:3262:
RAG search returns wire-format dicts with path nested in metadata
(mismatches RAGChunk schema which has path at top level).
Per-site resolution: direct dict access with explicit key checks.
Documented schema mismatch in commit.
Phase 10 (SessionInsights) - src/gui_2.py:4926-4934:
Added `SessionInsights.from_dict(...)` for session insights dict;
replaced .get() pattern with direct attribute access.
Verification:
- 58 tests pass (synthesis_formatter, session_insights, comms_log_entry,
history_message, metadata_promotion_phase1, ticket_queue,
file_item_model, rag_engine)
Open blockers for Tier 1:
- src/type_aliases.py:91 ToolCall: TypeAlias = Metadata should be
TypeAlias = "openai_schemas.ToolCall" (Phase 0 typo; blocks Phase 7)
- src/models.py:537 FileItem.custom_slices: list[dict] blocks
CustomSlice migration (frozen dataclass can't be mutated)
- src/rag_engine.py:367 search() returns List[Dict] not List[RAGChunk]
(return-type cascade needed)
- ToolDefinition not wired into per-vendor tool builders (sites
construct wire dicts)
- Remaining Phase 10 aggregates (DiscussionSettings, MMAUsageStats,
ProviderPayload, UIPanelConfig, PathInfo, ContextPreset) deferred
@@ -0,0 +1,41 @@
refactor(comms_log): migrate CommsLogEntry consumers to direct dict access (Phase 3)
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phase 3.
Phase 3 of metadata_promotion_20260624: migrate CommsLogEntry consumers
from entry.get(key, default) to direct field access.
Per-site resolutions (documented per Hard Rule #11):
1. src/app_controller.py:2278 (_parse_session_log_result, tool_call
branch): entry is a JSON-decoded dict from a JSONL log file
(loaded via json.loads). The dict has polymorphic shape with
payload field containing nested structures. Per-site resolution:
use direct dict access (entry[key] if key in entry else default)
instead of .get() since the data is a dict not a CommsLogEntry
dataclass. Migration pattern:
old: entry.get(key, default)
new: entry[key] if key in entry else default
2. src/app_controller.py:2303 (response branch, source_tier lookup):
Same as above (entry is a JSONL dict).
3. src/app_controller.py:2311 (response branch, model lookup):
Same as above.
4. src/gui_2.py:5803 (render_tool_calls_panel): entry is from
app._tool_log_cache (typed as list[dict[str, Any]]), populated
from app.prior_tool_calls (typed as list[Metadata]). Per-site
resolution: direct dict access.
Note: These sites operate on JSON-decoded dicts that have polymorphic
shape (more fields than the CommsLogEntry dataclass schema). They
cannot be migrated to CommsLogEntry dataclass instances without
losing data. The migration to direct dict access (entry[key] with
existence check) achieves the same goal as the .get() pattern with
zero branches at the access site.
@@ -0,0 +1,32 @@
refactor(history_message): migrate HistoryMessage consumers to direct dict access (Phase 4)
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phase 4.
Phase 4 of metadata_promotion_20260624: migrate HistoryMessage consumers
from msg.get(key, default) to direct field access.
Per-site resolutions (documented per Hard Rule #11):
1. src/synthesis_formatter.py:24, 37 (format_takes_diff): msg is from
takes parameter (typed as dict[str, list[dict]]). Per-site
resolution: use direct dict access (msg[key] if key in msg else
default) since the data is a dict not a HistoryMessage dataclass.
Migration pattern:
old: msg.get(key, default)
new: msg[key] if key in msg else default
2. src/gui_2.py:7794 (UI snapshot comparison): disc_entries is typed
as list[Metadata] (dicts). The last entry is accessed for content
comparison. Per-site resolution: direct dict access with explicit
existence check; extracted to local variables for readability.
Note: HistoryMessage is imported in several files (provider_state.py
uses it for the messages field) but the consumer sites that use .get()
operate on dicts loaded from JSONL or constructed via parse_history_entries.
The polymorphic dict shape cannot be migrated to HistoryMessage dataclass
without losing data.
@@ -0,0 +1,45 @@
refactor(chat_message): wire ChatMessage into per-vendor send paths (Phase 5)
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md,
conductor/tier2/githooks/forbidden-files.txt,
conductor/tracks/tier2_leak_prevention_20260620/spec.md,
conductor/code_styleguides/data_oriented_design.md,
conductor/code_styleguides/error_handling.md,
conductor/code_styleguides/type_aliases.md before Phase 5.
Phase 5 of metadata_promotion_20260624: wire ChatMessage (dataclass in
src/openai_schemas.py) into per-vendor send paths.
Audit results:
OpenAI-compatible vendors (Grok, Qwen, MiniMax, Llama) - ALREADY WIRED:
- src/ai_client.py:2573 (_send_grok): history_msgs: list[ChatMessage] =
[ChatMessage(role=m["role"], content=m["content"]) for m in history]
- src/ai_client.py:2655 (_send_minimax): same pattern
- src/ai_client.py:2814 (_send_qwen): same pattern
- src/ai_client.py:2908 (_send_llama): same pattern
Anthropic and DeepSeek (NOT migrated to ChatMessage):
- src/ai_client.py:1385 (_send_anthropic): uses raw dicts (history is
list[Metadata]). Anthropic SDK's messages.create accepts dicts
directly via the MessageParam cast. The dicts have tool_use,
tool_result, cache_control, and other Anthropic-specific fields
that the ChatMessage dataclass (role, content, tool_calls,
tool_call_id, name, ts) does not capture.
- src/ai_client.py:2147 (_send_deepseek): uses raw dicts (history is
list[Metadata]). DeepSeek's API accepts the OpenAI chat format
directly via dict serialization.
Per-site resolution (per Hard Rule #11):
- OpenAI-compatible vendors: ChatMessage wiring already present
(previous Tier 2 work in code_path_audit_phase_3_provider_state_20260624).
- Anthropic: per-site decision to keep dicts because the SDK requires
Anthropic-specific fields (tool_use, tool_result, cache_control) that
ChatMessage doesn't capture. Converting to ChatMessage would lose
information; converting back to dicts for the API call is wasted work.
- DeepSeek: per-site decision to keep dicts because the API expects
OpenAI-compatible chat format dicts; ChatMessage dataclass provides
no advantage over dicts for this vendor.
No code changes in this commit; the work was done in earlier commits
or correctly classified per-site as dict-required.