Skip to content

Let structural field representations own their behavior - #2966

Merged
trissim merged 6 commits into
refactor/id128-nominal-typefrom
fix/producer-digest-value-types
Oct 24, 2026
Merged

trissim merged 6 commits into
refactor/id128-nominal-typefrom
fix/producer-digest-value-types

Conversation

@trissim

@trissim trissim commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

StructuralRepresentation owns the absence of a field representation: it selects structural projection, schema and decoding and contributes no codec owners. Represented members own the other behavior. The zero-or-one tuple and every representation presence probe from 7f04146 are deleted.

Head d0a24e2f7de1330de0f2a157c665ea611b71536f, base refactor/id128-nominal-type, following merged #2945 on its original branch. Reviewer's requested InputId.mint fixture change is included. src/ and tools/ are byte-identical to the checked source head 5c41d99b8f816f0bdc18d342e9b810deb3fd2136; the final commit changes only tests/test_selected_tool_broker.py.

Final implementation

  • FieldRepresentation and StructuralRepresentation own for_value, project_view, producer_owners, decoder_for and schema_for. project_view avoids the existing claim family's unrelated project methods. Structural schema behavior lives directly on StructuralRepresentation, eliminating the extra FieldCodec forwarding method; FieldCodec has 46 direct methods, equal to main.
  • ValueDecoder._registered returns all registered candidates in precedence order. annotation_class refuses an empty candidate list; represented_class declares scalar decoding for a representation without a registered structural decoder. No new or moved KeyError catch.
  • TextStorage keeps its declared TextRepresentation capability check. ProducedTable keeps annotations:list[object] and asks each representation for its producer owners.
  • WakeClaim and SelectedWriteIntent retain MessageId source fields; selected-write submission and selected_turn decode their str inputs once. The three WakeClaim fixtures mint IDs; Reviewer's one selected-tool owner fixture now uses InputId.mint.
  • The carry decodes and encodes the complete WakeClaim, returning a context-typed dict display. A malformed record gets the file and original payload added to its exception, then is re-raised. Only this explicitly named carry file was formatted.
  • FieldCodec.record_data remains deleted: no callers; the literal grep matched a compiled cache and the unrelated test function name test_refused_record_data_raises_the_declared_error.

A: presence-probe grep

grep -rnE "representation\)? (is|is not) None|or FieldRepresentation|sys\.exception\(\)" src tools
# no output

B: exact requested debt commands

Executed nice 19 with timeout 300 and PYTHONPATH=src:tools. Final source revision 5c41d99; HEAD's src/tools diff against it is empty, so the test-only final commit does not change either measured tree.

python tools/debt_ratchet.py --root src --base origin/main --head HEAD
grew NoneAbsence:src/agent_comms/turn_input_source.py +1
introduced NoneAbsence:src/agent_comms/turn_input_source.py at lines [48, 90]
# exit 1: only the explicitly allowed TurnAcceptance.controller finding

python tools/debt_ratchet.py --root tools --base origin/main --head HEAD
# no findings, exit 0

No other finding remains. No baseline, exemption or pragma changed. No test suite or test replay ran.

Ruff check ran on all 145 Python files returned by git diff --name-only origin/main -- '*.py': 1,159 findings overall in inherited/untouched code, zero on the final changed lines. No whole-file formatting outside the ordered carry file.

KeyError grep

Before, at 86aef8b:

969:        except KeyError:
975:            except KeyError:
1532:        except KeyError:
3180:    except KeyError:
3188:    except KeyError:

After:

1638:        except KeyError:
3249:    except KeyError:

The two remaining handlers are unchanged: the spelling member lookup and _structural_decoder. Candidate lookup and represented compilation catch nothing.

Revised C: every actual producer digest change

One script invokes producer_stamp.stamped_digests() on an archive of 86aef8b and the clean checked HEAD source in fresh interpreters. The final test-only commit has identical src/tools. All eleven registered production projection digests differ.

Finding: ten tables have no matching declared codec/value column. Their columns are primitive types and StructuralRepresentation.producer_owners returns (). Their digest changes because ProducedTable is itself an existing hashed owner and its producer_owners source changes here. No narrower hash or hidden owner removes that dependency. MessageIdentitySource additionally reaches FieldRepresentation through its MessageId column.

