Skip to content

fix: reject module name collisions across packages (3/5) - #4463

Open
TomCC7 wants to merge 4 commits into
cc/feat/native-package-buildsfrom
cc/fix/package-module-collisions
Open

TomCC7 wants to merge 4 commits into
cc/feat/native-package-buildsfrom
cc/fix/package-module-collisions

Conversation

@TomCC7

@TomCC7 TomCC7 commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Depends on #4462. Layer 3 of 5; base is the preceding stack branch.

Problem

  • Independently authored packages can define modules with the same class name, causing one blueprint to silently replace another.
  • External module identity must remain consistent across blueprint configuration, RPC endpoints and worker processes.

Solution

  • Default external modules to their qualified Python definition names; keep existing short names for classes defined inside dimos and dimos.*.
  • Preserve explicit instance names and last-configuration-wins behavior for repeated declarations of the same class; reject collisions between different classes.
  • Use the same external identity for RPC and isolated Python facades, normalize multiprocessing's __mp_main__ alias, and support qualified or escaped configuration addresses. Streams, topics and TF frames remain unchanged.
  • Give the configuration documentation stable explicit instance names and correct the dimOS branding.

Validation: 92 focused local tests passed, including script-defined worker RPC and documentation branding; all 19 blueprint Python documentation blocks passed. Focused Ruff, mypy and whitespace checks passed. The transport documentation block now passes the former RPC hang but encounters an LCM handler startup failure also reproduced on unchanged layer 2. CI has not been rerun.

@github-actions github-actions Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go2 replay realtime (arm64)

Details
Benchmark suite Current: a76e782 Previous: 8b17f2f Ratio
peak memory 1613.082 MB 1582.812 MB 1.02
peak threads 354 threads 360 threads 0.98
network (transport) 2724.833 MB 2721.697 MB 1.00
disk write 1.559 MB 1.617 MB 0.96
instructions 115.504 G 115.471 G 1.00

This comment was automatically generated by workflow using github-action-benchmark.

@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

@@                        Coverage Diff                        @@
##           cc/feat/native-package-builds    #4463      +/-   ##
=================================================================
+ Coverage                          80.45%   80.48%   +0.02%     
=================================================================
  Files                               1655     1657       +2     
  Lines                             155457   155620     +163     
  Branches                           13154    13162       +8     
=================================================================
+ Hits                              125077   125253     +176     
+ Misses                             26801    26790      -11     
+ Partials                            3579     3577       -2     
Components Coverage Δ
Tests 95.19% <100.00%> (+0.01%) ⬆️
Flag Coverage Δ
OS-macos-latest 74.82% <100.00%> (+0.03%) ⬆️
OS-ubuntu-24.04-arm 74.54% <98.87%> (+0.03%) ⬆️
OS-ubuntu-latest 74.94% <100.00%> (+0.03%) ⬆️
Py-3.10 74.94% <100.00%> (+0.02%) ⬆️
Py-3.11 74.93% <100.00%> (+0.03%) ⬆️
Py-3.12 74.94% <100.00%> (+0.03%) ⬆️
SelfHosted-Large 32.14% <31.07%> (-0.01%) ⬇️
SelfHosted-Linux 39.89% <31.63%> (-0.02%) ⬇️
SelfHosted-macOS 40.18% <31.63%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/core/coordination/blueprint_config/parser.py 88.13% <100.00%> (+2.11%) ⬆️
dimos/core/coordination/blueprints.py 89.47% <100.00%> (+0.14%) ⬆️
dimos/core/coordination/module_coordinator.py 87.20% <100.00%> (-0.04%) ⬇️
dimos/core/coordination/test_blueprints.py 98.84% <100.00%> (+0.04%) ⬆️
dimos/core/module.py 78.84% <100.00%> (+0.57%) ⬆️
dimos/core/module_identity.py 100.00% <100.00%> (ø)
dimos/core/rpc_client.py 88.97% <100.00%> (+0.08%) ⬆️
dimos/core/test_external_module_names.py 100.00% <100.00%> (ø)
dimos/protocol/rpc/spec.py 96.22% <100.00%> (ø)

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@TomCC7
TomCC7 force-pushed the cc/fix/package-module-collisions branch from d966f78 to d9c1c33 Compare October 10, 2026 07:20
@TomCC7
TomCC7 marked this pull request as ready for review October 10, 2026 07:27
@greptile-apps

greptile-apps Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[High impact] Changes how module identity and naming work across the system.

Do not merge until script-defined modules use the same default identity in the parent and worker; neither higher dependent PR resolves this startup regression.

Findings

  1. P1 Script modules cannot start ▶

T-Rex evidence

Executable script-module lifecycle check

  • Defines Calculator in the executed script and exercises real forkserver deployment and lifecycle RPC with a matched-topic control, isolating the identity regression.

Executable four-snapshot validation command

  • Extracts the four specified snapshots and runs the identical harness with captured command records, making the comparison reproducible.

Python interpreter restoration output

  • Captures the successful installation of Python 3.12.15 into the untracked setup directory, resolving the missing interpreter blocker.

