Skip to content

Commit 7ba4157

Browse files
committed
T6 (mcpp#722, W7 residual 6/6): split step9_kernel_abi_interfaces_and_requirements
(target_side.cpp); the gate's own false failure at zero findings step9 (~401 lines) splits into five named steps at its own section boundaries: the kernel-abi interface enumeration, the layering and requirement checks (over TargetSideGather's `requirements`), the pin-and-linkage diagnostics, the same-OS check and report, and the platform-sdk closure visibility check. No phase-local struct is needed: each step reads and writes only `state` (plus `gather` for the one step that needs its `requirements`). This was the last of the six residuals check_function_sizes.sh reported at the base of this round; with it split, the gate ran clean over the whole of src/build/prepare/ for the first time -- and immediately failed for an unrelated reason: `--warnings-as-errors='*'` makes clang-tidy exit non-zero on the two pre-existing readability-function-size findings in the bundled third-party modules/libs/src/json/json.hpp, which the script's own `relevant` filter already excludes from the pass/fail decision but which its exit-code fallback then reads as "a diagnostic tool problem" -- a false failure this repository's own tree could not previously reach, since no earlier revision had zero findings under src/build/prepare itself. Dropping the flag leaves clang-tidy's exit code meaningful only for an actual tool failure (a bad compile command, a crash), which a plain warning never produces; `relevant` remains the sole pass/fail signal, as the surrounding comments already say it is. Verified: check_function_sizes.sh reports "ok" over the whole of src/build/prepare/; byte-identical on the seven fixtures.
1 parent c784348 commit 7ba4157

2 files changed

Lines changed: 143 additions & 105 deletions

File tree

‎.github/tools/check_function_sizes.sh‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,17 @@ echo "checking ${#FILES[@]} file(s) with $CLANG_TIDY (LineThreshold=$LINE_THRESH
137137
OUT="$(mktemp)"
138138
trap 'rm -f "$OUT"' EXIT
139139

140+
# No --warnings-as-errors: the only check enabled is readability-function-size
141+
# itself, and a finding in json.hpp (bundled third-party, reached through one
142+
# of these files' imports) would then make clang-tidy exit non-zero on every
143+
# run regardless of this decomposition's own state -- exactly the ambiguity
144+
# the "diagnostic tool problem" branch below exists to catch, and it cannot
145+
# tell the two apart from an exit code alone. The `relevant` filter is the
146+
# sole pass/fail signal; clang-tidy's own exit code is read only as a sign
147+
# that the tool itself failed to run (a bad compile command, a crash), which
148+
# a plain warning never produces.
140149
"$CLANG_TIDY" \
141150
--checks='-*,readability-function-size' \
142-
--warnings-as-errors='*' \
143151
--config="{CheckOptions: {readability-function-size.LineThreshold: '$LINE_THRESHOLD'}}" \
144152
-p "$REPO_DIR" \
145153
"${FILES[@]}" > "$OUT" 2>&1

‎src/build/prepare/target_side.cpp‎

Lines changed: 134 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -793,8 +793,7 @@ step9_target_side_include_broadcast(PrepareState& state, TargetSideGather& gathe
793793
}
794794

