Skip to content

Add: CPU-NPU Comm Endpoint Model - #1696

Open
ccyywwen wants to merge 3 commits into
hw-native-sys:mainfrom
ccyywwen:w2-comm-endpoint-model
Open

Add: CPU-NPU Comm Endpoint Model#1696
ccyywwen wants to merge 3 commits into
hw-native-sys:mainfrom
ccyywwen:w2-comm-endpoint-model

Conversation

@ccyywwen

@ccyywwen ccyywwen commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the cpu-npu-shared-memory endpoint model in Python only.

  • Add simpler.comm_endpoints with endpoint selectors, path parsing,
    endpoint registry resolution, node-scope relation queries, capability cache
    stubs, and SingleOwner backend planning.
  • Add internal Worker._resolve_region_spec(...) and
    Worker._plan_region(...) with lazy endpoint registry construction and
    registry epoch invalidation on close.
  • Add focused Python unit tests for selector validation, registry expansion,
    provider resolution, same-node/cross-node behavior, backend planning, and
    package import surface.

Scope

This PR intentionally does not add Orchestrator.create_region(...), does not
materialize regions, and does not touch C++ / nanobind / wire ABI.

HOST_MAP_DEVICE_HBM remains a capability contract only. Real probing must validate bidirectional host-device counter visibility.

Tests

  • pytest tests/ut/py/test_worker/test_comm_endpoints.py tests/ut/py/test_package_surface.py
  • pytest tests/ut/py/test_worker/test_l4_recursive.py tests/ut/py/test_worker/test_l3_l2_orch_comm.py tests/ut/py/test_worker/test_comm_endpoints.py

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b3d85c3b-f9f9-496b-89f3-8435bd977c0d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request adds endpoint and backend planning, changes remote L3 transport from sim to host_tcp, introduces worker-owned host-buffer handling, and adds a two-machine mixed-L3 vector-add example with paired hardware CI validation.

Changes

Endpoint planning

Layer / File(s) Summary
Endpoint model and registry
python/simpler/comm_endpoints.py, python/simpler/__init__.py
Adds endpoint selectors, registry resolution, node scopes, platform capabilities, and backend materialization plans.
Worker endpoint lifecycle
python/simpler/worker.py, tests/ut/py/test_worker/test_comm_endpoints.py, tests/ut/py/test_package_surface.py
Integrates endpoint planning with worker readiness, nested target inspection, operation leases, closure invalidation, and unit tests.

Host TCP runtime

