Skip to content

Move the nominal declaration cluster and its defining-module consumers - #3576

Closed
trissim wants to merge 2 commits into
mainfrom
work/package-declarations--P918
Closed

trissim wants to merge 2 commits into
mainfrom
work/package-declarations--P918

Conversation

@trissim

@trissim trissim commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary in numbers

  • P918, package_structure/package_declarations: 4 root module paths -> 0, one defining agent_comms.nominal package; 202 original ClassDefs retained (9 declaration/discovery, 190 codec including nested declarations, 2 JSON-schema, 1 sealing).
  • Current Core checkpoint: 2 commits, 705 files, +1028/-963 (git diff --stat origin/main...HEAD) with Git recognizing all four moves; 3,978 owner-source lines relocated, not 3,978 lines of behavior deleted. Only the codec's TYPE_CHECKING parent import changes inside those four files.
  • Actual Core closure at the owned 20eac base: 939 import observations / 700 files, including 51 lexical nested imports (scope count is not an all-conditional-import count). Paired ToAD: 105 imports / 90 files, including 5 nested imports.
  • No reexports, old compatibility modules, second codec or second registry. No tests, checkers, builds, providers or live installs run by this author; root owns combined execution and installation.

Paired consumer: OpenHCSDev/toad#1313, branch work/package-declarations--P918--toad, current checkpoint 54f6ecca1175d71107d58ad1558d13a7b688ac5d on ToAD main 40bc104824c449f061f58b70d1b358c70535d000 (2 commits, 91 files, +106/-106). Current Core checkpoint is 100f036a9ed21fcd0692353b0731cdf313df439c on 20eac8baf494ca03bad79f855e9683401c805a44. First real published checkpoints remain Core 27c136be6efe3a192e45ed58a91343d5c63ede86 and ToAD c3b1f71e817c2f31a09183fabbafa653c77021c1.

Before / after ownership

Before: four independently importable flat-root modules contained the declaration cluster, while 700 Core files and 90 ToAD files named their old addresses.

After: the SAME declarations live in nominal/{declared_family,field_codec,json_schema,sealed}.py; both initializers remain free of API reexports. Consumers import their defining modules. This is package ownership/relocation, not a claim to have factored away existing family implementation debt.

Declaration, metaclass and discovery

Required fact: the class selected by a family name must be the single class registered by FamilyMeta, not a second class reconstructed through an old module.

  • nominal/declared_family.py:34: FamilyMeta(AutoRegisterMeta, ABCMeta) still creates the same family roots and uses external LazyDiscoveryDict/RegistryConfig. Abstract and unnamed exclusion remains with AutoRegisterMeta. No new registry or import roster.
  • :148: DeclaredFamily and its public family queries retain their implementations.
  • :290: ModuleMembers._named_member retains the function-local reverse import of FieldCodec/MalformedRecord. It is not hoisted into a declaration-time initialization cycle.
  • nominal/field_codec.py:49-51 keeps sibling imports inside the cluster; :56 changes the existing TYPE_CHECKING RegistrationInheritance dependency to ..registration_inheritance.
  • nominal/sealed.py:14-21 keeps sealing based on actual __module__; the mechanism and all its implementations move together. No _sealed_home override or fake old module identity.

TIME-3 prevention: fact=declaration identity, at=the four old import paths, derive=the actual defining module, by=the unchanged declaration classes. The obsolete forwarding address is deleted, not made to look inhabited.

Codecs, tags and module-qualified identity

FieldCodec(MroDispatch, Sealed) and all codec/field/representation classes retain their names, bases, decorators, fields and ordering. Wire selectors remain declaration-derived, with no hand-kept schema or tool roster. Existing module-qualified comparisons/schema descriptions/type identities (field_codec.py:1064/1771/2884) continue deriving from the actual class module; moving a class changes its descriptive Python address, not its durable family tag. The PathText schema-description test now derives that description from the class rather than restating its address.

Concrete remaining runtime risk: comparison_digest (nominal/field_codec.py:2350) hashes module-qualified in-process comparison values; a moved type/value can therefore get a different observation key. The sole production caller is StandingRule.observation_key (standing_rules.py:283), not a wire decoder. Ordinary digest (field_codec.py:2345) hashes declared wire encoding and is a distinct path. Do not claim retained commander observations are unchanged from source compilation: root must exercise their actual read/handling path. No fake old __module__, digest converter or compatibility owner is added. External abstract exclusion was traced to metaclass-registry core.py:745-758, which excludes abstract/no-key classes before registration; this implementation is unchanged.

