Diff Coverage

Diff: origin/master...HEAD, staged and unstaged changes

Source File Diff Coverage (%) Missing Lines
hyper_parallel/codegen/__init__.py 100%  
hyper_parallel/codegen/artifact.py 56.9% 267-274,283,291-292,302-303,318-321,329,331,334-343,354-365,368-373,375,382-383
hyper_parallel/codegen/build.py 100%  
hyper_parallel/codegen/cli.py 100%  
hyper_parallel/codegen/emit/bundle.py 54.9% 98-100,108,142-143,147,150,154,166-171,174-175,180-183,187-188,196-201,209,228,253-254,259,265,274-275
hyper_parallel/codegen/emit/context.py 100%  
hyper_parallel/codegen/emit/modeling.py 57.0% 117,131-147,152-155,160,167-179,186-187,194,198,323-325,330,338-339,363,442-445,448-449,457,514,526-529,533-535,547,554,562-564,573,576,579,582,587-588,592-593,601-602,606-607,614-617,626-630,633-635,639,664,673,716,721
hyper_parallel/codegen/emit/parallel.py 91.7% 123
hyper_parallel/codegen/emit/patches.py 73.8% 78-81,89,102,112,120,124,126,133-139
hyper_parallel/codegen/emit/recorded.py 67.8% 68,78,81,83,106,143,153,158,162-163,236-237,246,256,261-264,266-267,269-272,275,306,323-324,329-337,341,353,370-381,391-397,400
hyper_parallel/codegen/emit/replacement.py 85.2% 29,35,41,46
hyper_parallel/codegen/emit/snapshot_patches.py 60.0% 65,91,115,133,135,140,166-168,172,184,188-189,198,201,210,215,229,233-234,241,243,254-255,261-265,272-279,281-283,287-291,295,300,315,320-328,333-337
hyper_parallel/codegen/emit/validation.py 93.5% 32-34
hyper_parallel/codegen/inline/__init__.py 100%  
hyper_parallel/codegen/inline/component_source.py 0.0% 17,19-20,23,27,30
hyper_parallel/codegen/inline/declaration_edits.py 100%  
hyper_parallel/codegen/inline/definition_edits.py 19.7% 28-33,41,48-58,63-69,80-88,93,102-108,116-119,124-130
hyper_parallel/codegen/inline/forward_edits.py 84.3% 43,46,79,97-98,102,109,112,115,123,126
hyper_parallel/codegen/inline/framework_spec.py 61.8% 149,155,262-267,315-316,343,353,434
hyper_parallel/codegen/inline/ir.py 86.1% 138,140,142,145,150
hyper_parallel/codegen/inline/meta_plan.py 48.1% 120-125,138-139,141,144,148-154,176,183-190,240
hyper_parallel/codegen/inline/observations.py 75.0% 39-42,58,65,67,70
hyper_parallel/codegen/inline/patch_engine.py 87.5% 69-71,91,127-128,144,147,286,290,309
hyper_parallel/codegen/inline/pipeline.py 58.4% 65,71,82,84-86,89,94-95,102-103,116-117,155,158,176,199-200,210-211,213,220,250-253,258,263-264,270,275,279-284
hyper_parallel/codegen/inline/recognition.py 86.0% 216,219,222,225,241,266,286,290,318-320,327,330-331,354,372,380,410-412,438,442,486,502
hyper_parallel/codegen/inline/replacement_pass.py 60.0% 62,73
hyper_parallel/codegen/inline/source_plan.py 42.1% 34-35,41,46-53
hyper_parallel/codegen/inline/strategy_pass.py 59.2% 102,104-105,107-108,117-119,122-129,151,154,160,176
hyper_parallel/codegen/inline/targets.py 68.0% 26,28,32-34,41,43,46
hyper_parallel/codegen/manager.py 88.6% 66,68,74,83
hyper_parallel/codegen/model_build_overlay.py 87.8% 41-47,75-79,122,127,308,341
hyper_parallel/codegen/plan/boundary_forms.py 100%  
hyper_parallel/codegen/plan/observation.py 93.0% 47,66,70-71,131,140
hyper_parallel/codegen/plan/placements.py 80.8% 34,44,52-54,84,90-91,100,112,121,123,136-138
hyper_parallel/codegen/planner_overlay.py 70.7% 34-37,42-45,63-64,72-81,87-88,100,110
hyper_parallel/codegen/session.py 86.4% 53,64,78,120,136-140,180,185,204,206,231-232,243
hyper_parallel/codegen/snapshot.py 78.3% 41,43,86,105,107,123,148-155,160-163
hyper_parallel/codegen/source/composition.py 89.7% 44,50,70-73,76-77,131,178,206
hyper_parallel/codegen/source/resolver.py 28.6% 360,423-426
hyper_parallel/codegen/train_sidecar.py 95.1% 58-59
hyper_parallel/distributed/_builder/forward_rewriter.py 100%  
hyper_parallel/distributed/context_parallel/wrappers.py 85.7% 454-455,472
hyper_parallel/distributed/mesh.py 90.8% 52,98,108,115,122,128,174
hyper_parallel/trainer/config/parallelism.py 100%  
hyper_parallel/trainer/config/resolver.py 66.7% 690
hyper_parallel/trainer/runtime/distributed.py 100%  
hyper_parallel/codegen/artifact.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
        try:
            descriptor = os.open(lock_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
            try:
                os.write(descriptor, str(os.getpid()).encode("ascii"))
            except BaseException:
                os.close(descriptor)
                descriptor = None
                try:
                    os.unlink(lock_path)
                except FileNotFoundError:
                    pass
                raise
            owner_identity = _file_identity(lock_path)
        except FileExistsError:
            if _remove_stale_lock(lock_path):
                continue
279
280
281
282
283
284
285
286
287
            if time.monotonic() >= deadline:
                raise TimeoutError(
                    f"codegen: timed out waiting for artifact lock {lock_path}"
                ) from None
            time.sleep(0.1)
    try:
        yield
    finally:
        os.close(descriptor)
287
288
289
290
291
292
293
294
295
296
        os.close(descriptor)
        if owner_identity is not None and _file_identity(lock_path) == owner_identity:
            try:
                os.unlink(lock_path)
            except FileNotFoundError:
                pass


def _remove_stale_lock(lock_path: str) -> bool:
    """Remove ``lock_path`` when its recorded owner process is dead."""
298
299
300
301
302
303
304
305
306
307
        identity = _file_identity(lock_path)
        stat_result = os.stat(lock_path)
        with open(lock_path, "r", encoding="ascii") as handle:
            value = handle.read().strip()
    except (FileNotFoundError, OSError, UnicodeError):
        return False

    try:
        pid = int(value)
    except ValueError:
314
315
316
317
318
319
320
321
322
323
324
    if not stale or _file_identity(lock_path) != identity:
        return False
    try:
        os.unlink(lock_path)
    except FileNotFoundError:
        return True
    except OSError:
        return False
    _LOGGER.warning("codegen: removed stale artifact lock %s", lock_path)
    return True

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

def _pid_is_alive(pid: int) -> bool:
    """Return whether ``pid`` still identifies a live process."""
    if pid <= 0:
        return False
    if os.name == "nt":
        return _windows_pid_is_alive(pid)
    try:
        os.kill(pid, 0)
    except ProcessLookupError:
        return False
    except PermissionError:
        return True
    except OSError as exc:
        if exc.errno == errno.ESRCH:
            return False
        if exc.errno == errno.EPERM:
            return True
        return True
    return True


def _windows_pid_is_alive(pid: int) -> bool:
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
    Windows does not implement the POSIX signal-zero probe; using it may
    terminate the target process. ``OpenProcess`` plus ``GetExitCodeProcess``
    is read-only and reports ``STILL_ACTIVE`` for a live owner.
    """
    kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
    open_process = kernel32.OpenProcess
    open_process.argtypes = (ctypes.c_ulong, ctypes.c_int, ctypes.c_ulong)
    open_process.restype = ctypes.c_void_p
    get_exit_code = kernel32.GetExitCodeProcess
    get_exit_code.argtypes = (ctypes.c_void_p, ctypes.POINTER(ctypes.c_ulong))
    get_exit_code.restype = ctypes.c_int
    close_handle = kernel32.CloseHandle
    close_handle.argtypes = (ctypes.c_void_p,)
    close_handle.restype = ctypes.c_int
    process = open_process(0x1000, False, pid)
    if not process:
        # Access denied proves that the process exists. Other errors are
        # treated conservatively except ERROR_INVALID_PARAMETER (no such PID).
        return ctypes.get_last_error() != 87
    try:
        exit_code = ctypes.c_ulong()
        if not get_exit_code(process, ctypes.byref(exit_code)):
            return True
        return exit_code.value == 259  # STILL_ACTIVE
    finally:
        close_handle(process)


def _file_identity(path: str) -> tuple[int, int, int] | None:
    """Return enough stat identity to avoid unlinking a replaced lock file."""
378
379
380
381
382
383
384
385
386
387
def _file_identity(path: str) -> tuple[int, int, int] | None:
    """Return enough stat identity to avoid unlinking a replaced lock file."""
    try:
        result = os.stat(path)
    except FileNotFoundError:
        return None
    return result.st_ino, result.st_mtime_ns, result.st_size


__all__ = [
hyper_parallel/codegen/emit/bundle.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
    swaps the complete bundle directory.

    """
    if getattr(meta, "status", None) == "not_required":
        logger.info("codegen: rendered audit-only bundle %s", layout.artifact_dir)
        modeling_name = os.path.basename(layout.modeling_path)
        return {
            modeling_name: _prepare_generated_python(
                copy_original_modeling(meta.source)
            ),
            os.path.basename(layout.diff_path): _NO_PATCH_DIFF,
104
105
106
107
108
109
110
111
112
            os.path.basename(layout.diff_path): _NO_PATCH_DIFF,
            "__init__.py": _strip_trailing_whitespace(emit_init_file(layout)),
        }
    if patch_plan is None:
        patch_plan = emission_patches_from_meta(meta)
    original_text = copy_original_modeling(meta.source)
    generated_text = _prepare_generated_python(
        emit_modeling_file(meta, patch_plan=patch_plan)
    )
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    # closure of the source's relative imports here using their original
    # basenames, so the generated bundle remains self-contained.
    resolved = resolve_remote_siblings(meta.source)
    if resolved:
        siblings, sibling_diffs = _emit_remote_siblings(resolved, meta, patch_plan)
        import_map = {
            os.path.basename(path): name
            for path, name in zip(resolved.values(), siblings)
        }
        files[modeling_name] = _rewrite_sibling_imports(
            files[modeling_name], import_map
        )
        files[os.path.basename(layout.diff_path)] = _strip_trailing_whitespace(
            emit_diff(original_text, files[modeling_name], layout)
        )
        files.update(siblings)
        files.update(sibling_diffs)
    verify_generated_source_structure(files)
    verify_recorded_patch_bundle(files, patch_plan=patch_plan)
    return files
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    meta: Any,
    patch_plan: Any,
) -> tuple[dict[str, str], dict[str, str]]:
    """Materialize remote-code siblings and their visible diffs."""
    siblings, originals, import_map = {}, {}, {}
    for path in resolved.values():
        basename = os.path.basename(path)
        with open(path, "r", encoding="utf-8", errors="replace") as handle:
            original = handle.read()
        materialized = _strip_trailing_whitespace(
            _materialize_sibling(original, meta, patch_plan, source_path=path)
        )
        rendered = _prepare_generated_python(materialized)
        output_name = (
            _generated_sibling_name(basename)
            if materialized != _strip_trailing_whitespace(original)
            else basename
        )
        import_map[basename] = output_name
        siblings[output_name] = rendered
        originals[output_name] = (basename, original)
    siblings = {
        name: _rewrite_sibling_imports(text, import_map)
        for name, text in siblings.items()
    }
    diffs = _remote_sibling_diffs(siblings, originals)
    return siblings, diffs


def _remote_sibling_diffs(
    siblings: dict[str, str],
192
193
194
195
196
197
198
199
200
201
202
203
204
205
    siblings: dict[str, str],
    originals: dict[str, tuple[str, str]],
) -> dict[str, str]:
    """Render diffs only for remote siblings whose source changed."""
    diffs = {}
    for output_name, rendered in siblings.items():
        basename, original = originals[output_name]
        if rendered == _strip_trailing_whitespace(original):
            continue
        diffs[f"{output_name}.diff"] = _strip_trailing_whitespace(
            unified_diff(
                _normalize_copied_source(original),
                rendered,
                fromfile=f"a/{basename}",
205
206
207
208
209
210
211
212
213
                fromfile=f"a/{basename}",
                tofile=f"b/{output_name}",
            )
        )
    return diffs


def _prepare_generated_python(source_text: str) -> str:
    """Mark copied source as generated and normalize comment-only URLs.
224
225
226
227
228
229
230
231
232
        text,
        flags=re.MULTILINE,
    )
    if text.startswith(_GENERATED_SOURCE_HEADER):
        return text
    return (
        _GENERATED_SOURCE_HEADER
        + text.rstrip()
        + "\n"
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
    *,
    source_path: str,
) -> str:
    """Apply source-owned strategy and recorded patches to one sibling."""
    source = getattr(meta, "source", None)
    architecture = (
        source.get("architecture")
        if isinstance(source, dict)
        else getattr(source, "architecture", None)
    )
    rendered = render_inline_strategies_for_source_unit(
        source_text,
        meta,
        model_type=architecture,
        patch_plan=patch_plan,
261
262
263
264
265
266
267
268
269
        meta,
        model_type=architecture,
        patch_plan=patch_plan,
    )
    return materialize_recorded_forwards(
        rendered,
        meta,
        patch_plan=patch_plan,
        source_path=source_path,
270
271
272
273
274
275
276
277
278
279
    )


def _generated_sibling_name(basename: str) -> str:
    stem, extension = os.path.splitext(basename)
    return f"{stem}_gen_npu{extension}"


def _rewrite_sibling_imports(
    source_text: str,
hyper_parallel/codegen/emit/modeling.py
113
114
115
116
117
118
119
120
121
    i = 0
    while i < len(tokens):
        edit, i = _relative_import_edit(tokens, i, unless_anchor)
        if edit is not None:
            edits.append(edit)

    if not edits:
        return text
    return _splice(text, edits)
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    """Parse one token position into an absolute relative-import edit."""
    token = tokens[index]
    if token.type != tokenize.NAME or token.string != "from":
        return None, index + 1
    cursor = _skip_import_trivia(tokens, index + 1)
    if cursor >= len(tokens) or not _is_dot_token(tokens[cursor]):
        return None, index + 1
    dots_token = tokens[cursor]
    dots = 0
    while cursor < len(tokens) and _is_dot_token(tokens[cursor]):
        dots += len(tokens[cursor].string)
        cursor += 1
    path, last_token, cursor = _relative_module_path(tokens, cursor)
    import_index = _skip_import_trivia(tokens, cursor)
    if import_index >= len(tokens) or tokens[import_index].string != "import":
        return None, index + 1
    absolute = _absolute_spec(anchor, dots, path)
    if absolute is None:
        return None, index + 1
    end = last_token.end if last_token is not None else dots_token.end
    return (dots_token.start, end, absolute), cursor + 1


def _skip_import_trivia(tokens: list[tokenize.TokenInfo], index: int) -> int:
    """Skip comments and physical/logical newlines between import tokens."""
    trivia = {tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT}
    while index < len(tokens) and tokens[index].type in trivia:
        index += 1
    return index


def _is_dot_token(token: tokenize.TokenInfo) -> bool:
    """Return whether a token contains only relative-import dots."""
    return token.type == tokenize.OP and bool(token.string) and set(token.string) == {"."}


def _relative_module_path(
    tokens: list[tokenize.TokenInfo], index: int
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
def _relative_module_path(
    tokens: list[tokenize.TokenInfo], index: int
) -> tuple[list[str], tokenize.TokenInfo | None, int]:
    """Collect the NAME (dot NAME)* portion of a relative import."""
    path: list[str] = []
    last_token = None
    while index < len(tokens):
        token = tokens[index]
        if token.type != tokenize.NAME or token.string == "import":
            break
        path.append(token.string)
        last_token = token
        index += 1
        if index >= len(tokens) or tokens[index].string != ".":
            break
        index += 1
    return path, last_token, index


def _rewrite_dynamic_relative_imports(text: str, anchor: list[str]) -> str:
    """Rewrite imports whose resolved package is not valid Python syntax."""
182
183
184
185
186
187
188
189
190
191
def _rewrite_dynamic_relative_imports(text: str, anchor: list[str]) -> str:
    """Rewrite imports whose resolved package is not valid Python syntax."""
    try:
        tree = ast.parse(text)
    except SyntaxError:
        return text
    edits = []
    for node in ast.walk(tree):
        if not isinstance(node, ast.ImportFrom) or node.level == 0:
            continue
190
191
192
193
194
195
196
197
198
199
200
201
202
        if not isinstance(node, ast.ImportFrom) or node.level == 0:
            continue
        absolute = _absolute_spec(anchor, node.level, (node.module or "").split("."))
        if absolute is None or _is_import_syntax_safe(absolute):
            continue
        assignments = []
        for alias in node.names:
            if alias.name == "*":
                raise ValueError(
                    f"codegen cannot rewrite a wildcard import from dynamic module {absolute!r}"
                )
            target = alias.asname or alias.name
            assignments.append(
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
        if isinstance(meta.source, dict)
        else getattr(meta.source, "module_name", "")
    )
    text = rewrite_relative_imports(text, module_name)
    text = compose_nested_model_sources(text, meta)
    text, emission_meta = _apply_inline_modeling(text, meta, patch_plan=patch_plan)
    source_path = (
        meta.source.get("file_path")
        if isinstance(meta.source, dict)
        else getattr(meta.source, "file_path", None)
    )
    text = materialize_recorded_forwards(
        text,
        emission_meta,
        patch_plan=patch_plan,
        source_path=(
334
335
336
337
338
339
340
341
342
        source_path=(
            None if getattr(emission_meta, "nested_components", None) else source_path
        ),
    )
    text = _lower_forward_boundaries(text, emission_meta, module_name)
    _verify_recorded_patch_materialization(
        text, emission_meta, patch_plan=patch_plan
    )
    return _banner(meta) + text
359
360
361
362
363
364
365
366
367
    wrapper_records = (
        getattr(patches, "inner_wrappers", ()) if patches is not None else ()
    )
    if not local_records and not replacement_records and not wrapper_records:
        return
    tree = ast.parse(text)
    classes = _class_index(tree)
    materialized = getattr(meta, "materialized_patches", None)
    if isinstance(materialized, list):
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
                "local_compute",
                "bound_method_toggle_forward",
            )
            continue
        host = classes.get(class_name)
        if host is None:
            continue
        valid = {"_forward_impl", "forward"} <= _class_methods(
            host
        ) and "ep_enable" in _class_state_names(host)
        if valid:
            _record_materialized(
                materialized,
                record.module_fqn,
                class_name,
                "local_compute",
453
454
455
456
457
458
459
460
461
                "local_compute",
                "same_class_toggle_forward",
            )
        else:
            missing.append(f"{record.module_fqn} ({class_name})")
    return missing


def _verify_replacement_records(
510
511
512
513
514
515
516
517
518
        and "cp_enable" in _class_state_names(host)
        and _class_dispatch_reads_state(host, "cp_enable")
    ):
        return "same_class_toggle_forward"
    subclass = next(
        (
            node
            for node in classes.values()
            if any(
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
            and "forward" in _class_methods(node)
        ),
        None,
    )
    if subclass is not None:
        return "subclass_forward"
    target_type = getattr(record, "target_type", None)
    replacement_backed = any(
        item.module_fqn == record.module_fqn and item.replacement_type is target_type
        for item in replacements
    )
    if replacement_backed and {"_forward_impl", "forward"} <= _class_methods(host):
        return "replacement_forward_runtime_binding"
    return None


def _verify_wrapper_records(
    classes: dict[str, ast.ClassDef], records: Any, replacements: Any, materialized: Any
543
544
545
546
547
548
549
550
551
    for record in records:
        _, host_name, target_fqn = _wrapper_identity(record)
        host = classes.get(host_name)
        if host is None:
            continue
        source_form = _wrapper_source_form(classes, host, record, replacements)
        if source_form:
            _record_materialized(
                materialized, target_fqn, host_name, "inner_wrapper", source_form
550
551
552
553
554
555
556
557
558
            _record_materialized(
                materialized, target_fqn, host_name, "inner_wrapper", source_form
            )
        else:
            missing.append(f"{target_fqn} (inner wrapper for {host_name})")
    return missing


def _call_name(node: ast.AST) -> str | None:
558
559
560
561
562
563
564
565
566
567
568
def _call_name(node: ast.AST) -> str | None:
    """Return the terminal name of a constructor call expression."""
    if isinstance(node, ast.Name):
        return node.id
    if isinstance(node, ast.Attribute):
        return node.attr
    return None


def verify_recorded_patch_bundle(
    files: dict[str, str],
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
    *,
    patch_plan: Any = None,
) -> None:
    """Verify recorded local-compute patches across all generated source units."""
    records = (
        getattr(patch_plan, "local_computes", ()) if patch_plan is not None else ()
    )
    wrappers = (
        getattr(patch_plan, "inner_wrappers", ()) if patch_plan is not None else ()
    )
    trees = {
        name: ast.parse(text) for name, text in files.items() if name.endswith(".py")
    }
    missing = [
        f"{record.module_fqn} ({record.module_type.__name__})"
        for record in records
        if not any(_tree_has_local_record(tree, record) for tree in trees.values())
    ]
    if missing:
        raise RuntimeError(
            "codegen: recorded local-compute patches were not materialized "
            "in their owning source units: " + ", ".join(missing)
        )
    replacements = getattr(patch_plan, "module_replacements", ())
    missing_wrappers = [
        f"{record.module_fqn} ({_wrapper_identity(record)[1]})"
        for record in wrappers
        if not any(
            _tree_has_wrapper_record(tree, record, replacements)
597
598
599
600
601
602
603
604
605
606
607
608
609
610
            _tree_has_wrapper_record(tree, record, replacements)
            for tree in trees.values()
        )
    ]
    if missing_wrappers:
        raise RuntimeError(
            "codegen: recorded inner-wrapper patches were not materialized "
            "in their owning source units: " + ", ".join(missing_wrappers)
        )
    if any("HPCodegen" in text for text in files.values()):
        raise RuntimeError(
            "codegen: generated bundle contains forbidden HPCodegen class names"
        )

610
611
612
613
614
615
616
617
618
619
620
621


def _tree_has_local_record(tree: ast.AST, record: Any) -> bool:
    """Return whether one source tree materializes a local-compute record."""
    if _bound_function_patch_materialized(tree, record):
        return True
    host = _class_index(tree).get(record.module_type.__name__)
    return (
        host is not None
        and {"_forward_impl", "forward"} <= _class_methods(host)
        and "ep_enable" in _class_state_names(host)
    )
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643


def _tree_has_wrapper_record(tree: ast.AST, record: Any, replacements: Any) -> bool:
    """Return whether one source tree materializes an inner-wrapper record."""
    _, class_name, _ = _wrapper_identity(record)
    host = _class_index(tree).get(class_name)
    if host is None or "forward" not in _class_methods(host):
        return False
    if "cp_enable" in _class_state_names(host) and _class_dispatch_reads_state(
        host, "cp_enable"
    ):
        return True
    target_type = getattr(record, "target_type", None)
    replacement_backed = any(
        item.module_fqn == record.module_fqn and item.replacement_type is target_type
        for item in replacements
    )
    return replacement_backed and {"_forward_impl", "forward"} <= _class_methods(host)


def _class_dispatch_reads_state(host: ast.ClassDef, state_name: str) -> bool:
    """Return whether a class dispatches on one state flag in either layer."""
660
661
662
663
664
665
666
667
668
def _bound_function_patch_materialized(tree: ast.AST, record: Any) -> bool:
    """Return whether a ``MethodType`` forward has an explicit EP toggle."""
    function_name = getattr(record.original_forward, "__name__", "")
    if not function_name:
        return False
    impl_name = f"{function_name}_hp_impl"
    functions = {
        node.name: node
        for node in getattr(tree, "body", ())
669
670
671
672
673
674
675
676
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
    }
    wrapper = functions.get(function_name)
    if wrapper is None or impl_name not in functions:
        return False
    return _function_reads_ep_toggle(wrapper) and _tree_binds_method_impl(
        tree, impl_name
    )
712
713
714
715
716
717
718
719
720
721
722
723
724
725
) -> tuple[str, Any]:
    """Render the artifact through the adapter-driven inline source pipeline."""

    source = getattr(meta, "source", None)
    architecture = (
        source.get("architecture")
        if isinstance(source, dict)
        else getattr(source, "architecture", None)
    )
    return render_inline_modeling_with_plan(
        text,
        meta,
        model_type=architecture,
        patch_plan=patch_plan,
hyper_parallel/codegen/emit/parallel.py
119
120
121
122
123
124
125
126
127
    / ``_hp_tp`` instance attributes that ``hp_install_boundaries`` binds
    at runtime — no per-boundary global constant is emitted.
    """
    if _plan_field(frozen_plan, "status") == "not_required":
        raise ValueError("codegen emit: not_required snapshot has no parallel boundaries")
    edits: list[TextEdit] = []
    for class_name, form, emitted, func, injection, deferred_bias in iter_emitted_forms(
        source_text,
        frozen_plan,
hyper_parallel/codegen/emit/patches.py
74
75
76
77
78
79
80
81
82
83
84
85


def emission_patches_from_meta(meta: Any) -> Optional[EmissionPatchSet]:
    """Rehydrate emitter views from plain snapshot data."""
    data = getattr(meta, "emission_patches", None)
    if not data:
        return None
    replacements = tuple(
        ModuleReplacementPatch(
            module_fqn=item["module_fqn"],
            source_type=_resolve_symbol(item["source_type"]),
            replacement_type=_resolve_symbol(item["replacement_type"]),
85
86
87
88
89
90
91
92
93
            replacement_type=_resolve_symbol(item["replacement_type"]),
        )
        for item in data.get("module_replacements", ())
    )
    local_computes = tuple(
        LocalComputePatch(
            module_fqn=item["module_fqn"],
            module_type=_resolve_symbol(item["module_type"]),
            factory=_resolve_symbol(item["factory"]),
 98
 99
100
101
102
103
104
105
106
            installed_forward=None,
        )
        for item in data.get("local_computes", ())
    )
    inner_wrappers = tuple(
        InnerWrapperPatch(
            module_fqn=item["module_fqn"],
            target_fqn=item["target_fqn"],
            wrapper=_resolve_symbol(item["wrapper"]),
108
109
110
111
112
113
114
115
116
            target_type=_resolve_symbol(item["target_type"]),
        )
        for item in data.get("inner_wrappers", ())
    )
    return EmissionPatchSet(replacements, local_computes, inner_wrappers)


def local_compute_binding_name(target: Any) -> str:
    """Return the explicit instance attribute used for one compute factory."""
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    """Return the explicit instance attribute used for one compute factory."""
    if isinstance(target, Mapping):
        target = target.get("_target_") or target.get("target") or target.get("name")
    else:
        target = getattr(target, "_target_", target)
    if isinstance(target, str):
        name = target.rsplit(":", 1)[-1].rsplit(".", 1)[-1]
    else:
        name = getattr(target, "__name__", "")
    if not name or not name.isidentifier() or keyword.iskeyword(name):
        raise ValueError(
            f"codegen: local-compute target {target!r} has no valid binding name"
        )
    return name
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    return name


def _resolve_symbol(path: str) -> Any:
    module_name, separator, qualname = path.partition(":")
    if not separator:
        raise ValueError(f"codegen: invalid patch symbol path {path!r}")
    value = importlib.import_module(module_name)
    for segment in qualname.split("."):
        value = getattr(value, segment)
    return value


__all__ = ["EmissionPatchSet", "emission_patches_from_meta", "local_compute_binding_name"]
hyper_parallel/codegen/emit/recorded.py
64
65
66
67
68
69
70
71
72
    for record in records:
        if source_path is not None and not _record_belongs_to_source(
            record, source_path
        ):
            continue
        original = _unbound(record.original_forward)
        groups[(record.module_type, _source_function_name(original))].append(record)

    rendered = source_text
74
75
76
77
78
79
80
81
82
83
84
85
86
87
        groups.items(), key=lambda item: (item[0][0].__name__, item[0][1])
    ):
        _require_one_contract(group, meta)
        if source_function and _has_module_function(rendered, source_function):
            rendered = _materialize_bound_module_function(
                rendered, source_function, group[0], meta
            )
            continue
        if not _has_source_class(rendered, host_type.__name__):
            continue
        rendered = _materialize_source_class(
            rendered, host_type.__name__, group[0], meta
        )
        _mark_class_source_lowering_skipped(meta, host_type.__name__)