Layer / File(s) Summary
Host TCP profile and session buffers
python/simpler/remote_l3_protocol.py, python/simpler/remote_l3_session.py, python/simpler/remote_l3_worker.py, python/simpler/task_interface.py
Replaces sim validation with host_tcp and adds worker-owned host-buffer allocation, release, and shared-memory fallback.
Remote worker manifests and defaults
python/simpler/worker.py
Uses host_tcp defaults, serializes remote callable payloads, includes inner worker registries, and handles childless host-buffer workers.
Host TCP transport documentation
docs/capability-survey.md, docs/remote-l3-worker-design.md, docs/remote-l3-worker-design/*, docs/user/how-to/run-on-multiple-chips.md
Updates transport status, implementation records, verification plans, and multi-chip usage to describe shipped host_tcp behavior.

Mixed-L3 validation

Layer / File(s) Summary
Mixed-L3 kernels and orchestration
examples/workers/l4/vector_add_mixed_l3/kernels/*
Adds vector addition, scalar addition, multiplication, and nested orchestration for the mixed-L3 workload.
Mixed-L3 runner and integration test
examples/workers/l4/vector_add_mixed_l3/*
Adds launch scripts, two-machine setup documentation, chip-callable construction, local and remote execution, output checks, and cleanup.
Paired pod CI validation
.github/workflows/ci.yml
Adds pod branch triggers and a paired a2a3 hardware job that synchronizes machines, starts the remote daemon, runs the mixed-L3 test, cleans up, and uploads logs. Existing jobs are disabled.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

A rabbit hops where host_tcp flows,
Through paired machines, the workload grows.
Kernels add and multiply bright,
Endpoint plans keep paths in sight.
Logs return before the moon—
Mixed-L3 validation finishes soon.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.40% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: adding the CPU-NPU communication endpoint model.
Description check ✅ Passed The description accurately summarizes the Python endpoint model, its tests, and the explicitly excluded scope.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch w2-comm-endpoint-model

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 8

🧹 Nitpick comments (3)
python/simpler/worker.py (2)

747-760: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Name the conflicting contexts in the error message.

_chip_descriptor_context now collects contexts from three sources: this worker, every local descendant, and every remote spec. When they disagree, the message does not say which values conflict or where they came from. A user who hits this on a deep L4 tree has no signal about which child or remote spec is wrong.

Include the distinct contexts in the message.

♻️ Proposed diagnostic improvement
     if not contexts:
         return "", ""
     first = contexts[0]
     if any(ctx != first for ctx in contexts[1:]):
-        raise RuntimeError("Worker.register: heterogeneous chip child contexts require separate callable namespaces")
+        distinct = sorted(set(contexts))
+        raise RuntimeError(
+            "Worker.register: heterogeneous chip child contexts require separate callable namespaces; "
+            f"found {distinct}"
+        )
     return first
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/worker.py` around lines 747 - 760, Update the
heterogeneous-context error in _chip_descriptor_context to include the distinct
conflicting platform/runtime contexts collected from the current worker, local
descendants, and remote specs. Preserve the existing validation and exception
behavior while making the message identify the differing values.

2674-2709: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Cache the encoded chip payload across remote specs.

_inner_registry_entries_for_spec runs once per RemoteWorkerSpec. Each call re-reads every chip blob with ctypes.string_at, re-hashes it with SHA-256, re-encodes it, and hex-encodes the result. With N remote specs and M chip callables this repeats N*M full-blob copies and digests.

Only descriptor depends on the spec, through spec.platform and spec.runtime. Remote specs commonly share those values.

This cost lands on the startup path. _open_remote_session derives startup_remaining_s after the manifest is built (Line 2752), so manifest construction is charged against the bounded startup budget.

Cache the blob, its digest, and the encoded payload per (platform, runtime) for the duration of one activation pass.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/worker.py` around lines 2674 - 2709, Update
_inner_registry_entries_for_spec to use an activation-scoped cache keyed by
(platform, runtime) and chip identity, storing each chip’s blob, SHA-256 digest,
and encoded payload. Reuse cached values for matching remote specs, while still
computing the descriptor per spec and validating it against state.descriptor;
retain the existing entry construction and hex encoding behavior.
tests/ut/py/test_worker/test_comm_endpoints.py (1)

92-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a mixed local and remote child case.

This test covers a remote child alone. No test covers an L4 parent that has both a local L3 child and a remote L3 child.

Both paths are formatted as L{level}[{child_index}] under the parent, and remote children hardcode L3. The paths stay distinct only because add_worker and add_remote_worker both draw child_index from the single _next_level_worker_id_count counter in worker.py. If either method ever gets its own counter, two endpoints collapse onto one path and EndpointRegistry._by_key keeps only the last record.

Add a case that calls both add_worker and add_remote_worker on one L4 parent, then asserts the two host paths differ and that the two children report different node scopes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ut/py/test_worker/test_comm_endpoints.py` around lines 92 - 107, Extend
test_remote_registry_assigns_distinct_node_scope_and_planning_rejects_cross_node,
or add a focused neighboring test, to create one L4 parent with both add_worker
and add_remote_worker children. Record both L3 child paths, assert their host
paths differ, and verify EndpointRegistry.same_node reports different node
scopes for the two children.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 984-987: Add a workflow-level concurrency group for the
st-pod-onboard-a2a3 job, keyed to the pod pair, and set cancel-in-progress to
false so overlapping runs queue instead of terminating the active run. Keep the
existing daemon cleanup and staging TTL behavior unchanged.
- Around line 19-20: Remove the hard-coded if: false from the pre-commit
workflow job so the existing CI protection remains enabled; if temporary
pod-validation gating is required, replace it with a branch-scoped condition.
Restore detect-changes and all affected jobs, and ensure every job listing
detect-changes in needs can execute once re-enabled.

In `@docs/capability-survey.md`:
- Line 37: Align the L4 status in the capability survey with the documented CI
coverage: since line 116 says no CI job starts the daemon, mark the remote
host_tcp capability as “Shipped, not CI-run” unless daemon coverage is
confirmed; otherwise update the CI statement to reflect the verified coverage.

In `@docs/remote-l3-worker-design.md`:
- Line 410: Update the communication-policy manifest schema entry in the remote
L3 worker design so host_tcp is the only accepted value; mark roce, hccs, and ub
as reserved or future values rather than supported options, consistent with the
daemon’s current behavior.

In `@docs/remote-l3-worker-design/implementation-record.md`:
- Around line 12-20: Align the host_tcp status and scope across all three audit
documents: update the entries in
docs/remote-l3-worker-design/implementation-record.md (lines 12-20) to use the
implementation-plan status definition and explicitly list remaining gaps; revise
the implemented claims in docs/remote-l3-worker-design/implementation-plan.md
(lines 8-14) to match that record; and update
docs/remote-l3-worker-design/pr-split-and-audit-plan.md (lines 369-370) to
describe PR 6 as host_tcp scope, identifying any coverage that remains
simulation-only.

In `@examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp`:
- Around line 49-56: Run clang-format -i on kernel_entry in
examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp (lines
49-56), kernel_add_scalar.cpp (lines 51-59), kernel_mul.cpp (lines 49-56), and
the orchestration flow in
examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp
(lines 42-54).

In `@python/simpler/remote_l3_session.py`:
- Around line 667-678: Update the preferred allocation path around
inner_worker.create_host_buffer and the EXPORT_BUFFER handling to preserve an
exportable descriptor for worker-owned HostBuffer instances. Store the backing
shared-memory name or host TCP descriptor in _RemoteBufferEntry rather than
relying on shm_name to interpret entry.data, and have ExportBufferResult use
that preserved descriptor while keeping the SharedMemory fallback unchanged.

In `@python/simpler/worker.py`:
- Around line 3435-3442: Update _plan_region to call _get_endpoint_registry()
once and store the result in a local registry variable, then use that same
instance for resolve_region_spec and BackendResolver construction. Keep the
existing readiness and operation-lease flow unchanged.

---

Nitpick comments:
In `@python/simpler/worker.py`:
- Around line 747-760: Update the heterogeneous-context error in
_chip_descriptor_context to include the distinct conflicting platform/runtime
contexts collected from the current worker, local descendants, and remote specs.
Preserve the existing validation and exception behavior while making the message
identify the differing values.
- Around line 2674-2709: Update _inner_registry_entries_for_spec to use an
activation-scoped cache keyed by (platform, runtime) and chip identity, storing
each chip’s blob, SHA-256 digest, and encoded payload. Reuse cached values for
matching remote specs, while still computing the descriptor per spec and
validating it against state.descriptor; retain the existing entry construction
and hex encoding behavior.

In `@tests/ut/py/test_worker/test_comm_endpoints.py`:
- Around line 92-107: Extend
test_remote_registry_assigns_distinct_node_scope_and_planning_rejects_cross_node,
or add a focused neighboring test, to create one L4 parent with both add_worker
and add_remote_worker children. Record both L3 child paths, assert their host
paths differ, and verify EndpointRegistry.same_node reports different node
scopes for the two children.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 25a3283f-0e80-4784-84bf-bca5f8821675

📥 Commits

Reviewing files that changed from the base of the PR and between c866c82 and 7b9df75.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • docs/capability-survey.md
  • docs/remote-l3-worker-design.md
  • docs/remote-l3-worker-design/implementation-plan.md
  • docs/remote-l3-worker-design/implementation-record.md
  • docs/remote-l3-worker-design/pr-split-and-audit-artifacts.md
  • docs/remote-l3-worker-design/pr-split-and-audit-plan.md
  • docs/user/how-to/run-on-multiple-chips.md
  • examples/workers/l4/vector_add_mixed_l3/README.md
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add_scalar.cpp
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_mul.cpp
  • examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp
  • examples/workers/l4/vector_add_mixed_l3/run_parent.sh
  • examples/workers/l4/vector_add_mixed_l3/start_machine_daemon.sh
  • examples/workers/l4/vector_add_mixed_l3/test_vector_add_mixed_l3.py
  • python/simpler/__init__.py
  • python/simpler/comm_endpoints.py
  • python/simpler/remote_l3_protocol.py
  • python/simpler/remote_l3_session.py
  • python/simpler/remote_l3_worker.py
  • python/simpler/task_interface.py
  • python/simpler/worker.py
  • tests/ut/py/test_package_surface.py
  • tests/ut/py/test_worker/test_comm_endpoints.py

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +19 to +20
pre-commit:
if: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔴 Critical | ⚡ Quick win

Do not merge with every pre-existing job disabled.

if: false now disables pre-commit, packaging-matrix, ut, st-sim-a2a3, st-sim-a5, profiling-flags-smoke, ut-a2a3, st-onboard-a2a3, detect-changes, ut-a5, and st-onboard-a5. Only st-pod-onboard-a2a3 remains active. On the default branch this removes all lint, unit-test, packaging, and scene-test protection.

If the disabling is temporary scaffolding for pod validation, gate it on the branch instead of hard-coding false, and restore the jobs before merge. Example gate:

♻️ Branch-scoped gate instead of a hard disable
   pre-commit:
-    if: false
+    if: github.ref_name != 'pod-ci' && github.ref_name != 'ci-multiserver-validation'

Note also that the disabled detect-changes job is still listed in needs: for several jobs. Once those jobs are re-enabled, detect-changes must be re-enabled too, otherwise they stay skipped.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pre-commit:
if: false
pre-commit:
if: github.ref_name != 'pod-ci' && github.ref_name != 'ci-multiserver-validation'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 19 - 20, Remove the hard-coded if:
false from the pre-commit workflow job so the existing CI protection remains
enabled; if temporary pod-validation gating is required, replace it with a
branch-scoped condition. Restore detect-changes and all affected jobs, and
ensure every job listing detect-changes in needs can execute once re-enabled.

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +984 to +987

ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "
pkill -f 'python -m simpler.remote_l3_worker --host ${REMOTE_DAEMON_HOST} --port ${REMOTE_DAEMON_PORT}' || true
" || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Scope this job to one run at a time.

The pkill -f pattern matches only the daemon host and port, not the run. REMOTE_DAEMON_PORT comes from POD_L3_DAEMON_PORT, which is fixed per machine pair. If two runs of st-pod-onboard-a2a3 overlap on the same pod pair, the second run's pre-start pkill at line 986 terminates the first run's live daemon, and both runs contend for the same listening port. The workflow triggers on pushes to two branches, so overlapping runs are reachable.

Add a concurrency group so the pod pair serves one run at a time.

🛡️ Proposed fix
   st-pod-onboard-a2a3:
     runs-on: [self-hosted, Linux, ARM64, pod-a2a3]
     timeout-minutes: 60
+    concurrency:
+      group: st-pod-onboard-a2a3
+      cancel-in-progress: false
     env:

Note that cancel-in-progress: false is required here. A cancelled run is SIGKILLed and never reaches its EXIT trap, which is the case the staging TTL sweep at line 959 already accounts for.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 984 - 987, Add a workflow-level
concurrency group for the st-pod-onboard-a2a3 job, keyed to the pod pair, and
set cancel-in-progress to false so overlapping runs queue instead of terminating
the active run. Keep the existing daemon cleanup and staging TTL behavior
unchanged.

Comment thread docs/capability-survey.md Outdated
The 7-level model (L6 Cluster … L0 Core) is declared in
[hierarchical-level-runtime.md](hierarchical-level-runtime.md). Its own status
table is accurate: L3 implemented; L4 local implemented, remote simulation only;
table is accurate: L3 implemented; L4 local implemented, remote host_tcp shipped;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the L4 status with the documented CI coverage.

Line 27 defines Shipped as covered by CI. Line 116 states that no CI job starts the daemon. Either use Shipped, not CI-run, or update the CI statement after confirming daemon coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/capability-survey.md` at line 37, Align the L4 status in the capability
survey with the documented CI coverage: since line 116 says no CI job starts the
daemon, mark the remote host_tcp capability as “Shipped, not CI-run” unless
daemon coverage is confirmed; otherwise update the CI statement to reflect the
verified coverage.

Comment thread docs/remote-l3-worker-design.md Outdated
hashid -> ChipCallable register payload, when needed
hashid -> Python import descriptor, when needed
comm policy: roce | hccs | ub | sim
comm policy: host_tcp | roce | hccs | ub

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Mark future profiles as unsupported in the manifest schema.

Line 410 lists host_tcp | roce | hccs | ub as communication-policy options. The daemon currently rejects every profile except host_tcp, as documented in docs/capability-survey.md Lines 110-114. Show only host_tcp as accepted in this cut. List the other profiles as reserved or future values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/remote-l3-worker-design.md` at line 410, Update the communication-policy
manifest schema entry in the remote L3 worker design so host_tcp is the only
accepted value; mark roce, hccs, and ub as reserved or future values rather than
supported options, consistent with the daemon’s current behavior.

Comment on lines +12 to +20
| 1 | Endpoint interface and local adapter | In progress | Local adapter and remote host_tcp endpoint are implemented; HCOMM endpoint adapters remain. |
| 2 | Worker eligibility metadata | In progress | Callable worker-id sets are intersected with owner/imported remote sidecar eligibility. |
| 3 | Remote task sidecars and dependency keys | In progress | Public `TaskArgs.add_tensor(RemoteTensorRef(...))` API, remote TensorMap keys, and remote payload-sidecar rejection are implemented. |
| 4 | Failed task poisoning | In progress | Remote task-failure poisoning and session-exit endpoint failure are verified; explicit health-expiry-only coverage remains. |
| 5 | Versioned remote frame codec | In progress | TASK/COMPLETION/CONTROL_REPLY/HELLO/CONTROL/HEALTH exist; core fuzz/bounds coverage is present, with more exhaustive corpus testing still possible. |
| 6 | Remote callable registry | In progress | Dispatcher `PYTHON_IMPORT`, inner manifest/control `PYTHON_IMPORT`, and inner manifest/control inline `CHIP_CALLABLE` are implemented; serialized payloads and staged chip blobs remain negotiated extensions. |
| 7 | Fork-safe simulation session runner | In progress | Daemon/session bootstrap and HELLO READY barrier are implemented for sim transport. |
| 8 | Remote control-plane parity | In progress | Registry, alloc/free/copy, export/import/release-import controls are implemented for sim; Remote CommDomain controls are reserved/unsupported. |
| 9 | Remote buffer registry | In progress | Sim owner/imported buffers, TASK materialization, public memory API, opaque handles, slot/import-ref capture, and deferred free/release-import are implemented. |
| 7 | Fork-safe host_tcp session runner | In progress | Daemon/session bootstrap and HELLO READY barrier are implemented for host_tcp transport. |
| 8 | Remote control-plane parity | In progress | Registry, alloc/free/copy, export/import/release-import controls are implemented for host_tcp; Remote CommDomain controls are reserved/unsupported. |
| 9 | Remote buffer registry | In progress | host_tcp owner/imported buffers, TASK materialization, public memory API, opaque handles, slot/import-ref capture, and deferred free/release-import are implemented. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align host_tcp status and PR scope across the audit documents.

The documents use conflicting completion and scope labels for the same runtime cut. Use one status definition, state remaining gaps, and remove stale simulation terminology.

  • docs/remote-l3-worker-design/implementation-record.md#L12-L20: align the In progress entries with the implementation plan and list the remaining gaps.
  • docs/remote-l3-worker-design/implementation-plan.md#L8-L14: align the implemented claims with the implementation record.
  • docs/remote-l3-worker-design/pr-split-and-audit-plan.md#L369-L370: rename the PR 6 scope from simulation to host_tcp and identify any simulation-only coverage.
📍 Affects 3 files
  • docs/remote-l3-worker-design/implementation-record.md#L12-L20 (this comment)
  • docs/remote-l3-worker-design/implementation-plan.md#L8-L14
  • docs/remote-l3-worker-design/pr-split-and-audit-plan.md#L369-L370
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/remote-l3-worker-design/implementation-record.md` around lines 12 - 20,
Align the host_tcp status and scope across all three audit documents: update the
entries in docs/remote-l3-worker-design/implementation-record.md (lines 12-20)
to use the implementation-plan status definition and explicitly list remaining
gaps; revise the implemented claims in
docs/remote-l3-worker-design/implementation-plan.md (lines 8-14) to match that
record; and update docs/remote-l3-worker-design/pr-split-and-audit-plan.md
(lines 369-370) to describe PR 6 as host_tcp scope, identifying any coverage
that remains simulation-only.

Comment on lines +49 to +56
extern "C" __aicore__ __attribute__((always_inline)) void kernel_entry(__gm__ int64_t *args) {
// Unpack arguments (Tensor* pointers from runtime)
__gm__ Tensor *src0_tensor = reinterpret_cast<__gm__ Tensor *>(args[0]);
__gm__ Tensor *src1_tensor = reinterpret_cast<__gm__ Tensor *>(args[1]);
__gm__ Tensor *out_tensor = reinterpret_cast<__gm__ Tensor *>(args[2]);
__gm__ float *src0 = reinterpret_cast<__gm__ float *>(src0_tensor->buffer.addr) + src0_tensor->start_offset;
__gm__ float *src1 = reinterpret_cast<__gm__ float *>(src1_tensor->buffer.addr) + src1_tensor->start_offset;
__gm__ float *out = reinterpret_cast<__gm__ float *>(out_tensor->buffer.addr) + out_tensor->start_offset;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Run the required C++ formatter before merge.

  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp#L49-L56: Run clang-format -i examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp.
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add_scalar.cpp#L51-L59: Run clang-format -i examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add_scalar.cpp.
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_mul.cpp#L49-L56: Run clang-format -i examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_mul.cpp.
  • examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp#L42-L54: Run clang-format -i examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp.

As per coding guidelines, **/*.{cc,cpp,cxx,h,hpp} requires clang-format -i <file>.

