Skip to content

Project Orrery artifacts without the content store, and write the execution overlay as its own file - #1295

Merged
anth-volk merged 11 commits into
mainfrom
orrery-projection-without-store
Oct 20, 2026
Merged

anth-volk merged 11 commits into
mainfrom
orrery-projection-without-store

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1294

Stack

main ← #1295 ← #1297 ← #1296 ← #1298 (GitHub stack #1328, linked on 2026-10-20 with gh stack link).

#1322 taken out of the stack (2026-10-20): CI runs only for pull requests into main on purpose, to limit the number of simultaneous runs on the organization's shared runners. #1322, which removed that filter, is closed, and the old stack #1323 was removed. 4ced66de0 on #1295 restores the four files #1322 changed to their versions on main, and each branch above merges the one below it: #1297 94a5bff93, #1296 b0406fd76, #1298 7cb857716. None of those merges had conflicts, and test_ci_integration_job.py passes on every branch (9 passed). No commit was rewritten. From now on only the bottom pull request, which targets main, gets CI; each one above gets CI once it becomes the bottom.

Why main was merged in (2026-10-20): GitHub builds each stacked pull request's test merge on top of the test merge of the pull request below it, starting from main: refs/pull/1322/merge has main as its first parent, and each later one has the previous one's. Once main gained #1305, #1296's change to rowwise_staging.py conflicted with it, so GitHub could not build #1296's test merge. It reported #1296 as conflicting although its branch contained its base, and started no CI for #1296 or #1298. main (a90eec3cb) was merged into #1322's branch, and each branch into the one above, with merge commits; #1296 is now mergeable.

Merge order: #1295, #1297, #1296, #1298, each after the one below it, with merge commits (or gh stack merge). Every branch above #1295 has its parent merged in rather than rebased, so no commit was rewritten. Squash-merging a lower pull request would leave its original commits in the branches above, which would then need rebasing.

Summary