102
103
104
105
106
107
108
109
110
        local = injection.get("local_compute_fn")
        module_fqn = injection.get("match")
        class_name = boundary_classes.get(module_fqn)
        if local is None or not module_fqn or class_name not in source_classes:
            continue
        grouped[class_name].append(SimpleNamespace(
            module_fqn=module_fqn,
            factory=_callable_identity(local),
        ))
139
140
141
142
143
144
145
146
    param_plan = getattr(meta, "param_plan", None) or {}
    boundary_classes = getattr(meta, "boundary_classes", None) or {}
    for module_fqn, owner_class in boundary_classes.items():
        if owner_class != class_name:
            continue
        entry = param_plan.get(module_fqn)
        if isinstance(entry, dict) and entry.get("is_boundary"):
            param_plan[module_fqn] = {**entry, "skip_source_lowering": True}
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def _callable_identity(value: Any) -> str:
    """Return a stable identity for a frozen callable declaration."""
    if isinstance(value, dict):
        return str(value.get("_target_") or value.get("target") or value.get("name"))
    return str(value)


def _record_belongs_to_source(record: Any, source_path: str) -> bool:
    """Return whether a recorded host is defined by this source unit."""
    candidates = (
        inspect.getsourcefile(record.module_type),
        inspect.getsourcefile(_unbound(record.original_forward)),
    )
    expected = os.path.normcase(os.path.abspath(source_path))
    return any(
        candidate is not None
        and os.path.normcase(os.path.abspath(candidate)) == expected
        for candidate in candidates
    )
232
233
234
235
236
237
238
239
240
        for record in records
    }
    factories = {record.factory for record in records}
    if len(contracts) != 1 or len(factories) != 1:
        fqns = ", ".join(sorted(record.module_fqn for record in records))
        raise RuntimeError(
            "codegen: recorded modules sharing one forward have incompatible "
            f"patch contracts: {fqns}"
        )
242
243
244
245
246
247
248
249

def _entry_for_record(meta: Any, record: Any) -> dict[str, Any]:
    entry = (getattr(meta, "param_plan", None) or {}).get(record.module_fqn)
    if entry is None:
        raise RuntimeError(
            f"codegen: recorded patch {record.module_fqn!r} has no frozen plan entry"
        )
    return entry
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def _injection_for_record(meta: Any, record: Any) -> dict[str, Any] | None:
    for injection in getattr(meta, "injections", None) or ():
        if injection.get("match") == record.module_fqn:
            return injection
    return None


def _function_info(node: ast.FunctionDef | ast.AsyncFunctionDef, source_text: str) -> FunctionInfo:
    """Build source-index information for one recorded function."""
    lines = source_text.splitlines(keepends=True)
    offsets = [0]
    for line in lines:
        offsets.append(offsets[-1] + len(line))

    def start(line_number: int) -> int:
        return offsets[line_number - 1]

    positional = [arg.arg for arg in (*node.args.posonlyargs, *node.args.args)]
    if positional and positional[0] in ("self", "module"):
        positional.pop(0)
    first_line = min(
        [node.lineno, *(item.lineno for item in node.decorator_list)]
    )
    return FunctionInfo(
        name=node.name,
        body_start=start(node.body[0].lineno),
        body_end=offsets[node.end_lineno],
        def_offset=start(first_line),
302
303
304
305
306
307
308
309
310
            _render_output_redistribute(),
            form,
        )
    else:
        body = _build_forward_body(source_text, injection, func, form, emitted)
    fallback = _render_forward_call(func).replace("outputs =", "return", 1)
    return "\n".join([
        "        if self.ep_enable:",
        textwrap.indent(body, "    "),
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    record: Any,
    meta: Any,
) -> str:
    """Turn an instance-bound module function into impl + explicit wrapper."""
    tree = ast.parse(source_text)
    node = next(
        item for item in tree.body
        if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef))
        and item.name == function_name
    )
    info = _function_info(node, source_text)
    impl_name = f"{function_name}_hp_impl"
    original = source_text[info.def_offset:info.body_end]
    original = original.replace(f"def {function_name}(", f"def {impl_name}(", 1)
    if not original.endswith("\n"):
        original += "\n"
    body = textwrap.dedent(_recorded_body(source_text, info, record, meta))
    body_edit = TextEdit(info.body_start, info.body_end, textwrap.indent(body, "    "))
    rendered = apply_edits(
        source_text,
        [TextEdit(info.def_offset, info.def_offset, original + "\n"), body_edit],
    )
    return _bind_module_impl(rendered, function_name, impl_name)