Lifecycle RPC output before PR4463

  • Runs the script against af742c1 and observes successful default start, proving the baseline works.

Lifecycle RPC timeout at PR4463

  • Runs the same script against d9c1c33 and observes mismatched identities and a default-start timeout, confirming the regression.

Lifecycle RPC timeout at PR4464

  • Runs the same script against e125047 and observes the same default-start timeout, proving PR4464 does not fix this path.

Lifecycle RPC timeout at PR4465

  • Runs the same script against 787fc72 and observes the same default-start timeout, proving PR4465 does not fix this path.

Higher-snapshot identity code and checkout status

  • Captures numbered identity source, matching relevant blob IDs, stack diff statistics, and unchanged tracked checkout status, corroborating the runtime results.

Full executed harness and runner source

  • Captures the complete source of both executed scripts using cat with command and exit metadata, preserving the exact validation implementation.

Evidence from the check

  • Defines Calculator in the executed script and exercises real forkserver deployment and lifecycle RPC with a matched-topic control, isolating the identity regression.

Evidence from the check

  • Extracts the four specified snapshots and runs the identical harness with captured command records, making the comparison reproducible.

Command output from the check

  • Captures the successful installation of Python 3.12.15 into the untracked setup directory, resolving the missing interpreter blocker.

Command output from the check

  • Runs the script against af742c1 and observes successful default start, proving the baseline works.

Command output from the check

  • Runs the same script against d9c1c33 and observes mismatched identities and a default-start timeout, confirming the regression.

Command output from the check

  • Runs the same script against e125047 and observes the same default-start timeout, proving PR4464 does not fix this path.

Command output from the check

  • Runs the same script against 787fc72 and observes the same default-start timeout, proving PR4465 does not fix this path.

Command output from the check

  • Captures numbered identity source, matching relevant blob IDs, stack diff statistics, and unchanged tracked checkout status, corroborating the runtime results.

Command output from the check

  • Captures the complete source of both executed scripts using cat with command and exit metadata, preserving the exact validation implementation.

View artifacts

Summary

This PR rejects different module classes that share an instance name. It also gives external classes qualified default names.

  • Different module classes cannot silently share an instance name.
  • External modules use their defining package and class as their default name.
  • Module settings accept qualified and shell-safe names without ambiguous roots.

Reviews (1) · Last reviewed commit: "fix(packages): qualify external module i..." · Reviewed by Greptile

Comment thread dimos/core/module_identity.py Outdated
"""Qualify external classes by their definition, independent of registration."""
if module_class.__module__ == "dimos" or module_class.__module__.startswith("dimos."):
return None
return f"{module_class.__module__}.{module_class.__qualname__}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Script modules cannot start

external_module_name() gives script-defined classes different names in the parent and its workers. Running examples/rpc_calls.py as a script names Calculator as __main__.Calculator in the parent. Python's forkserver workers reload the script as __mp_main__, so the module serves calls under __mp_main__.Calculator. RPCClient still calls __main__.Calculator, causing build and lifecycle calls to time out.

Normalize these two module names, or pass the parent's chosen identity to the worker before construction. This startup regression must be fixed before merging.

Knowledge Base Used:

Artifacts

Executable script-module lifecycle check

  • Defines Calculator in the executed script and exercises real forkserver deployment and lifecycle RPC with a matched-topic control, isolating the identity regression.

Executable four-snapshot validation command

  • Extracts the four specified snapshots and runs the identical harness with captured command records, making the comparison reproducible.

Python interpreter restoration output

  • Captures the successful installation of Python 3.12.15 into the untracked setup directory, resolving the missing interpreter blocker.

Lifecycle RPC output before PR4463

  • Runs the script against af742c1 and observes successful default start, proving the baseline works.

Lifecycle RPC timeout at PR4463

  • Runs the same script against d9c1c33 and observes mismatched identities and a default-start timeout, confirming the regression.

Lifecycle RPC timeout at PR4464

  • Runs the same script against e125047 and observes the same default-start timeout, proving PR4464 does not fix this path.

Lifecycle RPC timeout at PR4465

  • Runs the same script against 787fc72 and observes the same default-start timeout, proving PR4465 does not fix this path.

Higher-snapshot identity code and checkout status

  • Captures numbered identity source, matching relevant blob IDs, stack diff statistics, and unchanged tracked checkout status, corroborating the runtime results.

Full executed harness and runner source

  • Captures the complete source of both executed scripts using cat with command and exit metadata, preserving the exact validation implementation.

View artifacts

T-Rex Ran code and verified through T-Rex

seen.add(bp.name)
previous = seen.get(bp.name)
if previous is not None and previous is not bp.module:
raise ValueError(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function is called eliminate but behavior changed to raise error seems weird

from typing import Any


def external_module_name(module_class: type[Any]) -> str | None:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if only one function and no multiple files imports it then just keep it single file

@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Oct 10, 2026

This branch was successfully deployed

1 active (outdated) deployment
cachix — 39f1945f Deployed Oct 9, 2026 by TomCC7 via cachix-build-macos #12343
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant