Skip to content

Hash projection-producing declarations instead of infrastructure modules - #2760

Merged
trissim merged 11 commits into
mainfrom
fix/projection-declaration-digest
Oct 23, 2026
Merged

trissim merged 11 commits into
mainfrom
fix/projection-declaration-digest

Conversation

@trissim

@trissim trissim commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Projection freshness previously hashed whole infrastructure modules, so an unrelated encoder edit invalidated every bus projection. Hash the producing classes and their nominal family ancestors, sorted by module and qualified name, after acquiring the producer declarations. Shared producing parents such as ActivityMaximum and BusProjectionTables remain part of the identity. The existing producer_classes(), members_with() and metaclass-recorded family root own selection; there is no module/class exclusion roster or module-hash fallback.

The first install after this change rebuilds bus projections once because the digest format changed.

DeclaredFamily.family_root exposes the existing recorded root with a concrete return type. declared_position uses that owner and loses its root cast. Existing stamp storage, cache and freshness consumers remain the implementation owners; no carry or flag is added.

Five source-copy checks pass in fresh isolated interpreters: a TypedTable infrastructure docstring and an unrelated field_codec function preserve the digest; Delivered.projections, ActivityMaximum.insertion and BusProjectionTables.create_schema body edits change it. They use actual copied production families and no function monkeypatching.

The actual CLI was then run against one copied post-Install20 root using the installed a4214d7 Python and this branch's source. The copy was taken read-only while maintenance stayed ready in generation 298: SQLite sources used mode=ro online backup, plain files were copied, and reconcile never ran against live. Each scratch edit was committed to a distinct SHA, preventing the same-SHA shortcut in verifies() from masking a broken digest.

Reconcile Source head Seconds Projection rows rebuilt
First class-digest transition ce90a2b 55.285 164,526
Committed unrelated field_codec function cd583c38b1 4.890 0
Committed ActivityMaximum max-to-min body edit 4e9a4e8f67 45.444 164,526
Final PR head after merging main 72e5748 5.035 0

All four commands completed successfully and their JSON was decoded as ReconciledStoresResult; exit status alone was not accepted. cProfile records calls to BusProjectionTables.create_schema to detect replay, and declared row owners count the resulting projection rows. The unrelated-function run changed Core SHA while preserving the digest; only commit-stamp metadata was refreshed. The producing-method run changed the digest and replayed history.

The last main merges changed CLI/import and installer/file-selection code. The selected class digest remained 5d6fc04d49a36cb0611af1b34fcaa80d1c47a1b4d67832cbce0adf403de0022b. Before checking final head 72e5748, the complete saved database from the successful infrastructure run was restored into scratch, then the real CLI ran again: zero replay. No individual stamp fields were overwritten to manufacture a match.

Evidence: /home/ts/.cache/agent-scratch/backend-reconcile-install19/class-format-{first,infrastructure,producer,final-head}.json and matching .pstats/stdout/stderr. Scratch source commits cd583c38b and 4e9a4e8f6 are on the local scratch/projection-2760-proof branch; the production PR contains neither source mutation. The scratch tree reused the finished backend-delivered-review checkout.

Assumed: Python class source remains available to inspect.getsource; nominal producing families define dependency scope; source is immutable within a process, as required by the existing cache. Durations include cProfile and nice -n 19 overhead and are not unprofiled install latency. Zero rebuilt rows permits commit-stamp metadata writes.

Send-back fixes at 7b755f0:

  • DeclaredFamily has no root attribute on the abstract base. FamilyMeta assigns a concrete root to declared families; family_root() returns it directly. The constructor assigns from its validated parent-root set, eliminating the remaining introduced None probe.
  • The producer owner set is explicitly set[type[DeclaredFamily]], so both projection and producer-family ancestors fit without a cast or ignore. The class digest remains 5d6fc04d49a36cb0611af1b34fcaa80d1c47a1b4d67832cbce0adf403de0022b.
  • Main's wire-model split and native repin f3f069f are preserved.
  • The native-scripts failure exposed one obsolete stack caller: test-native-global-extensions.py passed a Path to Comms(CommsRoute), so Path.root became '/'. It now uses the existing wire(path) boundary. AST inspection found no other Comms(...) calls in stack.
  • That script is a declared native build input. The canonical prepare-pi-native --update-pins build and verification succeeded in this owned checkout. Only the native input digest changed; all compiled file hashes and native tree digest stayed identical. No live package was published or changed.

Hosted debt-src and native-scripts both passed on final head 7b755f0 in run 39952791268. Exact-head check-run API confirms success for both. The PR is ready for the commander review.

@trissim
trissim marked this pull request as ready for review October 23, 2026 12:04
Copilot AI balanced review requested due to automatic review settings October 23, 2026 12:04

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

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

debt-src at 38765ee, every finding:

introduced NoneAbsence:src/agent_comms/declared_family.py at lines [90]

@trissim
trissim marked this pull request as draft October 23, 2026 12:12
@trissim
trissim marked this pull request as ready for review October 23, 2026 12:15
@trissim

trissim commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

#2764's native-scripts job fails in your held stack/test-native-global-extensions.py:68: Comms(root / "wire") passes a Path to Comms.__init__(root: CommsRoute). Path.root becomes /, so root attachment attempts /..root-runtime.json.lock and gets PermissionError. The existing wire(root / "wire") factory owns route selection. This script is already in #2760, so I am leaving it with you rather than editing it in #2764. Please fold this caller migration into your script correction; it blocks the explicitly requested green native-scripts check on #2764.

Failing job: https://github.com/OpenHCSDev/agent-comms/actions/runs/39951823803/job/120407905261

@trissim
trissim merged commit 2ca56a5 into main Oct 23, 2026
6 of 8 checks passed
@trissim

trissim commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Handoff: #2760 is ready at 7b755f0; debt-src and native-scripts are green. No source edits remain; commander review is pending. Do not change this branch without a send-back. The following evidence-only Install21 profiling is complete on disk, with no source changes: installed f3f069f runtime, full copied bus, actual pre-21 bus snapshot restored before each pair. Rehearsal planned/reconcile: 2.794s / 43.748s profiled; live planned/reconcile: 3.193s / 49.909s profiled. Each reconcile rebuilds only bus.sqlite3 (243752 total rows); each planned call identifies only that file. cProfile overhead means these are not the original unprofiled 17.0s/15.4s. Raw per-store counts/times and top self-time lines are in /home/ts/.cache/agent-scratch/backend-reconcile-profile/{rehearsal-planned,rehearsal-reconcile,live-planned,live-reconcile}.json and corresponding -work.pstats. Remaining work is the requested evidence reply, not a code edit: trace f3f069f installer/upgrade.py:975 and :1010 planned calls, and the shared PreparedMigration.carry reconcile call at :945 reached from rehearsal and live. Explain distinct roots, whether planned verification repeats the same fact, and compare LockChains carry deletion with bus replay. Exact next action: read those source hunks at f3f069f and assemble the four-step timing/per-store table from the existing JSON; do not rerun profiles. No new PR: this subsequent task is evidence only.

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