795795
static std::expected<void, std::string>
796-
step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGather& gather) {
797-
namespace tsd = mcpp::targetside;
796+
step9_kernel_abi_interface_enumeration(PrepareState& state) {
798797
// INTERFACE ENUMERATION — THE RESOLUTION-TIME HALF OF THE CAPABILITY
799798
// MODEL (design 2026-09-20 §5.5; openkal SPEC 0.14 §3.3, §6.2).
800799
//
@@ -816,113 +815,116 @@ step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGath
816815
// writes `[kernel-abi]` reaches neither loop below, so this addition
817816
// changes no command line and no diagnostic for every project built
818817
// before it.
819-
{
820-
// THE LIST COMES FROM THE PACKAGE THAT RESOLVED AS THE LAYER, NOT
821-
// FROM THE FIRST ONE IN THE GRAPH THAT STATED ONE. A graph may
822-
// carry more than one candidate for a layer — a workspace member
823-
// beside a dependency, a second implementation reached through a
824-
// feature that did not activate — and only one of them is the
825-
// provider this build resolved. Reading whichever came first in
826-
// `packages` would compare a consumer's requirements against an
827-
// implementation the build is not using, which is a wrong answer
828-
// rather than a missing one.
829-
std::vector<std::string> providedInterfaces;
830-
std::string providerId;
831-
for (auto& pkg : state.packages) {
832-
if (pkg.manifest.kernelAbiProvidesInterfaces.empty()) continue;
833-
// `impl` is `name@version`; the name is what precedes the
834-
// separator. A substring test would match `openkal` against
835-
// `openkal-linux@0.15.0` and read one implementation's list
836-
// as another's.
837-
if (!state.resolvedTargetSide.kernelAbi.impl.empty()) {
838-
auto const& impl = state.resolvedTargetSide.kernelAbi.impl;
839-
const auto at = impl.find('@');
840-
const auto implName = at == std::string::npos
841-
? impl : impl.substr(0, at);
842-
if (implName != pkg.manifest.package.name) continue;
843-
}
844-
providedInterfaces = pkg.manifest.kernelAbiProvidesInterfaces;
845-
providerId = pkg.manifest.package.name;
846-
break;
818+
// THE LIST COMES FROM THE PACKAGE THAT RESOLVED AS THE LAYER, NOT
819+
// FROM THE FIRST ONE IN THE GRAPH THAT STATED ONE. A graph may
820+
// carry more than one candidate for a layer — a workspace member
821+
// beside a dependency, a second implementation reached through a
822+
// feature that did not activate — and only one of them is the
823+
// provider this build resolved. Reading whichever came first in
824+
// `packages` would compare a consumer's requirements against an
825+
// implementation the build is not using, which is a wrong answer
826+
// rather than a missing one.
827+
std::vector<std::string> providedInterfaces;
828+
std::string providerId;
829+
for (auto& pkg : state.packages) {
830+
if (pkg.manifest.kernelAbiProvidesInterfaces.empty()) continue;
831+
// `impl` is `name@version`; the name is what precedes the
832+
// separator. A substring test would match `openkal` against
833+
// `openkal-linux@0.15.0` and read one implementation's list
834+
// as another's.
835+
if (!state.resolvedTargetSide.kernelAbi.impl.empty()) {
836+
auto const& impl = state.resolvedTargetSide.kernelAbi.impl;
837+
const auto at = impl.find('@');
838+
const auto implName = at == std::string::npos
839+
? impl : impl.substr(0, at);
840+
if (implName != pkg.manifest.package.name) continue;
847841
}
848-
// A REQUIREMENT NOBODY ANSWERED IS SAID SO, because otherwise
849-
// "yes" and "never asked" are the same reading.
850-
//
851-
// Three situations exist and two of them build: the provider
852-
// states a list and it contains the requirement (build); it
853-
// states a list and does not (refuse, below); it states nothing
854-
// at all (build, and until this note, in silence). The third is
855-
// deliberate --- `provides-interfaces` is younger than the
856-
// implementations that exist, and a graph that has not adopted it
857-
// must keep building --- but a consumer reading a green build
858-
// cannot tell it from the first. One line closes that, and it
859-
// costs nothing to a graph where the provider does declare.
860-
std::size_t uncheckedRequirements = 0;
861-
for (auto& pkg : state.packages) {
862-
const auto& need = pkg.manifest.kernelAbiRequiresInterfaces;
863-
if (need.empty()) continue;
864-
if (providerId.empty()) {
865-
uncheckedRequirements += need.size();
866-
continue;
867-
}
868-
auto missing = mcpp::targetside::interfaces_not_provided(
869-
need, providedInterfaces);
870-
if (missing.empty()) continue;
871-
refusal::record(refusal::Code::InterfaceNotProvided);
872-
std::string names;
873-
for (auto const& mI : missing) {
874-
names += "\n ";
875-
names += mI;
876-
}
877-
// THE CODE IS PRINTED, THE WAY E0006 IS, BECAUSE SOMETHING
878-
// READS THIS. A refusal that only a person can recognise
879-
// forces every machine consumer to match prose --- and prose
880-
// that a package's own compile error could coincidentally
881-
// contain. The mcpp-index compatibility measurement
882-
// distinguishes "this graph does not supply what the member
883-
// asked for" from "the member did not build" on exactly this
884-
// token, and that distinction decides whether a member counts
885-
// against a compatibility figure.
886-
// THE LABEL SAYS WHICH IMPLEMENTATION WAS RESOLVED, NOT
887-
// "provided by". The missing names are listed immediately
888-
// above it, and `provided by fakekernel` under `openkal.space`
889-
// reads as the statement that fakekernel provides it --- the
890-
// exact opposite of what this refusal is about. Read once,
891-
// rendered, which is the only way that kind of defect is
892-
// visible: every assertion on this message matches an
893-
// identifier inside it, and an identifier is in the right
894-
// place under either wording.
895-
return std::unexpected(std::format(
896-
"'{}' requires interfaces the resolved implementation does "
897-
"not provide. [interface-not-provided]{}\n"
898-
" the resolved implementation is {} ({} interface{}), "
899-
"and none of those listed above is among them.\n"
900-
" This is refused before anything is compiled "
901-
"because dependency resolution is the earliest time the "
902-
"question can be answered. Select an implementation that "
903-
"provides them, or remove them from [kernel-abi] "
904-
"requires-interfaces in '{}'.",
905-
pkg.manifest.package.name, names, providerId,
906-
providedInterfaces.size(),
907-
providedInterfaces.size() == 1 ? "" : "s",
908-
pkg.manifest.package.name));
842+
providedInterfaces = pkg.manifest.kernelAbiProvidesInterfaces;
843+
providerId = pkg.manifest.package.name;
844+
break;
845+
}
846+
// A REQUIREMENT NOBODY ANSWERED IS SAID SO, because otherwise
847+
// "yes" and "never asked" are the same reading.
848+
//
849+
// Three situations exist and two of them build: the provider
850+
// states a list and it contains the requirement (build); it
851+
// states a list and does not (refuse, below); it states nothing
852+
// at all (build, and until this note, in silence). The third is
853+
// deliberate --- `provides-interfaces` is younger than the
854+
// implementations that exist, and a graph that has not adopted it
855+
// must keep building --- but a consumer reading a green build
856+
// cannot tell it from the first. One line closes that, and it
857+
// costs nothing to a graph where the provider does declare.
858+
std::size_t uncheckedRequirements = 0;
859+
for (auto& pkg : state.packages) {
860+
const auto& need = pkg.manifest.kernelAbiRequiresInterfaces;
861+
if (need.empty()) continue;
862+
if (providerId.empty()) {
863+
uncheckedRequirements += need.size();
864+
continue;
909865
}
910-
911-
if (uncheckedRequirements > 0) {
912-
// THE IMPLEMENTATION IS NAMED FROM THE RESOLVED LAYER, not
913-
// from whichever package happened to be first: the note has
914-
// to say WHOSE silence this is, or a reader cannot act on it.
915-
const auto& impl = state.resolvedTargetSide.kernelAbi.impl;
916-
mcpp::ui::info("note", std::format(
917-
"kernel-abi interfaces: {} states none, {} requirement{} "
918-
"unchecked",
919-
impl.empty() ? std::string("the resolved implementation")
920-
: impl,
921-
uncheckedRequirements,
922-
uncheckedRequirements == 1 ? "" : "s"));
866+
auto missing = mcpp::targetside::interfaces_not_provided(
867+
need, providedInterfaces);
868+
if (missing.empty()) continue;
869+
refusal::record(refusal::Code::InterfaceNotProvided);
870+
std::string names;
871+
for (auto const& mI : missing) {
872+
names += "\n ";
873+
names += mI;
923874
}
875+
// THE CODE IS PRINTED, THE WAY E0006 IS, BECAUSE SOMETHING
876+
// READS THIS. A refusal that only a person can recognise
877+
// forces every machine consumer to match prose --- and prose
878+
// that a package's own compile error could coincidentally
879+
// contain. The mcpp-index compatibility measurement
880+
// distinguishes "this graph does not supply what the member
881+
// asked for" from "the member did not build" on exactly this
882+
// token, and that distinction decides whether a member counts
883+
// against a compatibility figure.
884+
// THE LABEL SAYS WHICH IMPLEMENTATION WAS RESOLVED, NOT
885+
// "provided by". The missing names are listed immediately
886+
// above it, and `provided by fakekernel` under `openkal.space`
887+
// reads as the statement that fakekernel provides it --- the
888+
// exact opposite of what this refusal is about. Read once,
889+
// rendered, which is the only way that kind of defect is
890+
// visible: every assertion on this message matches an
891+
// identifier inside it, and an identifier is in the right
892+
// place under either wording.
893+
return std::unexpected(std::format(
894+
"'{}' requires interfaces the resolved implementation does "
895+
"not provide. [interface-not-provided]{}\n"
896+
" the resolved implementation is {} ({} interface{}), "
897+
"and none of those listed above is among them.\n"
898+
" This is refused before anything is compiled "
899+
"because dependency resolution is the earliest time the "
900+
"question can be answered. Select an implementation that "
901+
"provides them, or remove them from [kernel-abi] "
902+
"requires-interfaces in '{}'.",
903+
pkg.manifest.package.name, names, providerId,
904+
providedInterfaces.size(),
905+
providedInterfaces.size() == 1 ? "" : "s",
906+
pkg.manifest.package.name));
924907
}
925908

909+
if (uncheckedRequirements > 0) {
910+
// THE IMPLEMENTATION IS NAMED FROM THE RESOLVED LAYER, not
911+
// from whichever package happened to be first: the note has
912+
// to say WHOSE silence this is, or a reader cannot act on it.
913+
const auto& impl = state.resolvedTargetSide.kernelAbi.impl;
914+
mcpp::ui::info("note", std::format(
915+
"kernel-abi interfaces: {} states none, {} requirement{} "
916+
"unchecked",
917+
impl.empty() ? std::string("the resolved implementation")
918+
: impl,
919+
uncheckedRequirements,
920+
uncheckedRequirements == 1 ? "" : "s"));
921+
}
922+
return {};
923+
}
924+
925+
static std::expected<void, std::string>
926+
step9_layering_and_requirement_checks(PrepareState& state, TargetSideGather& gather) {
927+
namespace tsd = mcpp::targetside;
926928
if (auto why = tsd::check_layering(state.resolvedTargetSide)) {
927929
refusal::record(refusal::Code::LayerOrdering);
928930
return std::unexpected(*why);
@@ -959,7 +961,11 @@ step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGath
959961
refusal::record(refusal::Code::HostCannotServe);
960962
return std::unexpected(state.unservedTargetDiagnosis);
961963
}
964+
return {};
965+
}
962966

967+
static void
968+
step9_pin_and_linkage_diagnostics(PrepareState& state) {
963969
// THE TARGET AND THE COMPILER ARE NOT BOUND TOGETHER, AND THE
964970
// TARGET ROW'S CONVENTION IS A FALLBACK RATHER THAN A RULE.
965971
//
@@ -1051,7 +1057,11 @@ step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGath
10511057
"target's system comes from the dependency graph: those "
10521058
"packages are compiled into this build as objects, and there "
10531059
"is no shared object to link against. The artifact is static.");
1060+
}
10541061

1062+
static std::expected<void, std::string>
1063+
step9_same_os_check_and_report(PrepareState& state) {
1064+
namespace tsd = mcpp::targetside;
10551065
// Reported, and reported HERE rather than recorded in a manifest field.
10561066
//
10571067
// A line a project writes states an intention, and it goes stale the
@@ -1138,7 +1148,11 @@ step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGath
11381148
}
11391149
mcpp::ui::info("Target", tsd::format_report(
11401150
state.resolvedTargetSide, reportedTargetName, mcpp::log::is_verbose()));
1151+
return {};
1152+
}
11411153

1154+
static std::expected<void, std::string>
1155+
step9_platform_sdk_closure_visibility(PrepareState& state) {
11421156
// CLOSURE VISIBILITY — design §6. Distinct from the five-layer
11431157
// report above: a platform dependency is not a LAYER (no engine
11441158
// vocabulary names it, and `mcpp.targetside` — the pure, layer-only
@@ -1196,6 +1210,22 @@ step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGath
11961210
return {};
11971211
}
11981212

1213+
static std::expected<void, std::string>
1214+
step9_kernel_abi_interfaces_and_requirements(PrepareState& state, TargetSideGather& gather) {
1215+
if (auto r = step9_kernel_abi_interface_enumeration(state); !r)
1216+
return std::unexpected(r.error());
1217+
1218+
if (auto r = step9_layering_and_requirement_checks(state, gather); !r)
1219+
return std::unexpected(r.error());
1220+
1221+
step9_pin_and_linkage_diagnostics(state);
1222+
1223+
if (auto r = step9_same_os_check_and_report(state); !r)
1224+
return std::unexpected(r.error());
1225+
1226+
return step9_platform_sdk_closure_visibility(state);
1227+
}
1228+
11991229
static std::expected<void, std::string> step9_layer_conditional_config(PrepareState& state) {
12001230
// ── L1b: conditional sections whose predicate names a target-side layer ──
12011231
//

0 commit comments

Comments
 (0)