Skip to content

Make chunked plans own dependency graphs (Task G4) - #72

Open
asinghvi17 wants to merge 5 commits into
claude/g3-graph-identityfrom
claude/g4-plan-owns-graph
Open

Make chunked plans own dependency graphs (Task G4)#72
asinghvi17 wants to merge 5 commits into
claude/g3-graph-identityfrom
claude/g4-plan-owns-graph

Conversation

@asinghvi17

Copy link
Copy Markdown
Member

Task G4 of regrid-notes/2026-08-21-regridding-simplification-plan.md, Phase 2 — the last card of the phase. Stacked on #71 (which is stacked on #70); base is claude/g3-graph-identity, not main and not claude/perf-ladder.

Record: regrid-notes/2026-08-23-g4-plan-owns-graph.md.

What landed

ChunkedPlan gains one field and the module one accessor:

struct ChunkedPlan{...,G<:Union{Nothing,ChunkDependencyGraph}}
    ...
    dependencies::G
end
dependencies(plan::ChunkedPlan) = plan.dependencies   # builds nothing

The relation is chosen once, at construction:

dependencies plan holds construction cost
nothing (default) none nothing at all — a dedicated method returns without even calling support_radius
true one built here, at the plan's own radius one chunk_dependency_graph
a ChunkDependencyGraph that object, by reference two spacestamp calls, after validate_dependencies
false none, explicitly nothing; rejects a stray refine/narrow

refine/narrow are keywords of lazy plan_regrid (and the ChunkedPlan constructor it forwards to) and of nothing else. chunk_dependency_graph(plan; refine, narrow) is deleted; the space form lost both keywords; the narrow phase moved to a private _builddependencies that only plan construction calls. regrid/regrid! take none. chunkgraph.jl now precedes plans.jl in the include order.

connectedchunkpairs is deleted — since #69 it ran line for line the loop _chunkgraph runs to fill its rows. Its one assertion in test_lazy.jl now reads the graph's own rows.

Phase 2 gate, as tests

one logical plan exposes exactly one validated relation, and a narrow phase cannot be supplied after the plan exists

Four new testsets, 62 assertions. The "not after the fact" half is a method error, not a runtime throw: Base.kwarg_decl over every method of chunk_dependency_graph, restrict, regrid and regrid! shows refine/narrow absent and over plan_regrid shows them present; methods(chunk_dependency_graph, Tuple{ChunkedPlan}) is empty; the field is on an immutable struct. "Exactly one" is proved with a probe space that counts every chunktree call: 0 after a default plan, and unchanged by five dependencies calls on a plan that owns one.

Production

scripts/copdem_production.jl:764 — the call site this card exists to remove — is gone. dagplan constructs the global ChunkedPlan with dependencies = true and the narrow phase, and reads GR.dependencies(globalplan); the driver gained check("the graph is the global plan's own relation", ...). [measured] on the real GLO-90 × IGeo7-L12 pair: 326 064 edges, equal DependencyIdentity, 0.118 s warm — identical to before.

Per-column plans own none, and the card's "share a row view" is not possible at this shaperegrid_chunk's destination is a rooted one-chunk subtree grid, a different space from the 66 175-chunk PartialGrid a row view stamps, so validate_dependencies refuses it (correctly). [measured], benchmark/plan_dependency_ownership.jl, 25 columns × 5 samples:

per-column arm median bytes × 66 175
A dependencies = nothing — today 1.00 µs 784 B 0.07 s / 0.05 GB
B dependencies = true 512 µs 541 664 B 33.8 s / 35.8 GB
C restrict(graph, [d]) 193 µs 424 304 B 12.7 s / 28.1 GB

C's cost is the O(nsourcechunks) transpose G3 warned about, on the exact shape it warned about.

Gates

benchmark/chunk_graph_gates.jl before and after: the relation is identical on every relation field across all 26 rows, including the production pair's 326 064 / 326 386 edges and the 72 / 394 crossing. Both runs print verdict: PASS on 9 oracle-checked case(s); 4 case(s) unchecked. Production case timing +0.6 %.