Consumer closure and evidence owners

Core production, hooks, tests, tools, nested imports, module-object imports (cli_bridges/shared.py, tools/debt_ratchet.py, etc.) and executable test strings point to nominal. DecoratorBinding continues deriving the decorator module; FamilyFlattened continues deriving mechanism paths from real module objects. Existing phase owner evidence/exclusions move to the new codec path; PackageDeclarationsPhase intentionally keeps all four OLD-path absence checks.

ToAD migrates production/test/support imports and the active keymap plan's declaration address on its own allocated checkout. Core also migrates the executable support controllers retained under docs/refactor and stack/test-native-global-extensions.py. These are executable imports, unlike historical hashes/transcripts. DuplicatesPhase's constructed owner path at plan_phases.py:477 becomes nominal/field_codec.py; literal full-path replacement alone would miss it. Core's Hatch wheel includes src/agent_comms recursively, so no package membership roster is added. Wheel contents still require root's actual build proof. The changed stack control is outside NativeBuildInputs.paths()'s recipe/declared input set (stack/native/repository-inputs.json); no native input is edited. Root still owes its archive-head pin verification before approval; author ran no checker/build.

Read-only paired source cuts reused: Textual c27e535fe2f05406de3c9e90ac61352f59815bca; ui-theme ba614bcb90b38c1f70789059a3c6aef8c017971b; metaclass-registry 60138d533ef0758c5f093d9110ba9f5656f0934a; NRA 9242a6bad968ee301e3572563f532f53fe240e41. Retained source map records zero syntactic nominal imports in Textual/ui-theme/metaclass-registry/formbridge/pinned audit skill. These are source cuts, not claims of latest/installed packages.

Source evidence and codemod limits

Reused the complete scan 437f51f3b623a3c1eb46253c7170e494e1e2a01a, canonical package census/import evidence at c50ebef93a0cfa6918aa471f5d0921383266363e, and /home/ts/.cache/agent-scratch/checkout-caller/disposition-nominal-closure.json (5,662 file-cut observations; zero parse omissions). Did not rerun detectors or a complete census.

Additional bounded source receipt: /home/ts/.cache/agent-scratch/package-declarations/relocation-source-evidence.json. It uses NRA ModuleSyntaxIndex and PythonModulePathIdentity for actual import scopes and owner ClassDefs/bases/decorators/writes/decisions; no product module is imported. Zero parse omissions in the selected source patch. JSON-schema has no self-name token and was separately enumerated from its original Git blob, rather than silently omitted by retrieval.

Native operation inventory read from NRA module_move_codemod.py:543-964: RelocateSymbolsToNewModuleOperation moves selected symbols; its consumer mutation loop handles scoped ImportFrom statements. It does not cover this complete module-file lifecycle/deletion, module-object import rewriting, embedded executable strings, Python module identity/sealing or discovery effects. Source-binding-preserving operations explicitly retain bindings and are prohibited here. This is an authored module/import patch, not a native codemod execution proof; no simulated/native behavioral result is claimed. The one-shot source transformation is removed after use; its command/result remains in this PR.

Command used: PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=<NRA checkout>:<existing cached tree_sitter/tree_sitter_python distributions> /home/ts/code/projects/agent-comms/.venv/bin/python <owned scratch>/move_nominal.py. Initial import failed with missing tree_sitter before edits; reused already-cached dependencies via process-local PYTHONPATH, without installing/syncing packages. Applied result: 791 edited consumer/owner files across both roots, four owner-file renames, no parse omissions. No elapsed-time performance claim.

OPEN: arbitrary computed module imports/reflection, external installed skill distributions outside the pinned audited subtree, and final accepted P883/P904/DisclosureIdentity integration. Literal source search is not proof that computed bindings do not exist. Historical transcripts/source hashes keep their original paths; active configuration and executable consumers must not.

Integration source cuts (not feature acceptance)