📍 Affects 4 files
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp#L49-L56 (this comment)
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add_scalar.cpp#L51-L59
  • examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_mul.cpp#L49-L56
  • examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp#L42-L54
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp` around
lines 49 - 56, Run clang-format -i on kernel_entry in
examples/workers/l4/vector_add_mixed_l3/kernels/aiv/kernel_add.cpp (lines
49-56), kernel_add_scalar.cpp (lines 51-59), kernel_mul.cpp (lines 49-56), and
the orchestration flow in
examples/workers/l4/vector_add_mixed_l3/kernels/orchestration/vector_add_mixed_l3_orchestration.cpp
(lines 42-54).

Source: Coding guidelines

Comment thread python/simpler/remote_l3_session.py Outdated
Comment on lines +667 to +678
try:
buf = inner_worker.create_host_buffer(int(nbytes))
entry = _RemoteBufferEntry(
buf,
int(nbytes),
generation,
RemoteAddressSpace.REMOTE_DEVICE,
owner=inner_worker,
)
except _NoHostBufferChildrenError:
buf = shared_memory.SharedMemory(create=True, size=int(nbytes))
entry = _RemoteBufferEntry(buf, int(nbytes), generation, RemoteAddressSpace.REMOTE_DEVICE)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve an exportable descriptor for worker-owned buffers.

inner_worker.create_host_buffer() returns a HostBuffer, but this branch stores it in _RemoteBufferEntry.data. EXPORT_BUFFER later calls _RemoteBufferEntry.shm_name, which raises for every non-SharedMemory value. The preferred allocation path therefore cannot export a buffer. Store the backing shared-memory name or host TCP descriptor with the entry, then use it in ExportBufferResult.

Also applies to: 789-790

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/remote_l3_session.py` around lines 667 - 678, Update the
preferred allocation path around inner_worker.create_host_buffer and the
EXPORT_BUFFER handling to preserve an exportable descriptor for worker-owned
HostBuffer instances. Store the backing shared-memory name or host TCP
descriptor in _RemoteBufferEntry rather than relying on shm_name to interpret
entry.data, and have ExportBufferResult use that preserved descriptor while
keeping the SharedMemory fallback unchanged.

