Skip to content

Hash every class that produces projection rows into the projection digest - #2777

Merged
trissim merged 2 commits into
mainfrom
fix/projection-digest-producers
Oct 23, 2026
Merged

trissim merged 2 commits into
mainfrom
fix/projection-digest-producers

Conversation

@trissim

@trissim trissim commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Defect

#2773's projection digest left out the classes whose code decides projection row content: MessageKind.route_rows, the roles' activity_rows, CommandTarget.direct_names, ChannelActivity.from_message, the claim scopes and the response policies. Editing any of them left stale projections marked fresh.

Evidence on main: editing ConversationRole.activity_rows (messages.py) leaves BusProjectionTables._producer_digest() at 3a79e1f3ed68fff9 before and after. On this branch the same edit moves it from ce848e21ba1151ae to e2d495136f7281f3.

Shape

  • One declaration. The ProjectionSource capability (projection_source.py) is declared on the producing classes. Its __init_subclass__ registry is the digest's set.
  • Deleted: ProducedRow.producer_capabilities, ProducedRow.producer_classes and the (family, capability) pairs in messages.py. BusProjectionTables declares only producer_package().
  • DeclaredFamily.discover_package is now public, so the digest can import the package before reading the registry.

How the classes were found

I profiled a full rebuild of a copy of the live bus (19,503 records). 40 classes outside the old digest ran code during production. Each family is marked at its root; the digest has 156 owners, up from 31, and none of the old 31 are lost.

Still outside the digest, on purpose:

  • Mechanism modules: field_codec, typed_table, declared_family, mro_dispatch, core_stamp.
  • Module-level validators: audience_manifest._bounded_text, _canonical_json and _digest, and channel_targets.exact_stored_target. They only raise and never shape row content.

Guard

test_every_class_that_produces_projection_rows_is_in_the_digest profiles a rebuild and fails on any agent_comms class that ran and is not in the digest. With the MessageKind mark removed, it fails and names agent_comms.messages.MessageKind.

Four new cases in test_projection_digest_tracks_producing_source: activity_rows, route_rows, ThreadTarget.direct_names and ChannelActivity.from_message.

Tests

tests/test_bus.py -k "digest or projection": 13 passed.

Cost

The digest now changes on more edits, so installs rebuild projections (about 15 s) more often. That is the price of the rows being correct.

🤖 Generated with Claude Code

…gest

The projection digest from #2773 hashed only the record family, the claim
transitions and their capability classes. The code that decides row content
also lives on MessageKind.route_rows, the message roles' activity_rows,
CommandTarget.direct_names, ChannelActivity.from_message, the claim scopes and
the response policies. None of those were hashed, so editing them left stale
projections marked fresh. Proven with the interpreter on main: changing
ConversationRole.activity_rows left the digest at 3a79e1f3ed68fff9.

The capability is now declared on the classes themselves. ProjectionSource
(projection_source.py) registers every class that inherits it, and the
digest hashes the produced rows plus every ProjectionSource class. The
(family, capability) pairs and producer_classes are deleted.
BusProjectionTables declares only the package it produces from.

The classes were found by profiling a full rebuild of a copy of the live bus
(19,503 records): 40 classes outside the old digest ran row-producing code.
Each family is marked at its root. The old 31 owners are all still covered;
the digest now has 156 owners.

test_every_class_that_produces_projection_rows_is_in_the_digest profiles a
rebuild and fails on any class that ran and is not in the digest, apart from
the decode, store and dispatch mechanism modules. With the MessageKind mark
removed it fails and names MessageKind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim
trissim marked this pull request as ready for review October 23, 2026 13:25
Copilot AI balanced review requested due to automatic review settings October 23, 2026 13:25

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 reached their quota limit.

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

@github-actions

Copy link
Copy Markdown

debt-src at 1573ed4, every finding:

grew LintFindings:src/agent_comms/activity_clocks.py +1
grew LintFindings:src/agent_comms/audience_manifest.py +1
grew LintFindings:src/agent_comms/channel_targets.py +1
grew LintFindings:src/agent_comms/read_basis.py +1
grew LintFindings:src/agent_comms/response_policy.py +1
grew LintFindings:src/agent_comms/task_sources.py +1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim
trissim merged commit 3d2edd5 into main Oct 23, 2026
7 of 8 checks passed
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