Root's explicit sequence: P883 carrying P872 and matched ToAD consumer first; P904 follows that accepted owner shape; retain #3574/#3575; P918 merges accepted main and resolves relocation once across all consumers. This source checkpoint does not cherry-pick, rename or port those pending feature implementations. Expected overlap alerts are one ordered migration relation, not permission to land ahead of those behaviors.

Controls authored; execution owed by root

tests/test_declared_family.py adds cold-process controls for both declaration/codec entry-import orders, actual lazy family and ModuleMembers lookup, consumer class identity, sealed codec home, a genuinely new slots/MI family member, abstract exclusion, declaration-derived tag round-trip and schema creation. No registry/schema roster is maintained. Existing codec, family, schema, tool/CLI discovery and ownership fixtures migrate with their consumers.

Root's combined selection should include tests/test_declared_family.py, tests/test_field_codec.py, tests/test_field_codec_comparison.py, tests/guards/test_field_codec_ownership.py, tests/guards/test_debt_ratchet.py, tests/test_command_families.py, tests/test_boundary_decoding.py, tests/test_tools.py, plus the actual P883/P904 producer/consumer selection. Root then owes installed wheel/tool/member identity comparison and the saved-session concurrent-native-reply + fresh-DM/open-ToAD-tab/return journey. No author execution claimed.

Assumed: root retains the accepted-source integration sequence and owns qualification/install; historical source receipts are immutable observations rather than executable consumers.

four owners moved
zero forwarding addresses
the registry did not need witness protection

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

debt-tools at 8824b93, every finding:

concurrent.futures.process._RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/process.py", line 255, in _process_worker
    r = call_item.fn(*call_item.args, **call_item.kwargs)
  File "/home/runner/work/agent-comms/agent-comms/src/agent_comms/child_process.py", line 2279, in _work
    return work()
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2662, in counted
    before = cls.formats(repo, base, root, changed)
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2624, in formats
    return ContentCache.memo(partial(cls.measured_formats, repo, ref, root, changed),
           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                             cls.__name__, revision(repo, ref), root, *sorted(changed))
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 142, in memo
    return cls.store(compute(), *parts)
                     ~~~~~~~^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2654, in measured_formats
    raise ValueError(f"{cls.__name__} could not measure {ref}: {result.stderr.decode()}")
ValueError: UncarriedRecordFormat could not measure 20eac8baf494ca03bad79f855e9683401c805a44: Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import importlib.util, os, sys; sys.path[:0] = sys.argv[2].split(os.pathsep); spec = importlib.util.spec_from_file_location('stored_formats', sys.argv[1]); module = sys.modules[spec.name] = importlib.util.module_from_spec(spec); spec.loader.exec_module(module); module.main(sys.argv[3:])
                                                                                                                                                                                                                                         ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "<frozen importlib._bootstrap_external>", line 763, in exec_module
  File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
  File "/home/runner/work/agent-comms/agent-comms/tools/stored_formats.py", line 18, in <module>
    from agent_comms.nominal.field_codec import FieldCodec
ModuleNotFoundError: No module named 'agent_comms.nominal'

