Repository navigation
feat(measure): add the leaf modules of the measurement core: instruction sheet, result manifest, signing and what they stand on - #2157
Draft
zoroyihan7 wants to merge 9 commits into
Conversation
The bottom layer of the measurement core: the modules that import only the measurement contract, the common helpers and each other. They are taken from multibranch-dev as they are, with the tests whose imports are all in this change or below it. - spec: the instruction sheet (MeasurementSpec v1) the application hands a runner, its sha256 and the fingerprint of its measurement content. - manifest: the signed result manifest (MeasurementResult v1) a runner writes, read strictly. - signing: Ed25519 signing of the manifest bytes; cryptography is imported on first use. - surface: the inputs that decide what a test measures, hashed into surface_sha256, and the checks that hold a test's YAML to them. - docs, fsafe: the strict document readers the sheet and the manifest share, and symlink-proof file access under a directory the caller does not control. - phases: where the time of a test goes, and how the phases add up. - repro: runs the case of a repro test against a live server and keeps its verdict. - boot_watch, log_causes, returncodes, ports: the limit on a server's start-up, what a failed test's logs say went wrong, the return codes only hosted measurement produces, and the ports local measurement leaves alone. - magpie_launchers, profile_traces, aiter_merge_hook: Magpie's launchers in the InferenceX checkout, where a profile test leaves its traces, and the start-up hook that moves aiter's merged tuned tables below the test. - framework/tables, jit/builds, jit/notes, jit_kinds: the first modules of the framework and jit subpackages, and the kinds of compiled-code cache. Tests: the eight files whose imports are within this change (phases, repro, signing, surface, magpie_launchers, profile_traces, jit builds and notes). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
measure/signing.py imports the cryptography package on first use, as the hosted-measurement modules do with their other third-party libraries, so the extra that holds the hosted-measurement dependencies names it. The runner extra already did, for the signing the sealed runner does. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Code metrics gate: PASSEDJudged: the 42 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.
A10 Raw vocabulary comparison (advisory, never fails): 1
Thresholds and sources: |
…only CodeQL flags py/overly-permissive-file: the copy of a Magpie launcher was given mode 0o755, which makes it world readable. Magpie runs it as the user that placed it, so 0o700 is all it needs, as for the other files and directories this layer creates. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bundle verifies a result bundle read from a sandbox (the manifest, its signature and the files it lists) and places the files in the output directory, checking each byte a second time as it is copied and landing all files or none. It imports only docs, fsafe, manifest and signing, so it sits in this layer; it moves here from the hosted path because the tests of spec and manifest build their documents with bundle_factory, which imports it. Tests: test_bundle, test_spec and test_manifest, with bundle_factory. They are taken from multibranch-dev as they are. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
| continue | ||
| try: | ||
| remove(name, dir_fd=parent) | ||
| except OSError: |
| [ | ||
| (lambda: _sweep(point_yaml(conc=4), point_yaml(conc=8, port=8001)), "more than the concurrency level", False), | ||
| (lambda: _sweep(point_yaml(conc=4), point_yaml(conc=4)), "appears twice", False), | ||
| (lambda: _sweep(), "at least one", True), |
…aves Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Oct 30, 2026
Open
zoroyihan7
added a commit
that referenced
this pull request
Oct 30, 2026
Every file this PR carries now matches origin/multibranch-dev e81281d, except the two test files named below. Moved to dev's text: aiperf_patch (finds the client submodule by its name), bootstrap (template step, runner start line), cache_build (build target, pinned build tools), cache_layout, hardware (released_gpus, AMD_GPU_BOARDS), gpu_identity and its test (dev is now main's table plus the device-id helpers, r9700 and radeon8060s included), bootstrap_rig, conftest, test_aiperf_patch, requirements/runner.lock. Added (dev tests of this PR's modules): test_bootstrap_entry, test_bootstrap_template_step, test_cache_build_target. Removed: runner/service.py, runner/tests/test_service.py and measure/live_log.py. On dev, service imports measure.boot_watch (#2157) and measure.failures (B3), so it can no longer land below them; live_log has no other reader in this PR. They go with the runner core. Kept off dev: conftest drops the card_watch / sandbox.card_occupancy fixtures (both are later layers); test_aiperf_patch still leaves out the test that reads the export through measure.agentx_requests. Co-Authored-By: Claude <noreply@anthropic.com>
…aves Co-Authored-By: Claude <noreply@anthropic.com>
…branch-dev e81281d Every module and test this PR carries now equals origin/multibranch-dev e81281d. Changed from dev: aiter_merge_hook, boot_watch, jit/builds, log_causes, manifest, phases, profile_traces, spec, surface and the tests jit/tests/test_builds, test_manifest, test_profile_traces, test_spec. Unchanged: the other 24 files. Added, because spec.py now reads the short-prompt and long-context plans of the instruction sheet: measure/short_prompts/{__init__,plan}.py and measure/long_context/{__init__,plan}.py (as on dev; they import only measure.docs and each other). The rest of those two packages (the passes, clients, staging) is a later layer and is not added. profile_traces.py imports is_capture_fragment from hyperloom.orchestrator.trace_analysis; the function is on main in _capture_shapes.py, but only dev's package __init__ exports it. The __init__ gains that one export; dev's other exports there are not needed here and are not added. Nothing removed. Co-Authored-By: Claude <noreply@anthropic.com>
…aves Co-Authored-By: Claude <noreply@anthropic.com>
…aves Brings main's hyperloom_common layout (#2308) in through the base. Co-Authored-By: Claude <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on a merge of the two stacks. The base branch of this PR,
feature/yihan/measure-leaves-base, mergesfeature/yihan/sandbox-layer(#2154, which carries the measurement contract #2153) andfeature/yihan/runner-basics(#2156, which carries the rule pack #2155). It has no PR of its own and nothing else is added to it, so the diff below is this PR's own. On 2026-10-30 all four were refreshed tomultibranch-deve81281d60on top of the currentmain(20d8b2043), and the base branch merged them again (8604af291). The modules here importhyperloom.contracts.measurementandhyperloom.contracts.recipe(#2153),hyperloom.common.outside_facts(#2155) and, forpyproject.toml, thehostedextra that #2154 defines; no single stack has all of these. The base merge resolves two one-line conflicts by keeping both sides:_DEV_ONLYinplugs/tests/test_architecture.py(mainlistshyperloom.measureandhyperloom.sandboxthere; #2156 removesmeasure, #2154 removessandbox, so the base keeps onlyhyperloom_multibranch) and the package-data list inpyproject.toml(the rule pack'scommon/outside_facts/packs/*.yaml; the contracts' schemas are now covered bymain's owncontracts/*.json). When the four PRs below have merged, this PR retargets tomainwithgit rebase --onto main feature/yihan/measure-leaves-base feature/yihan/measure-leaves.Summary
Adds the bottom layer of the measurement core,
hyperloom.measure: the modules that import only the measurement contract, the common helpers and each other, among them the instruction sheet (spec), the result manifest (manifest),signingand the check of a result bundle (bundle). All of it is taken frommultibranch-devate81281d60as it is, with the tests whose imports are all in this change or below it; the exceptions are listed under "What differs frommultibranch-dev". Commits on top of the base merge:feat(measure): add the measurement core's leaf modules: the modules and their tests.build(hosted): list cryptography in the hosted extra:signingimportscryptography.fix(measure): place a launcher in the checkout readable by its owner only: the one change CodeQL asked for (below).feat(measure): add the result bundle check and the tests it lets run:bundleand the tests ofspec,manifestandbundle.chore(measure): bring the measurement core's leaf modules up to multibranch-dev e81281d60(after merging the refreshed base): nine modules and four test files changed onmultibranch-devsince555e863eb(aiter_merge_hook,boot_watch,jit/builds,log_causes,manifest,phases,profile_traces,spec,surface; testsjit/tests/test_builds,test_manifest,test_profile_traces,test_spec) and take dev's version.specnow reads the short-prompt and long-context plans of the sheet, so the two plan modules and their package markers are added (short_prompts/plan.py,long_context/plan.py);profile_tracesnow askshyperloom.orchestrator.trace_analysiswhether a trace is a CUDA-graph capture sidecar, so that package's__init__exportsis_capture_fragment(the function is already onmain, in_capture_shapes.py). Nothing was removed.The modules (lines), and everything each imports from this repository:
spec.pyMeasurementSpecv1) the application hands a runner, its sha256 and the fingerprint of its measurement contentcontracts.measurement,docs,surface,short_prompts.plan,long_context.planmanifest.pyMeasurementResultv1) a runner writes, read strictlycontracts.measurement,docs,jit_kindsbundle.pydocs,fsafe,manifest,signingsigning.pycryptographyis imported on first usesurface.pysurface_sha256, and the checks that hold a test's YAML to themcontracts.recipe,common.outside_facts(#2155)docs.pyshort_prompts/plan.py,long_context/plan.py(+ two__init__)docs;long_context.planalsoshort_prompts.planfsafe.pyphases.pycontracts.measurementrepro.pyreprotest against a live server and keeps its verdictcontracts.measurementboot_watch.pyorchestrator.actions.cancel_channel(onmain)log_causes.pycommon.outside_facts(#2155)returncodes.py,ports.pymagpie_launchers.pycommon.benchmark_config(onmain)profile_traces.pyprofiletest leaves its torch-profiler traces, and whether any of them is of a serving step rather than a CUDA-graph captureorchestrator.trace_analysis(is_capture_fragment, onmain; exported by this PR)aiter_merge_hook.py/tmpframework/tables.py(+__init__)AITER_CONFIG_*variable names, read from aiter's sourcejit/builds.py,jit/notes.py,jit_kinds.py(+jit/__init__)Measured on a tree that holds only the base and this PR (no other
measureorsandboxmodule frommultibranch-dev): each of the 26measuremodules imports in a fresh isolated interpreter (python -I). No module importssocket,local,compile,farm,failures,archive,hostedor any other module of the measurement core above this layer, and none imports a module ofhyperloom.sandbox.Tests (306, all passing):
test_spec(93),test_manifest(54),test_bundle(46),test_surface(23),test_phases(19),test_repro(19),test_signing(14),test_profile_traces(12),jit/tests/test_builds(11),test_magpie_launchers(9),jit/tests/test_notes(6), with the helpertests/bundle_factory.pythat builds signed bundles and instruction sheets for the first three.What differs from
multibranch-devorigin/multibranch-devate81281d60(checked file by file: 26 modules and 14 test files, helpers and package markers included), exceptpyproject.tomlandorchestrator/trace_analysis/__init__.py. The third commit is onmultibranch-devtoo, so that this stays true.pyproject.toml: thehostedextra, which feat(sandbox): add the sandbox socket and the E2B provider #2154 defines withe2b, gainscryptography>=42and a comment that says what each entry is for. Onmultibranch-devthe extra also listsboto3; that arrives with the PR whose module imports it (the result archive). With feat(sandbox): add the sandbox socket and the E2B provider #2154'stestextra pulling inhosted, the test shards now installcryptographyas a declared dependency; until now they had it only throughclaude-agent-sdk. Therunnerextra already listed it.measure/profile_client.py(68 lines) is not here. It imports three names (benchmark_serving_path_in,ensure_benchmark_lib_patched,ensure_benchmark_serving_patched) fromhyperloom.orchestrator.actions.executors, whose__init__exports them onmultibranch-devand not onmain: that export is one of the small edits to existingmainfiles (the PR-0 kind) and comes with them.test_profile_client.pyand its helpertests/_inferencex.pywait with it.measure/tests/conftest.pyandgpu_free_host.py(the fixture that makes a runner test independent of the GPUs of the host) are not here: no test in this change runs a runner or reads a GPU. They arrive with the first test that does.orchestrator/trace_analysis/__init__.py(an existingmainfile): gains one export,is_capture_fragmentfrom_capture_shapes(already onmain), whichprofile_tracesimports. Onmultibranch-devthe same__init__also exportscount_gpu_kernel_events,discover_trace_inputsandTRACELENS_REFfor the toolbox; nothing here needs them, so they are not added.What is not in this PR, and why
test_log_causes(293) andtest_returncodes_and_failures(215):measure/failures.py.test_boot_watch(220) andtest_ports(95):measure/local.pyandmeasure/socket.py.test_aiter_merge_hook(252) and the two files underframework/tests/:framework/merge.py,base.py,rows.py.jit/tests/test_key.py,test_locations.py,test_session.py,test_store.py:jit/key.py,locations.py,session.py,store.py.test_spec_sections(53):hosted_spec.py.log_causes,boot_watch,ports,returncodes,aiter_merge_hook,framework/tables,docs,fsafe,jit_kindsand the two plan modules (1408 of the 4193 lines). The plan modules are exercised throughtest_spec(the sheet reads them); their own packages' tests need the passes, which are a later layer. The first six wait for the tests above.docs,fsafeandjit_kindshave no dedicated test file onmultibranch-deveither; heredocsis exercised through the tests ofspec,manifestandbundle,fsafethrough those ofbundleandjit_kindsthrough those ofmanifest.framework/tablesis tested onmultibranch-devby theframeworktests above (base and rows).profile_client.pyandcommon/accuracy.py(64 lines): the second keeps thecommondirectory at the size feat(common): add the rule pack and the outside_facts package that owns each outside-project fact #2155 left it (the open question on that PR) and has no reader belowmeasure/accuracy.py.bundlewith the hosted path, PR-6b; it moves here, see "Size"): the middle layer (failures,farm,attachments,compile,archive,frameworkbase, rows, merge and copies,jitkey, locations, store and session,pins,round_marks,accuracy), the upper layer (socket,local,hosted_spec, ...), the runner core (run,jit,inventory,rewrite,rounds,snapshot,platform_env,__main__) and the hosted path. They import these modules, and land after them in the order of the revised plan on Agent stuck at Download model from HuggingFace #121..importlinterlines:multibranch-devhas none formeasure, so none are added.Size
4193 production Python lines in
measure(plus 4 lines inorchestrator/trace_analysis/__init__.py) against the 1000-line diff budget (size-exceptionlabel, reason here), 2401 lines of tests. The reason is the layering, not a choice of grouping: these are the modules of the measurement core that import nothing above it, so they can be read and merged before the rest; the rest cannot be reviewed without them.bundleis here, and not with the hosted path, because the tests ofspecandmanifestbuild their documents withbundle_factory, which imports it, and it imports onlydocs,fsafe,manifestandsigning; without it the two largest modules of the layer (1114 lines) would have had no test in the change. The largest file isspec.py(689 lines, module limit 1200), the next isbundle.py(445). The set splits cleanly if the reviewers prefer:spec,manifest,bundle,signing,surface,docs,fsafe,jit_kindsand the two plan modules with the tests of the first three (the instruction sheet, the result manifest and the bundle check: 2613 production lines) against the rest (the phases, the log readers, the local-test helpers and the jit and framework leaves: 1580 lines);specneedssurface,docsand the plans,manifestneedsdocsandjit_kinds,bundleneedsdocs,fsafe,manifestandsigning, and nothing in the second half depends on the first.CI state
Not re-checked at the refreshed head (
533f6beb9): CI was still to run when this body was written. The earlier head (7cf88a191) was green exceptmain's then-red collection error (fixed onmainby #2149, which the refreshed base now contains) and the coverage jobs that followed it.CodeQL flagged one alert on the first run (
py/overly-permissive-fileinmagpie_launchers.py: the copy of a launcher was given mode0o755, which is world readable); the third commit narrows it to0o700, the owner who runs Magpie, as for the other files this layer creates, and CodeQL passes. The test that asserts the mode asserts the new one. The same change is onmultibranch-dev, so this PR stays byte-identical to it.Review template
multibranch-devwith the code (306 tests, see above). Run locally at533f6beb9on Python 3.10 and 3.11 (-n 4), on the tree of base plus this PR only:pytest src/hyperloom/measure src/hyperloom/contracts src/hyperloom/plugs src/hyperloom/sandbox src/hyperloom/orchestrator/trace_analysis scripts/tests src/hyperloom/common/tests/test_dedup_guard.py src/hyperloom/common/tests/test_llm_client_architecture.py src/hyperloom/inference_optimizer/tests/test_common_import_lint.py src/hyperloom/inference_optimizer/tests/test_packaging_lint.py: 2264 passed, 13 skipped on each (the measure tests of this PR alone: 306 passed on each; the skipped ones need a GPU, an envd binary, a checkout of the real aiperf client, node, vulture or complexipy). Also run:ruff check .andruff format --check .(2406 files),lint-imports --no-cache(11 kept, 0 broken). Not re-run at this head: the wheel-contents check, Gitleaks, bandit andscripts/code_metrics.py(no jscpd on this machine); the results below are from7cf88a191, and CI runs the gates.aiter_merge_hook.py. B108 is the literal/tmp/aiter_configsthat the hook names because aiter writes there and nothing else can redirect it; B102 is theexecthat runs thesitecustomize.pythis file shadows, which is the hook's job (it is read fromsys.pathas Python'ssitewould have read it). The code-metrics design check A10 (advisory, never fails) notesspec.py:101comparing the string'confirm'toPurpose.CONFIRM; it is as onmultibranch-dev.mainimportshyperloom.measure, no CLI, entry point or flag uses it, and the legacy flow behaves as before. What exists afterwards: 40 new files underhyperloom/measure(26 modules, 14 test files, helpers and package markers), one more export (is_capture_fragment) fromhyperloom.orchestrator.trace_analysis, andcryptographyin thehostedextra (so in thetestextra, where it was already installed through another dependency).🤖 Generated with Claude Code