Projection Column reaching a changed codec/value family 86aef8b Final source
answered_source none; changed ProducedTable ancestor bc57e1d78a849c5becc377632adadfaadf725433f3d3c5f5afa74c31263de694 67504a16bb0180238612b950cd5bd292b2ff3738cddd5b8ca4f6c00d4ba77c62
awaiting_answer_source none; changed ProducedTable ancestor 1403608744e1324ade348c7ac153ee48a42992d848cb0fca14ce1a523c39f1da fda7823abaa3aa012f05dbadab8f3e98d65b48b435632ae38e9a6b1d29064dbb
bus_activity_index none; changed ProducedTable ancestor 75bd85cad57706f53056e3eea84074d797ad4edf8f90e792fb57582a4ce2ed88 f06ffbd5b3ff80a27b906196eaf093d91a3695ac31ce9c4347c27440eeb9dcc5
bus_display_index none; changed ProducedTable ancestor 44eac88cc9389bf74f39b1f7edc34b3116d87eabce4221f25412a768d3804a29 6f18f39634b1761c2d4e0702375f1d1ff7d5468e16f52247cb00153d9784909a
bus_route_counts none; changed ProducedTable ancestor 85eaa85f36105d7428e52da82e5e0ac89eab9c01d9d11996a349395b29cf582d 506e0eb03311f7c90fdd32fec16681fa244882af6fe3309bf4b5f54b84ac3a5f
claim_operations none; changed ProducedTable ancestor cf1e112b8fdaa3a81e17ca0097d5b0d9ec3f211f25dc0cbff495d818db4b72b2 b86ce77c8c59ec32c2e04a3a57f363624a0cc068b9131327be712e09ca3291b1
held_resources none; changed ProducedTable ancestor 01454194b39741d32840c72a021f999365dc9d31f1d14cbe1047ef771d1f74ff 800ccb9dd5792d419c4c0de88929487e61f1613a27ec28a691d09f0bd6de1121
message_identity_source message_id: MessageId → MessageIdText / FieldRepresentation 9e9b97d2d7a20c886fc537d925c769fc0e8486149f25f5eda4e67c370f10a057 a35724a5c3af9b9ff16bad7e9d3533e2d2975383ee4c7a030675bf330f5dcd13
received_source none; changed ProducedTable ancestor a1d6f035d022aa807bd5c0cfd467b451c04140b75f8992601ff685150f465fc2 7dfbfda460b1e74ade3e2c54eb2fe59ccf01c7fe4991c2302f3c249938142d7a
sent_activity none; changed ProducedTable ancestor c9babf5e9a20c633e0fb99840909f9370f6d40a3f5863e6869081dd357a99cab 52887129c322c71fecedbe8db8a48d375ad4407142cb206f87cd0b59f2d0f389
sent_source none; changed ProducedTable ancestor 54ca2824accbe87753a101301a69dbfe9e5ce03d8b26bfc3e731ea28d61ebb96 435ff1037387f6b3e6fc2cf1054d937c0df31991ff327e035f4a3ed036d3e087

Primitive columns for those ten findings:

  • claim_operations: operation_id:str, seq:int
  • held_resources: resource:str, claim_seq:int
  • bus_activity_index: last_message:float, last_user_input:float, target:str
  • sent_activity: sender:str, last_sent:float
  • bus_display_index: last_message:float, last_user_input:float, participant:str
  • sent_source: lookup:str, seq:int
  • received_source: lookup:str, seq:int
  • awaiting_answer_source: lookup:str, seq:int, recipient:str, starts_direct_turn:bool
  • answered_source: original:int, seq:int (its foreign key references MessageIdentitySource.seq)
  • bus_route_counts: seq:int, target:str, sender:str, sender_lookup:str, timestamp:float

Assumed and representation-query callers

  • getsource still hashes each whole producer owner. Changing ProducedTable invalidates every inheriting producer, including primitive-column tables. Existing undeclared helper dependencies are not inferred.
  • Source is immutable while the build computes the cached digest; each source-version comparison starts a fresh interpreter.
  • Existing serialized message IDs satisfy their declared spelling. Malformed carry data refuses with the file and original payload, with no repair path.
  • These direct callers retain the resolved value type and now receive a concrete representation member (AST inventory; no parse omissions in changed modules):
    • field_codec.py:587 — FieldPlan.schema_fields
    • field_codec.py:662 — DeclaredFieldPlan.claims
    • field_codec.py:750 — InlineFieldPlan.inlined
    • field_codec.py:787 — InlineFamilyPlan.claims
    • field_codec.py:1250 — StructuralRepresentation.for_value
    • field_codec.py:2028 — FieldCodec._value_representation
    • field_codec.py:2127 — FieldCodec.decode_record
    • field_codec.py:2249 — FieldCodec.value_schema
    • field_codec.py:2268 — FieldCodec._project_structure
    • field_codec.py:3242 — compile_decoder
    • typed_table.py:188 — TextStorage.accepts
    • typed_table.py:2115 — ProducedTable.producer_owners
  • Source searches found no other direct Core/Toad callers. External reflective consumers are outside this source inventory.