Comment thread python/simpler/worker.py
- Add pure-Python endpoint selectors, registry resolution, capability cache, and SingleOwner backend planning.

- Wire Worker internal resolve/plan helpers with lazy registry epochs while keeping create_region and materialization out of W2.

- Cover selector, registry, planner, and package-surface behavior with focused unit tests.
@ccyywwen
ccyywwen force-pushed the w2-comm-endpoint-model branch from 7b9df75 to 74c9abf Compare August 5, 2026 07:00
@ccyywwen ccyywwen changed the title Add: CPU-NPU Shared-memory Endpoint Model Add: CPU-NPU Comm Endpoint Model Aug 5, 2026
- Move Sequence to collections.abc for ruff's typing rules

- Split long endpoint and test expressions so ruff E501 passes
Keep region resolution and backend planning on the same EndpointRegistry instance so a concurrent close cannot clear the memo between lookups.

@ChaoWao ChaoWao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Summary

The code itself is good: clean module boundaries, no dependency on the nanobind extension (pinned by a test), deterministic resolution, structured error reasons instead of string matching, and a real test per branch. If this were a greenfield endpoint helper I would approve it.

But W2's deliverable is a frozen model, and four of the frozen items disagree with domain-membership.md in ways that get expensive once W5 builds on them. Three of those four stop being redesign work and become "reuse the types the sibling PR already froze" — see below.