def _materialize_source_class(
    source_text: str,
349
350
351
352
353
354
355
356
357
) -> str:
    """Rewrite a source-defined host even when old meta normalization skips it."""
    func = build_source_index(source_text).find_forward(class_name)
    if func is None:
        raise RuntimeError(
            f"codegen: recorded source host {class_name!r} defines no forward"
        )
    body = _recorded_body(source_text, func, record, meta)
    impl = _build_forward_impl_edit(
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385


def _bind_module_impl(source_text: str, wrapper_name: str, impl_name: str) -> str:
    """Add the instance ``_forward_impl`` binding beside MethodType(forward)."""
    tree = ast.parse(source_text)
    lines = source_text.splitlines(keepends=True)
    offsets = [0]
    for line in lines:
        offsets.append(offsets[-1] + len(line))
    edits: list[TextEdit] = []
    for node in ast.walk(tree):
        if not isinstance(node, ast.Assign) or len(node.targets) != 1:
            continue
        target = node.targets[0]
        value = node.value
        if not (
            isinstance(target, ast.Attribute)
            and target.attr == "forward"
            and isinstance(value, ast.Call)
            and isinstance(value.func, ast.Name)
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
            and value.args
            and isinstance(value.args[0], ast.Name)
            and value.args[0].id == wrapper_name
        ):
            continue
        owner = ast.unparse(target.value)
        indent = " " * node.col_offset
        binding = f"{indent}{owner}._forward_impl = MethodType({impl_name}, {owner})\n"
        edits.append(TextEdit(offsets[node.lineno - 1], offsets[node.lineno - 1], binding))
    if not edits:
        raise RuntimeError(
            f"codegen: source function {wrapper_name!r} is not installed with MethodType"
        )
    return apply_edits(source_text, edits)


__all__ = ["materialize_recorded_forwards"]
hyper_parallel/codegen/emit/replacement.py
25
26
27
28
29
30
31
32
33
    rules or inspects a live model.
    """
    payload = snapshot._emission_view() if hasattr(snapshot, "_emission_view") else snapshot  # pylint: disable=protected-access
    if not isinstance(payload, dict):
        raise TypeError("replacement snapshot must be a CodegenSnapshot or dict")
    replacements = payload.get("replacements", {})
    declarations = replacements.get("declarations", ())
    applications = replacements.get("applications", ())
    declarations_by_id = {item["rule_id"]: item for item in declarations}
31
32
33
34
35
36
37
38
39
    declarations = replacements.get("declarations", ())
    applications = replacements.get("applications", ())
    declarations_by_id = {item["rule_id"]: item for item in declarations}
    if len(declarations_by_id) != len(declarations):
        raise ValueError("replacement snapshot contains duplicate rule_id values")
    records = []
    for application in applications:
        rule_id = application.get("rule_id")
        declaration = declarations_by_id.get(rule_id)
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    for application in applications:
        rule_id = application.get("rule_id")
        declaration = declarations_by_id.get(rule_id)
        if declaration is None:
            raise ValueError(
                f"replacement application references unknown rule_id {rule_id!r}"
            )
        source_identity = application.get("source_type") or declaration.get("source_type")
        if not isinstance(source_identity, str) or not source_identity:
            raise ValueError(
                f"replacement application {rule_id!r} has no resolved source_type"
            )
        source_type = source_identity.replace(":", ".", 1)
        record = {
hyper_parallel/codegen/emit/snapshot_patches.py
61
62
63
64
65
66
67
68
69
        )
        if local is not None:
            local_computes.append(local)
        if wrapper is not None:
            inner_wrappers.append(wrapper)
    return {
        "module_replacements": replacements,
        "local_computes": local_computes,
        "inner_wrappers": inner_wrappers,
87
88
89
90
91
92
93
94
95
    )
    source_type = _source_type_identity(source, class_name)
    observed_type = boundary_types.get(module_fqn)
    if source_type is None and _is_remote_boundary_type(observed_type):
        source_type = observed_type
    bound_forward = _bound_forward_identity(source, module_fqn)
    local = _local_compute_patch(
        injection,
        source,
111
112
113
114
115
116
117
118


def _is_remote_boundary_type(value: Any) -> bool:
    """Return whether an observed type identifies non-framework source."""
    return isinstance(value, str) and not value.startswith(
        ("hyper_parallel.", "torch.")
    )

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
) -> Optional[dict[str, Any]]:
    """Build one local-compute emission record."""
    local_compute = injection.get("local_compute_fn")
    if local_compute is None:
        return None
    if declared_type is None:
        raise ValueError(
            "snapshot local_compute_fn requires a source module and "
            f"boundary class for {module_fqn!r}"
        )
    if source_type is None and bound_forward is None:
        return None
    module_type = (
        (_imported_type_identity(source, class_name) if bound_forward else source_type)
        or source_type
        or declared_type
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    """Build one inner-wrapper emission record."""
    wrapper = injection.get("inner_wrapper")
    if wrapper is None:
        return None
    target_type = replacement_types.get(module_fqn) or source_type or declared_type
    if target_type is None:
        raise ValueError(
            "snapshot inner_wrapper requires an observed replacement or "
            f"boundary class for {module_fqn!r}"
        )
    return {
        "module_fqn": module_fqn,
        "target_fqn": injection.get("inner_target") or "self",
        "wrapper": import_target_path(wrapper),
        "target_type": target_type,
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def _source_class_names(source: dict[str, Any]) -> set[str]:
    """Return classes defined by the snapshot's modeling source file."""
    file_path = source.get("file_path")
    if not file_path:
        return set()
    try:
        with open(file_path, "r", encoding="utf-8", errors="replace") as handle:
            tree = ast.parse(handle.read(), filename=file_path)
    except (OSError, SyntaxError):
        return set()
    return {node.name for node in tree.body if isinstance(node, ast.ClassDef)}


def _source_type_identity(
194
195
196
197
198
199
200
201
202
203
204
205
    source: dict[str, Any], class_name: Optional[str]
) -> Optional[str]:
    """Resolve a class to the remote source unit that actually defines it."""
    if not class_name:
        return None
    module_name = source.get("module_name")
    if not isinstance(module_name, str) or not module_name:
        return None
    if class_name in _source_class_names(source):
        return f"{module_name}:{class_name}"

    package, separator, _ = module_name.rpartition(".")
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    candidates = []
    for path in resolve_remote_siblings(source).values():
        sibling_source = {"file_path": path}
        if class_name not in _source_class_names(sibling_source):
            continue
        stem = os.path.splitext(os.path.basename(path))[0]
        sibling_module = f"{package}.{stem}" if separator else stem
        candidates.append(f"{sibling_module}:{class_name}")
    if len(candidates) > 1:
        raise ValueError(
            f"snapshot class {class_name!r} is defined by multiple bundled source units: "
            f"{sorted(candidates)}"
        )
    return candidates[0] if candidates else None
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    """Resolve a model-owned function installed through ``MethodType``."""
    file_path = source.get("file_path")
    module_name = source.get("module_name")
    if not file_path or not module_name or not module_fqn:
        return None
    try:
        with open(file_path, "r", encoding="utf-8", errors="replace") as handle:
            tree = ast.parse(handle.read(), filename=file_path)
    except (OSError, SyntaxError):
        return None

    boundary_name = module_fqn.rsplit(".", 1)[-1]
    candidates = set()
    for node in ast.walk(tree):
237
238
239
240
241
242
243
244
245
246
247
    candidates = set()
    for node in ast.walk(tree):
        candidate = _method_type_forward_name(node, boundary_name)
        if candidate:
            candidates.add(candidate)
    if len(candidates) > 1:
        raise ValueError(
            f"snapshot boundary {module_fqn!r} has multiple MethodType forwards: "
            f"{sorted(candidates)}"
        )
    return f"{module_name}:{next(iter(candidates))}" if candidates else None
250
251
252
253
254
255
256
257
258
259
def _method_type_forward_name(node: ast.AST, boundary_name: str) -> Optional[str]:
    """Return the function assigned as one boundary's MethodType forward."""
    if not isinstance(node, ast.Assign) or len(node.targets) != 1:
        return None
    target, call = node.targets[0], node.value
    valid_target = (
        isinstance(target, ast.Attribute)
        and target.attr == "forward"
        and isinstance(target.value, ast.Attribute)
        and target.value.attr == boundary_name
257
258
259
260
261
262
263
264
265
266
267
268
269
        and target.attr == "forward"
        and isinstance(target.value, ast.Attribute)
        and target.value.attr == boundary_name
    )
    if not valid_target or not isinstance(call, ast.Call):
        return None
    if _ast_name(call.func) != "MethodType" or not call.args:
        return None
    return call.args[0].id if isinstance(call.args[0], ast.Name) else None


def _imported_type_identity(
    source: dict[str, Any], class_name: Optional[str]
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
def _imported_type_identity(
    source: dict[str, Any], class_name: Optional[str]
) -> Optional[str]:
    """Resolve an imported boundary class from modules referenced by the source."""
    file_path = source.get("file_path")
    if not file_path or not class_name:
        return None
    try:
        with open(file_path, "r", encoding="utf-8", errors="replace") as handle:
            tree = ast.parse(handle.read(), filename=file_path)
    except (OSError, SyntaxError):
        return None

    explicit_modules = _explicit_import_modules(tree, class_name)
    if len(explicit_modules) > 1:
        raise ValueError(
            f"snapshot class {class_name!r} is imported from multiple modules: "
            f"{sorted(explicit_modules)}"
        )
    if explicit_modules:
        return f"{next(iter(explicit_modules))}:{class_name}"
    candidates = _exporting_import_modules(tree, class_name)
    if len(candidates) > 1:
        raise ValueError(
            f"snapshot class {class_name!r} is exported by multiple imported modules: "
            f"{candidates}"
        )
    return candidates[0] if candidates else None


def _explicit_import_modules(tree: ast.AST, class_name: str) -> set[str]:
    """Return modules that explicitly import one class name."""
    return {
        node.module
        for node in tree.body
        if isinstance(node, ast.ImportFrom)
        and node.level == 0
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340


def _exporting_import_modules(tree: ast.AST, class_name: str) -> list[str]:
    """Return imported modules that export one class name."""
    modules = {
        node.module
        for node in tree.body
        if isinstance(node, ast.ImportFrom) and node.level == 0 and node.module
    }
    candidates = []
    for module_name in sorted(modules):
        try:
            module = importlib.import_module(module_name)
        except (ImportError, AttributeError):
            continue
        if hasattr(module, class_name):
            candidates.append(f"{module_name}:{class_name}")
    return candidates


def _ast_name(node: ast.AST) -> Optional[str]:
    """Return the terminal name of a callable expression."""
    if isinstance(node, ast.Name):
        return node.id
    if isinstance(node, ast.Attribute):
        return node.attr
    return None


__all__ = ["emission_patches_from_snapshot_payload"]
hyper_parallel/codegen/emit/validation.py
28
29
30
31
32
33
34
35
36
37
38
        if not filename.endswith(".py") or filename == "__init__.py":
            continue
        try:
            tree = ast.parse(source_text, filename=filename)
        except SyntaxError as exc:
            errors.append(f"{filename}: invalid Python source ({exc.msg})")
            continue
        for class_node in (
            node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)
        ):
            _verify_class(filename, class_node, errors)
hyper_parallel/codegen/inline/component_source.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# limitations under the License.
# ============================================================================
"""Public entry for rendering a real replacement component as source."""

from typing import Any, Callable

from hyper_parallel.codegen.inline.attention import render_attention_class
from hyper_parallel.codegen.inline.expansion import ExpandedSource


def render_component_source(
    component: type, *, interface: Callable[..., Any]
) -> ExpandedSource:
    """Render a component and the source closure of its injected interface."""
    return render_attention_class(component, interface=interface)


__all__ = ["render_component_source"]
hyper_parallel/codegen/inline/definition_edits.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37


def drop_shadowed_definitions(text: str, imported_names: Iterable[str]) -> str:
    """Remove decorated definitions shadowing imported runtime helpers."""
    names = {name for name in imported_names if name}
    if not names:
        return text
    tree = ast.parse(text)
    offsets = _line_offsets(text)
    edits = [
        TextEdit(start, _skip_trailing_blank_lines(text, end), "")
        for node in tree.body
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))
        and node.name in names
37
38
39
40
41
42
43
44
45
        and node.name in names
        and node.decorator_list
        for start, end in (_node_span(node, offsets),)
    ]
    return apply_edits(text, edits) if edits else text


def apply_class_removals(
    text: str, patches: Iterable[ClassRemovalPatch]
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def apply_class_removals(
    text: str, patches: Iterable[ClassRemovalPatch]
) -> str:
    """Rewrite surviving references and delete classes made unused by patches."""
    patch_list = list(patches)
    if not patch_list:
        return text
    tree = ast.parse(text)
    offsets = _line_offsets(text)
    names = {patch.old_name for patch in patch_list}
    removable = {name for name in names if not _name_is_referenced(tree, name)}
    if not removable:
        return text
    replacements = {patch.old_name: patch.new_name for patch in patch_list}
    classes = {
        node.name: node
        for node in tree.body
        if isinstance(node, ast.ClassDef) and node.name in removable
    }
    deletion_spans = [_node_span(node, offsets) for node in classes.values()]
    edits = _reference_edits(tree, offsets, removable, replacements, deletion_spans)
    for name, node in classes.items():
        del name
        start, end = _node_span(node, offsets)
        edits.append(TextEdit(start, _skip_trailing_blank_lines(text, end), ""))
    return apply_edits(text, edits) if edits else text


def _reference_edits(
    tree: ast.AST,
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    replacements: dict[str, str],
    deletion_spans: list[tuple[int, int]],
) -> list[TextEdit]:
    """Rewrite references that survive class deletion."""
    edits = []
    for node in ast.walk(tree):
        if not isinstance(node, ast.Name) or node.id not in removable:
            continue
        start, end = _node_span(node, offsets)
        if any(span <= start < stop for span, stop in deletion_spans):
            continue
        edits.append(TextEdit(start, end, replacements[node.id]))
    return edits


def _name_is_referenced(tree: ast.AST, name: str) -> bool:
    """Return whether a name survives outside its own definition."""
    return any(
        (isinstance(node, ast.Name) and node.id == name)
        or (isinstance(node, ast.Attribute) and node.attr == name)
        for node in ast.walk(tree)
    )
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111


def _node_span(node: ast.AST, offsets: tuple[int, ...]) -> tuple[int, int]:
    """Return a node span including decorators."""
    line, column = node.lineno, node.col_offset
    decorators = getattr(node, "decorator_list", None)
    if decorators:
        first = min(decorators, key=lambda item: item.lineno)
        if first.lineno < line:
            line, column = first.lineno, max(0, first.col_offset - 1)
    return (
        offsets[line - 1] + column,
        offsets[node.end_lineno - 1] + node.end_col_offset,
    )
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133


def _line_offsets(source_text: str) -> tuple[int, ...]:
    """Return absolute offsets for source line starts."""
    offsets = [0]
    for line in source_text.splitlines(keepends=True):
        offsets.append(offsets[-1] + len(line))
    return tuple(offsets)


def _skip_trailing_blank_lines(text: str, end: int) -> int:
    """Advance beyond whitespace following a deleted definition."""
    while end < len(text) and text[end] in " \t":
        end += 1
    while end < len(text) and text[end] == "\n":
        end += 1
        while end < len(text) and text[end] in " \t":
            end += 1
    return end


__all__ = ["apply_class_removals", "drop_shadowed_definitions"]
hyper_parallel/codegen/inline/forward_edits.py
39
40
41
42
43
44
45
46
47
48
49
50
    edits: list[TextEdit] = []
    for patch in patch_list:
        cls = index.find_class(patch.class_name)
        if cls is None:
            continue
        func = cls.methods.get(patch.method_name)
        if func is None:
            continue
        body = _bind_forward_args(_bind_hidden_arg(patch.body, func), func)
        prefix = _parallel_state_prefix(body)
        if patch.merge_original_body:
            edits.extend(_merged_forward_edits(source_text, patch, func, body, prefix))
75
76
77
78
79
80
81
82
83
) -> list[TextEdit]:
    """Merge dispatch with the original body when no separate impl is needed."""
    fallback = _forward_impl_fallback(func)
    if fallback not in body:
        raise RuntimeError(
            f"codegen: merged strategy for {patch.class_name}."
            f"{patch.method_name} has no original-forward fallback"
        )
    dispatch = body.replace(fallback, "", 1).rstrip()
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def _bind_hidden_arg(body: str, func: FunctionInfo) -> str:
    """Bind a strategy shell's hidden-input placeholder to its host signature."""
    if _HIDDEN_ARG_TOKEN not in body:
        return body
    if not func.param_names:
        raise RuntimeError(
            f"codegen: inline strategy body references {_HIDDEN_ARG_TOKEN!r} "
            "but the target method has no positional parameter to bind it to"
        )
    return body.replace(_HIDDEN_ARG_TOKEN, func.param_names[0])


def _bind_forward_args(body: str, func: FunctionInfo) -> str:
    """Bind a dispatch shell's argument token to the original signature."""
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def _bind_forward_args(body: str, func: FunctionInfo) -> str:
    """Bind a dispatch shell's argument token to the original signature."""
    token = "__hp_forward_args__"
    if token not in body:
        return body
    args = list(func.param_names)
    if func.vararg_name:
        args.append(f"*{func.vararg_name}")
    args.extend(f"{name}={name}" for name in func.kwonly_names)
    if func.kwarg_name:
        args.append(f"**{func.kwarg_name}")
    return body.replace(token, ", ".join(args))


def _forward_impl_fallback(func: FunctionInfo) -> str:
119
120
121
122
123
124
125
126
127
128
129
130
def _forward_impl_fallback(func: FunctionInfo) -> str:
    """Render the dispatch-shell fallback that calls the extracted method."""
    args = list(func.param_names)
    if func.vararg_name:
        args.append(f"*{func.vararg_name}")
    args.extend(f"{name}={name}" for name in func.kwonly_names)
    if func.kwarg_name:
        args.append(f"**{func.kwarg_name}")
    return f"return self._forward_impl({', '.join(args)})"


__all__ = ["forward_extract_edits"]
hyper_parallel/codegen/inline/framework_spec.py
145
146
147
148
149
150
151
152
153
    except ImportError:
        return None
    component = getattr(module, attr, None)
    if not isinstance(component, type):
        return None
    if (
        target.startswith(_COMPONENTS_PREFIX)
        or getattr(component, "_hp_module_replacement", False)
    ):
151
152
153
154
155
156
157
158
159
        target.startswith(_COMPONENTS_PREFIX)
        or getattr(component, "_hp_module_replacement", False)
    ):
        return component
    return None


def _component_replacement_target(component: type) -> ReplacementTarget | None:
    """Read a wrap-style component's own constructor as its replacement target.
258
259
260
261
262
263
264
265
266
267
268
269
270
271
        [] if target.interface else [ImportPatch(target.module, (target.component,))]
    )
    snippets: tuple[ModuleSnippetPatch, ...] = ()
    if target.interface:
        provider = _family_provider(model_type, "codegen")
        renderer = getattr(provider, "render_replacement_source", None)
        if not callable(renderer):
            return None
        render_source = cast(Callable[..., Any], renderer)
        expanded = render_source(  # pylint: disable=not-callable
            component, interface=_interface_function(factory, target)
        )
        imports.extend(
            ImportPatch(module="", names=(), raw=line) for line in expanded.imports
311
312
313
314
315
316
317
318
319
320
    if target is None:
        return None
    if _direct_component_class(target) is not None:
        return _component_replacement_spec(target, model_type, module_type=module_type)
    if not adapter_path_parts(target):
        return None
    model_type = _family_key(model_type, target)
    factory = _factory_function(target, model_type)
    if factory is None:
        return None
339
340
341
342
343
344
345
346
347
    needs no codegen declaration.  A factory with no constructor call to sink --
    or a rule with no ``module_type`` naming the source class it replaces -- has
    no spec, and the rule is left to the native path.
    """
    del target
    # The source class the constructor call replaces: without the rule's
    # ``module_type`` there is no call site to rewrite, and guessing one would
    # silently target the wrong class.
    old_ctor = class_name_of(module_type)
349
350
351
352
353
354
355
356
357
        return None
    replacement = replacement_target(factory)
    if replacement is None:
        return None
    return _build_replacement_spec(factory, replacement, old_ctor, model_type)