The Orrery artifact is built in two halves. The build machine keeps evidence capture and verification against the content store. Projection needs only the compiler schema and the execution overlay, which makes it the half a collector worker can take over later. This PR makes that possible without changing what builds publish:

  • The projection imports without the build runtime. microcosm.graph.orrery now imports and projects a schema plus overlay in a process where numpy, pandas, microcosm-frame and microcosm.graph.store cannot be imported. Two things pulled them in before:

    • orrery_evidence imported evidence for one protocol string and a hash helper;
    • the package init imported the executor, store, kernels, codecs and evidence eagerly.

    microcosm.graph now loads those runtime exports on first access (PEP 562). __all__ and every public name are unchanged, and the declared dependencies are untouched (that's O2).

  • The execution overlay has its own file format. microcosm.graph.execution_overlay.execution_overlay_bytes and load_execution_overlay write and read the overlay as canonical JSON, keeping its existing protocol, microcosm.graph.execution-evidence.v1.

  • UK finalize writes graph.execution.json beside graph.orrery.json and registers it as a build output: in the dataset manifest, a refused build's evidence manifest, and a failed build's orrery-failure/ bundle. It is not added to the Orrery publication set (orrery-publication/, orrery.upload.json); that waits for O5.

Overlay file format

  • Path: graph.execution.json in the build output directory, next to graph.schema.json and graph.orrery.json.
  • Protocol: microcosm.graph.execution-evidence.v1, the overlay's own protocol field. No wrapper protocol was added.
  • Encoding: canonical JSON (UTF-8, sorted keys, no whitespace), with no transport tags. integer_literal and float_literal are added by the projection only.
  • Reader: a regular file within the schema's 32 MiB serialized limit, which collection and projection already apply to the overlay. It refuses duplicate keys, non-finite numbers, values outside the schema's JSON bounds and other protocols. Graph-binding and record checks stay in the projection.

To project from the files:

orrery_json_from_schema(
    json.loads(schema_bytes),
    execution=load_execution_overlay(path),
)

Commits

Local checks were limited to the test files this branch adds or modifies, at the user's request; the rest of the suite is left to CI. Commit 1 ran the complete engine-free category before that change arrived. Commit 2's full-category run was stopped at about 40%. Every commit also passed tools/ci_test_plan.py verify, tools/graph_acceptance_burndown.py --verify, ruff check ., ruff format --check on the changed files, and a byte-identity harness. The harness runs a deterministic local-only finalize_graph, with and without a dataset manifest, over a fixed two-phase toy state, and compares every file's digest with origin/main.

  1. Import the Orrery projection without numpy, pandas or the content store (dd71e0e71)
    • Red: 2 failed, for the intended reason. The restricted interpreter's finder raised on numpy, imported from microcosm/graph/__init__.py through kernel.py. One guard test passed (all public exports still resolve).
    • Green: 3 passed.
    • Complete engine-free category: 18,567 passed, 149 skipped, 3 xfailed, 1 failed. The failure, test_us_release_head_to_head_scorer.py::test_spawned_workers_score_identically_to_sequential_cli, is environmental: the scorer refuses --worker-max-slices on the local Python 3.14.6, which its own version table lists as unsupported. It is unrelated to this change.
    • Harness: byte-identical.
  2. Read and write the execution overlay as its own file (632c266cb)
    • Red: 11 failed, for the intended reason (AttributeError: execution_overlay_bytes and load_execution_overlay didn't exist yet). The 2 commit-1 tests passed.
    • Green: 13 passed.
    • Harness: byte-identical.
  3. Write the UK execution overlay beside the Orrery artifact (8d159a8c5)
    • Red: 4 failed, for the intended reason. The overlay file was missing (FileNotFoundError), or absent from the manifest, the evidence manifest or the failure bundle (KeyError). One guard passed (no overlay without recorded execution).
    • Green: 33 passed: both branch-changed test files in full, including the 15 existing finalize tests.
    • Harness: every existing file is byte-identical: graph.orrery.json, graph.schema.json, the evidence files, orrery.upload.json, the receipt, and everything in orrery-publication/. The only differences are the new graph.execution.json and exactly one new output entry in each manifest (orrery/graph.execution.json in the dataset manifest, graph.execution.json in the evidence manifest).

The new UK round-trip test runs a synthetic full build. Projecting graph.schema.json with the overlay read back from graph.execution.json must give bytes identical to the graph.orrery.json that finalize wrote, and the loaded overlay must equal collect_execution_evidence re-run against the store.

Findings and risks

  • Overlay size.
    • Synthetic UK build (4 phases, 4 summaries): graph.execution.json is 121,145 bytes, beside a 348,283-byte graph.orrery.json (about 35%).
    • f10 fixture: not measured. No f10 build output exists on the machine this was made on, and no real build was run. The overlay is embedded whole in the Orrery artifact, which the plan measures at 24.4 MB for f10. The declaration-only graph is about 6.9 MB (Orrery export fails on full UK local builds: execution evidence exceeds the graph metadata bound #1290). So the f10 overlay should be at most about 17.5 MB, and it can never exceed 32 MiB, because collect_execution_evidence applies the schema's serialized bound.
    • Staging cost: registered outputs are staged, so a staged bundle carries the overlay bytes twice (once inside graph.orrery.json).
  • Orrery export fails on full UK local builds: execution evidence exceeds the graph metadata bound #1290 still applies. At full UK local scale, collect_execution_evidence fails on that 32 MiB bound, so those builds produce neither an Orrery artifact nor an overlay file, before and after this PR. The collector-side size policy (O4) will need to decide what the overlay carries at that scale.
  • Disclosure. The overlay carries every target's achieved value and weight extremes, but it is already embedded in graph.orrery.json, which is registered and staged the same way. The new file therefore adds no new disclosure, and it stays out of the public publication set.
  • Package init behaviour. import microcosm.graph no longer imports the runtime modules. Any code that reached a submodule as an attribute (microcosm.graph.store.X) without importing it would now fail; I found no such use in the workspace. from microcosm.graph import store and from microcosm.graph import ContentStore both still work, and a guard test checks every __all__ name. Errors from a broken runtime module now surface on first use instead of at package import.
  • Overlap with B4 (Reconstruct declaration-only Orrery publications for UK builds before #1144 #1291). B4 is adding declaration-only reconstruction as a new module. This PR doesn't touch orrery.py, and changes only two import lines in orrery_evidence.py. If Reconstruct declaration-only Orrery publications for UK builds before #1144 #1291 adds package exports, each one needs to go either in the eager imports (standard-library-only modules) or in _RUNTIME_MODULE_EXPORTS in microcosm/graph/__init__.py.
  • Not done here.
    • No CLI flag. python -m microcosm.graph.orrery has no --execution PATH option; O3 can add one if the worker wants a command rather than the API.
    • Reference links aren't rebased. The overlay's native-evidence links are relative to the build directory, so a projection written elsewhere would need rebasing (documented).
    • Overlay written only after a successful projection. If the projection itself fails (for example over the 64 MiB output cap), no overlay is written. O5 may want the reverse.

🤖 Generated with Claude Code

anth-volk and others added 3 commits October 16, 2026 01:27
A collector worker is to project Orrery artifacts from a saved compiler
schema and execution overlay, without the build machine's content store.
Importing microcosm.graph.orrery pulled in the whole build runtime for two
reasons: orrery_evidence took one protocol string and a hash helper from
evidence, which imports the store, kernels and manifests; and the package
init eagerly imported the executor, store, kernels, codecs and evidence, so
any microcosm.graph module brought numpy, pandas and microcosm-frame with it.

The package init now keeps declarations, the schema, serialization and
weight-update receipts eager and loads the runtime exports on first access
(PEP 562); __all__ and every public name are unchanged. The overlay protocol
moves to a new standard-library-only execution_overlay module and sha256 to
canonical; evidence imports both, so its names stay importable. The tests
run the projection and the command in an interpreter that refuses those
imports and require the in-process bytes. Declared dependencies are
unchanged.

Refs #1294

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The execution overlay is the projection's only input besides the schema,
but it existed only in memory and, once projected, embedded at
metadata.execution of the Orrery artifact. A collector worker that
projects later needs it as a file it can read without the store.

execution_overlay_bytes serializes an overlay as canonical JSON, and
load_execution_overlay reads it back as an equal object, so projecting
the file gives byte-identical Orrery JSON. The file keeps the overlay's
existing protocol, microcosm.graph.execution-evidence.v1, rather than
adding a wrapper protocol. The reader is standard-library only. It refuses
non-regular files and files over the schema's 32 MiB serialized limit
(which collection and projection already apply to the overlay) before
parsing. It also refuses duplicate keys, non-finite numbers, other
protocols and values outside the schema's JSON bounds. Graph binding and
record checks stay in the projection. The restricted-import test now reads
the overlay through this reader.

Refs #1294

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UK finalize collected the execution overlay and projected it straight
into graph.orrery.json, so the overlay itself never reached disk. The
collector is to project builds from the schema and the overlay, so
finalize now also writes the overlay as graph.execution.json, using
execution_overlay_bytes, and registers it as a build output like the
other graph files: in the dataset manifest's outputs, in the evidence
manifest of a refused build, and in the failure bundle.

It is deliberately left out of the Orrery publication set (the preserved
orrery-publication/ directory and orrery.upload.json). The emitter's file
roles and the runs service's contract do not admit it yet. Apart from the
new manifest entry, every existing file stays byte-identical. The
overlay's content is already embedded in graph.orrery.json, which is
registered and staged the same way, so the new file discloses nothing
new.

Refs #1294

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pull_request trigger was filtered to branches: [main]. A stacked pull
request targets another pull request's branch, so GitHub started no Tests
run for it at all. The filter is removed. Pushes still run the workflow
only for main.

Nothing else in the workflow depends on the base branch. The concurrency
group is keyed on the pull request number, and country selection reads the
pull request's own changed files from the API. Pull requests from this
repository's branches get the same token permissions and secrets whatever
their base.

New tests read the workflow's triggers. Pull requests into main, into
another pull request's branch and into a nested branch name must all run
it, and pushes must run it only for main. The agent guide and a changelog
fragment say so.

Fixes #1321

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tore

Stack this branch on ci-pull-requests-into-any-base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk changed the base branch from main to ci-pull-requests-into-any-base October 19, 2026 21:09
@anth-volk
anth-volk added this pull request to stack #1323 October 19, 2026 21:09
anth-volk and others added 5 commits October 20, 2026 16:48
The previous test checked three literal branch names against the trigger's
branches and branches-ignore lists. GitHub matches those entries as glob
patterns, so a membership check proves nothing about other bases: a filter
listing exactly those three names passed it, although pull requests into any
other base would get no run, and a filter of '**', which runs for every base,
failed it.

The intended design is no base-branch filter at all, so the test now asserts
that the pull_request trigger has neither a branches nor a branches-ignore
key. _workflow_triggers is typed as dict[str, Any].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every push to a pull request's branch now runs the full Tests workflow on
the organization's shared runners, whatever the base, so merging one change
up a stack of N pull requests starts N full runs. The agent guide says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tore

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub builds each stacked pull request's test merge on top of main, so
once main moved on (#1289, #1305), the stack's test merges had to include
it. main's new commits do not touch this pull request's files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tore

Brings in main (#1289, #1305) through the base branch. No conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk removed this pull request from stack #1323 October 20, 2026 18:01
@anth-volk
anth-volk changed the base branch from ci-pull-requests-into-any-base to main October 20, 2026 18:01
This branch carried #1322 through three merges of its branch
(`ci-pull-requests-into-any-base`). #1322 removed the `branches: [main]`
filter from the Tests workflow so stacked pull requests would get CI.
That is not wanted: CI runs only for pull requests into `main` on purpose,
to limit the number of simultaneous runs on the organization's shared
runners. #1322 is being closed.

This restores the four files #1322 changed to their versions on `main`
(`a90eec3cb`), which is also this branch's merge base with `main`:

- `.github/workflows/test.yml`: the `pull_request` trigger filters on
  `main` again;
- `docs/agent-guide.md`: the CI paragraph no longer says any base runs;
- `packages/microcosm-build/tests/engine_free/shared/test_ci_integration_job.py`:
  #1322's two trigger tests are removed;
- `changelog.d/1321-ci-pull-requests-into-any-base.changed.md`: deleted.

The branch's own commits are not rewritten, so `8d159a8`, which
microcosm-collector#9 records as its source, stays in the history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk added this pull request to stack #1328 October 20, 2026 18:03
@anth-volk
anth-volk merged commit ea45714 into main Oct 20, 2026
10 checks passed
@anth-volk
anth-volk deleted the orrery-projection-without-store branch October 20, 2026 22:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project Orrery artifacts without the content store, and write the execution overlay as its own file

1 participant