First: this overlaps #1599 more than it looks

domain-membership.md §3 defines the contract as

AttachmentPlan = (member EndpointId, CanonicalBufferIdentity) -> capability + attachment

This PR builds the left key. #1599 ("Add: the Buffer/Tensor wire ABI and owner-side create_buffer", open since 2026-07-30) builds the right key — the doc names it explicitly: "CanonicalBufferIdentity(wire 类型名为 CanonicalIdentity)". Neither builds the arrow; that is W5.

The two branches merge cleanly (git merge-tree → no conflicts; they touch disjoint regions of worker.py). The collision is semantic:

Axis of the capability formula #1599 already ships this PR introduces instead
backing / backend BackendKind {FORK_SHM, POSIX_SHM, VMM_WINDOW, REMOTE_SIDECAR, DEVICE_MALLOC, FORK_COW}, wire-frozen with static_assert BackingKind {DEVICE_HBM, HOST_SHM}
authorization AccessMode {READ, WRITE, READWRITE}, validated on decode — absent
address space AddressSpace {HOST, DEVICE} folded into EndpointDeployment
a capability gate validate_buffer_descriptor, literally commented "address_space x backend_kind capability gate … (capability matrix)" BackendResolver, a different matrix over (deployment, deployment, same_node)
buffer identity CanonicalIdentity = owner_instance_id + buffer_id + generation — no buffer concept

