graflo.architecture.evolution.preview¶
What a merge would do, and every way it could refuse — without refusing.
:func:~graflo.architecture.evolution.merge.merge_manifests raises at the
first refusal. That is right for a function that returns a manifest — a
half-merged model is worse than none — but it makes authoring a merge a
game of whack-a-mole: fix the contradiction the message names, run again, learn
about the next one. Three declarations that each refuse take three runs to
discover.
This module is the other view. :func:preview_merge walks the same
declarations and reports every problem it finds, as data:
- the declaration graph — classes and their attributes on each side, the
clusters that collapse them, the canonical names the maps establish, and the
edges between them. This is the
class_A - attr_a - attr_b - class_Bpicture the authoring model is actually about; - findings, each naming the nodes it is about, at one of three severities —
possible(found structurally, by this module),refusal(what merge actually raised, if it was asked to try) andnote(an acknowledged heuristic, such as an entry taken as already applied); - an outcome, from a real merge attempt.
Nothing here is a second implementation of the resolution rules. Every check
calls the function in :mod:~graflo.architecture.evolution.canonical that
merge itself calls, in units small enough — one declaration, one map entry,
one member — that a refusal on one unit does not hide the others. A refusal
carries its check and its subjects, so the finding it becomes is
pinned to the same nodes the message names, and there is no parallel copy of
the rules to fall out of date.
The consistency invariant, asserted in the tests: whatever merge refuses,
the structural pass has a finding of a matching kind for, and a merge that
succeeds leaves no refusal finding behind.
Merging two branches of one lineage needs none of this.
:func:~graflo.architecture.evolution.merge3.merge_three_way already returns
its conflicts rather than raising them, one record per contested slot, so
:func:build_merge3_preview only has to put them in the shape they already
have: slots form a tree — vertex/person contains vertex/person/field/age
— and the tree is what shows where in the model two branches collided.
Attributes¶
AttributeLayer = Literal['equivalence', 'vocabulary', 'rename', 'demotion', 'fusion']
module-attribute
¶
EdgeKind = Literal['member', 'map', 'property_map', 'property_equivalence', 'suggested', 'fusion', 'demotion', 'property_rename', 'derivation', 'local_key']
module-attribute
¶
FindingKind = Literal['cluster-overlap', 'shared-into', 'occupied-into', 'unknown-member', 'disagreement', 'ambiguous-reference', 'unnamed-cluster', 'incomplete', 'dangling-entry', 'satisfied', 'name-collision', 'near-collision', 'prefixed', 'property-disagreement', 'property-rename-collision', 'property-retarget', 'unknown-property', 'identity-disagreement', 'identity-coverage', 'identity-collision', 'origin', 'key-space', 'field-type-conflict', 'field-units-conflict', 'identity-mode-conflict', 'identity-funnel-conflict', 'secondary-identity-conflict', 'edge-type-disagreement', 'lookup_demotion', 'attached', 'shared_key_space', 'attach_order', 'double-home', 'vocabulary_override', 'auto_local_key', 'reference_only', 'self-relation', 'observation-fusion']
module-attribute
¶
NodeKind = Literal['class', 'relation', 'attribute', 'merged', 'canonical', 'ghost', 'resource', 'field']
module-attribute
¶
RoutingRole = Literal['owner', 'attached', 'reference']
module-attribute
¶
Severity = Literal['refusal', 'possible', 'note']
module-attribute
¶
__all__ = ['AttributeLayer', 'BranchSource', 'EdgeKind', 'FindingKind', 'Merge3Preview', 'MergeFinding', 'MergeOutcome', 'MergePreview', 'NodeKind', 'PreviewBranch', 'PreviewCluster', 'PreviewDemotion', 'PreviewEdge', 'PreviewIdentity', 'PreviewNode', 'RoutingRole', 'RoutingRow', 'Severity', 'SlotNode', 'build_merge3_preview', 'expected_kinds', 'kind_for_check', 'merge_notes', 'outcome_from_exception', 'outcome_from_manifest', 'preview_merge', 'routing_rows', 'routing_table', 'with_merge_result']
module-attribute
¶
logger = logging.getLogger(__name__)
module-attribute
¶
Classes¶
BranchSource
¶
Bases: ConfigBaseModel
One thing that feeds a branch: a resource's derivation or local key, or a member that carries a property branch.
Source code in graflo/architecture/evolution/preview_identity.py
Attributes¶
auto = PydanticField(default=False, description='Merge added this local key: nothing declared one.')
class-attribute
instance-attribute
¶
derive_at = PydanticField(default=None, description='The declared descend step path for the resource.')
class-attribute
instance-attribute
¶
exists = PydanticField(default=True, description='False when no side has a resource of this name.')
class-attribute
instance-attribute
¶
field = PydanticField(default=None, description='Raw field a local key reads.')
class-attribute
instance-attribute
¶
foo = PydanticField(default=None, description='Transform function.')
class-attribute
instance-attribute
¶
input = PydanticField(default_factory=list, description='Raw fields a derivation reads.')
class-attribute
instance-attribute
¶
label = PydanticField(default='', description='One-line caption: transform and guard, or tag.')
class-attribute
instance-attribute
¶
member = PydanticField(default=None, description='The member a member-keyed entry is for, or the member carrying a property branch.')
class-attribute
instance-attribute
¶
module = PydanticField(default=None, description='Transform module.')
class-attribute
instance-attribute
¶
params = PydanticField(default_factory=dict, description='Transform keyword arguments.')
class-attribute
instance-attribute
¶
produces = PydanticField(default_factory=list, description='Members of the group the resource produces on its side.')
class-attribute
instance-attribute
¶
resource = PydanticField(default=None, description='Union resource name; None for a property branch.')
class-attribute
instance-attribute
¶
side = PydanticField(default=None, description='The side the resource or member comes from.')
class-attribute
instance-attribute
¶
tag = PydanticField(default=None, description="The tag a local key value carries; '' is untagged.")
class-attribute
instance-attribute
¶
tag_omitted = PydanticField(default=False, description='The tag was left out and defaults to the origin.')
class-attribute
instance-attribute
¶
when = PydanticField(default=None, description='The declared guard, as written.')
class-attribute
instance-attribute
¶
Merge3Preview
¶
Bases: ConfigBaseModel
A three-way merge as a slot tree: what moved, and where the branches met.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
clean = PydanticField(default=True, description='Whether the merge left no decision to make.')
class-attribute
instance-attribute
¶
conflicts = PydanticField(default=0, description='Contested slot count.')
class-attribute
instance-attribute
¶
contested
property
¶
The contested slots, in tree order.
merged_hash = PydanticField(default=None, description='Content hash of the merged manifest, if there is one.')
class-attribute
instance-attribute
¶
nodes = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
warnings = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
Methods:¶
children_of(node_id)
¶
Slots directly under node_id; pass None for the roots.
MergeFinding
¶
Bases: ConfigBaseModel
One thing wrong with the declarations, or one acknowledged heuristic.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
check = PydanticField(default=None, description="The refusal's own name for the rule.")
class-attribute
instance-attribute
¶
completion = PydanticField(default=None, description='The declaration that would settle it, when there is one.')
class-attribute
instance-attribute
¶
edges = PydanticField(default_factory=list, description='Edge ids this finding is about.')
class-attribute
instance-attribute
¶
error_type = PydanticField(default=None, description='Exception type, for a finding merge raised.')
class-attribute
instance-attribute
¶
kind = PydanticField(..., description='Which rule it is an instance of.')
class-attribute
instance-attribute
¶
message = PydanticField(..., description='What to tell the author.')
class-attribute
instance-attribute
¶
nodes = PydanticField(default_factory=list, description='Node ids this finding is about.')
class-attribute
instance-attribute
¶
severity = PydanticField(..., description='How much it matters.')
class-attribute
instance-attribute
¶
source = PydanticField(..., description='Whether merge raised it, or this module found it.')
class-attribute
instance-attribute
¶
MergeOutcome
¶
Bases: ConfigBaseModel
What a real merge attempt produced, or refused with.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
check = PydanticField(default=None, description='The rule that refused.')
class-attribute
instance-attribute
¶
completion = PydanticField(default=None, description='The extension that would settle an incomplete refusal.')
class-attribute
instance-attribute
¶
edges = PydanticField(default=None, description='Edge count of the merged schema.')
class-attribute
instance-attribute
¶
error_type = PydanticField(default=None, description='Exception type.')
class-attribute
instance-attribute
¶
kinds = PydanticField(default_factory=list, description='For a naming refusal, the kind of every problem it lists, in order.')
class-attribute
instance-attribute
¶
message = PydanticField(default=None, description='The refusal, in full.')
class-attribute
instance-attribute
¶
status = PydanticField(..., description='Whether merge ran, and how it ended.')
class-attribute
instance-attribute
¶
version = PydanticField(default=None, description='Version of the merged schema.')
class-attribute
instance-attribute
¶
vertices = PydanticField(default=None, description='Vertex count of the merged schema.')
class-attribute
instance-attribute
¶
MergePreview
¶
Bases: ConfigBaseModel
The declaration graph, everything wrong with it, and what merge did.
Source code in graflo/architecture/evolution/preview.py
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 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 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | |
Attributes¶
blocking
property
¶
Findings that would stop a merge: the refusal and every possible one.
clusters = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
edges = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
findings = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
left_name = PydanticField(default='left', description='Name of the left manifest.')
class-attribute
instance-attribute
¶
name_conflict = PydanticField(default='error', description="The op's policy for names no equivalence covers.")
class-attribute
instance-attribute
¶
nodes = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
outcome = PydanticField(default_factory=lambda: MergeOutcome(status='not_attempted'))
class-attribute
instance-attribute
¶
refused
property
¶
Whether the merge attempt refused.
right_name = PydanticField(default='right', description='Name of the right manifest.')
class-attribute
instance-attribute
¶
routing = PydanticField(default_factory=list, description='Every resource producing a merged class, once merge went through.')
class-attribute
instance-attribute
¶
Methods:¶
attributes_of(node_id)
¶
Attribute nodes owned by the class node node_id, in declared order.
edges_between(source, target)
¶
Every edge from node source to node target.
focus(target)
¶
The part of this preview one cluster, merged attribute or rest is about.
An integer names the cluster op.vertex_equivalences[target] folded into.
See :func:~graflo.architecture.evolution.preview_focus.focus.
Source code in graflo/architecture/evolution/preview.py
focus_targets(attributes='nontrivial')
¶
Every target :meth:focus takes, in reading order.
See :func:~graflo.architecture.evolution.preview_focus.focus_targets.
Source code in graflo/architecture/evolution/preview.py
node(node_id)
¶
with_outcome(outcome, *, subjects=())
¶
A copy carrying outcome, and the finding a refusal becomes.
The structural pass usually found the refusal too — it calls the same
check — so the two are folded into one finding marked refusal
rather than listed twice. Reporting one problem as two would undercut
the only number this is for: how many things are actually wrong.
Source code in graflo/architecture/evolution/preview.py
PreviewBranch
¶
Bases: ConfigBaseModel
One funnel branch, or one derive attribute.
Source code in graflo/architecture/evolution/preview_identity.py
Attributes¶
fields = PydanticField(default_factory=list, description='Merged attributes the branch reads.')
class-attribute
instance-attribute
¶
id = PydanticField(..., description='Branch id, as the funnel names it.')
class-attribute
instance-attribute
¶
kind = PydanticField(..., description='What the branch keys on.')
class-attribute
instance-attribute
¶
position = PydanticField(..., description='1-based order a record tries it in; 0 for a `derive` entry.')
class-attribute
instance-attribute
¶
sep = PydanticField(default=None, description="What joins a local key's tag and value; None for other kinds.")
class-attribute
instance-attribute
¶
sources = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
PreviewCluster
¶
Bases: ConfigBaseModel
One equivalence declaration, resolved as far as it could be.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
allow = PydanticField(default_factory=list, description="The declaration's `allow` entries.")
class-attribute
instance-attribute
¶
declarations = PydanticField(default_factory=list, description="Positions, in the op's vertex or relation equivalences, of the declarations folded into this group; empty when merge synthesized it.")
class-attribute
instance-attribute
¶
declared_identity = PydanticField(default=False, description='Whether the declaration states an `identity`.')
class-attribute
instance-attribute
¶
declared_into = PydanticField(default=None, description='`into` as the author wrote it, if any.')
class-attribute
instance-attribute
¶
declared_left = PydanticField(default_factory=list, description='Left members the declarations name; the rest a vocabulary joined.')
class-attribute
instance-attribute
¶
declared_right = PydanticField(default_factory=list, description='Right members the declarations name; the rest a vocabulary joined.')
class-attribute
instance-attribute
¶
derived_identity = PydanticField(default=False, description='Whether its `identity` has a derived or `local_key` branch.')
class-attribute
instance-attribute
¶
id = PydanticField(..., description='Stable id of the cluster.')
class-attribute
instance-attribute
¶
identity = PydanticField(default=None, description='How the merged class is keyed; None for a relation group.')
class-attribute
instance-attribute
¶
into = PydanticField(default=None, description='Merged name; None when it could not be resolved.')
class-attribute
instance-attribute
¶
kind = PydanticField(..., description='Whether it collapses classes or relations.')
class-attribute
instance-attribute
¶
left = PydanticField(default_factory=list, description='Left members.')
class-attribute
instance-attribute
¶
right = PydanticField(default_factory=list, description='Right members.')
class-attribute
instance-attribute
¶
synthesized = PydanticField(default=False, description='Declared by merge itself under `union_right`.')
class-attribute
instance-attribute
¶
PreviewDemotion
¶
Bases: ConfigBaseModel
A member key the new identity demotes to a lookup-only secondary.
Source code in graflo/architecture/evolution/preview_identity.py
Attributes¶
fields = PydanticField(default_factory=list, description='The key fields, as the member spells them after its vocabulary renames.')
class-attribute
instance-attribute
¶
key_space = PydanticField(..., description='What names the demoted key.')
class-attribute
instance-attribute
¶
member
instance-attribute
¶
merged_fields = PydanticField(default_factory=list, description='Their names on the merged class.')
class-attribute
instance-attribute
¶
side
instance-attribute
¶
tags = PydanticField(default_factory=list, description="Every key space the op's tags name for it.")
class-attribute
instance-attribute
¶
PreviewEdge
¶
Bases: ConfigBaseModel
One thing a declaration says about a pair of names.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
declared_by = PydanticField(default='', description="Where it was declared: a map scope, or a cluster's merged name.")
class-attribute
instance-attribute
¶
effective = PydanticField(default=True, description='False when a later declaration sent the attribute elsewhere.')
class-attribute
instance-attribute
¶
id = PydanticField(..., description='Stable id: `kind:source->target`.')
class-attribute
instance-attribute
¶
kind = PydanticField(..., description='Which declaration said it.')
class-attribute
instance-attribute
¶
label = PydanticField(default='', description='Short caption, when useful.')
class-attribute
instance-attribute
¶
layer = PydanticField(default=None, description='For an attribute edge, which declaration it comes from.')
class-attribute
instance-attribute
¶
source = PydanticField(..., description='Node id this edge leaves.')
class-attribute
instance-attribute
¶
target = PydanticField(..., description='Node id this edge enters.')
class-attribute
instance-attribute
¶
PreviewIdentity
¶
Bases: ConfigBaseModel
How a merged class is keyed, and where every key value comes from.
Source code in graflo/architecture/evolution/preview_identity.py
Attributes¶
branches = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
demoted = PydanticField(default_factory=list)
class-attribute
instance-attribute
¶
derive = PydanticField(default_factory=list, description='`derive` entries: attributes a branch keys on, computed per resource.')
class-attribute
instance-attribute
¶
derive_at = PydanticField(default_factory=dict)
class-attribute
instance-attribute
¶
digest_field = PydanticField(default=None, description='Where a funnel stores its digest.')
class-attribute
instance-attribute
¶
mode
instance-attribute
¶
retire = PydanticField(default=None, description="What happens to each member's own key.")
class-attribute
instance-attribute
¶
Methods:¶
role_of(attribute)
¶
Positions of the branches that key on merged attribute.
PreviewNode
¶
Bases: ConfigBaseModel
One class, relation or attribute in the declaration graph.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
exists = PydanticField(default=True, description='False when a declaration names it but the manifest does not.')
class-attribute
instance-attribute
¶
field_type = PydanticField(default=None, description='Declared type of an attribute, when it has one.')
class-attribute
instance-attribute
¶
id = PydanticField(..., description='Stable id, as `subject()` builds it: `left:Firm.firm_id`.')
class-attribute
instance-attribute
¶
identity = PydanticField(default=False, description="Whether this attribute takes part in its class's identity.")
class-attribute
instance-attribute
¶
identity_mode = PydanticField(default=None, description='natural / hash / blank / assigned, for a class.')
class-attribute
instance-attribute
¶
kind = PydanticField(..., description='What this node stands for.')
class-attribute
instance-attribute
¶
name = PydanticField(..., description='The name as its side spells it.')
class-attribute
instance-attribute
¶
owner = PydanticField(default=None, description='For an attribute, the node id of its class.')
class-attribute
instance-attribute
¶
side = PydanticField(default=None, description='Which manifest it comes from; merged names have none.')
class-attribute
instance-attribute
¶
RoutingRow
¶
Bases: ConfigBaseModel
One resource producing a merged class, and the key its records reach it by.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
key = PydanticField(..., description="The class's primary identity fields for an owner; the secondary identity (key space) it finds the class by otherwise.")
class-attribute
instance-attribute
¶
members = PydanticField(..., description='The members of that side it produces, in source names.')
class-attribute
instance-attribute
¶
resource = PydanticField(..., description='The union resource.')
class-attribute
instance-attribute
¶
role = PydanticField(..., description='How it reaches the class.')
class-attribute
instance-attribute
¶
side = PydanticField(..., description='The side the resource came from.')
class-attribute
instance-attribute
¶
vertex = PydanticField(..., description='The merged class.')
class-attribute
instance-attribute
¶
SlotNode
¶
Bases: ConfigBaseModel
One addressable location in the manifest, and what each branch did to it.
Source code in graflo/architecture/evolution/preview.py
Attributes¶
base_excerpt = PydanticField(default=None, description="The ancestor's state here, for whoever decides.")
class-attribute
instance-attribute
¶
clean_ops = PydanticField(default_factory=list, description='Ops the merge applied here without a decision.')
class-attribute
instance-attribute
¶
contested = PydanticField(default=False, description='Whether both branches changed this slot.')
class-attribute
instance-attribute
¶
depth = PydanticField(..., description='How many segments deep it sits.')
class-attribute
instance-attribute
¶
id = PydanticField(..., description='The slot as a path: `vertex/person/field/age`.')
class-attribute
instance-attribute
¶
left_ops = PydanticField(default_factory=list, description='What the left branch did here, by op name.')
class-attribute
instance-attribute
¶
parent = PydanticField(default=None, description='The containing slot, or None at the root.')
class-attribute
instance-attribute
¶
reason = PydanticField(default=None, description='Why it could not be reconciled automatically.')
class-attribute
instance-attribute
¶
right_ops = PydanticField(default_factory=list, description='What the right branch did here.')
class-attribute
instance-attribute
¶
segment = PydanticField(..., description="This slot's own last segment.")
class-attribute
instance-attribute
¶
Functions:¶
build_merge3_preview(result, *, base=None)
¶
Project a :class:~graflo.architecture.evolution.merge3.MergeResult onto its slot tree.
Slots are paths and contain one another, so the set of slots a merge touched is already a tree once its prefixes are filled in. Contested slots carry what each branch did and the ancestor's state; slots the merge settled on its own carry the ops it applied, which is the context that makes a conflict legible — a rename colliding with three field edits is one conflict about the vertex, with the field edits visible beneath it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
Any
|
What |
required |
base
|
GraphManifest | None
|
The common ancestor. Unused today; accepted so a caller can pass it without knowing whether the excerpt came from the result. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
Merge3Preview
|
|
Merge3Preview
|
is exactly the case worth drawing. |
Source code in graflo/architecture/evolution/preview.py
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 | |
expected_kinds(outcome)
¶
Structural finding kinds that should accompany outcome.
The invariant this module is tested against: whatever merge refused, the structural pass saw something of a matching kind. An empty set means the refusal is one the preview is not asked to anticipate -- a structural merge error from deep inside the union, say -- and asserts nothing.
Source code in graflo/architecture/evolution/preview.py
kind_for_check(check, error_type=None)
¶
The finding kind a refusal's check is an instance of.
Falls back to the exception type, and finally to disagreement -- the
most general of the four classes.
Source code in graflo/architecture/evolution/preview.py
merge_notes(report)
¶
What a merge that went through changed about what resources do, as notes.
A member key demoted beside a funnel of several branches no longer deduplicates the member's own records; a resource is attached to a merged class; members of one side share a key space; a resource runs before the one whose nodes it needs.
Source code in graflo/architecture/evolution/preview.py
outcome_from_exception(exc)
¶
The outcome a refusal is, and the node ids it names.
Source code in graflo/architecture/evolution/preview.py
outcome_from_manifest(manifest)
¶
The outcome a merged manifest is.
Source code in graflo/architecture/evolution/preview.py
preview_merge(left, right, op, *, canonical_maps=(), attempt=True)
¶
The declaration graph of a merge, and everything wrong with it.
Walks op's equivalences and canonical maps against left and right
without refusing: each declaration, each map entry and each member is put
through the same check
:func:~graflo.architecture.evolution.merge.merge_manifests uses, one
at a time, so a problem with one does not hide the rest. Every refusal
becomes a possible finding naming the nodes it is about.
With attempt, merge is then run for real and its result -- the merged
schema's shape, or the one refusal it raised, with the completion that
would settle it -- is recorded as the outcome and as a single refusal
finding. Set it to False to describe the declarations without merging.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
GraphManifest
|
The left manifest, in whatever vocabulary it is in. |
required |
right
|
GraphManifest
|
The right manifest. |
required |
op
|
MergeManifestsOp
|
The merge op: equivalences (with their identities) and canonical maps. |
required |
canonical_maps
|
Sequence[tuple[Side, CanonicalMap]]
|
Extra |
()
|
attempt
|
bool
|
Whether to run a real merge for the authoritative outcome. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
MergePreview
|
|
MergePreview
|
declarations -- that is the point -- so an empty |
|
MergePreview
|
|
|
MergePreview
|
like. |
Source code in graflo/architecture/evolution/preview.py
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 | |
routing_rows(manifest, report)
¶
Every resource producing a merged class, with its role and key there.
Rows are grouped by merged class and follow the union's resource order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
manifest
|
GraphManifest
|
The merged manifest report describes. |
required |
report
|
MergeReport
|
The report returned beside it by
:func: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
One |
list[RoutingRow]
|
|
list[RoutingRow]
|
reference. |
Source code in graflo/architecture/evolution/preview.py
2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 | |
routing_table(rows)
¶
The routing rows as text: one block per merged class, named on its first row.
Columns: merged resource side members role key. No rows, no table.
Source code in graflo/architecture/evolution/preview.py
with_merge_result(preview, merged, report)
¶
preview with the outcome, routing and notes of a merge that went through.
For a caller that ran the merge itself -- the CLI does, once -- on a
preview built with attempt=False; :func:preview_merge folds its own
attempt in the same way.