Refactor: finish the PTO2 retirement, one identifier per commit - #1980
Conversation
|
Important Review skippedToo many files! This PR contains 315 files, which is 215 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (315)
You can disable this status message by setting the 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. Comment |
6d93b70 to
4e15283
Compare
`PTO2ResourceShape` becomes `ResourceShape` and `PTO2_NUM_RESOURCE_SHAPES` becomes `NUM_RESOURCE_SHAPES`. Both names are free: nothing else in the tree, in the CANN headers, or in pto-isa spells either of them, so this is a plain prefix strip. 474 occurrences across 46 files. The constant is that enum's cardinality, so it moves with the type rather than in a commit of its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskDescriptor` -> `TaskDescriptor`, `PTO2TaskPayload` -> `TaskPayload`, `PTO2PreparedTask` -> `PreparedTask`, and the seven `PTO2_TASKPAYLOAD_*` field offsets lose the prefix with them. All plain strips: no declaration anywhere in the tree, in the CANN headers or in pto-isa holds any of these names. 561 occurrences across 81 files. The offset macros describe the layout of the payload the AICore reads, so they belong to `TaskPayload` and move with it rather than in a commit of their own. The shared-memory layout diagrams in `runtime/shared_memory.h` and `docs/RUNTIME_LOGIC.md` already write `TaskDescriptor[]` and `TaskPayload[]`, so two of their three rows become literally true here. They are corrected once, in the commit that renames `SharedMemoryHeader`, when every name in the box is a name that exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SharedMemoryHeader` -> `SharedMemoryHeader`, `PTO2SharedMemoryRingHeader` -> `SharedMemoryRingHeader`, `PTO2SharedMemoryHandle` -> `SharedMemoryHandle`, `PTO2SharedMemory` -> `SharedMemory`, and the `pto2_sm_layout` namespace becomes `sm_layout`. All plain strips; 602 occurrences across 82 files. The namespace is the case rule 9 has in mind when it asks for "clear names or a `namespace`" in place of the prefix: `sm_layout::ring_segment_offsets` is already qualified, so the `pto2_` on the namespace itself was pure noise. This is also where the shared-memory layout diagrams become true, which is what the `ChipTaskSlotState` commit deferred them for. Every row of those boxes now names a type that exists under exactly that spelling — `SharedMemoryHeader`, `TaskDescriptor[]`, `TaskPayload[]`, `ChipTaskSlotState[]` — in all four `runtime/shared_memory.h` copies and in the `sizeof` formula in both `tensormap_and_ringbuffer/docs/RUNTIME_LOGIC.md` copies. The two multi-ring boxes widen by four columns because the corrected name no longer fits beside the `Ring N:` prefix. The bare `TaskSlotState` that remains in `docs/orchestrator.md`, `docs/callable-identity-registration.md` and `docs/hierarchical-level-runtime.md` is the host orchestrator's own type and stays as it is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SchedulerState` -> `SchedulerState`, `PTO2SchedulerLayout` -> `SchedulerLayout`, `PTO2SchedProfilingData` -> `SchedProfilingData`, and the two `PTO2_SCHED_CYCLE_*` markers lose the prefix with them. All plain strips: no declaration in the tree, in the CANN headers or in pto-isa holds any of these names. 397 occurrences across 71 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2OrchestratorState` -> `OrchestratorState`, `PTO2OrchestratorLayout` -> `OrchestratorLayout`, `PTO2OrchProfilingData` -> `OrchProfilingData`. All plain strips; 236 occurrences across 42 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TensorMap` becomes `ChipTensorMap` — not `TensorMap`, because `src/common/hierarchical/tensormap.h:46` already declares a `class TensorMap`: the host orchestrator's producer lookup, which resolves `TensorKey` to a host `TaskSlot`. This one is the chip runtime's lazily-invalidated device-side map that the AICPU orchestrator walks to infer dependencies. Two maps, two contexts, so `.claude/rules/codestyle.md` rule 13 gives the bare name to the L3+ side and the `Chip` prefix to this one. Its satellites take the same prefix, so the cluster reads one way throughout: `ChipTensorMapEntry`, `ChipTensorMapLayout`, `ChipTensorMapProfilingData`, `chip_tensormap_get_profiling`, and the three capacity constants `CHIP_TENSORMAP_POOL_SIZE` / `CHIP_TENSORMAP_NUM_BUCKETS` / `CHIP_TENSORMAP_CLEANUP_INTERVAL`. `PTO2LookupResult` is a plain strip to `LookupResult`: it names no map of its own and nothing else claims the name. 445 occurrences across 61 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2ReadyQueue` becomes `ChipReadyQueue` — not `ReadyQueue`, because `src/common/hierarchical/types.h:509` already declares a `class ReadyQueue` for the host orchestrator. This one is the device-side sharded queue the AICPU scheduler threads claim from. Rule 13 gives the bare name to the L3+ side. `ChipReadyQueueSlot` and the two capacity constants `CHIP_READY_QUEUE_SIZE` / `CHIP_PROF_READYQUEUE_SIZE` follow it, so the queue and its slot type read the same way. `PTO2LocalReadyBuffer` is a plain strip to `LocalReadyBuffer` — it is a per-thread staging buffer rather than a queue, and nothing else claims the name. 212 occurrences across 32 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskState` becomes `ChipTaskState`, with its three enumerators `CHIP_TASK_PENDING` / `CHIP_TASK_COMPLETED` / `CHIP_TASK_CONSUMED`. `TaskState` is not available: `src/common/hierarchical/types.h:203` declares an `enum class TaskState` for the host orchestrator, and that one is bound into Python — both `python/simpler/task_interface.py` and `tests/ut/py/test_task_interface.py` import the name. Rule 13 gives the bare name to the L3+ side; the enumerators keep the type's prefix so a reader cannot mistake a chip-side PENDING for the host's. The lifecycle flags in the same header are plain strips — `TaskLifecycleFlag`, `LIFECYCLE_FLAGS_NONE`, `READY_CLAIMED`, `COMPLETION_DONE`, `SUBTASK_DEFERRED`, `DISPATCH_PROPAGATED` — because nothing else in the tree, in the CANN headers or in pto-isa claims any of them. They move here rather than in a commit of their own: they are the other half of the same 64-byte slot's state word. 362 occurrences across 40 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The five ring types take the `Chip` prefix as one cluster: `ChipTaskRing`, `ChipHeapRing`, `ChipRingSet`, `ChipRingFlowControl`, `ChipRingSegmentOffsets`. `HeapRing` is the name that forces it — `src/common/hierarchical/ring.h:151` declares a `struct HeapRing` inside the host orchestrator's `class Ring`, which owns `mmap`ed host slabs with a mutex and condition variable. The chip runtime's rings live in the device shared-memory image and are advanced by atomic counters. Rule 13 gives the bare names to the L3+ side. The other four do not collide on their own, but they are the same ring: splitting the cluster would leave `ChipHeapRing` and `RingFlowControl` as fields of one struct, which reads as two subsystems rather than one. 85 occurrences across 25 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskAllocator` -> `TaskAllocator`, `PTO2TaskAllocResult` -> `TaskAllocResult`, `PTO2_ALLOC_DEADLOCK_TIMEOUT_CYCLES` -> `ALLOC_DEADLOCK_TIMEOUT_CYCLES`. 84 occurrences across 33 files. All three are plain strips, and `TaskAllocResult` is the one worth naming: the host orchestrator has a `struct AllocResult` in `src/common/hierarchical/ring.h:86`, so dropping `Task` as well as the prefix would have collided. Keeping it distinguishes the chip runtime's ring allocation from the host's heap-slab allocation without needing the `Chip` prefix. The timeout is the reclaim backstop that allocator enforces, so it moves with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2FaninPool` -> `FaninPool`, `PTO2FaninSpillEntry` -> `FaninSpillEntry`, `PTO2FaninBuilder` -> `FaninBuilder`, `PTO2FaninForEachReturn` -> `FaninForEachReturn`, `PTO2FaninCallbackResult` -> `FaninCallbackResult`, and the `FANOUT_SCOPE_BIT` constant. 327 occurrences across 53 files. One dependency-edge mechanism, so it moves as one commit: the pool that holds the spill entries, the builder that fills them, the traversal's return type, and the bit that marks a scope reference. The two caps stay prefixed as `CHIP_FANIN_INLINE_CAP` and `CHIP_MAX_FANIN`: both are object-like macros in `runtime/runtime_types.h`, which the whole tree includes. A macro captures its identifier textually rather than declaring anything, so a bare `MAX_FANIN` would silently rewrite any unrelated `MAX_FANIN` a caller happens to declare, instead of colliding where the compiler can say so. `FANOUT_SCOPE_BIT` is an `inline constexpr` and needs no such protection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2DepListEntry` -> `DepListEntry` and `PTO2DepListPool` -> `DepListPool`. 124 occurrences across 35 files. The four constants that size and instrument the pool keep a prefix — `CHIP_DEP_LIST_POOL_SIZE`, `CHIP_DEP_POOL_CLEANUP_INTERVAL`, `CHIP_DEP_DEGREE_DEBUG_THRESHOLD`, `CHIP_DEP_DEGREE_WARN_THRESHOLD` — because they are object-like macros in `runtime/runtime_types.h` and a macro rewrites its identifier in every translation unit that includes the header rather than declaring something the compiler can diagnose. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two state machines lose the prefix together: `EarlyDispatchState` with its `EARLY_DISPATCH_*` values and the `EarlyDispatchLaunchState` sub-state, `EarlySyncDrainState` with its `EARLY_SYNC_DRAIN_*` values, and `EARLY_DISPATCH_CORE_MASK_WORDS`. 356 occurrences across 25 files. An enum and its enumerators cannot be split across commits without leaving the type and its values on two conventions, and the drain state is the handshake the dispatch state waits on, so the two read as one mechanism. `CHIP_EARLY_DISPATCH_QUEUE_SIZE` keeps a prefix: unlike the enumerators, it is an object-like macro in `runtime/runtime_types.h`, so a bare name would capture the identifier textually across every including translation unit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SubtaskSlot` -> `SubtaskSlot` with `SUBTASK_SLOT_COUNT` and the three `SUBTASK_MASK_AIC` / `SUBTASK_MASK_AIV0` / `SUBTASK_MASK_AIV1` selectors, and `PTO2DispatchPayload` -> `DispatchPayload` with `DISPATCH_MAX_ARGS`. 442 occurrences across 72 files. All five constants here are `inline constexpr` in `runtime/submit_types.h` rather than macros, so they can take the bare name: a clash would be a redeclaration the compiler reports, not a silent textual rewrite. The masks name the slots, so they move with the slot type; the payload is what a dispatch writes into one, so its argument cap moves with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2ScopeMode` -> `ScopeMode` is a plain strip. The two capacities are not: `CHIP_MAX_SCOPE_DEPTH` and `CHIP_SCOPE_TASKS_CAP` keep a prefix because `src/common/hierarchical/types.h:117` already declares `static constexpr int32_t MAX_SCOPE_DEPTH = 64` for the host orchestrator — and because the chip runtime's version is an object-like macro, the bare name would not have collided cleanly. It would have textually rewritten the host's declaration into `static constexpr int32_t 64 = 64;` in any translation unit that saw the chip header first. Rule 13 gives the bare name to the L3+ side regardless. The two scope-stats collector bounds do take bare names — `SCOPE_STATS_MAX_RING_DEPTH`, `SCOPE_STATS_MAX_SCOPE_DEPTH` — since they are already qualified by what they bound and nothing else spells them. 176 occurrences across 62 files. These are what the `SIMPLER_SCOPE` commit left behind: it renamed the macro and its guard, not the mode enum the macro sets or the caps that bound a scope. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2_ALIGN_UP` becomes `CHIP_ALIGN_UP` rather than `ALIGN_UP`, because CANN already defines `ALIGN_UP` — in `acl/ops/acl_dvpp.h` and `acl/dvpp/hi_media_common.h`, both reachable from translation units that include our headers. No grep of this repository can see that, which is why the check has to run against the external headers we compile against and not only against the tree. `PTO2_ALIGN_SIZE` takes the same prefix even though `ALIGN_SIZE` is free. The two are one pair — the granularity and the macro that rounds to it — and splitting their spelling would read as two unrelated constants. `PTO2_PACKED_OUTPUT_ALIGN` is a plain strip to `PACKED_OUTPUT_ALIGN`: it belongs to the packed-output layout rather than to the arena's alignment, and nothing claims the name. 343 occurrences across 70 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last of the identifier work: the waits `TENSOR_DATA_TIMEOUT_CYCLES` / `TENSOR_DATA_TIMEOUT_MS`, the caps `DEFERRED_RELEASE_CAP` and `EXT_PARAMS_COUNT`, the three `MODE_*` runtime modes, the types `LaunchSpec` and `OutputLayout`, the `ORCHESTRATION_CONFIG_DEFINED` include guard, and the file-local `read_runtime_status` helper. 239 occurrences across 83 files. Four keep a prefix because they are object-like macros rather than `constexpr`: `CHIP_TASK_WINDOW_SIZE`, `CHIP_HEAP_SIZE`, `CHIP_BLOCK_NOTIFY_INTERVAL` and `CHIP_PUBLICATION_REQUEST_TIMEOUT_CYCLES`. `HEAP_SIZE` is the one that proves the rule rather than merely satisfying it: three cpput fixtures declare `static constexpr uint64_t HEAP_SIZE = 4096;`, and `#define HEAP_SIZE (256 * 1024 * 1024)` rewrites that declaration into `static constexpr uint64_t (256 * 1024 * 1024) = 4096;`. The runtime build never sees it — the C++ unit tests are a separate CMake project — so the gate for a rename has to compile both. `read_runtime_status` is `static` in all four `host/runtime_maker.cpp` copies, so the prefix bought it nothing that internal linkage did not already provide. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both named a `PTO2_*` variable that nothing reads, and both failed silently because an unrecognised environment variable is simply ignored. `tools/benchmark_rounds.sh --serial-orch-sched` set `PTO2_SERIAL_ORCH_SCHED=1` for its second arm. The runtime reads `SIMPLER_TMR_SERIAL_ORCH_SCHED_ENABLE` (`tensormap_and_ringbuffer/host/runtime_maker.cpp`), so the serial arm ran with serial orch->sched still off: the script measured the parallel path twice and reported the pair as a serial-versus-parallel comparison. Any measurement taken through that flag is void. `error_hint(SIMPLER_ERROR_SCHEDULER_TIMEOUT)` told the user to raise `PTO2_SCHEDULER_TIMEOUT_MS`. The knob is `SIMPLER_SCHEDULER_TIMEOUT_MS` (`common/platform/include/host/runtime_timeout_config.h`), which CI already sets by that name, so following the hint on a scheduler-timeout fatal changed nothing and made a slow kernel look like a real deadlock. Found while sweeping the `PTO2` prefix out of the runtime: both survived only because they are strings, so no compiler ever checked them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last of the prefix, and the only tier of it that was never an identifier: the brand as a word. `PTO2 shared memory` becomes `shared memory`, `PTO2 integration:` becomes what that map is for, `Extension to the PTO2 runtime` names `tensormap_and_ringbuffer`, and the doc titles say what they document. Log text moves with the docs that quote it, so the documented string keeps matching the emitted one: `progress: completed=`, `total submitted tasks`, `completed tasks`, `dispatch starting with`, `scheduler timeout sub_class=`, `=== Shared Memory Layout ===` and two failure messages, together with every mention of them in `profiling_levels.md` and `device_log_profiling.md`. Four file-local identifiers go too: `read_pto2_runtime_status`, `normalize_pto2_task_id_int`, and the locals `pto2_sm` and `pto2_count` — the last renamed to `window_tasks`, which is what it counts. Three references named things that do not exist, which is how a stale comment becomes a lie rather than just noise: - `pto2_task_slot(sched, task_id)`, cited by `runtime_types.h` and `runtime_init.cpp` as the way to compute a slot. There is no such function; the slot is `local_id` masked by the window size, and that is what the comment now says — including why the window has to be a power of two. - `pto2_run_runtime`, which `docs/task-flow.md` names five times as the L2 ABI edge. The entry point is `simpler_run`. - `pto2_init_*` flags, which `docs/dynamic-linking.md` lists among the fields `SchedulerContext::deinit()` resets. It resets no such flag, and none exists under any spelling, so the clause is gone. `docs/dfx/profiling-config-naming.md` claimed `PTO2_` was "the device runtime's internal namespace" and then illustrated it with `CHIP_MAX_RING_DEPTH`, `SIMPLER_ERROR_*` and `RuntimeContext` — three names that had already left it. It now states the convention that actually holds, including why an object-like macro takes `CHIP_` where a `constexpr` does not, and records why `PTO2_RING_TASK_WINDOW` / `PTO2_RING_HEAP` / `PTO2_RING_DEP_POOL` keep the legacy spelling: they are read from the environment by name, so a rename is ignored silently instead of failing to compile, and retiring them needs a cross-repo migration. `.claude/rules/codestyle.md` is untouched. Its `PTO2` mentions are the rule that bans the prefix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rule 10 still described a ~6.6k-occurrence backlog across 367 files. There are 129 occurrences left and every one is deliberate: the three `PTO2_RING_*` environment knobs, `PTO2_MANUAL_MAX_SEQ` (pypto-lib's, documented here only), and the rule's own illustrations of the banned spelling. Left as it was, the rule would send the next contributor looking for a sweep that no longer exists — and, worse, would let a genuine regression look like leftover backlog. A `PTO2` match now means a Tier-C knob or a defect. Two additions come from doing the work rather than from restating it: - Why an environment variable is the worst case in Tier C: an unrecognised name is ignored, so the rename fails silently in production instead of at compile time. Two knobs had already drifted that way and were dead when found. - What to check a target name against. The bare name may be held by the host orchestrator under `src/common/hierarchical/` (rule 13 decides who keeps it), by an external header the same translation units include (CANN defines `ALIGN_UP`), or — for an object-like macro — by any declaration at all, since a macro rewrites its identifier textually instead of colliding where the compiler can report it. Checking only the first of the three is how `#define HEAP_SIZE` came to rewrite a unit test's `static constexpr uint64_t HEAP_SIZE = 4096`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2_RING_TASK_WINDOW`, `PTO2_RING_HEAP` and `PTO2_RING_DEP_POOL` are no longer read. `CallConfig.runtime_env` carries the same three values per task, and is strictly more expressive: two tasks in one process can hold different ring sizes, which a process-wide export never allowed. So the env layer was not a fallback worth keeping — it was a second way to say the same thing, in a weaker form, and the one spelling of it that could not be renamed. Removing it deletes the whole parsing path from all four `host/runtime_maker.cpp` copies — `trim_copy`, `parse_uint_token`, `apply_env_ring_value[s]` and the scalar / comma-separated grammar they implemented — leaving per-task entries over the compile-time default with nothing in between. `<cctype>` and (in host_build_graph) `<limits>` were there only for that grammar and go with it. Net -283 lines. What replaces it is one warning. An unrecognised environment variable is *ignored*, so a caller that still exports one of these would otherwise run on the 256 MB default with the sizing it asked for nowhere in evidence — and the observable symptom is a heap-exhaustion deadlock that looks like a runtime regression rather than a configuration change. `warn_on_retired_ring_env()` reports each retired name that is set, once per bind, and points at `CallConfig.runtime_env`. It is a migration aid with no behavioral effect; delete it once no caller sets them. **Every diagnostic that advertised these variables had to move with them**, or the removal would have manufactured the same defect this branch already fixed twice (`PTO2_SERIAL_ORCH_SCHED`, `PTO2_SCHEDULER_TIMEOUT_MS`): a hint naming a variable nothing reads. So the device-side ring-buffer and orchestrator deadlock reports, the fanin-spill capacity report, the five `error_hint()` strings, the two capacity tables in `docs/troubleshooting/`, the `running-onboard` triage table, and the runnable command in `docs/dfx/scope-stats.md` now name `runtime_env.ring_task_window` / `ring_heap` / `ring_dep_pool`. Two unit tests assert on that hint text and move with it. `MULTI_RING.md` loses the two env tiers from its precedence ladder and its env-fallback section, which was the only place the comma-separated per-ring grammar was documented. The cross-repo edge is real and named where it matters. The deepseek example's own comment records that pypto-lib's daily CI sizes this network the same way, and `.claude/skills/multi-repo-qwen-setup` documented exporting `PTO2_RING_HEAP=4294967296` for batch-16 qwen prefill — 4 GiB, against a 256 MB default. That skill now gives the values as `CallConfig.runtime_env` fields and states outright that a runner still exporting the old names deadlocks exactly as its own gotcha section describes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4e15283 to
7f16161
Compare
`simpler_setup/runtime_compiler.py` sets `SIMPLER_CMAKE_DIR` to
`PROJECT_ROOT / "cmake"`, which is `simpler_setup/_assets/cmake` in an installed
package. The `SKBUILD_MODE` install block never created it, so every runtime cmake
configure from a wheel install failed on the first `include()`:
CMake Error at CMakeLists.txt:21 (include):
include could not find requested file:
.../site-packages/simpler_setup/_assets/cmake/host_log_sources.cmake
which then surfaces as `ValueError: empty compile database` from the clang-tidy
pre-commit hook, and because every gated CI job declares `pre-commit` in `needs:`,
it skips the entire test matrix rather than failing one job.
All four files under `cmake/` are reachable from a platform configure, so the whole
directory ships: `host_log_sources.cmake` and `profiling_config.cmake` are included
unconditionally by the platform `CMakeLists.txt`, `profiling_config.cmake`
configures `profiling_build_config.h.in`, and `sanitizers.cmake` is included for a
sanitizer build. Installing only the file named in the error would have failed at
the next `include()` instead.
Dates from hw-native-sys#1845, which added `include("${SIMPLER_CMAKE_DIR}/host_log_sources.cmake")`
to six platform `CMakeLists.txt` without an install rule to match. It stayed hidden
because the hook only configures on a build-cache miss, and `tools/verify_packaging.sh`
checks the entry points rather than the asset tree.
Verified by building the wheel both ways: `pip wheel --no-build-isolation --no-deps .`
produces zero `simpler_setup/_assets/cmake/*` entries before this change and all four
after.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Acknowledged on the skipped review — 314 files is over the 100-file limit, and the PR body records that consequence up front. Splitting is possible (three stacked PRs of ~7 commits each) but each would then block on the one below it; every one of the 22 commits is independently reviewable and independently builds both the runtime Separately, |
…nsor An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things about it: which task produced it, the version its OverlapMap keys on, whether dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself, in `src/common/task_interface/`, so one type served the boundary and both runtimes' working state. `create_from_chip_args` recorded the mismatch as an assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling `ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while `ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a `make()` factory. The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the runtime's tensor to reach the argument boundary, and got there by promoting the runtime-private header into `task_interface/` rather than adding strides to the 40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a mailbox doubling for a capability that PR noted was not yet used: two months on, `make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors. with a cost argument that applies equally here; nobody undid it at L2. `ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view. struct ChipTensor { PTOBufferHandle buffer; uint64_t start_offset; uint32_t shapes[MAX_TENSOR_DIMS]; uint32_t strides[MAX_TENSOR_DIMS]; uint32_t ndims; DataType dtype; AddressSpace address_space; }; `simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the geometry. One copy each, shared across architectures, placed the way `src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg` was an existing namespace. `Runtime::set_orch_args` is the single place one becomes the other. Both runtimes call it only from `host/runtime_maker.cpp`, so adoption happens on the host before any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of converting per run. From there inward nothing holds the argument form: orchestration, the payload, the TensorMap and the kernels all name their runtime's type. A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's include path, so existing `#include "tensor.h"` lines resolve to both types without an include sweep. That shim names the two headers by their path under `src/common`, which every platform target but `aicore` already had on its include path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings carry. `is_contiguous` and `extent_elem` become methods that compute from the geometry; a runtime that reads them per task caches them on its own `Tensor`. The view ops and the copy helpers that maintained those caches move with them — an argument is not a thing you take views of, and nothing outside a runtime called them. `init_external` and both factories lose their `manual_dep` / `version` parameters, which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a friend, and the boundary header no longer includes `task_id.h`: it names no TaskId at all. `sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B wire `Tensor`. `ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level layout so three copy paths could each be a single 64-byte `memcpy`, held by 21 hand-written `offsetof` assertions across four trees. Two of the three were shaped backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` / `__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` / `::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a `PTO2TensorMapEntry *` field, its comment noting this was "harmless because `link_entry()` overwrites `next_in_bucket` immediately after". Each struct now assigns the fields it wants, by name. The optimization the `memcpy` existed for survives as intent: a canonically contiguous source has the derived pair recomputed from `shapes` rather than read across. `PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an entry. The entry keeps its own two-cache-line split and the assertions describing it; what goes is the claim that its bytes agree with a different struct's. A source that names one runtime's `Tensor` cannot be compiled under the other, and 57 scene-test sources were: a `host_build_graph` case naming the `tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer` classes taking an hbg class's `CALLABLE` verbatim. That worked only because `ChipTensor` happened to be identical in both trees — the coupling this change removes. Each borrowing case now carries its own sources, 73 files, and names local paths. The two class-reuse cases rebase the inherited `CALLABLE` onto their own `kernels/` copy through a `_rebase_callable` helper, so the Python that drives them stays in one file while the C++ each runtime compiles is its own. `task_timing_slots` carries the runtime in a function default rather than a `@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the helper builds the path from the runtime it is driving. The cost is real: `spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`, `paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist once per runtime and the copies can drift. A case that asserts something about `host_build_graph` should not depend on a file the other runtime owns. `examples/` orchestration and kernel sources lose their `Generated by PyPTO IR Compiler` marker: they are this repository's sources, and this change edits them. `tensor_create_info.h`'s doc paragraph said `host_build_graph` has no initial-value fill "unlike the tensormap_and_ringbuffer copy of this header", which hw-native-sys#1981 made false by removing that fill; both copies now describe what is there. The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980 finished that retirement repo-wide — so they carry the current ones. `test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify packing Graph boundaries into the payload's tensor slots, and read that pool as `ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` — the assertion was true only while one type served both roles. Verification: full rebuild of both runtimes on both architectures, cpput 119/119, pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim sweeps build only the cases they run, so every orchestration source was also syntax-checked against its runtime's include path — 129 (source, runtime, arch) compiles, which is what caught a copy under host_build_graph/ still calling simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a Python driver mentions rather than its @scene_test decorator; that is what caught task_timing_slots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ChipHeapRing` and `ChipTaskRing` do not exist. `TaskAllocator` unified the task
window and the heap — its own header says so ("Unified task slot + heap buffer
allocator … checks both resources BEFORE committing to either") and so does the
allocator unit test — but four documents still described the two as live types, and
`ChipRingSet` as an aggregate of them:
struct ChipRingSet {
ChipHeapRing heap_ring; // neither member exists
ChipTaskRing task_ring;
FaninPool fanin_pool;
};
The real struct is `TaskAllocator task_allocator; FaninPool fanin_pool;`.
Both names now survive nowhere but in prose, which is what makes this worth fixing
rather than leaving: retiring the `PTO2` prefix in #1980 renamed these mentions along
with everything else, so a description that had been stale since the two types were
folded together started reading as a current one. The rename's own collision check
could not have caught it — it asks whether the target name is taken, not whether the
source name still names anything.
So `MULTI_RING.md` §4.1 gives `ChipRingSet` its real members and says why there is no
separate ring type to hold, §4.2's before/after shows the layout that actually
preceded the per-ring array, and `RUNTIME_LOGIC.md` labels its two structure sections
as the task-window and heap halves of the one allocator instead of two types. The
allocator test's header drops the same two names for what the class guarantees.
`docs/dfx/scope-stats.md` had the ring formula as `min(depth, MAX_RING_DEPTH−1)`;
`scope_stats.h` computes it with `CHIP_MAX_RING_DEPTH`, and the bare spelling is the
host orchestrator's own constant, so the doc pointed at the wrong one.
…nsor An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things about it: which task produced it, the version its OverlapMap keys on, whether dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself, in `src/common/task_interface/`, so one type served the boundary and both runtimes' working state. `create_from_chip_args` recorded the mismatch as an assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling `ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while `ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a `make()` factory. The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the runtime's tensor to reach the argument boundary, and got there by promoting the runtime-private header into `task_interface/` rather than adding strides to the 40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a mailbox doubling for a capability that PR noted was not yet used: two months on, `make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors. with a cost argument that applies equally here; nobody undid it at L2. `ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view. struct ChipTensor { PTOBufferHandle buffer; uint64_t start_offset; uint32_t shapes[MAX_TENSOR_DIMS]; uint32_t strides[MAX_TENSOR_DIMS]; uint32_t ndims; DataType dtype; AddressSpace address_space; }; `simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the geometry. One copy each, shared across architectures, placed the way `src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg` was an existing namespace. `Runtime::set_orch_args` is the single place one becomes the other. Both runtimes call it only from `host/runtime_maker.cpp`, so adoption happens on the host before any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of converting per run. From there inward nothing holds the argument form: orchestration, the payload, the TensorMap and the kernels all name their runtime's type. A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's include path, so existing `#include "tensor.h"` lines resolve to both types without an include sweep. That shim names the two headers by their path under `src/common`, which every platform target but `aicore` already had on its include path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings carry. `is_contiguous` and `extent_elem` become methods that compute from the geometry; a runtime that reads them per task caches them on its own `Tensor`. The view ops and the copy helpers that maintained those caches move with them — an argument is not a thing you take views of, and nothing outside a runtime called them. `init_external` and both factories lose their `manual_dep` / `version` parameters, which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a friend, and the boundary header no longer includes `task_id.h`: it names no TaskId at all. `sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B wire `Tensor`. `ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level layout so three copy paths could each be a single 64-byte `memcpy`, held by 21 hand-written `offsetof` assertions across four trees. Two of the three were shaped backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` / `__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` / `::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a `PTO2TensorMapEntry *` field, its comment noting this was "harmless because `link_entry()` overwrites `next_in_bucket` immediately after". Each struct now assigns the fields it wants, by name. The optimization the `memcpy` existed for survives as intent: a canonically contiguous source has the derived pair recomputed from `shapes` rather than read across. `PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an entry. The entry keeps its own two-cache-line split and the assertions describing it; what goes is the claim that its bytes agree with a different struct's. A source that names one runtime's `Tensor` cannot be compiled under the other, and 57 scene-test sources were: a `host_build_graph` case naming the `tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer` classes taking an hbg class's `CALLABLE` verbatim. That worked only because `ChipTensor` happened to be identical in both trees — the coupling this change removes. Each borrowing case now carries its own sources, 73 files, and names local paths. The two class-reuse cases rebase the inherited `CALLABLE` onto their own `kernels/` copy through a `_rebase_callable` helper, so the Python that drives them stays in one file while the C++ each runtime compiles is its own. `task_timing_slots` carries the runtime in a function default rather than a `@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the helper builds the path from the runtime it is driving. The cost is real: `spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`, `paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist once per runtime and the copies can drift. A case that asserts something about `host_build_graph` should not depend on a file the other runtime owns. `examples/` orchestration and kernel sources lose their `Generated by PyPTO IR Compiler` marker: they are this repository's sources, and this change edits them. 364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`, shadowing the type with a parameter name. The parameter is `TensorT` now: a generated helper that means "any tensor with .data()" should not name one, and the shadowing is what made the rename ambiguous in the first place. `tensor_create_info.h`'s doc paragraph said `host_build_graph` has no initial-value fill "unlike the tensormap_and_ringbuffer copy of this header", which hw-native-sys#1981 made false by removing that fill; both copies now describe what is there. The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980 finished that retirement repo-wide — so they carry the current ones. `test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify packing Graph boundaries into the payload's tensor slots, and read that pool as `ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` — the assertion was true only while one type served both roles. Verification: full rebuild of both runtimes on both architectures, cpput 119/119, pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim sweeps build only the cases they run, so every orchestration source was also syntax-checked against its runtime's include path — 129 (source, runtime, arch) compiles, which is what caught a copy under host_build_graph/ still calling simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a Python driver mentions rather than its @scene_test decorator; that is what caught task_timing_slots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nsor An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things about it: which task produced it, the version its OverlapMap keys on, whether dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself, in `src/common/task_interface/`, so one type served the boundary and both runtimes' working state. `create_from_chip_args` recorded the mismatch as an assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling `ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while `ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a `make()` factory. The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the runtime's tensor to reach the argument boundary, and got there by promoting the runtime-private header into `task_interface/` rather than adding strides to the 40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a mailbox doubling for a capability that PR noted was not yet used: two months on, `make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors. with a cost argument that applies equally here; nobody undid it at L2. `ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view. struct ChipTensor { PTOBufferHandle buffer; uint64_t start_offset; uint32_t shapes[MAX_TENSOR_DIMS]; uint32_t strides[MAX_TENSOR_DIMS]; uint32_t ndims; DataType dtype; AddressSpace address_space; }; `simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the geometry. One copy each, shared across architectures, placed the way `src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg` was an existing namespace. `Runtime::set_orch_args` is the single place one becomes the other. Both runtimes call it only from `host/runtime_maker.cpp`, so adoption happens on the host before any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of converting per run. From there inward nothing holds the argument form: orchestration, the payload, the TensorMap and the kernels all name their runtime's type. A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's include path, so existing `#include "tensor.h"` lines resolve to both types without an include sweep. That shim names the two headers by their path under `src/common`, which every platform target but `aicore` already had on its include path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings carry. `is_contiguous` and `extent_elem` become methods that compute from the geometry; a runtime that reads them per task caches them on its own `Tensor`. The view ops and the copy helpers that maintained those caches move with them — an argument is not a thing you take views of, and nothing outside a runtime called them. `init_external` and both factories lose their `manual_dep` / `version` parameters, which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a friend, and the boundary header no longer includes `task_id.h`: it names no TaskId at all. `sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B wire `Tensor`. `ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level layout so three copy paths could each be a single 64-byte `memcpy`, held by 21 hand-written `offsetof` assertions across four trees. Two of the three were shaped backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` / `__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` / `::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a `PTO2TensorMapEntry *` field, its comment noting this was "harmless because `link_entry()` overwrites `next_in_bucket` immediately after". Each struct now assigns the fields it wants, by name. The optimization the `memcpy` existed for survives as intent: a canonically contiguous source has the derived pair recomputed from `shapes` rather than read across. `PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an entry. The entry keeps its own two-cache-line split and the assertions describing it; what goes is the claim that its bytes agree with a different struct's. A source that names one runtime's `Tensor` cannot be compiled under the other, and 57 scene-test sources were: a `host_build_graph` case naming the `tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer` classes taking an hbg class's `CALLABLE` verbatim. That worked only because `ChipTensor` happened to be identical in both trees — the coupling this change removes. Each borrowing case now carries its own sources, 73 files, and names local paths. The two class-reuse cases rebase the inherited `CALLABLE` onto their own `kernels/` copy through a `_rebase_callable` helper, so the Python that drives them stays in one file while the C++ each runtime compiles is its own. `task_timing_slots` carries the runtime in a function default rather than a `@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the helper builds the path from the runtime it is driving. The cost is real: `spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`, `paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist once per runtime and the copies can drift. A case that asserts something about `host_build_graph` should not depend on a file the other runtime owns. `examples/` orchestration and kernel sources lose their `Generated by PyPTO IR Compiler` marker: they are this repository's sources, and this change edits them. 364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`, shadowing the type with a parameter name. The parameter is `TensorT` now: a generated helper that means "any tensor with .data()" should not name one, and the shadowing is what made the rename ambiguous in the first place. ## Kernels name no runtime A kernel reads a payload element and its code is identical whichever orchestrator filled it, so naming a runtime there carries no information — and several kernels are compiled under both. `examples/a2a3/host_build_graph/deepseek_v4_flash_decode` re-points all 368 of the `tensormap_and_ringbuffer` case's incores at that case's directory; `test_task_timing_e2e` drives one AIV kernel under both. Each runtime's `runtime/tensor.h` therefore exports using TaskTensor = simpler::{hbg,tmr}::Tensor; and every kernel names `TaskTensor`. It resolves per translation unit, so it is one type per build, not a third type. The alternative was duplicating 13 MB of generated MoE kernels into the hbg tree, where the two copies would drift. The name is not `Tensor`: `buffer.h`'s L3+ wire `Tensor` is visible in every orchestration translation unit, and one spelling meaning two types by context is what this change exists to remove. Cross-runtime *orchestration* sources need no name — `const auto &a = orch_args.tensor(0).ref()` is enough, and only kernels must spell the type inside a `reinterpret_cast`. `tensor_create_info.h`'s doc paragraph said `host_build_graph` has no initial-value fill "unlike the tensormap_and_ringbuffer copy of this header", which hw-native-sys#1981 made false by removing that fill; both copies now describe what is there. The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980 finished that retirement repo-wide — so they carry the current ones. `test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify packing Graph boundaries into the payload's tensor slots, and read that pool as `ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` — the assertion was true only while one type served both roles. Verification: full rebuild of both runtimes on both architectures, cpput 119/119, pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim sweeps build only the cases they run, so every orchestration source was also syntax-checked against its runtime's include path — 129 (source, runtime, arch) compiles, which is what caught a copy under host_build_graph/ still calling simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a Python driver mentions rather than its @scene_test decorator; that is what caught task_timing_slots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
host_build_graph is whole-graph-resident: the host builds the entire graph before the device starts, and no task slot or heap byte is reclaimed during a run. All three premises of a ring were therefore already false — alloc() caps ids at the table's size so they never wrap, there is no reclaim channel back to the allocator, and a full table is a one-shot "graph too large" verdict that no wait can make satisfiable. hw-native-sys#1980 retired the PTO2 prefix on these names but left the ring semantics untouched. A task id is now its own table index. task_window_mask, get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement are gone; every segment is indexed by the id directly. Producer dedup keys on the TaskId itself, so append_fanin_or_fail loses the ring and slot parameters that were derivable from it. The task count stays configurable through runtime_env.ring_task_window — that is orthogonal to the ring, and a graph larger than the default still only needs the knob, not a rebuild. Worker.run's shared RuntimeEnv validation still requires a power of two, which this layer no longer needs but has no reason to reject. ChipRingFlowControl::current_task_index is deleted outright. It existed so a device-side orchestrator could publish its ring head incrementally to a concurrently running scheduler; with host orchestration the count is a one-shot scalar. The host reads it from its own allocator, and the device keeps using host_total_tasks, which on_orchestration_done latches into the scheduler beside the task-table pointer for update_completed_watermark. This also removes a boot-time read of that counter whose value was discarded, and the cross-module contract that had the allocator's local id depend on the counter's per-boot reset. The shared-memory header shrinks from 256 to 192 bytes. Renaming is confined to names carrying ring or window: SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState -> TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE -> CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their neighbours never had. The ring_task_window knob keeps its name — it is the cross-runtime RuntimeEnv ABI.
…nsor (#1974) An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things about it: which task produced it, the version its OverlapMap keys on, whether dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself, in `src/common/task_interface/`, so one type served the boundary and both runtimes' working state. `create_from_chip_args` recorded the mismatch as an assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling `ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while `ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a `make()` factory. The fusion dates to #1093, which needed the strided view #808 had just given the runtime's tensor to reach the argument boundary, and got there by promoting the runtime-private header into `task_interface/` rather than adding strides to the 40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a mailbox doubling for a capability that PR noted was not yet used: two months on, `make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors. with a cost argument that applies equally here; nobody undid it at L2. `ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view. struct ChipTensor { PTOBufferHandle buffer; uint64_t start_offset; uint32_t shapes[MAX_TENSOR_DIMS]; uint32_t strides[MAX_TENSOR_DIMS]; uint32_t ndims; DataType dtype; AddressSpace address_space; }; `simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the geometry. One copy each, shared across architectures, placed the way `src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg` was an existing namespace. `Runtime::set_orch_args` is the single place one becomes the other. Both runtimes call it only from `host/runtime_maker.cpp`, so adoption happens on the host before any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of converting per run. From there inward nothing holds the argument form: orchestration, the payload, the TensorMap and the kernels all name their runtime's type. A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's include path, so existing `#include "tensor.h"` lines resolve to both types without an include sweep. That shim names the two headers by their path under `src/common`, which every platform target but `aicore` already had on its include path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings carry. `is_contiguous` and `extent_elem` become methods that compute from the geometry; a runtime that reads them per task caches them on its own `Tensor`. The view ops and the copy helpers that maintained those caches move with them — an argument is not a thing you take views of, and nothing outside a runtime called them. `init_external` and both factories lose their `manual_dep` / `version` parameters, which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a friend, and the boundary header no longer includes `task_id.h`: it names no TaskId at all. `sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor cap. `MAILBOX_SIZE` is unaffected — since #1729 the frame is sized by the 144 B wire `Tensor`. `ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level layout so three copy paths could each be a single 64-byte `memcpy`, held by 21 hand-written `offsetof` assertions across four trees. Two of the three were shaped backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` / `__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` / `::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a `PTO2TensorMapEntry *` field, its comment noting this was "harmless because `link_entry()` overwrites `next_in_bucket` immediately after". Each struct now assigns the fields it wants, by name. The optimization the `memcpy` existed for survives as intent: a canonically contiguous source has the derived pair recomputed from `shapes` rather than read across. `PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an entry. The entry keeps its own two-cache-line split and the assertions describing it; what goes is the claim that its bytes agree with a different struct's. A source that names one runtime's `Tensor` cannot be compiled under the other, and 57 scene-test sources were: a `host_build_graph` case naming the `tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer` classes taking an hbg class's `CALLABLE` verbatim. That worked only because `ChipTensor` happened to be identical in both trees — the coupling this change removes. Each borrowing case now carries its own sources, 73 files, and names local paths. The two class-reuse cases rebase the inherited `CALLABLE` onto their own `kernels/` copy through a `_rebase_callable` helper, so the Python that drives them stays in one file while the C++ each runtime compiles is its own. `task_timing_slots` carries the runtime in a function default rather than a `@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the helper builds the path from the runtime it is driving. The cost is real: `spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`, `paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist once per runtime and the copies can drift. A case that asserts something about `host_build_graph` should not depend on a file the other runtime owns. `examples/` orchestration and kernel sources lose their `Generated by PyPTO IR Compiler` marker: they are this repository's sources, and this change edits them. 364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`, shadowing the type with a parameter name. The parameter is `TensorT` now: a generated helper that means "any tensor with .data()" should not name one, and the shadowing is what made the rename ambiguous in the first place. ## Kernels name no runtime A kernel reads a payload element and its code is identical whichever orchestrator filled it, so naming a runtime there carries no information — and several kernels are compiled under both. `examples/a2a3/host_build_graph/deepseek_v4_flash_decode` re-points all 368 of the `tensormap_and_ringbuffer` case's incores at that case's directory; `test_task_timing_e2e` drives one AIV kernel under both. Each runtime's `runtime/tensor.h` therefore exports using TaskTensor = simpler::{hbg,tmr}::Tensor; and every kernel names `TaskTensor`. It resolves per translation unit, so it is one type per build, not a third type. The alternative was duplicating 13 MB of generated MoE kernels into the hbg tree, where the two copies would drift. The name is not `Tensor`: `buffer.h`'s L3+ wire `Tensor` is visible in every orchestration translation unit, and one spelling meaning two types by context is what this change exists to remove. Cross-runtime *orchestration* sources need no name — `const auto &a = orch_args.tensor(0).ref()` is enough, and only kernels must spell the type inside a `reinterpret_cast`. `tensor_create_info.h`'s doc paragraph said `host_build_graph` has no initial-value fill "unlike the tensormap_and_ringbuffer copy of this header", which #1981 made false by removing that fill; both copies now describe what is there. The copies were taken from sources whose spellings `main` has since retired — #1980 finished that retirement repo-wide — so they carry the current ones. `test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify packing Graph boundaries into the payload's tensor slots, and read that pool as `ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` — the assertion was true only while one type served both roles. Verification: full rebuild of both runtimes on both architectures, cpput 119/119, pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim sweeps build only the cases they run, so every orchestration source was also syntax-checked against its runtime's include path — 129 (source, runtime, arch) compiles, which is what caught a copy under host_build_graph/ still calling simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a Python driver mentions rather than its @scene_test decorator; that is what caught task_timing_slots.
host_build_graph is whole-graph-resident: the host builds the entire graph before the device starts, and no task slot or heap byte is reclaimed during a run. All three premises of a ring were therefore already false — alloc() caps ids at the table's size so they never wrap, there is no reclaim channel back to the allocator, and a full table is a one-shot "graph too large" verdict that no wait can make satisfiable. hw-native-sys#1980 retired the PTO2 prefix on these names but left the ring semantics untouched. A task id is now its own table index. task_window_mask, get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement are gone; every segment is indexed by the id directly. Producer dedup keys on the TaskId itself, so append_fanin_or_fail loses the ring and slot parameters that were derivable from it. TaskAllocator::task_head is gone too: with nothing retiring, the next id is both the occupancy and the run's total, so active_count answers both questions. The task count stays configurable through runtime_env.ring_task_window — that is orthogonal to the ring, and a graph larger than the default still only needs the knob, not a rebuild. Any positive count is accepted, since nothing masks with it. The power-of-two, >= 4 requirement belongs to tensormap_and_ringbuffer, which does mask, and is enforced in that runtime's own resolve; neither the RuntimeEnv setter nor Worker.run constrains the value, so host_build_graph's own bound is the only one it passes through. ChipRingFlowControl::current_task_index is deleted outright. It existed so a device-side orchestrator could publish its ring head incrementally to a concurrently running scheduler; with host orchestration the count is a one-shot scalar, so it becomes a plain int32 in SharedMemoryTaskHeader that the host writes once after orchestration and the restack ships with the rest of the header. It packs into existing padding, so the shared-memory header still shrinks from 256 to 192 bytes, and update_completed_watermark reads the bound from the table it is walking rather than taking it as an argument. This also removes a boot-time read of that counter whose value was discarded, and the cross-module contract that had the allocator's local id depend on the counter's per-boot reset. TaskHeaderView::advance_lock goes with the ring it guarded: nothing on the device advances a reclaim cursor, so the field had no reader. The same for the `uint8_t ring_id = 0` locals in prepare_task and in the tensor-wait diagnostics — every TaskId::make in this runtime emits ring 0, so they only made a constant look configurable, and the wait timeouts no longer print a ring that is always the same. Renaming is confined to names carrying ring or window: SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState -> TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE -> CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their neighbours never had. The ring_task_window knob keeps its name — it is the cross-runtime RuntimeEnv ABI.
host_build_graph is whole-graph-resident: the host builds the entire graph before the device starts, and no task slot or heap byte is reclaimed during a run. All three premises of a ring were therefore already false — alloc() caps ids at the table's size so they never wrap, there is no reclaim channel back to the allocator, and a full table is a one-shot "graph too large" verdict that no wait can make satisfiable. #1980 retired the PTO2 prefix on these names but left the ring semantics untouched. A task id is now its own table index. task_window_mask, get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement are gone; every segment is indexed by the id directly. Producer dedup keys on the TaskId itself, so append_fanin_or_fail loses the ring and slot parameters that were derivable from it. TaskAllocator::task_head is gone too: with nothing retiring, the next id is both the occupancy and the run's total, so active_count answers both questions. The task count stays configurable through runtime_env.ring_task_window — that is orthogonal to the ring, and a graph larger than the default still only needs the knob, not a rebuild. Any positive count is accepted, since nothing masks with it. The power-of-two, >= 4 requirement belongs to tensormap_and_ringbuffer, which does mask, and is enforced in that runtime's own resolve; neither the RuntimeEnv setter nor Worker.run constrains the value, so host_build_graph's own bound is the only one it passes through. ChipRingFlowControl::current_task_index is deleted outright. It existed so a device-side orchestrator could publish its ring head incrementally to a concurrently running scheduler; with host orchestration the count is a one-shot scalar, so it becomes a plain int32 in SharedMemoryTaskHeader that the host writes once after orchestration and the restack ships with the rest of the header. It packs into existing padding, so the shared-memory header still shrinks from 256 to 192 bytes, and update_completed_watermark reads the bound from the table it is walking rather than taking it as an argument. This also removes a boot-time read of that counter whose value was discarded, and the cross-module contract that had the allocator's local id depend on the counter's per-boot reset. TaskHeaderView::advance_lock goes with the ring it guarded: nothing on the device advances a reclaim cursor, so the field had no reader. The same for the `uint8_t ring_id = 0` locals in prepare_task and in the tensor-wait diagnostics — every TaskId::make in this runtime emits ring 0, so they only made a constant look configurable, and the wait timeouts no longer print a ring that is always the same. Renaming is confined to names carrying ring or window: SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState -> TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE -> CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their neighbours never had. The ring_task_window knob keeps its name — it is the cross-runtime RuntimeEnv ABI.
`.claude/rules/codestyle.md` rule 10 said the retirement was complete and that "there is no backlog to work through". Two of its three claims held: no `PTO2` *identifier* is left, and a new one is a defect. The third was false — the rule's own grep, `PTO Runtime2?|PTO2|pto2_|pto_runtime2`, found 38 brand banners across 36 files in `src/`. The claim had been measured with `PTO2|pto2_`, which cannot see a brand name with a space in it. #1980's title was "finish the PTO2 retirement" and it finished exactly that, verifiably — 62 remaining under its own pattern, reproducible today. The sentence generalised from "PTO2 identifiers" to "the retirement". ## What changed **The 38 banners**, following the style already in the tree — `orchestrator_core/orchestrator.cpp` opens `* host_build_graph orchestrator implementation`, so the runtime's directory name leads and the subsystem words are lower case, with type names keeping their case: * PTO Runtime2 - TensorMap Interface -> * host_build_graph TensorMap interface * PTO Runtime2 - Ring Buffer Data … -> * tensormap_and_ringbuffer ring buffer data … The four `PTO Runtime C API` banners are in the platform layer, which serves both runtimes, so they take the name the canonical header already uses for itself: `simpler host-runtime C API`. **Eighteen comments naming a `pto_*` that does not exist.** These are `doc-consistency.md` §3 defects rather than naming preferences — a reader who greps the name finds nothing: - `pto_submit_task` x16 -> `rt_submit_task`, the actual orchestration entry in `orchestration/orchestration_api.h`. - `pto_runtime_c_api` x2 -> `runtime_c_api`, the actual file name. `git grep -w` returning only comments is what established each was absent. **`tests/lint/check_retired_names.py`**, wired into pre-commit. Rule 10 already demanded that "the count only goes down"; nothing enforced it, and a count written into prose cannot stay true. The hook fails on any new `PTO Runtime`, `PTO Runtime2`, or bare `Runtime2`, so the rule can now point at it and drop the number it could not keep current. The hook is deliberately narrow, and the reason is the third population rule 10 lumped into one Tier A row. ## What is deliberately untouched **Every live `pto_cpu_sim_*` / `pto_sim_*` hook** — 33 occurrences, all left alone. `cpu_sim_context.cpp` exports them for "pto-isa via `dlsym(RTLD_DEFAULT)`", and `device_runner_base.cpp` fetches `pto_sim_register_hooks` by `dlsym`. Renaming one produces **no compile error** — just a hook that is never found at run time. That is the "handful of Tier-C names hiding in it" rule 10's no-sweep ban was written to protect, and it is real; it just hides in the lowercase `pto_*` namespace, not in the banner namespace. So the hook checks only the brand spellings, and rule 10's Tier A is split into A1 (brand prose, mechanically safe) and A2 (dangling `pto_*` references, grep first), with the `dlsym` trap named in Tier C. **Six mentions that named a retired variable only for history** — "the now-retired `PTO2_RING_*` environment variables", "the process-wide `PTO2_RING_*` env, since retired" — now state the current mechanism and what it enables instead. They explained a design by contrast with something the reader cannot find. (`per_task_runtime_env/README.md` also had "shared the process-wide process-wide", a duplicated line from #1980's edit.) `PTO2_*` is deliberately left out of the hook, because what remains of that spelling is load-bearing in two ways the hook cannot distinguish: - Twelve occurrences belong to `warn_on_retired_ring_env()` in each `host/runtime_maker.cpp` — a `kRetired[]` array of env names and the comment explaining it — plus three doc sites that tell a reader what the warning they just saw means. The names cannot leave without the warning leaving, and that warning is one day old (#1980, 2026-08-25); rule 10 holds it up as the model for retiring a knob rather than silently falling back. - Eight are `PTO2_MANUAL_MAX_SEQ`, pypto-lib's own variable, which the qwen READMEs tell a user to `export` literally. So banning the spelling would either delete a live diagnostic or break working instructions. ## Verification Comments and one new lint script; no declaration, signature or expression changes. - Full product build — both arches, sim and onboard, all four runtimes. - cpput 119/119. - The hook returns 0 over all 2294 tracked files, 1 on a probe containing `PTO Runtime2 - Something`, 1 on a bare `Runtime2`, and 0 on `codestyle.md` itself, which is exempt because a rule has to spell what it bans. - `clang-format --dry-run --Werror` clean on all 42 changed C++ files; every one of them is a matched a2a3/a5 pair.
Summary
This finishes the
PTO2retirement. 21 commits, one identifier or one coherent cluster each, 313 files. EveryPTO2occurrence this repo reads is gone: 5795 -> 62 (git grep -Io -E "PTO2|pto2_" | wc -l, base vs head), across 17 files, and every one that remains is deliberate.The commits, in order:
ResourceShape,NUM_RESOURCE_SHAPESTaskDescriptor,TaskPayload,PreparedTask, 7TASKPAYLOAD_*offsetsSharedMemoryHeader/RingHeader/Handle,SharedMemory,sm_layoutSchedulerState,SchedulerLayout,SchedProfilingData,SCHED_CYCLE_*OrchestratorState,OrchestratorLayout,OrchProfilingDataChipTensorMap+ 5 satellites + 3CHIP_TENSORMAP_*ChipReadyQueue,ChipReadyQueueSlot, 2 caps,LocalReadyBufferChipTaskState+ 3CHIP_TASK_*+ 6 lifecycle flagsChipTaskRing/ChipHeapRing/ChipRingSet/…TaskAllocator,TaskAllocResult,ALLOC_DEADLOCK_TIMEOUT_CYCLESFaninPool/FaninSpillEntry/FaninBuilder/…,CHIP_MAX_FANINDepListEntry,DepListPool, 4CHIP_DEP_*EarlyDispatchState/EarlySyncDrainState+ 14 enumeratorsSubtaskSlot, 4SUBTASK_*,DispatchPayload,DISPATCH_MAX_ARGSScopeMode,CHIP_MAX_SCOPE_DEPTH,CHIP_SCOPE_TASKS_CAP, 2SCOPE_STATS_*CHIP_ALIGN_SIZE/CHIP_ALIGN_UP,PACKED_OUTPUT_ALIGNCHIP_HEAP_SIZE,CHIP_TASK_WINDOW_SIZEPTO2_RING_*env knobs and retarget their diagnosticsBold = took a prefix rather than the bare name. The name check has three sources, and only the first is greppable in this repo:
src/common/hierarchical/already declaresTensorMap,ReadyQueue,TaskState(bound into Python),HeapRing/Ring,AllocResultandMAX_SCOPE_DEPTH. Rule 13 gives those to the L3+ context and the chip runtime takesChip/CHIP_.ALIGN_UPinacl/ops/acl_dvpp.handacl/dvpp/hi_media_common.h. Nothing inside this repository can see that.runtime/runtime_types.hkeepCHIP_even where the bare name is free, whileinline constexprsiblings insubmit_types.htake it.The bug in my own process, and the fix
#define HEAP_SIZE (256 * 1024 * 1024)rewrote three cpput fixtures'static constexpr uint64_t HEAP_SIZE = 4096;intostatic constexpr uint64_t (256 * 1024 * 1024) = 4096;.I did not catch it per-commit, because my gate was
pip install --no-build-isolation -e .— which builds the four runtime.sofiles and not the C++ unit-test targets, a separate CMake project. So the gate now compiles both (.docs/gate.sh), and the affected commits were replayed with the corrected plan rather than patched afterwards, so every commit here builds both trees. Rule 10 records the three-source check so the next person does not re-derive it.Two dead environment variables
Both surfaced only because this work made me read every
PTO2_*string, and both failed silently — an unrecognised env var is ignored:tools/benchmark_rounds.sh --serial-orch-schedsetPTO2_SERIAL_ORCH_SCHED=1. The runtime readsSIMPLER_TMR_SERIAL_ORCH_SCHED_ENABLE. The serial arm therefore ran with serial orch→sched off: the script measured the parallel path twice and reported the pair as a serial-versus-parallel comparison. Any measurement taken through that flag is void.error_hint(SIMPLER_ERROR_SCHEDULER_TIMEOUT)told users to raisePTO2_SCHEDULER_TIMEOUT_MS; the knob isSIMPLER_SCHEDULER_TIMEOUT_MS, which CI already sets by that name. Following the hint on a scheduler-timeout fatal changed nothing and made a slow kernel look like a deadlock.Three references to things that do not exist
pto2_task_slot(sched, task_id)— cited byruntime_types.handruntime_init.cppas how to compute a slot. No such function; it islocal_idmasked by the window size, which the comment now says, including why the window is a power of two.pto2_run_runtime— named five times indocs/task-flow.mdas the L2 ABI edge. It issimpler_run.pto2_init_*flags — listed indocs/dynamic-linking.mdamong whatSchedulerContext::deinit()resets. It resets no such flag and none exists under any spelling.Also: the four shared-memory layout diagrams that #1969 deliberately deferred are now correct, since every row (
SharedMemoryHeader,TaskDescriptor[],TaskPayload[],ChipTaskSlotState[]) names a type that exists under exactly that spelling. The two multi-ring boxes widen by four columns to fit.The ring env knobs are removed, not kept
The first version of this PR retained
PTO2_RING_TASK_WINDOW/PTO2_RING_HEAP/PTO2_RING_DEP_POOLas Tier C. They are now gone, because they were never a contract worth keeping:CallConfig.runtime_envalready carries the same three values per task, which is strictly more expressive — two tasks in one process can hold different ring sizes, which a process-wide export never allowed. The env layer was a second, weaker way to say the same thing.The removal deletes the whole parsing path from all four
host/runtime_maker.cppcopies (trim_copy,parse_uint_token,apply_env_ring_value[s], and the scalar / comma-separated grammar), leaving per-task entries over the compile-time default with nothing in between. Net -283 lines, and two includes that existed only for that grammar.Every diagnostic that advertised those variables moved with them. Otherwise the removal would have manufactured the third instance of the exact defect this PR already fixes twice: a hint naming a variable nothing reads. So the device-side ring-buffer and orchestrator deadlock reports, the fanin-spill capacity report, five
error_hint()strings, both capacity tables indocs/troubleshooting/, therunning-onboardtriage table and the runnable recipe indocs/dfx/scope-stats.mdnow nameruntime_env.ring_task_window/ring_heap/ring_dep_pool. Two unit tests assert on that hint text and move with it.MULTI_RING.mdloses the two env tiers from its precedence ladder and the env-fallback section that was the only documentation of the comma-separated grammar.One warning replaces the read. An unrecognised environment variable is ignored, so a caller still exporting one would run on the 256 MB default with its requested sizing nowhere in evidence — and the symptom is a heap-exhaustion deadlock that reads as a runtime regression rather than a config change.
warn_on_retired_ring_env()names each retired variable that is set, once per bind, and points atCallConfig.runtime_env. Verified live: with all three exported, ana2a3simscene test logs all three warnings and passes — proving both that the warning fires and thatPTO2_RING_TASK_WINDOW=64is now genuinely inert..claude/skills/multi-repo-qwen-setuptold you to exportPTO2_RING_HEAP=4294967296for batch-16 qwen prefill — 4 GiB against a 256 MB default. That skill now gives the values asCallConfig.runtime_envfields and says outright that a runner still exporting the old names deadlocks exactly as its own gotcha section describes. A pypto-lib / pypto-serving change has to land for those paths; the warning is what makes the gap visible rather than silent, and is deletable once no caller sets them.What is left
PTO2_MANUAL_MAX_SEQ(pypto-lib's knob, documented here and never read here), this rule file's own examples of the banned spelling, the retired-name list inside the warning, and prose recording that these names are gone. Rule 10 previously described a "~6.6k occurrences across 367 files" backlog; it now says the retirement is complete, so a newPTO2match is a defect rather than leftover backlog for a regression to hide behind.Cross-repo
RuntimeContext-style names are reachable from orchestration sources outside this repo. As with #1963, #1966 and #1969, this lands without compatibility aliases; matching renames and merge order are coordinated outside this PR.Testing
All at the final commit, rebased onto
main, afterpip install --no-build-isolation -e .:a2a3simscene sweep — 59 passed, 8 skipped, and again with all three retired env vars exported (warnings fire, values ignored)a5simscene sweep — 52 passeda2a3onboard sweep (-m "not sdma" --exclude-level 4) — 153 passed, 1 skippeda2a3quarantined SDMA step — 2 passedtest_comm_lifecycle— 1/1clang-format --dry-run --Werrorover 246 sources,markdownlint-cli2over 45 docs,ruff,bash -n— all clean