"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2913, in <module>
    raise SystemExit(main())
                     ~~~~^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2895, in main
    result = compare(Path.cwd(), args.base, args.head, args.root, args.workers)
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2863, in compare
    combined[measure] = measure.combine([part.result() for part in parts[measure]],
                                         ~~~~~~~~~~~^^
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/_base.py", line 447, in result
    return self.__get_result()
           ~~~~~~~~~~~~~~~~~^^
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/_base.py", line 396, in __get_result
    raise self._exception
ValueError: UncarriedRecordFormat could not measure 20eac8baf494ca03bad79f855e9683401c805a44: Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import importlib.util, os, sys; sys.path[:0] = sys.argv[2].split(os.pathsep); spec = importlib.util.spec_from_file_location('stored_formats', sys.argv[1]); module = sys.modules[spec.name] = importlib.util.module_from_spec(spec); spec.loader.exec_module(module); module.main(sys.argv[3:])
                                                                                                                                                                                                                                         ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "<frozen importlib._bootstrap_external>", line 763, in exec_module
  File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
  File "/home/runner/work/agent-comms/agent-comms/tools/stored_formats.py", line 18, in <module>
    from agent_comms.nominal.field_codec import FieldCodec
ModuleNotFoundError: No module named 'agent_comms.nominal'

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

debt-src at 8824b93, every finding:

concurrent.futures.process._RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/process.py", line 255, in _process_worker
    r = call_item.fn(*call_item.args, **call_item.kwargs)
  File "/home/runner/work/agent-comms/agent-comms/src/agent_comms/child_process.py", line 2279, in _work
    return work()
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2662, in counted
    before = cls.formats(repo, base, root, changed)
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2624, in formats
    return ContentCache.memo(partial(cls.measured_formats, repo, ref, root, changed),
           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                             cls.__name__, revision(repo, ref), root, *sorted(changed))
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 142, in memo
    return cls.store(compute(), *parts)
                     ~~~~~~~^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2654, in measured_formats
    raise ValueError(f"{cls.__name__} could not measure {ref}: {result.stderr.decode()}")
ValueError: UncarriedRecordFormat could not measure 20eac8baf494ca03bad79f855e9683401c805a44: Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import importlib.util, os, sys; sys.path[:0] = sys.argv[2].split(os.pathsep); spec = importlib.util.spec_from_file_location('stored_formats', sys.argv[1]); module = sys.modules[spec.name] = importlib.util.module_from_spec(spec); spec.loader.exec_module(module); module.main(sys.argv[3:])
                                                                                                                                                                                                                                         ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "<frozen importlib._bootstrap_external>", line 763, in exec_module
  File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
  File "/home/runner/work/agent-comms/agent-comms/tools/stored_formats.py", line 18, in <module>
    from agent_comms.nominal.field_codec import FieldCodec
ModuleNotFoundError: No module named 'agent_comms.nominal'

"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2913, in <module>
    raise SystemExit(main())
                     ~~~~^^
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2895, in main
    result = compare(Path.cwd(), args.base, args.head, args.root, args.workers)
  File "/home/runner/work/agent-comms/agent-comms/tools/debt_ratchet.py", line 2863, in compare
    combined[measure] = measure.combine([part.result() for part in parts[measure]],
                                         ~~~~~~~~~~~^^
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/_base.py", line 447, in result
    return self.__get_result()
           ~~~~~~~~~~~~~~~~~^^
  File "/opt/hostedtoolcache/Python/3.14.9/x64/lib/python3.14/concurrent/futures/_base.py", line 396, in __get_result
    raise self._exception
ValueError: UncarriedRecordFormat could not measure 20eac8baf494ca03bad79f855e9683401c805a44: Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import importlib.util, os, sys; sys.path[:0] = sys.argv[2].split(os.pathsep); spec = importlib.util.spec_from_file_location('stored_formats', sys.argv[1]); module = sys.modules[spec.name] = importlib.util.module_from_spec(spec); spec.loader.exec_module(module); module.main(sys.argv[3:])
                                                                                                                                                                                                                                         ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "<frozen importlib._bootstrap_external>", line 763, in exec_module
  File "<frozen importlib._bootstrap>", line 491, in _call_with_frames_removed
  File "/home/runner/work/agent-comms/agent-comms/tools/stored_formats.py", line 18, in <module>
    from agent_comms.nominal.field_codec import FieldCodec
ModuleNotFoundError: No module named 'agent_comms.nominal'

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

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.

@trissim
trissim marked this pull request as draft October 29, 2026 02:36
trissim added a commit that referenced this pull request Oct 29, 2026
The ratchet ran the checkout's tools/stored_formats.py against both
revisions' packages. #3576's reader imports agent_comms.nominal.field_codec,
which main's package does not have, so the base side crashed with
ModuleNotFoundError and debt-src/debt-tools went red on every run. The
reader is now archived with the revision's package and run from there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnH6dR85kyFKcc2tQAJLhK
@trissim

trissim commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #3614 (Core 5936216), paired with OpenHCSDev/toad#1330 (3d0ccc8fc). The replacement rebuilds the same four-owner relocation, active consumers and cold discovery/identity controls on current main, with the ordered stable-schema correction. Targeted old/current comparison found no unique migration work missing: three owners are byte-identical; cold control behavior survives; the sole old-only changed path, installer/probes/owner_actions.py, was deleted by main 24a8882. Closing only the duplicate carrier; all branches and commits, including original 100f036 and the retained local rebase, stay intact. No integration or runtime acceptance implied.

@trissim trissim closed this Oct 29, 2026
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