def _component_replacement_spec(
    target: str, model_type: str | None, *, module_type: str | None
430
431
432
433
434
435
436
437
438
    strategy (imports only), preserving the runtime wrapper path.
    """
    resolved = inner_wrapper_target(target)
    if resolved is None:
        return StrategySpec(kind=CP_ATTENTION_KIND, imports=())
    if resolved.inline_body is not None:
        return StrategySpec(
            kind=CP_ATTENTION_KIND,
            subclass_shell=resolved.inline_body,
hyper_parallel/codegen/inline/ir.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

    def __post_init__(self) -> None:
        """Require a complete method patch or an imports-only declaration."""
        if self.target_class is not None and self.body_template is None:
            raise ValueError("Inline strategy target_class requires a body_template")
        if self.target_class is not None and (not self.target_class or not self.body_template.strip()):
            raise ValueError("Inline strategy class and body must be nonempty")
        if not self.method_name.isidentifier():
            raise ValueError("Inline strategy method_name must be a Python identifier")
        if self.subclass_shell is not None:
            if self.target_class is not None or self.body_template is not None:
                raise ValueError(
                    "Inline strategy subclass_shell is exclusive with "
                    "target_class and body_template"
                )
            if not self.subclass_shell.strip():
                raise ValueError("Inline strategy subclass shell must be nonempty")
hyper_parallel/codegen/inline/meta_plan.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
        meta, rules, model_type, boundary_classes
    )
    if not ep_fqns:
        return
    mark_fqns = _expanded_ep_boundaries(ep_fqns, strip_patterns, param_plan)
    for fqn in mark_fqns:
        entry = param_plan.get(fqn)
        if isinstance(entry, dict):
            param_plan[fqn] = {**entry, "is_boundary": False}
        boundary_classes.pop(fqn, None)


def _collect_ep_boundaries(
    meta: Any,
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    """Collect EP host FQNs and sub-boundary patterns from inline rules."""
    ep_fqns: set[str] = set()
    strip_patterns: tuple[str, ...] = ()
    for rule in rules:
        resolved = _ep_rule_hosts(rule, model_type, boundary_classes)
        if resolved is None:
            continue
        spec, host_classes = resolved
        if spec.strip_boundary_subpatterns:
            strip_patterns = spec.strip_boundary_subpatterns
        if host_classes:
            # Persist the derived classes so a re-emission of this
            # already-normalized meta (whose boundary entries the strip below
            # consumes) can still resolve its patch hosts.
            recorded = set(getattr(meta, "external_state_classes", None) or ())
            meta.external_state_classes = sorted(recorded | host_classes)
        for fqn, cls in boundary_classes.items():
            if cls not in host_classes:
                continue
            if any(fnmatch(fqn, pattern) for pattern in rule.match):
                ep_fqns.add(fqn)
    return ep_fqns, strip_patterns


def _expanded_ep_boundaries(
172
173
174
175
176
177
178
179
180
            for pat in strip_patterns:
                if fnmatch(local_suffix, pat):
                    mark_fqns.add(fqn)
                    break
    return mark_fqns


def _ep_rule_hosts(
    rule: SourceObservation, model_type: str | None, boundary_classes: dict[str, str]
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def _ep_rule_hosts(
    rule: SourceObservation, model_type: str | None, boundary_classes: dict[str, str]
) -> tuple[Any, set[str]] | None:
    """Resolve an inline EP rule and the source classes that host it."""
    if rule.local_compute_target is None:
        return None
    spec = strategy_spec(rule.local_compute_target, model_type)
    if spec is None or spec.body_template is None:
        return None
    if spec.target_class is not None:
        return spec, {spec.target_class}
    return spec, rule_block_classes(rule, boundary_classes)


def _mark_shared_class_boundaries(meta: Any, full_class_map: dict[str, str]) -> None:
    """Mark source lowering as skipped for classes shared with a non-boundary instance.
236
237
238
239
240
241
242
243
244
        if class_name not in non_boundary_classes:
            continue
        entry = param_plan.get(fqn)
        if isinstance(entry, dict):
            param_plan[fqn] = {**entry, "skip_source_lowering": True}
            logger.info(
                "codegen: boundary %s (class %s) marked skip_source_lowering "
                "-- the class is shared with a non-boundary instance; the "
                "runtime per-instance wrapper is used instead",
hyper_parallel/codegen/inline/observations.py
35
36
37
38
39
40
41
42
43
44
45
46
                    replace_target=target,
                )
            )
    for record in getattr(meta, "injections", None) or []:
        local = projected_target_path(record.get("local_compute_fn"))
        inner = projected_target_path(record.get("inner_wrapper"))
        if local is not None or inner is not None:
            rules.append(
                SourceObservation(
                    match=_matches(record),
                    inner_wrapper_target=inner,
                    local_compute_target=local,
54
55
56
57
58
59
60
61
62
    declared = record.get("replacement_target")
    parts = str(declared or "").split(".")
    if len(parts) >= 4 and parts[:2] == ["hyper_parallel", "models"] and parts[3] == "adapter":
        return declared
    return record.get("factory")


def _matches(record: dict[str, Any]) -> tuple[str, ...]:
    """Normalize one observation's selected FQNs."""
61
62
63
64
65
66
67
68
69
70
71
72
73
def _matches(record: dict[str, Any]) -> tuple[str, ...]:
    """Normalize one observation's selected FQNs."""
    value = record.get("fqns") or record.get("match") or record.get("fqn")
    if value is None:
        return ()
    if isinstance(value, str):
        return (value,)
    if isinstance(value, Iterable):
        return tuple(str(item) for item in value)
    return (str(value),)


__all__ = ["collect_source_observations"]
hyper_parallel/codegen/inline/patch_engine.py
65
66
67
68
69
70
71
72
73
74
75
    if waves:
        edits.extend(_constructor_edits(source_text, waves[0], hits))
    text = apply_edits(source_text, edits) if edits else source_text
    for wave in waves[1:]:
        wave_edits = _constructor_edits(text, wave, hits)
        if wave_edits:
            text = apply_edits(text, wave_edits)
    return text, hits


def _apply_constructor_followups(
87
88
89
90
91
92
93
94
95
        source_text = apply_edits(source_text, deferred_edits)
    if patch_set.constructor_replaces:
        _require_scoped_rewrites(patch_set.constructor_replaces, hits)
    if patch_set.class_removals:
        source_text = apply_class_removals(source_text, patch_set.class_removals)
    return source_text


def _apply_forward_patches(
123
124
125
126
127
128
129
130
131
132
            patch.new_ctor for patch in remaining if patch.new_ctor != patch.old_ctor
        }
        wave = [patch for patch in remaining if _is_wave_ready(patch, remaining, introduced)]
        if not wave:
            names = sorted({patch.old_ctor for patch in remaining})
            raise ValueError(
                f"codegen: constructor replacement dependency cycle among {names}"
            )
        chosen = {id(patch) for patch in wave}
        remaining = [patch for patch in remaining if id(patch) not in chosen]
140
141
142
143
144
145
146
147
148
149
150
151
    introduced: set[str],
) -> bool:
    """Return whether a constructor patch has no remaining dependency."""
    if patch.old_ctor in introduced:
        return False
    if patch.mode != "name":
        return True
    return not any(
        other is not patch
        and other.mode == "wrap_source"
        and other.old_ctor == patch.old_ctor
        for other in remaining
282
283
284
285
286
287
288
289
290
291
292
293
294
    offsets = _line_offsets(source_text)
    insertions: dict[int, list[str]] = defaultdict(list)
    for patch in pending:
        if patch.mode != "wrap_source":
            continue
        root_attr = patch.scope_fqns[0].split(".", 1)[0]
        constructors = _root_constructors(tree, root_attr)
        if len(constructors) != 1:
            continue
        function = constructors[0]
        _, end = _node_span(function.body[-1], offsets)
        insertions[end].append(_render_deferred_replacement(patch))
        hits[patch.old_ctor] += 1
305
306
307
308
309
310
311
312
313
        if not isinstance(node, ast.ClassDef):
            continue
        for child in node.body:
            if not isinstance(child, ast.FunctionDef) or child.name != "__init__":
                continue
            if any(
                isinstance(target, ast.Attribute)
                and isinstance(target.value, ast.Name)
                and target.value.id == "self"
hyper_parallel/codegen/inline/pipeline.py
61
62
63
64
65
66
67
68
69
    Returns:
        The rendered modeling source.
    """

    rendered, _ = render_inline_modeling_with_plan(
        source_text,
        meta,
        model_type,
        patch_plan=patch_plan,
67
68
69
70
71
72
73
74
75
        meta,
        model_type,
        patch_plan=patch_plan,
    )
    return rendered


def render_inline_modeling_with_plan(
    source_text: str,
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    *,
    patch_plan: Any = None,
) -> tuple[str, Any]:
    """Render source and return the independently normalized emission plan."""
    rules = collect_source_observations(meta)
    if not rules:
        return source_text, meta
    patches = patch_plan
    recorded_local_compute = bool(
        getattr(patches, "local_computes", ()) if patches is not None else ()
    )
    strategy_rules = (
        tuple(replace(rule, local_compute_target=None) for rule in rules)
        if recorded_local_compute
        else rules
    )
    _require_inline_coverage(strategy_rules, model_type)
    patch_set = build_source_patch_plan(
        rules,
        strategy_rules,
        model_type,
        _observed_boundary_classes(meta, patch_plan),
 98
 99
100
101
102
103
104
105
106
107
        model_type,
        _observed_boundary_classes(meta, patch_plan),
        getattr(meta, "external_state_classes", None),
    )
    _add_recorded_forward_host_imports(source_text, patch_set, patch_plan)
    _materialize_imported_forward_hosts(source_text, patch_set)
    rendered = apply_patch_set(source_text, patch_set)
    # The copied modeling source brings its own decorated helpers that share
    # names with the library functions the artifact imports, and a local
    # definition wins over the import: the native path calls the library
112
113
114
115
116
117
118
119
120
121
    # on purpose) keep their definitions.
    rendered = drop_shadowed_definitions(
        rendered, _library_import_names(rendered) & _decorated_names(source_text)
    )
    normalized_meta = normalize_inline_meta(meta, strategy_rules, model_type)
    return rendered, normalized_meta


def _add_recorded_forward_host_imports(
    source_text: str,
151
152
153
154
155
156
157
158
159
160
161
162
        for record in replacements
    }
    for patch in patch_set.forward_extracts:
        if patch.class_name in source_classes or patch.class_name in imported_names:
            continue
        replacement_type = replacement_types.get(patch.class_name)
        if replacement_type is None:
            continue
        patch_set.imports.append(
            ImportPatch(replacement_type.__module__, (replacement_type.__name__,))
        )
        imported_names.add(patch.class_name)
172
173
174
175
176
177
178
179
180
    )
    for record in wrappers:
        target_type = getattr(record, "target_type", None)
        if target_type is None:
            continue
        target_fqn = (
            record.module_fqn
            if record.target_fqn == "self"
            else f"{record.module_fqn}.{record.target_fqn}"
195
196
197
198
199
200
201
202
203
204
    remaining = []
    rendered: set[str] = set()
    for patch in patch_set.forward_extracts:
        if patch.class_name in source_classes:
            remaining.append(patch)
            continue
        import_index = next(
            (
                index
                for index, item in enumerate(patch_set.imports)
206
207
208
209
210
211
212
213
214
215
216
217
            ),
            None,
        )
        if import_index is None:
            remaining.append(patch)
            continue
        if patch.class_name in rendered:
            continue
        rendered.add(patch.class_name)
        imported = patch_set.imports[import_index]
        other_names = tuple(name for name in imported.names if name != patch.class_name)
        alias = f"_{patch.class_name}Base"
216
217
218
219
220
221
222
223
224
        other_names = tuple(name for name in imported.names if name != patch.class_name)
        alias = f"_{patch.class_name}Base"
        replacement_imports = []
        if other_names:
            replacement_imports.append(ImportPatch(imported.module, other_names))
        replacement_imports.append(ImportPatch(
            module="",
            names=(),
            raw=f"from {imported.module} import {patch.class_name} as {alias}",
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    *,
    patch_plan: Any = None,
) -> str:
    """Render only strategy forwards owned by one sibling source unit."""
    rules = collect_source_observations(meta)
    if not rules:
        return source_text
    recorded_local_compute = bool(
        getattr(patch_plan, "local_computes", ())
        if patch_plan is not None
        else ()
    )
    strategy_rules = (
        tuple(replace(rule, local_compute_target=None) for rule in rules)
        if recorded_local_compute
        else rules
    )
    _require_inline_coverage(strategy_rules, model_type)
    patches = build_strategy_patches(
        strategy_rules,
        model_type,
        _observed_boundary_classes(meta, patch_plan),
        getattr(meta, "external_state_classes", None),
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
        model_type,
        _observed_boundary_classes(meta, patch_plan),
        getattr(meta, "external_state_classes", None),
    )
    source_classes = {
        node.name
        for node in ast.parse(source_text).body
        if isinstance(node, ast.ClassDef)
    }
    patches.forward_extracts = [
        patch for patch in patches.forward_extracts
        if patch.class_name in source_classes
    ]
    if not patches.forward_extracts:
        return source_text
    patches.module_snippets.clear()
    patches.constructor_replaces.clear()
    patches.class_removals.clear()
    return apply_patch_set(source_text, patches)


def _library_import_names(text: str) -> set[str]:
    """Names the artifact imports from the library, i.e. the winning bindings.
hyper_parallel/codegen/inline/recognition.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

def inner_wrapper_target(factory_path: str | None) -> InnerWrapperTarget | None:
    """Recover an inner wrapper's emitted helper contract from its source."""
    if not factory_path:
        return None
    module_name, _, factory_name = factory_path.rpartition(".")
    if not module_name or not factory_name:
        return None
    tree = _module_source_tree(module_name)
    if tree is None:
        return None
    factory_node = _module_function(tree, factory_name)
    if factory_node is None:
        return None
    request_owner = _request_owner(factory_node, tree)
    replacement_name = _replacement_callable(request_owner)
    helper_name = (
        _forward_helper_name(request_owner, replacement_name)
237
238
239
240
241
242
243
244
245
    }
    if not helper_name or helper_name not in module_functions:
        inline_body = _nested_forward_body(request_owner, replacement_name)
        if inline_body is None:
            return None
        return InnerWrapperTarget(inline_body=inline_body)
    return InnerWrapperTarget(
        helper_module=module_name,
        helper_name=helper_name,
262
263
264
265
266
267
268
269
270

def _replacement_callable(request_owner: ast.AST | None) -> str | None:
    """Resolve the callable installed by an inner-wrapper request."""
    if request_owner is None:
        return None
    return _rewrite_request_callable(request_owner) or _returned_nested_callable(request_owner)


def _request_owner(factory_node: ast.AST, tree: ast.Module) -> ast.AST | None:
282
283
284
285
286
287
288
289
290
291
292
293
294
    for node in ast.walk(factory_node):
        if not isinstance(node, ast.Return) or not isinstance(node.value, ast.Call):
            continue
        if not isinstance(node.value.func, ast.Name):
            continue
        delegate = functions.get(node.value.func.id)
        if delegate is not None and _rewrite_request_callable(delegate) is not None:
            return delegate
    return None


def _returned_nested_callable(tree: ast.AST) -> str | None:
    """Return a nested callable returned directly by an inner wrapper."""
314
315
316
317
318
319
320
321
322
323
324
            continue
        try:
            with open(path, "r", encoding="utf-8") as handle:
                return handle.read()
        except (OSError, UnicodeError):
            return None
    return None


def _module_source_tree(module_name: str) -> ast.Module | None:
    """Parse cached module source into an isolated syntax tree."""
323
324
325
326
327
328
329
330
331
332
333
334
335
def _module_source_tree(module_name: str) -> ast.Module | None:
    """Parse cached module source into an isolated syntax tree."""
    source = _module_source(module_name)
    if source is None:
        return None
    try:
        return ast.parse(source)
    except SyntaxError:
        return None


def _rewrite_request_callable(tree: ast.AST) -> str | None:
    """Return the replacement callable passed to ``_ForwardRewriteRequest``."""
350
351
352
353
354
355
356
357
358
        for child in ast.walk(node):
            if isinstance(child, ast.Return) and isinstance(child.value, ast.Call):
                if isinstance(child.value.func, ast.Name):
                    return child.value.func.id
    return None


def _cp_mesh_companion_attr(tree: ast.AST) -> str | None:
    """Return the companion attribute whose value is the wrapper's CP mesh."""
368
369
370
371
372
373
374
375
376
    for node in ast.walk(tree):
        if not isinstance(node, ast.keyword) or node.arg != "companion_attrs":
            continue
        if not isinstance(node.value, ast.Dict):
            continue
        for key, value in zip(node.value.keys, node.value.values):
            if (
                isinstance(key, ast.Constant)
                and isinstance(key.value, str)
376
377
378
379
380
381
382
383
384
                and isinstance(key.value, str)
                and isinstance(value, ast.Name)
                and value.id == "cp_mesh"
            ):
                return key.value
    return None


def _cp_mesh_setattr_attr(tree: ast.AST) -> str | None:
406
407
408
409
410
411
412
413
414
415
416
        value = node.value
        targets = node.targets if isinstance(node, ast.Assign) else (node.target,)
        if not isinstance(value, ast.Name) or value.id != "cp_mesh":
            continue
        for target in targets:
            if isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name):
                return target.attr
    return None


def _nested_forward_body(tree: ast.AST, replacement_name: str | None) -> str | None:
434
435
436
437
438
439
440
441
442
443
444
445
        ),
        None,
    )
    if forward is None:
        return None
    companion_attrs = _companion_attr_bindings(tree)
    original_forward = _original_forward_binding(tree)
    if original_forward is None:
        return None

    class ClosureBindings(ast.NodeTransformer):
        """Rewrite captured closure bindings to generated-instance state."""
482
483
484
485
486
487
488
489
490
    ):
        body = body[1:]
    lowered = [ClosureBindings().visit(ast.fix_missing_locations(node)) for node in body]
    if not lowered:
        return None
    active = "\n".join(ast.unparse(node) for node in lowered)
    return (
        "if self.cp_enable:\n"
        f"{textwrap.indent(active, '    ')}\n\n"
498
499
500
501
502
503
504
505
506
    for node in ast.walk(tree):
        if not isinstance(node, ast.keyword) or node.arg != "companion_attrs":
            continue
        if not isinstance(node.value, ast.Dict):
            continue
        for key, value in zip(node.value.keys, node.value.values):
            if (
                isinstance(key, ast.Constant)
                and isinstance(key.value, str)
hyper_parallel/codegen/inline/replacement_pass.py
58
59
60
61
62
63
64
65
66
    """

    patch_set = InlinePatchSet()
    scopes_by_target: dict[str, set[str]] = defaultdict(set)
    fqns_by_target: dict[str, set[str]] = defaultdict(set)
    specs_by_target: dict[str, Any] = {}
    for rule in rules:
        target = rule.replace_target
        if target is None:
69
70
71
72
73
74
75
76
77
        if spec is None:
            continue
        specs_by_target.setdefault(target, spec)
        scopes_by_target[target].update(_scope_attrs(rule))
        fqns_by_target[target].update(fqn for fqn in rule.match if fqn)
    for target, spec in specs_by_target.items():
        scope_attrs = tuple(sorted(scopes_by_target[target]))
        if not scope_attrs:
            logger.warning(
hyper_parallel/codegen/inline/source_plan.py
30
31
32
33
34
35
36
37
38
39
    boundary_classes: Mapping[str, str] | None,
    external_state_classes: Collection[str] | None,
) -> InlinePatchSet:
    """Build the complete ordered patch set for one modeling source."""
    replacement = build_replacement_patches(observations, model_type)
    strategy = build_strategy_patches(
        strategy_observations,
        model_type,
        boundary_classes,
        external_state_classes,
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
        model_type,
        boundary_classes,
        external_state_classes,
    )
    return merge_patch_sets(replacement, strategy)


def merge_patch_sets(*patch_sets: InlinePatchSet) -> InlinePatchSet:
    """Merge pass outputs without changing their established application order."""
    merged = InlinePatchSet()
    for patch_set in patch_sets:
        merged.imports.extend(patch_set.imports)
        merged.module_snippets.extend(patch_set.module_snippets)
        merged.constructor_replaces.extend(patch_set.constructor_replaces)
        merged.forward_extracts.extend(patch_set.forward_extracts)
        merged.class_removals.extend(patch_set.class_removals)
    return merged


__all__ = ["build_source_patch_plan", "merge_patch_sets"]
hyper_parallel/codegen/inline/strategy_pass.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
                    patch_set, spec, rule, target, model_type,
                    boundary_classes, subclassed,
                )
                continue
            if spec.body_template is None:
                continue
            if spec.target_class is not None:
                host_classes = {spec.target_class}
            else:
                host_classes = rule_block_classes(rule, boundary_classes)
                if not host_classes:
                    # Re-emission of an already-normalized meta: the boundary
                    # entries the first pass stripped are gone, but the pass
                    # persisted the derived classes in
                    # ``meta.external_state_classes`` — the surviving record of
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
                    # which classes an inline body replaced. (Today the EP
                    # shell is the only body-bearing strategy, so the whole
                    # record is this rule's host set; a second body-bearing
                    # strategy would need a kind filter here.)
                    host_classes = set(external_state_classes or ())
                if not host_classes:
                    raise _unmaterialized_strategy_error(
                        spec.kind, target, rule, model_type
                    )
            for host_class in sorted(host_classes):
                key = (host_class, spec.method_name)
                if key in emitted:
                    if emitted[key] != spec.body_template:
                        raise ValueError(f"Conflicting inline strategies for {host_class}.{spec.method_name}")
                    continue
                emitted[key] = spec.body_template
                patch_set.forward_extracts.append(
                    ForwardExtractPatch(
                        class_name=host_class,
                        method_name=spec.method_name,
                        body=spec.body_template,
147
148
149
150
151
152
153
154
155
156
157
158
) -> None:
    """Materialize CP dispatch in the original host class exactly once."""
    host_classes = rule_block_classes(rule, boundary_classes)
    if not host_classes:
        raise _unmaterialized_strategy_error(spec.kind, target, rule, model_type)
    helper_names = [name for patch in spec.imports for name in patch.names]
    if len(helper_names) > 1:
        raise ValueError(
            f"codegen: CP strategy {target!r} carries multiple helper "
            f"imports for one subclass shell: {helper_names}"
        )
    for host_class in sorted(host_classes):
156
157
158
159
160
161
162
163
164
            f"imports for one subclass shell: {helper_names}"
        )
    for host_class in sorted(host_classes):
        if host_class in subclassed:
            continue
        subclassed.add(host_class)
        patch_set.forward_extracts.append(
            ForwardExtractPatch(
                class_name=host_class,
172
173
174
175
176
177
178
179
180
def _unmaterialized_strategy_error(
    kind: str, target: str, rule: SourceObservation, model_type: str | None
) -> RuntimeError:
    """The error for a declared strategy that selects no boundary module."""
    return RuntimeError(
        f"codegen: {kind} strategy {target!r} matched no boundary "
        f"module (patterns {list(rule.match)}, model_type="
        f"{model_type!r}) — the declared strategy cannot be "
        "materialized; check the match pattern or the plan's "
hyper_parallel/codegen/inline/targets.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

def projected_target_path(value: Any) -> str | None:
    """Return the dotted target represented by a frozen observation value."""
    if value is None:
        return None
    if isinstance(value, str):
        return value or None
    if isinstance(value, Mapping):
        target = value.get("_target_") or value.get("target")
        return str(target) if target else None
    module = getattr(value, "__module__", None)
    qualname = getattr(value, "__qualname__", None)
    return f"{module}.{qualname}" if module and qualname else None


def import_target_path(value: Any) -> str:
    """Return an importable ``module:qualname`` or reject an invalid target."""
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def import_target_path(value: Any) -> str:
    """Return an importable ``module:qualname`` or reject an invalid target."""
    target = projected_target_path(value)
    if not target:
        raise ValueError(f"snapshot injection target is not importable: {target!r}")
    if ":" in target:
        return target
    module_name, separator, name = target.rpartition(".")
    if not separator or not module_name or not name:
        raise ValueError(f"snapshot injection target is not importable: {target!r}")
    return f"{module_name}:{name}"


__all__ = ["import_target_path", "projected_target_path"]
hyper_parallel/codegen/manager.py
62
63
64
65
66
67
68
69
70
71
72
    Distributed launchers must use a dedicated sidecar instead of invoking
    this function independently on every training rank.
    """
    if not isinstance(snapshot, CodegenSnapshot):
        raise TypeError("snapshot must be a CodegenSnapshot")
    if snapshot.status not in (CodegenStatus.DERIVED, CodegenStatus.NOT_REQUIRED):
        raise ValueError(
            "snapshot-driven generation requires status 'derived' or 'not_required', "
            f"got {snapshot.status.value!r}"
        )
    source = snapshot.source
70
71
72
73
74
75
76
77
78
            f"got {snapshot.status.value!r}"
        )
    source = snapshot.source
    if not source.get("file_path"):
        raise ValueError("snapshot source must include a modeling file_path")
    model_type = source.get("model_type")
    public_model_type = artifact_model_type(str(model_type)) if model_type else None
    model_name = (
        _model_type_to_modeling_token(str(public_model_type))
79
80
81
82
83
84
85
86
87
        if model_type
        else source.get("architecture")
    )
    if artifact_dir is None and source.get("model_type"):
        layout = resolve_model_artifact_layout(
            family_dir_for_model_type(str(source["model_type"])),
            model_name=str(model_name) if model_name else None,
        )
    else:
hyper_parallel/codegen/model_build_overlay.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


def _prepare_model_source_compat(hf_config: Any) -> None:
    """Run an optional model-owned compatibility hook before construction."""
    model_type = getattr(hf_config, "model_type", None)
    adapter = get_model_adapter(model_type) if model_type else None
    loader = getattr(adapter, "codegen", None) if adapter is not None else None
    provider = loader() if loader is not None else None
    prepare = getattr(provider, "prepare_model_import", None)
    if prepare is not None:
        prepare()


@dataclass
class CodegenModelBuildResult:
71
72
73
74
75
76
77
78
79
80
81
82
83
    pretrained_model_name_or_path: Any,
    is_hf_model: bool,
) -> None:
    """Record deterministic source identity from the constructed meta model."""
    model_type = type(model)
    source_path = inspect.getsourcefile(model_type)
    architectures = list(getattr(hf_config, "architectures", None) or ())
    architecture = architectures[0] if architectures else model_type.__name__
    session.record_source({
        "model_type": getattr(hf_config, "model_type", None),
        "architecture": architecture,
        "architectures": architectures,
        "model_class": f"{model_type.__module__}:{model_type.__qualname__}",
118
119
120
121
122
123
124
125
126
127
128
129
130
131
            applications=(),
            unmatched=exc.unmatched,
        )
        raise
    session.record_replacements(
        declarations=replacement_api.describe_replacement_declarations(specs),
        applications=applications,
        unmatched=(),
    )
    return model


@contextmanager
def _observe_replacement_installations(
304
305
306
307
308
309
310
311
312
            dict(kwargs),
            load_base_model=False,
        )
        if "trust_remote_code" in kwargs:
            init_kwargs["trust_remote_code"] = kwargs["trust_remote_code"]
        _prepare_model_source_compat(hf_config)
        with _codegen_model_init_context():
            _, model = auto_model._init_model(  # pylint: disable=protected-access
                cls,
337
338
339
340
341
342
343
344
345
            load_base_model,
            session,
        )
        if freeze_config is not None:
            model_builder._apply_parameter_freezing(  # pylint: disable=protected-access
                model,
                freeze_config,
            )
        method_context = model_builder._build_replacement_context(  # pylint: disable=protected-access
hyper_parallel/codegen/plan/observation.py
43
44
45
46
47
48
49
50
51

def observe_emission_plan(plan: Any, model: Any) -> EmissionPlanObservation:
    """Project a native sharding plan without changing or applying it."""
    if plan is None:
        return EmissionPlanObservation()
    return EmissionPlanObservation(
        param_plan=_observe_boundary_plan(plan),
        injections=_observe_injections(plan),
        boundary_classes=_observe_boundary_classes(plan, model),
62
63
64
65
66
67
68
69
70
71
72
73
74
75
        entry: dict[str, Any] = {}
        for name in ("in_src", "in_dst", "out_src", "out_dst"):
            value = getattr(spec, name, None)
            if value is not None:
                entry[name] = named_placement_to_dict(value)
        for name in ("out_names", "_deferred_bias_params"):
            value = getattr(spec, name, None)
            if value:
                key = "deferred_bias_params" if name.startswith("_") else name
                entry[key] = list(value)
        for name in ("is_boundary", "region_dispatch"):
            value = getattr(spec, name, None)
            if value is not None:
                entry[name] = value
127
128
129
130
131
132
133
134
135
            owner_module == root_module
            or owner_module.startswith("torch.")
            or owner_module.startswith("hyper_parallel.")
        ):
            continue
        candidates = []
        parts = boundary_fqn.split(".")
        for index in range(1, len(parts) + 1):
            ancestor_fqn = ".".join(parts[:index])
136
137
138
139
140
141
142
143
144
            ancestor_type = type(model.get_submodule(ancestor_fqn))
            if ancestor_type.__module__ == owner_module:
                candidates.append((ancestor_fqn, ancestor_type))
        if not candidates:
            continue
        component_fqn, component_type = candidates[0]
        identity = f"{component_type.__module__}:{component_type.__qualname__}"
        components[(component_fqn, identity)] = {
            "fqn": component_fqn,
hyper_parallel/codegen/plan/placements.py
30
31
32
33
34
35
36
37
38
def placement_to_string(placement: Any) -> str:
    """Serialize one placement to its canonical source representation."""
    if isinstance(placement, StridedShard):
        if placement.uneven_shard:
            raise TypeError("cannot observe StridedShard(uneven_shard=True)")
        return f"SS({placement.dim},{placement.split_factor})"
    if isinstance(placement, Shard):
        if placement.uneven_shard:
            raise TypeError("cannot observe Shard(uneven_shard=True)")
40
41
42
43
44
45
46
47
    if isinstance(placement, Replicate):
        return "R"
    if isinstance(placement, Partial):
        return f"P({placement.reduce_op})"
    raise TypeError(
        f"cannot serialize placement {placement!r} of unknown type "
        f"{type(placement).__name__}"
    )
48
49
50
51
52
53
54
55
56
57


def named_placement_to_dict(named: Any) -> dict[str, Any]:
    """Serialize a nested named-placement contract to plain dictionaries."""
    if not named:
        return {}
    return {
        str(getattr(name, "value", name)): _value_to_data(value)
        for name, value in named.items()
    }
80
81
82
83
84
85
86
87
88
    except (IndexError, ValueError) as exc:
        raise ValueError(f"malformed shard placement {text!r}: invalid dim") from exc
    if kind == "S":
        if len(parts) != 1:
            raise ValueError(f"malformed shard placement {text!r}: too many args")
        return Shard(dim)
    if len(parts) != 2:
        raise ValueError(f"malformed strided shard placement {text!r}: expected SS(dim,factor)")
    try:
86
87
88
89
90
91
92
93
94
    if len(parts) != 2:
        raise ValueError(f"malformed strided shard placement {text!r}: expected SS(dim,factor)")
    try:
        split_factor = int(parts[1])
    except ValueError as exc:
        raise ValueError(
            f"malformed strided shard placement {text!r}: invalid split_factor"
        ) from exc
    return StridedShard(dim, split_factor)
 96
 97
 98
 99
100
101
102
103
104

def parse_named_placement(data: dict[str, Any]) -> Any:
    """Parse a nested named-placement contract from plain dictionaries."""
    if not data:
        return {}
    return _value_from_data(data)


def value_to_data(value: Any) -> Any:
108
109
110
111
112
113
114
115
116

def _value_to_data(value: Any) -> Any:
    """Recursively project placements and planner values into plain data."""
    if isinstance(value, (Partial, Replicate, Shard, StridedShard)):
        return placement_to_string(value)
    if hasattr(value, "to_dict"):
        return value.to_dict()
    if isinstance(value, dict):
        return {
117
118
119
120
121
122
123
124
125
126
127
            str(getattr(key, "value", key)): _value_to_data(item)
            for key, item in value.items()
        }
    if isinstance(value, (list, tuple)):
        return [_value_to_data(item) for item in value]
    if callable(value):
        return getattr(value, "__name__", str(value))
    return value


def _value_from_data(value: Any) -> Any:
132
133
134
135
136
137
138
139
140
141
142
        return {
            str(getattr(key, "value", key)): _value_from_data(item)
            for key, item in value.items()
        }
    if isinstance(value, list):
        return [_value_from_data(item) for item in value]
    return value


__all__ = [
    "named_placement_to_dict",
hyper_parallel/codegen/planner_overlay.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49


def _override_declared_params(plan_overrides: dict[str, Any], model: Any) -> set[str]:
    """Return parameter FQNs already owned by exact or glob overrides."""
    module_names = tuple(name for name, _ in model.named_modules())
    declared = set()
    for key, spec in plan_overrides.items():
        matches = (
            (name for name in module_names if fnmatchcase(name, key))
            if any(char in key for char in "*?[")
            else (key,)
        )
        for module_fqn in matches:
            prefix = f"{module_fqn}." if module_fqn else ""
            declared.update(prefix + name for name in (spec.params or {}))
    return declared


class CodegenShardingPlanner(ShardingPlanner):
    """Add audit-only coverage without changing the Trainer's native planner."""
59
60
61
62
63
64
65
66
67
68
        groups = super()._group_by_boundary(param_roles)
        normalized: dict[str, list[tuple[str, ParamRole]]] = {}
        for module_fqn, group in groups.items():
            if self._infer_boundary_type(module_fqn, group) != "unknown":
                normalized[module_fqn] = group
                continue
            for param_fqn, role in group:
                owner = param_fqn.rsplit(".", 1)[0]
                normalized.setdefault(owner, []).append((param_fqn, role))
        return normalized
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        return normalized

    def _derive_boundary_specs(self, plan: Any, boundary_groups: Any, **kwargs: Any) -> None:
        """Append explicit replicated audit entries after native derivation."""
        super()._derive_boundary_specs(plan, boundary_groups, **kwargs)
        if not self._derive:
            return
        model = kwargs["model"]
        parameters_by_name = dict(model.named_parameters())
        override_declared = _override_declared_params(self._plan_overrides, model)
        for boundary_fqn, group in boundary_groups.items():
            if boundary_fqn in plan.modules:
                continue
            fallback = self._build_replicated_fallback_spec(
                boundary_fqn,
                group,
                parameters_by_name,
                override_declared,
83
84
85
86
87
88
89
90
91
92
                group,
                parameters_by_name,
                override_declared,
            )
            if fallback is not None:
                plan.modules[boundary_fqn] = fallback

    @staticmethod
    def _build_replicated_fallback_spec(
        boundary_fqn: str,
 96
 97
 98
 99
100
101
102
103
104
    ) -> Optional[ModuleShardingSpec]:
        """Declare communication-free metadata for replicated leftovers."""
        replicable = (ParamRole.REPLICATED, ParamRole.NORM, ParamRole.BIAS)
        if any(role not in replicable for _, role in group):
            return None
        prefix = f"{boundary_fqn}." if boundary_fqn else ""
        params: dict[str, NamedPlacement] = {}
        for param_fqn, _ in group:
            parameter = parameters_by_name.get(param_fqn)
106
107
108
109
110
111
112
113
114
                continue
            relative = param_fqn[len(prefix):] if prefix else param_fqn
            params[relative] = _multi_dim(tp=Replicate(), cp=Replicate(), ep=Replicate())
        if not params:
            return None
        return ModuleShardingSpec(params=params, in_src={}, in_dst={}, is_boundary=False)


@contextmanager
hyper_parallel/codegen/session.py
49
50
51
52
53
54
55
56
57

    @property
    def status(self) -> CodegenStatus:
        """Return the current session status."""
        return self._status

    @property
    def has_replacement_applications(self) -> bool:
        """Whether native model construction installed any replacement."""
60
61
62
63
64
65
66
67
68
    def record_source(self, source: Mapping[str, Any]) -> None:
        """Record source and model identity once while collecting."""
        self._require_open(CodegenStatus.COLLECTING)
        if self._source_recorded:
            raise RuntimeError("codegen source has already been recorded")
        self._source = self._as_mapping(source, "source")
        self._source_recorded = True

    def record_replacements(
74
75
76
77
78
79
80
81
82
    ) -> None:
        """Record native replacement declarations and observed applications."""
        self._require_open(CodegenStatus.COLLECTING)
        if self._replacements_recorded:
            raise RuntimeError("codegen replacements have already been recorded")
        self._replacements = ReplacementSnapshot.from_data(
            declarations=declarations,
            applications=applications,
            unmatched=unmatched,
116
117
118
119
120
121
122
123
124
    def mark_not_required(self, reason: str) -> None:
        """Finish collection when the native build has no sharding plan."""
        self._require_open(CodegenStatus.COLLECTING)
        if not self._source_recorded:
            raise RuntimeError("record_source() must run before mark_not_required()")
        self._reason = self._require_reason(reason)
        self._status = CodegenStatus.NOT_REQUIRED

    def mark_generating(self) -> None:
132
133
134
135
136
137
138
139
140
141
142
143
144
        self._status = CodegenStatus.GENERATED

    def mark_skipped(self, reason: str) -> None:
        """Mark generation as intentionally skipped with a stable reason."""
        self._require_open(CodegenStatus.COLLECTING, CodegenStatus.DERIVED)
        if not self._source_recorded:
            raise RuntimeError("record_source() must run before mark_skipped()")
        self._reason = self._require_reason(reason)
        self._status = CodegenStatus.SKIPPED

    def mark_failed(
        self,
        stage: str,
176
177
178
179
180
181
182
183
184
185
186
187
188
189
            RuntimeError: If collection or generation is incomplete.
        """
        if self._finished:
            if self._snapshot is None:
                raise RuntimeError("finished codegen session has no snapshot")
            return self._snapshot
        if self._status == CodegenStatus.COLLECTING:
            raise RuntimeError("codegen session is still collecting")
        if self._status == CodegenStatus.GENERATING:
            raise RuntimeError("codegen session is still generating")
        if self._status == CodegenStatus.DERIVED and generator is not None:
            publish_snapshot = self._build_snapshot(CodegenStatus.DERIVED)
            self.mark_generating()
            try:
200
201
202
203
204
205
206
207
208
209
210
        elif self._status == CodegenStatus.NOT_REQUIRED and generator is not None:
            publish_snapshot = self._build_snapshot(CodegenStatus.NOT_REQUIRED)
            try:
                generator(publish_snapshot)
            except Exception as exc:  # pylint: disable=broad-exception-caught
                # Publication must not invalidate an already successful native build.
                self.mark_failed(
                    "generation",
                    str(exc) or type(exc).__name__,
                    {"exception_type": type(exc).__name__},
                )
227
228
229
230
231
232
233
234
235
236
    def _require_open(self, *statuses: CodegenStatus) -> None:
        if self._finished:
            raise RuntimeError("codegen session is already finished")
        if statuses and self._status not in statuses:
            expected = ", ".join(status.value for status in statuses)
            raise RuntimeError(
                f"codegen session is {self._status.value}; expected one of: {expected}"
            )

    @staticmethod
239
240
241
242
243
244
245
246
247

    @staticmethod
    def _require_reason(reason: str) -> str:
        if not isinstance(reason, str) or not reason.strip():
            raise ValueError("codegen reason must be a non-empty string")
        return reason


__all__ = ["CodegenBuildSession"]
hyper_parallel/codegen/snapshot.py
37
38
39
40
41
42
43
44
45
46
47

def copy_mapping(value: Mapping[str, Any], path: str) -> dict[str, Any]:
    """Return a deep copy of a string-keyed observation mapping."""
    if not isinstance(value, Mapping):
        raise TypeError(f"{path} must be a mapping")
    if not all(isinstance(key, str) for key in value):
        raise ValueError(f"{path} mapping keys must be strings")
    return deepcopy(dict(value))


def _copy_records(
82
83
84
85
86
87
88
89
90
        )

    def to_dict(self) -> dict[str, Any]:
        """Return an isolated mutable representation for emission."""
        return deepcopy(
            {
                "declarations": list(self.declarations),
                "applications": list(self.applications),
                "unmatched": list(self.unmatched),
101
102
103
104
105
106
107
108
109
110
111
    details: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        if not isinstance(self.stage, str) or not self.stage:
            raise ValueError("failure stage must be a non-empty string")
        if not isinstance(self.reason, str) or not self.reason:
            raise ValueError("failure reason must be a non-empty string")
        object.__setattr__(
            self,
            "details",
            copy_mapping(self.details, "failure.details"),
119
120
121
122
123
124
125
126
127
        details: Optional[Mapping[str, Any]] = None,
    ) -> "FailureSnapshot":
        """Build an isolated failure record."""
        if not stage or not reason:
            raise ValueError("failure stage and reason must be non-empty")
        return cls(stage, reason, details or {})

    def to_dict(self) -> dict[str, Any]:
        """Return an isolated mutable representation for emission."""
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
    reason: Optional[str] = None
    failure: Optional[FailureSnapshot] = None

    def __post_init__(self) -> None:
        if not isinstance(self.status, CodegenStatus):
            raise TypeError("snapshot status must be a CodegenStatus")
        if not isinstance(self.replacements, ReplacementSnapshot):
            raise TypeError("snapshot replacements must be a ReplacementSnapshot")
        if self.failure is not None and not isinstance(self.failure, FailureSnapshot):
            raise TypeError("snapshot failure must be a FailureSnapshot or None")
        object.__setattr__(self, "source", copy_mapping(self.source, "snapshot.source"))
        object.__setattr__(
            self,
            "diagnostics",
            copy_mapping(self.diagnostics, "snapshot.diagnostics"),
        )
        for name in ("plan",):
            value = getattr(self, name)
            if value is not None:
                object.__setattr__(
                    self,
                    name,
                    copy_mapping(value, f"snapshot.{name}"),
                )
hyper_parallel/codegen/source/composition.py
40
41
42
43
44
45
46
47
48
        One source string containing the primary and nested model definitions.
    """
    components = getattr(meta, "nested_components", None) or ()
    if not components:
        return source_text
    rendered = source_text
    included_modules: set[str] = set()
    for component in components:
        identity = component.get("type")
46
47
48
49
50
51
52
53
54
    included_modules: set[str] = set()
    for component in components:
        identity = component.get("type")
        if not isinstance(identity, str) or ":" not in identity:
            raise ValueError(f"invalid nested component identity: {identity!r}")
        module_name, class_name = identity.split(":", 1)
        class_name = class_name.rsplit(".", 1)[-1]
        replaced = _replace_auto_model_construction(
            rendered,
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


def _read_module_source(module_name: str) -> str:
    """Read an installed module without importing its runtime dependencies."""
    spec = importlib.util.find_spec(module_name)
    path = None if spec is None else spec.origin
    if not path or not os.path.isfile(path):
        raise FileNotFoundError(
            f"codegen: nested model source {module_name!r} is not readable"
        )
    with open(path, "r", encoding="utf-8", errors="replace") as handle:
        return handle.read()


def _append_source_module(primary: str, nested: str, module_name: str) -> str:
    """Append one nested module after removing module-only syntax."""
127
128
129
130
131
132
133
134
135
    return result


def _is_docstring(node: ast.Expr) -> bool:
    return isinstance(node.value, ast.Constant) and isinstance(node.value.value, str)


class _RenameBindings(ast.NodeTransformer):
    """Rename colliding nested-module globals and their references."""
174
175
176
177
178
179
180
181
182
        """Render imports whose dynamic package contains non-Python identifiers."""
        assignments = []
        for alias in node.names:
            if alias.name == "*":
                raise ValueError(
                    f"codegen cannot compose a wildcard import from dynamic module {module!r}"
                )
            imported = ast.Call(
                func=ast.Name(id="__import__", ctx=ast.Load()),
202
203
204
205
206
207
208
209
210
) -> str | None:
    """Replace an observed AutoModel construction, or reject the candidate."""
    attribute = component_fqn.rsplit(".", 1)[-1]
    if not attribute:
        raise ValueError("nested component FQN must not be empty")
    pattern = re.compile(
        rf"(?m)^(?P<indent>\s*)self\.{re.escape(attribute)}\s*=\s*"
        r"AutoModel\.from_config\((?P<config>[^\n]+)\)\s*$"
    )
hyper_parallel/codegen/source/resolver.py
356
357
358
359
360
361
362
363
364
    if not model_id:
        return None
    try:
        # Transformers is optional for repository-only source resolution.
        from transformers import AutoConfig  # pylint: disable=import-outside-toplevel
    except ImportError:
        return None
    kwargs: dict[str, Any] = {}
    if _trust_remote_code(config):
419
420
421
422
423
424
425
426
427
428
429
430
    path = getattr(model, "pretrained_model_name_or_path", None)
    if path is None:
        path = getattr(model, "model_name_or_path", None)
    if path is None:
        path = getattr(model, "config_path", None)
    if path is None:
        kwargs = getattr(model, "_kwargs", {})
        path = kwargs.get("pretrained_model_name_or_path") or kwargs.get("config_path", "")
    return path or ""


def _trust_remote_code(config: Any) -> bool:
hyper_parallel/codegen/train_sidecar.py
54
55
56
57
58
59
60
61
62
63
def _monitor_sidecar(process: subprocess.Popen, config_path: str) -> None:
    """Reap the Codegen process and report failure without stopping training."""
    return_code = process.wait()
    if return_code == 0:
        logger.info("Codegen sidecar completed for %s", config_path)
        return
    logger.warning(
        "Codegen sidecar failed for %s with exit code %s; native training continues",
        config_path,
        return_code,
hyper_parallel/distributed/context_parallel/wrappers.py
450
451
452
453
454
455
456
457
458
459
    fired = {"hit": False}

    def cp_aware_sdpa(q: Any, k: Any, v: Any, **kw: Any) -> Any:
        """CP-aware SDPA replacement: all-gather K/V plus the D-04 mask."""
        fired["hit"] = True
        return _cp_sdpa_call(orig_sdpa, cp_mesh, q, k, v, kw)

    F.scaled_dot_product_attention = cp_aware_sdpa
    try:
        out = original_forward(hidden_states, *args, **kwargs)
468
469
470
471
472
473
474
475
476
            f"all-gathered; continuing would produce silent numerical "
            f"errors). Please explicitly set inner_wrapper='sdpa_qkv' "
            f"(the (q,k,v) convention), or provide a custom inner_wrapper "
            f"callable")
    return out


@inner_wrapper
def flex_hf_cp_wrapper(
hyper_parallel/distributed/mesh.py
48
49
50
51
52
53
54
55
56

def _positive_world_size(value: Any) -> int:
    """Validate the process-group or inferred world size."""
    if isinstance(value, bool) or not isinstance(value, int) or value < 1:
        raise ValueError(f"world_size must be a positive integer, got {value!r}")
    return value


@dataclass(frozen=True)
 94
 95
 96
 97
 98
 99
100
101
102

    @property
    def dense_world_size(self) -> int:
        """Return the rank count in one pipeline stage."""
        return self.dp_size * self.spec.cp_size * self.spec.tp_size


def resolve_parallel_layout(
    spec: ParallelTopologySpec, world_size: int
104
105
106
107
108
109
110
111
112
    """Validate a world size and resolve its DP/FSDP/EP layout."""
    world_size = _positive_world_size(world_size)
    non_dp_size = spec.tp_size * spec.cp_size * spec.pp_size
    if world_size % non_dp_size != 0:
        raise ValueError(
            f"world_size {world_size} is not divisible by non-DP size "
            f"{non_dp_size}"
        )
    dp_size = world_size // non_dp_size
111
112
113
114
115
116
117
118
119
        )
    dp_size = world_size // non_dp_size
    fsdp_data_parallel_size = dp_size * spec.cp_size
    if fsdp_data_parallel_size % spec.dp_shard_size != 0:
        raise ValueError(
            "DP+CP size "
            f"{fsdp_data_parallel_size} is not divisible by FSDP shard size "
            f"{spec.dp_shard_size}"
        )
118
119
120
121
122
123
124
125
126
            f"{spec.dp_shard_size}"
        )
    dense_world_size = dp_size * spec.cp_size * spec.tp_size
    if dense_world_size % spec.ep_size != 0:
        raise ValueError(
            f"expert domain size ({dense_world_size}) must be divisible by "
            f"ep_size ({spec.ep_size})"
        )
    expert_data_parallel_size = dense_world_size // spec.ep_size
124
125
126
127
128
129
130
131
132
            f"ep_size ({spec.ep_size})"
        )
    expert_data_parallel_size = dense_world_size // spec.ep_size
    if expert_data_parallel_size % spec.edp_shard_size != 0:
        raise ValueError(
            f"expert data-parallel size ({expert_data_parallel_size}) must be "
            f"divisible by edp_shard_size ({spec.edp_shard_size})"
        )
    return ParallelLayout(
170
171
172
173
174
175
176
177
178
            else tuple(mesh_dim_names)
        )
        missing = tuple(name for name in names if name not in self.mesh_dim_names)
        if missing:
            raise KeyError(f"logical mesh has no dimensions {missing!r}")
        shape_by_name = dict(zip(self.mesh_dim_names, self.mesh_shape))
        return LogicalDeviceMesh(
            mesh_dim_names=names,
            mesh_shape=tuple(shape_by_name[name] for name in names),
hyper_parallel/trainer/config/resolver.py
686
687
688
689
690
691
692
693
694
        raise ConfigResolutionError(path, "DataLoader configuration must be a YAML mapping")

    target_node = dict(node)
    if "dataloader_type" in target_node:
        raise ConfigResolutionError(f"{path}.dataloader_type", "renamed to sampler_type")

    if "batch_adapter" in target_node:
        raise ConfigResolutionError(
            f"{path}.batch_adapter",