suite before (f9f268a) after
lib/GlobalRegridding/test 3 828 / 1 broken / 0 fail 3 891 / 1 / 0 (+62 new gate tests, +1 tag assertion)
test/systems/crosssystem/regrid.jl 202 / 0 202 / 0
test/scripts/copdem_policy.jl 87 / 0 87 / 0
test/scripts/copdem_source_mode.jl 7 / 0 7 / 0
regrid_acceptance.jl not baselined 22 / 0
CopernicusDEM/runtests.jl not baselined 16 258 / 3 broken / 0 fail

🤖 Generated with Claude Code

https://claude.ai/code/session_019DuGKTmvs5B4EynwZddKMg

asinghvi17 and others added 4 commits August 23, 2026 21:16
`ChunkedPlan` gains one `dependencies` field and the module one non-building
accessor, `dependencies(plan)`. The relation is chosen once, at construction:
`dependencies = nothing` (the default) holds none and does no relation work at
all; `true` builds one at the plan's own `support_radius`; a
`ChunkDependencyGraph` is adopted by reference after `validate_dependencies`
certifies it; `false` holds none and rejects a stray narrow phase.

`refine`/`narrow` are now keywords of lazy `plan_regrid` and of the
`ChunkedPlan` constructor it forwards to, and of nothing else.
`chunk_dependency_graph(plan; refine, narrow)` is deleted and the space form
lost both keywords; the narrow phase moved to a private `_builddependencies`
that only plan construction calls. An eager plan names each of the three
keywords it refuses. `chunkgraph.jl` now precedes `plans.jl` so the plan's
field type can name the graph's.

Production's `dagplan` no longer builds a graph beside a plan: it constructs
the global `ChunkedPlan` with the narrow phase and reads
`GR.dependencies(globalplan)`, and the driver asserts that the object the
schedule, refcount cache, prefetcher and validator share is that one. The
relation is unchanged, measured: 326,064 edges, equal `DependencyIdentity`,
0.118 s warm. `regrid_chunk`'s per-column plans deliberately own none — a row
view of the global graph is not their relation, because their destination is a
different space, and `validate_dependencies` refuses it; a one-destination
graph per column would cost 511x the time and 691x the allocation of the
default (`benchmark/plan_dependency_ownership.jl`).

`connectedchunkpairs` is deleted. Since #69 it ran line for line the loop
`_chunkgraph` runs to fill its rows; its one assertion now reads the graph's
own rows.

Gates: `benchmark/chunk_graph_gates.jl` before and after is identical on every
relation field across all 26 rows, both runs PASS on 9 oracle-checked cases.
GlobalRegridding 3828 -> 3891 pass (+62 for the four new Phase 2 gate
testsets, +1 for one added tag assertion), 1 broken, 0 fail; crosssystem
regrid 202/0, copdem_policy 87/0, copdem_source_mode 7/0 all unchanged.

Record: regrid-notes/2026-08-23-g4-plan-owns-graph.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DuGKTmvs5B4EynwZddKMg
Phase 2 is complete. G4's card gets its landed note, including the one action
it could not complete as written: production's per-column plans cannot take a
validated row view, because their destination is a rooted one-chunk subtree
grid rather than the global space the graph and its views are stamped against.
"Never rebuild a one-destination graph per column" is met by construction and
measured; "share the global graph or validated row views" would need
destination-subspace re-stamping, which no card owns and which nothing would
consume until E1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DuGKTmvs5B4EynwZddKMg
The `restrict` docstring now says the thing G4's measurement made concrete: a
row view is the relation of those rows OF THAT SPACE, so a plan whose
destination is its own smaller grid over the same cells has a different
`spacestamp` and is refused — which is why production's per-column plans own no
relation at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DuGKTmvs5B4EynwZddKMg
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.

1 participant