The concrete cost. §3 gives the canonical reason backing must be in the formula:

HOST × VMM_WINDOW = ❌ — 部署与互连都对,但 backing 是 VMM ⇒ host-map 仍失败

VMM_WINDOW and DEVICE_MALLOC are separate values in #1599. This PR collapses both into BackingKind.DEVICE_HBM and asks one global boolean PlatformCapability.HOST_MAP_DEVICE_HBM — so BackendResolver will emit HOST_DIRECT_MAP_ACCESS over a VMM backing, which halHostRegister rejects at the driver level (ascend_hal_base.h:2401; hardware-constraints.md §5). The distinction that makes the rule expressible exists in #1599 and is discarded here.

Suggested ordering: #1599 lands first, this PR rebases and keys its plan on BackendKind / AccessMode / CanonicalIdentity. #1599 is older, larger, and its byte layout freezes on merge; this PR is pure Python and far cheaper to move. The reverse order freezes a second backend vocabulary a week after the first, and one of them then has to be deleted.


Must fix

1. The cross-node hard-reject reintroduces a modelling error the design retracted on 2026-08-03

comm_endpoints.py:505-510_plan_member returns CROSS_NODE_UNSUPPORTED before consulting any capability. §4.1's rewrite note calls the old boolean form "既不准确,也制造了一个特例化的恒假分支", and §9.1 states the replacement rule directly:

请求的 adapter 不可用时才失败,而不是「因为跨机所以失败」

#1623 established a cross-host domain on two-host A3 silicon with max_diff == 0. Cross-node narrows the available adapters — C/T available, D explicitly refused with a reason — it is not a pre-emptive reject.

2. node_scope_id is derived from local-vs-remote, not node identity — and a test pins the wrong answer

_RegistryBuilder.add_worker_children allocates a fresh node_scope_id per RemoteWorkerSpec. Two live consequences:

  • test_comm_endpoints.py:94-98 registers endpoint="127.0.0.1:1234" and asserts not same_node(root, remote). A loopback remote worker is on the same node by construction.
  • Two remote L3s on one physical host get distinct scope ids and are treated as cross-node.

RemoteWorkerSpec.endpoint carries the host and is already validated to numeric IPv4 / localhost at worker.py:4116; node scope should come from there.

3. EndpointId is a bare registry-local integer, and BackendPlan carries nothing else

ResolvedRegionSpec.members keeps full records, but BackendPlan.provider_endpoint_id / ordered_member_endpoint_ids / MemberMaterialization.endpoint_id are ints only, allocated from a counter that restarts at 0 for every registry. A plan is therefore uninterpretable without the exact registry instance that produced it, and nothing binds the two — epoch sits on the registry but is not part of the id, and _record_for does not check it.

§3 requires session_id precisely "才能区分同一路径的不同 incarnation"; §10 bans the bare index ("不以「第 N 个 worker」的裸索引表达"). #1599 solves the same problem for buffers with owner_instance_id (a full-width random draw) plus generation; the same shape works here.

Related: the path root is the building worker's level, so one chip is L3/L2[0] from an L3 and L4/L3[0]/L2[0] from its parent. §3 requires worker_path to be cross-process resolvable.

4. Backing is derived solely from the MemberSet, and the flagship case cannot be expressed

_backing_for_provider maps provider deployment → one BackingKind for the whole region, and plan() opens with del layout. §7's headline row — the brick this design exists to lay ("本设计要补的那块砖") — is HOST_CPU + 同机 DEVICE_*"host-map control Buffer + device-local/VMM payload Buffer;逐 Buffer 选 direct/copy adapter". That needs two backings and per-Buffer capability inside one domain. LayoutSummary already carries counter_bytes / payload_bytes hinting at the split, then ignores them. W2 ⑤ states the prohibition: "禁止仅从 MemberSet 推导后端".

This is the item that reduces to "use #1599's BackendKind and key capability on CanonicalIdentity".


Should fix

5. Every unsupported-plan message duplicates its endpoint label

Reproduced by running the module:

host access to device HBM is unsupported: L4 HOST_CPU: L4 HOST_CPU
cross-node region member is unsupported: L4 HOST_CPU: L4/L3[0]/L2[0] DEVICE_AICORE, L4 HOST_CPU

_plan_device_hbm_member / _plan_host_shm_member / _plan_member interpolate _endpoint_label(member), then _unsupported() appends the offending labels again (comm_endpoints.py:580-582). Drop the label from the call sites and let _unsupported own the formatting. The tests assert with in, which is why this passes.

6. Converge the worker-path format with #1599

work-breakdown.md §4 item 2 asks for exactly one thing to be shared — the format, not the storage:

只共享路径的格式/格式化工具,不共享存储或语义

The storage split is implemented correctly on both sides. The format is not: three spellings are now in flight.

Source Spelling
this PR, EndpointRegistry L4/L3[0]/L2[5]
#1599, worker.py::_create_buffer_locked owner_worker_path=f"L{self.level}"
#1599, buffer.py:265 intern_worker_path(f"remote/{owner_worker_id}")