git diff --stat 86aef8b61..HEAD:

 src/agent_comms/envelope_claim_transitions.py |   3 +-
 src/agent_comms/field_codec.py                | 211 +++++++++++++++++---------
 src/agent_comms/selected_turn.py              |   3 +-
 src/agent_comms/selected_write_plan.py        |   6 +-
 src/agent_comms/typed_table.py                |  13 +-
 tests/test_carry_wake_claim_turn_ids.py       |   4 +-
 tests/test_envelope_claim_transitions.py      |   4 +-
 tests/test_selected_tool_broker.py            |   6 +-
 tools/cutover/carry_wake_claim_turn_ids.py    |  44 +++---
 9 files changed, 180 insertions(+), 114 deletions(-)

git diff --stat origin/main...HEAD:

 plans/ID128-NOMINAL-PLAN.md                     |  34 +-
 src/agent_comms/acp_extension.py                |  13 +-
 src/agent_comms/agent_activity.py               |   3 +-
 src/agent_comms/agent_backend.py                |  44 +-
 src/agent_comms/backend.py                      |  80 +--
 src/agent_comms/commander/order.py              |   3 +-
 src/agent_comms/cursor_owner.py                 |   2 +-
 src/agent_comms/cursor_publication.py           |   6 +-
 src/agent_comms/envelope_claim_transitions.py   |  11 +-
 src/agent_comms/field_codec.py                  | 849 ++++++++++++++----------
 src/agent_comms/following_inputs.py             |  13 +-
 src/agent_comms/goal_turn_permit.py             |   4 +-
 src/agent_comms/goals.py                        |   8 +-
 src/agent_comms/historical_native_inputs.py     |   4 +-
 src/agent_comms/input_attempt.py                |   6 +-
 src/agent_comms/input_disposition.py            |   5 +-
 src/agent_comms/input_drain.py                  |  17 +-
 src/agent_comms/installer/launch.py             |   4 +-
 src/agent_comms/maintenance_barrier.py          |   9 +-
 src/agent_comms/manual_compaction_bridge.py     |   4 +-
 src/agent_comms/message_reference.py            |   4 +-
 src/agent_comms/messages.py                     |   6 +-
 src/agent_comms/native_input_record.py          |  27 +-
 src/agent_comms/native_prompt_binding.py        |  14 +-
 src/agent_comms/native_runtime_input.py         |   4 +-
 src/agent_comms/native_turn_context.py          |   4 +-
 src/agent_comms/nk_foreground.py                |   6 +-
 src/agent_comms/ordinary_turn_rules.py          |   4 +-
 src/agent_comms/owned_send.py                   | 151 ++---
 src/agent_comms/owned_turn.py                   |  34 +-
 src/agent_comms/pi_native_backend.py            |   3 +-
 src/agent_comms/plan_phases.py                  |  90 ++-
 src/agent_comms/private_registry_guard.py       |   4 +-
 src/agent_comms/private_send_claim.py           |   3 +-
 src/agent_comms/private_send_stage.py           |  20 +-
 src/agent_comms/proven_source_coverage.py       |   3 +-
 src/agent_comms/publisher.py                    |   4 +-
 src/agent_comms/queued_input.py                 |  27 +-
 src/agent_comms/registration.py                 |  17 +-
 src/agent_comms/registry_store.py               |   4 +-
 src/agent_comms/schedule_rules.py               |   2 +
 src/agent_comms/selected_actions.py             |   4 +-
 src/agent_comms/selected_participant.py         |   4 +-
 src/agent_comms/selected_turn.py                |   7 +-
 src/agent_comms/selected_write_plan.py          |   8 +-
 src/agent_comms/send_outcome.py                 |  45 +-
 src/agent_comms/started_input.py                |  15 +-
 src/agent_comms/task_sources.py                 |   6 +-
 src/agent_comms/thread_identity.py              |  35 +-
 src/agent_comms/threads.py                      |  18 +-
 src/agent_comms/todos.py                        |  10 +-
 src/agent_comms/tracked_turn.py                 |  18 +-
 src/agent_comms/turn_context.py                 |   4 +-
 src/agent_comms/turn_goal_account.py            |   6 +-
 src/agent_comms/turn_input_source.py            | 172 ++++-
 src/agent_comms/turn_inputs.py                  |  69 +-
 src/agent_comms/turn_lease.py                   | 131 ++--
 src/agent_comms/turn_runner.py                  |  10 +-
 src/agent_comms/typed_table.py                  |  24 +-
 src/agent_comms/worker.py                       |   2 +
 tests/goal_stop_journey.py                      |  24 +-
 tests/native_backend_fixture.py                 |  54 +-
 tests/pi_session_turn.py                        |   2 +
 tests/test_absence_owners.py                    |  35 +-
 tests/test_acp.py                               |   5 +-
 tests/test_acp_extension.py                     |  38 +-
 tests/test_acp_queue_contract.py                |  15 +-
 tests/test_active_turn.py                       |  12 +-
 tests/test_activity_text.py                     |  14 +-
 tests/test_agent_backend.py                     |  10 +-
 tests/test_atomic_turn_source_owner.py          |  26 +-
 tests/test_backend.py                           |   8 +-
 tests/test_bus.py                               |  38 +-
 tests/test_bus_files.py                         |   8 +-
 tests/test_bus_history_seq.py                   |   4 +-
 tests/test_carry_wake_claim_turn_ids.py         |  85 +++
 tests/test_channel_bus_ownership.py             |  12 +-
 tests/test_channels.py                          |   4 +-
 tests/test_claim_admission_verifier.py          |   7 +-
 tests/test_claim_bus_read.py                    |  23 +-
 tests/test_cli.py                               |  10 +-
 tests/test_context_manifest_deltas.py           |  35 +-
 tests/test_context_source_inspection.py         |   8 +-
 tests/test_coordination_response.py             |   3 +-
 tests/test_current_input_origin.py              |  77 ++-
 tests/test_declarations.py                      |  32 +-
 tests/test_envelope_claim_transitions.py        |  19 +-
 tests/test_field_codec.py                       |  63 +-
 tests/test_goal_answers.py                      |   6 +-
 tests/test_goal_execution.py                    |   4 +-
 tests/test_goal_failure_observation.py          |   5 +-
 tests/test_goal_input_review.py                 |   6 +-
 tests/test_goal_reply_lock_scope.py             |  17 +-
 tests/test_goal_resume.py                       |   6 +-
 tests/test_goal_standby.py                      |  23 +-
 tests/test_goal_standby_liveness.py             |  41 +-
 tests/test_goal_wait_certified_reply.py         |   5 +-
 tests/test_historical_notifications.py          |  10 +-
 tests/test_history_view_declaration.py          |   3 +-
 tests/test_holder_standing_rules.py             |  18 +-
 tests/test_input_delivery_history.py            |  17 +-
 tests/test_input_disposition.py                 |  73 +-
 tests/test_input_documents.py                   | 197 ++++--
 tests/test_install.py                           |   3 +-
 tests/test_interrupted_delivery_recovery.py     |   3 +-
 tests/test_l0_goal_input_closure.py             |  17 +-
 tests/test_live_drain_failure.py                |   7 +-
 tests/test_maintenance_barrier.py               |  18 +-
 tests/test_mcp_acceptance.py                    |  50 +-
 tests/test_message_notifications.py             |   7 +-
 tests/test_native_channel_reply_roundtrip.py    |   9 +-
 tests/test_native_context_reference.py          |   2 +-
 tests/test_native_retry_exhaustion_installed.py |  12 +-
 tests/test_native_unknown_recovery.py           |   5 +-
 tests/test_observer_death.py                    |   3 +-
 tests/test_optional_awareness_projection.py     |   4 +-
 tests/test_ordinary_admission_rules.py          |   3 +-
 tests/test_owned_turn_goal_replacement.py       |  27 +-
 tests/test_preflight_feedback.py                |  10 +-
 tests/test_private_idle_drain.py                |  15 +-
 tests/test_project_resume.py                    |   8 +-
 tests/test_read_ledger.py                       |   4 +-
 tests/test_registration_authority.py            |  23 +-
 tests/test_registration_inheritance.py          |   5 +-
 tests/test_registration_process_identity.py     |   9 +-
 tests/test_registration_transitions.py          |  11 +-
 tests/test_reservation_rules.py                 |  19 +-
 tests/test_retained_context_operations.py       |   4 +-
 tests/test_roster_restoration.py                |   3 +-
 tests/test_selected_tool_broker.py              |   7 +-
 tests/test_stack_native_compaction.py           |   9 +-
 tests/test_stack_persistent_compaction.py       |  23 +-
 tests/test_task_decisions.py                    |  12 +-
 tests/test_thread_identity.py                   |  20 +-
 tests/test_tool_output.py                       |  24 +-
 tests/test_tracked_native_retry.py              |  24 +-
 tests/test_turn_context_wire.py                 |  14 +-
 tests/test_turn_declaration.py                  |  31 +-
 tests/test_turn_goal_account.py                 |   5 +-
 tests/test_turn_identity_equality.py            |  11 +-
 tests/test_turn_inbox.py                        |   5 +-
 tests/test_turn_lease_release.py                |  16 +-
 tests/test_turn_record.py                       |   7 +-
 tests/test_unscoped_claim_history.py            |  18 +-
 tests/verify_connector_tools.py                 |   6 +-
 tools/cutover/carry_wake_claim_turn_ids.py      |  71 ++
 146 files changed, 2501 insertions(+), 1323 deletions(-)

@trissim
trissim marked this pull request as ready for review October 24, 2026 01:50
Copilot AI balanced review requested due to automatic review settings October 24, 2026 01:50

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.

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.

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