pub fn ci_topo_node_names(cd: &CanteiroDag) -> Vec<String>Expand description
Substrate-canonical per-Acao topological-order node-name projection
every consumer of an owned canteiro_types::CanteiroDag that needs
the parents-before-children flat list of author-declared node names
keys off — folds the three-line
let topo = cd.topo_order().expect(...); topo.iter().filter_map(|id| cd.nodes.get(id).map(|n| n.name.clone())).collect() chain onto one
substrate primitive returning Vec<String> verbatim, running the
topo_order() axis internally so consumers reach for one dispatch.
The topological-node-name projection carries the “in what order does
the DAG hand back the author-declared node names?” surface every
per-Acao downstream consumer fans on: the
caixa_actions::RenderedAcao::node_names_topo artifact the M0
renderer’s validate returns (paired with the declared edge count
from ci_declared_edge_count), the deferred
sui-supercacheci::canteiro::emit_gha workflow renderer’s per-job
jobs.<name> map key ordering (GitHub Actions preserves declaration
order for readability, so an author-facing workflow whose jobs are
emitted in parents-before-children topological order reads as a
build-then-test-then-publish narrative rather than a
hash-map-arbitrary-order jumble), a future feira lint --acao
per-caixa admission verb’s per-repo topological-summary print, a
future M4 acao.pleme.io/v1alpha1/Acao CR materializer’s admission
webhook per-node ordering pin.
Prior to this lift the
topo.iter().filter_map(|id| cd.nodes.get(id).map(|n| n.name.clone())) .collect() expression was inlined at three sites in the
caixa-actions crate — the production
[caixa_actions::validate]’s node_names_topo field construction
at caixa-actions/src/lib.rs:155, plus two byte-parity pins in the
same crate’s test module — and at two more sites in this crate’s own
require_acao_view byte-parity test at
caixa-core/src/render.rs:37769 / caixa-core/src/render.rs:37773
(which reconstruct the same list through the compound helper’s
returned CanteiroDag to pin that the two paths agree). Five
open-coded copies of the same three-line topo + filter_map + collect
chain expressed no compile-time link back to a substrate primitive,
so a future refactor of the projection shape (a promotion of the
plain Vec<String> to a Vec<(String, EnvClass)> once consumers
need the per-node env-class alongside the name, a per-:ci
stable-tie-breaking pass that sorts sibling nodes lexicographically
once the underlying shigoto_dag::Dag::toposort axis grows a
tie-break axis, a per-node canonicalization pass that trims
whitespace once the canteiro-types axis grows a per-node
canonicalization step) would have had to be threaded through five
open-coded copies in lockstep or the M0 renderer’s
node_names_topo artifact would silently disagree with its own
byte-parity pins. Lifting the projection to a typed function on the
substrate primitive means every downstream consumer of the Acao’s
topological-node-name surface reaches for exactly one typed dispatch.
Runs cd.topo_order() internally with an .expect(...) on the
Err(_) arm carrying the substrate-canonical message every consumer
would otherwise re-author verbatim — the Err(_) arm is
unreachable-by-construction after a successful decompose_ci
(documented on the peer decompose_ci docstring and the
canteiro-types CanteiroDag::topo_order docstring: “decompose
already rejects cycles, so an error here is an internal invariant
break”). Panicking here surfaces any future substrate-contract
regression at the call site rather than silently returning an empty
Vec<String> that a consumer’s downstream logic would misread as
“no nodes to render”.
Peer of the sibling ci_declared_edge_count usize-scalar
projection on the borrowed canteiro_types::CiRun axis — extends
the “one typed dispatch on the substrate primitive, thin projections
at each consumer” discipline onto the owned
canteiro_types::CanteiroDag axis (the sibling primitive projects
through the borrowed run’s node-list shape; this primitive projects
through the owned DAG’s topo-order + node-map shape). Together the
two per-Acao scalar-projection primitives cover the two axes the
M0 [caixa_actions::RenderedAcao] artifact carries (edge_count
through the borrowed run, node_names_topo through the owned DAG),
so every future per-Acao consumer that materializes a
RenderedAcao-shaped view reads through two substrate one-liners.
§Panics
Panics if cd.topo_order() returns [Err(_)] — an unreachable arm
after a successful decompose_ci (which rejects every cyclic
input via CiDecomposeFailure). A caller reaching this panic has
constructed a canteiro_types::CanteiroDag outside
decompose_ci and passed one whose internal
[shigoto_dag::Dag] is cyclic — a substrate-contract regression
worth surfacing at the call site, not silently masking with an
empty Vec<String>.