2121//! invocations (`repository_plan`, `invocation_targets`, `build_argv`);
2222//! the query/aggregate Starlark wiring lives in `//dx/roots:roots.bzl`.
2323//! Slice 3 freezes the measured cold/warm winner (the `//...` baseline;
24- //! see [`frozen_strategy`] and [`FROZEN_EVIDENCE`]). The remaining
25- //! benchmark dimensions (source/BUILD edits, target churn, actions,
26- //! materialized bytes, projection time, retained memory) plus concurrency,
27- //! interruption, remote materialization, and reuse certification land in
28- //! later WP4 slices; the effective roots stay on the frozen baseline until
29- //! then.
24+ //! see [`frozen_strategy`] and [`FROZEN_EVIDENCE`]). Slice 4 lands the
25+ //! incrementality dimensions for the frozen baseline (source/BUILD edits,
26+ //! target churn, actions, materialized bytes, projection time, retained
27+ //! memory; see [`INCREMENTALITY_EVIDENCE`] and the `PLAN_*`/`SERVER_*`
28+ //! consts). Concurrency, interruption, remote materialization, and reuse
29+ //! certification land in later WP4 slices; the effective roots stay on the
30+ //! frozen baseline until then.
3031
3132use std:: collections:: BTreeSet ;
3233use std:: path:: { Path , PathBuf } ;
@@ -77,11 +78,12 @@ pub const WARM_WEIGHT: u64 = 2;
7778/// Weighted scores (`cold_ms + WARM_WEIGHT * warm_ms`, warm medians 372
7879/// vs 350): baseline 8457 + 2*372 = 9201 beats query-file 8983 + 2*350 =
7980/// 9683 outright; the baseline also wins every tie by [`RootStrategy::ALL`]
80- /// order. The remaining [`BenchmarkDimension`] rows (source/BUILD edits,
81- /// target churn, actions, materialized bytes, projection time, retained
82- /// memory) plus concurrency, interruption, remote materialization, and
83- /// reuse certification land in later WP4 slices and cannot displace this
84- /// freeze without new measured evidence plus a freeze change here.
81+ /// order. The incrementality rows now land in [`INCREMENTALITY_EVIDENCE`]
82+ /// (#25 slice) and confirm the freeze: the query-file control matches the
83+ /// baseline on every dimension within noise. Concurrency, interruption,
84+ /// remote materialization, and reuse certification land in later WP4 slices
85+ /// and no row here can displace this freeze without new measured evidence
86+ /// plus a freeze change here.
8587pub const FROZEN_STRATEGY : RootStrategy = RootStrategy :: RecursivePattern ;
8688
8789/// Returns the frozen repository-root strategy (see [`FROZEN_STRATEGY`]).
@@ -102,6 +104,77 @@ pub const FROZEN_EVIDENCE: [(RootStrategy, bool, u64, u64); 4] = [
102104 ( RootStrategy :: PackageShards , false , 2000 , 300 ) ,
103105] ;
104106
107+ /// Measured incrementality evidence for the frozen baseline (M25 WP4 slice
108+ /// 4, issue #25): steady-state warm-server wall times and executed actions
109+ /// per edit/churn [`BenchmarkDimension`], as `(dimension,
110+ /// baseline_wall_ms, queryfile_wall_ms, actions_executed)`.
111+ ///
112+ /// Methodology (2026-09-15, Linux x86_64, Bazel 9.2.0 via Bazelisk
113+ /// v1.29.0): scratch copy of the workspace (rsync, `.git`/`bazel-*`
114+ /// excluded) with its own warm persistent server, so the live repo is
115+ /// never dirtied. Every cell applies one probe edit, builds the codegen
116+ /// plan aspect (`//generation:codegen.bzl%dx_codegen_plan_aspect`) with the
117+ /// `dx_codegen_plans` output group, records `Elapsed time` plus the
118+ /// executed-action summary, then reverts to pristine. Probes are
119+ /// comment-only (source: `//` line on `generation/codegen.proto`; BUILD:
120+ /// `#` line on `generation/BUILD.bazel`) except churn, which adds/removes
121+ /// a trivial `filegroup`; each rep carries a unique comment tag so no rep
122+ /// action-cache-hits a previous one, and a throwaway warm-up probe per
123+ /// dimension absorbs the first-probe package-reload artifact (see below).
124+ /// Reported walls are medians over 3 measured reps. The query-file
125+ /// candidate reads the `roots_pattern_fixture` shape (holding `//...`)
126+ /// via `--target_pattern_file`, so it is an equivalent-semantics control:
127+ /// it matches the baseline on every row within noise and cannot displace
128+ /// the freeze.
129+ ///
130+ /// Findings pinned below:
131+ /// - Source edits re-execute exactly 2 actions (`GenProtoDescriptorSet`
132+ /// and `ProstGenProto` on `//generation:codegen_proto`). Comment-only
133+ /// probes leave outputs byte-identical (md5-verified, 0 bytes
134+ /// rewritten), so these walls are a LOWER BOUND: semantic edits cost at
135+ /// least this plus downstream propagation.
136+ /// - BUILD edits cost re-analysis only at steady state (0 actions). The
137+ /// discarded warm-up probe deterministically re-executed the same 2
138+ /// proto actions once (package reload coinciding with a restored source
139+ /// mtime); reps 1-3 with unique comments execute nothing.
140+ /// - Target add/remove cost re-analysis only (0 actions); remove is
141+ /// marginally slower than add.
142+ /// - `TargetAddRemove` rows keep the slower of the add/remove medians
143+ /// (add: 524/542 ms, remove: 531/535 ms baseline/query-file).
144+ pub const INCREMENTALITY_EVIDENCE : [ ( BenchmarkDimension , u64 , u64 , u64 ) ; 3 ] = [
145+ ( BenchmarkDimension :: SourceEdit , 446 , 471 , 2 ) ,
146+ ( BenchmarkDimension :: BuildEdit , 442 , 469 , 0 ) ,
147+ ( BenchmarkDimension :: TargetAddRemove , 531 , 542 , 0 ) ,
148+ ] ;
149+
150+ /// Files materialized in `bazel-bin` for the `dx_codegen_plans` output
151+ /// group over `//...`: 3 `.dxcodegen.pb` shards (see [`PLAN_MATERIALIZED_BYTES`]).
152+ pub const PLAN_MATERIALIZED_FILES : u64 = 3 ;
153+
154+ /// Bytes materialized for the plan output group: the 3 shards total 238
155+ /// bytes. Per-probe re-materialization is 0 bytes at steady state: edit
156+ /// probes reproduce byte-identical outputs, which Bazel leaves in place.
157+ pub const PLAN_MATERIALIZED_BYTES : u64 = 238 ;
158+
159+ /// Warm wall time (median ms) materializing only the plan output group:
160+ /// the Bazel-layer projection cost behind `dx codegen` selection.
161+ pub const PLAN_GROUP_WARM_MS : u64 = 413 ;
162+
163+ /// Warm wall time (median ms) building `//...` default outputs with the
164+ /// aspect applied but no output group requested. Excludes the one-time
165+ /// 130543 ms first build of never-built default outputs in the scratch
166+ /// workspace; the plan group (`PLAN_GROUP_WARM_MS`) stays cheaper than
167+ /// full default outputs. CLI-layer link-tree projection timing is not
168+ /// implemented yet and stays open.
169+ pub const DEFAULT_OUTPUTS_WARM_MS : u64 = 502 ;
170+
171+ /// Bazel server peak resident set (VmHWM KiB) after the full benchmark
172+ /// matrix plus one full default-outputs build: ~2.5 GiB retained for the
173+ /// `//...` analysis graph. An upper bound for plan-only iteration, which
174+ /// never approaches it (warm plan builds sit near 0.4 s with 0 executed
175+ /// actions).
176+ pub const SERVER_PEAK_RSS_KB : u64 = 2628812 ;
177+
105178/// Repository-root strategy candidates under O34.
106179#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
107180pub enum RootStrategy {
@@ -673,6 +746,53 @@ mod tests {
673746 assert_eq ! ( select_strategy( & samples) , frozen_strategy( ) ) ;
674747 }
675748
749+ #[ test]
750+ fn incrementality_evidence_covers_the_measured_dimensions_once ( ) {
751+ let dims: Vec < BenchmarkDimension > =
752+ INCREMENTALITY_EVIDENCE . iter ( ) . map ( |row| row. 0 ) . collect ( ) ;
753+ assert_eq ! (
754+ dims,
755+ vec![
756+ BenchmarkDimension :: SourceEdit ,
757+ BenchmarkDimension :: BuildEdit ,
758+ BenchmarkDimension :: TargetAddRemove ,
759+ ]
760+ ) ;
761+ }
762+
763+ #[ test]
764+ fn incrementality_control_matches_baseline_within_noise ( ) {
765+ for ( dimension, baseline_ms, queryfile_ms, actions) in INCREMENTALITY_EVIDENCE {
766+ let slower = baseline_ms. max ( queryfile_ms) ;
767+ let faster = baseline_ms. min ( queryfile_ms) ;
768+ assert ! (
769+ slower * 100 <= faster * 120 ,
770+ "{dimension:?}: baseline {baseline_ms} ms vs query-file {queryfile_ms} ms diverge past 20%"
771+ ) ;
772+ assert ! (
773+ actions <= 2 ,
774+ "{dimension:?}: {actions} executed actions exceed the measured maximum"
775+ ) ;
776+ }
777+ assert_eq ! (
778+ INCREMENTALITY_EVIDENCE [ 0 ] . 3 , 2 ,
779+ "source edits re-execute 2 actions"
780+ ) ;
781+ }
782+
783+ #[ test]
784+ fn plan_materialization_stays_cheaper_than_default_outputs ( ) {
785+ assert_eq ! ( PLAN_MATERIALIZED_FILES , 3 ) ;
786+ assert_eq ! ( PLAN_MATERIALIZED_BYTES , 238 ) ;
787+ assert ! (
788+ PLAN_GROUP_WARM_MS < DEFAULT_OUTPUTS_WARM_MS ,
789+ "plan group {} ms must stay cheaper than default outputs {} ms" ,
790+ PLAN_GROUP_WARM_MS ,
791+ DEFAULT_OUTPUTS_WARM_MS
792+ ) ;
793+ assert ! ( SERVER_PEAK_RSS_KB > 0 ) ;
794+ }
795+
676796 #[ test]
677797 fn baseline_plan_keeps_the_canonical_selection_identity ( ) {
678798 let plan = repository_plan ( ) ;
0 commit comments