Pure planning for :class:~graflo.architecture.evolution.ops.ProjectManifestOp.
Selector validation and manifest unwrapping live here; the induced-connectivity
kernel itself lives at layer 2 in
:mod:graflo.architecture.schema.projection so manifest projection and schema
context projection cannot drift apart. The depth walk borrows the same way,
from :mod:graflo.architecture.schema.context.graph — the hop machinery is shared
with rank-then-budget schema context rather than reimplemented here.
Attributes
Classes
Functions:
compute_projection(manifest, op)
Compute survivor/removal sets without mutating manifest.
Source code in graflo/architecture/evolution/project.py
| def compute_projection(
manifest: GraphManifest, op: ProjectManifestOp
) -> SubschemaSelection:
"""Compute survivor/removal sets without mutating *manifest*."""
schema = manifest.graph_schema
if schema is None:
raise ValueError("project_manifest requires graph_schema")
if op.strict:
_validate_strict(manifest, op)
keep_edge_ids = (
_selector_edge_ids(op.keep_edges) if op.keep_edges is not None else None
)
if keep_edge_ids is not None and op.keep_inverse_edges:
# A materialized pair is two declared edges; keeping one reading of the
# fact and dropping the other would leave a schema that states half of it.
edge_config = schema.core_schema.edge_config
keep_edge_ids = keep_edge_ids | {
mirror
for edge_id in keep_edge_ids
if (mirror := materialized_inverse_id(edge_config, edge_id)) is not None
and mirror in edge_config
}
keep_vertices = op.keep_vertices
if op.depth > 0:
keep_vertices = _expand_seeds(schema, op, keep_edge_ids)
return select_induced(
schema.core_schema,
keep_vertices=keep_vertices,
keep_edge_ids=keep_edge_ids,
connectivity=op.connectivity,
)
|