f"L{self.level}" agrees with this PR's root segment by coincidence; remote/3 does not parse under _PATH_SEGMENT_RE at all. One shared format_worker_path() fixes it, and it is cheapest now — #1599's side table has no consumers yet.

7. _require_ready_for_region_planning is a weaker duplicate of the _operation_lease admission fence

worker.py:5282-5287 re-checks _lifecycle is READY with the same error string as _operation_lease (worker.py:5257), but skips the two other conditions the lease enforces — _consume_worker_host_mapped_cleanup_error_locked and _ordered_cleanup_error. It then runs twice more per call (_plan_region_get_endpoint_registry → again), so one plan takes three _hierarchical_start_cv acquisitions. P0.2 centralised admission on the lease. Keep the static level < 3 check and drop the lifecycle branch.

8. Non-canonical adapter vocabulary

MaterializationMode.{HOST_DIRECT_MAP_ACCESS, HOST_COPY_ACCESS, DEVICE_IMPORT_ACCESS, HOST_SHM_ACCESS} against §3's "用规范的 adapter 名,不要自造": direct-map/device-peer, owner-delegated copy, explicit transfer, HCCL collective. explicit transfer — the one adapter that mints a new CanonicalBufferIdentity, and per §9.1 "在跨机上是常规手段,不是降级" — has no representation. Since W2's deliverable is the frozen vocabulary, this is the part most expensive to rename later.

9. 626 new lines, one docstring, no contract comments

The load-bearing invariants a reader cannot recover from the code are all undocumented: under excludes the path itself; overlapping at + under is an error rather than a dedupe; member order in ordered_member_endpoint_ids is selector order then (level, index) — which becomes the rank order; endpoint_id is registry-local. Per .claude/rules/comments.md these are exactly the present-tense facts worth a comment, and per doc-consistency.md §5 a frozen contract belongs in docs. Nothing in-repo records what W2 froze.


Consider

  • _plan_region can never return a supported plan in production. No production code assigns _platform_capability_cache (only test_comm_endpoints.py:37), and StaticPlatformCapabilityCache().get answers False for everything — so any region with ≥2 members returns UnsupportedRegionPlan. Verified. Fine for a plan-only PR; say so in the docstring rather than leaving a working-looking entry point.
  • Registry epoch invalidation is unreachable. Topology freezes at init() and CLOSED is terminal, so no registry is ever rebuilt and a usable registry's epoch is always 0. The PR body lists it as a delivered feature.
  • EndpointRegistry.from_worker reads five private Worker attributes on the root and every child, typed Any. A topology-snapshot accessor on Worker would keep worker.py owning its own shape.
  • EndpointSelector is exported and directly constructible, bypassing at() / under() validation (test_comm_endpoints.py:47 does this). Validate in __post_init__ or drop it from __all__.
  • §5/§6 encapsulation. The root builds one global registry including remote children's spec.device_ids, whereas §6 wants subtree selectors expanded "各 L3 本地展开" so "L4 不必知道 chip 拓扑". Today's RemoteWorkerSpec already hands the root that list, so this PR is not inventing the knowledge — but if local expansion is still the intent, this is the moment to say so.

CI and stale feedback

st-onboard-a5 is red, and it is not this PR. The single failure is

FAILED tests/st/a2a3/tensormap_and_ringbuffer/spmd_paged_attention_highperf/
  ::TestSpmdPagedAttentionHighPerf::test_run - RuntimeError: run failed with code -100

a device-side AICPU rc=-100. This diff is pure Python — no C++, no kernel, no scheduler — and the only behaviour change in worker.py outside new methods is one _invalidate_endpoint_registry() call in close(). The same test has prior history with this signature (#1070). I have re-run the failed job; if it reproduces it needs its own triage rather than silence.

The 9 existing CodeRabbit items on this PR are stale. All 7 inline threads are isOutdated and anchored to files absent from this 5-file diff (.github/workflows/ci.yml, docs/remote-l3-worker-design/*, examples/workers/l4/vector_add_mixed_l3/**, python/simpler/remote_l3_session.py), and the review body reviews _chip_descriptor_context / remote-spec encoding. They predate the branch reset onto c866c827; CodeRabbit has not re-reviewed since (Review skipped: incremental reviews are disabled). Nothing there needs answering.


Verification note. I could not run the new tests locally — the build-stamp guard correctly refuses a _task_interface from another worktree, and a fresh editable install fails on missing nanobind (a local setup gap, unrelated to this PR). CI's ut job is green on both ubuntu and macOS and covers exactly these two files. The selector semantics, the default-cache planning outcome, and the duplicated-label defect above were verified by importing comm_endpoints.py directly, which needs no extension.

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