Skip to content

Commit 615884c

Browse files
committed
Stage demand cache identity once per scan
1 parent 87879ba commit 615884c

4 files changed

Lines changed: 89 additions & 15 deletions

File tree

NRA_SCAN_PERFORMANCE_HANDOFF.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11
# NRA scan-performance handoff
22

3+
## 2026-08-08 cache-policy and staged-demand-signature checkpoint
4+
5+
A corrected one-worker DQDock profile puts 38.0 of 74.6 process-CPU seconds
6+
inside demanded-family extraction. Class projection is the largest single
7+
family at 15.2 seconds, but two follow-up experiments rejected the apparent
8+
local fixes: disabling eager AutoRegister graph construction saved at most
9+
2.4 seconds because most attributed time belongs to the shared syntax index,
10+
and a header-only class core is unsafe for 39 of the 41 live class-family
11+
consumers. The slowest individual modules are only 2.0--2.4 seconds, so there
12+
is no exceptional shard tail to isolate. More class/index micro-optimization
13+
cannot plausibly bridge the remaining order-scale target.
14+
15+
The retained change moves cache policy ahead of cache identity construction:
16+
cache-disabled source stores now return before hashing family and demand
17+
identities. Cache-enabled workers receive each demand signature staged once
18+
by the parent scan and reuse it for load, content-signature, native-store, and
19+
AST-store operations. This removes about 15,600 pointless identity builds on
20+
a DQDock ``--no-cache`` scan without introducing a second cache authority.
21+
22+
Against a same-host detached control at ``87879ba``, two DQDock no-cache runs
23+
changed from 24.101/24.125 seconds wall (22.967/22.742 internal) to
24+
20.826/20.533 seconds wall (19.622/19.486 internal), roughly a 15% controlled
25+
cold improvement. A fresh empty-cache scan completes in 23.308 seconds wall
26+
and 21.346 internal; its unchanged follow-up completes in 1.546 seconds wall
27+
and 0.582 internal. OpenHCS no-cache completes in 15.938 seconds wall and
28+
14.907 internal versus the retained 18.170/17.145 gate. DQDock retains all
29+
12 expected findings across 252 detectors and OpenHCS retains all 45. The
30+
analysis-cache suite passes all 146 tests, including a regression that makes
31+
worker-side demand-signature reconstruction fail.
32+
33+
This is a material transferable gain, not the requested order-of-magnitude
34+
collapse. The next architectural gate is a detector-declared candidate-seed
35+
contract or a shared demanded-event bundle that can avoid constructing entire
36+
unused families. It must demonstrate exact survivor collapse on saved
37+
DQDock and OpenHCS artifacts before production wiring; further local class
38+
header or syntax-index polishing is rejected by the measured ceiling above.
39+
340
## 2026-08-08 shared demanded-event checkpoint
441

542
The report-witness experiment reached a measured ceiling and was stopped.

nominal_refactor_advisor/analysis.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ class CompactProjectionBuildRequest:
995995
config: DetectorConfig
996996
local_detector_types: tuple[type[IssueDetector], ...] = ()
997997
family_demands: tuple[tuple[type[CollectedFamily], object], ...] = ()
998+
family_demand_signatures: tuple[tuple[type[CollectedFamily], str], ...] = ()
998999
bundle_families: tuple[type[CollectedFamily], ...] = ()
9991000

10001001

@@ -1042,6 +1043,7 @@ def add_runtime_projection(
10421043
fallback_local_detector_types = request.local_detector_types
10431044
ast_families = list(request.missing_families)
10441045
demand_by_family = dict(request.family_demands)
1046+
demand_signature_by_family = dict(request.family_demand_signatures)
10451047
for family in tuple(ast_families):
10461048
demand = demand_by_family.get(family)
10471049
if demand is None:
@@ -1053,6 +1055,7 @@ def add_runtime_projection(
10531055
family_cache_dir=source.family_cache_dir,
10541056
family=family,
10551057
demand=demand,
1058+
demand_signature=demand_signature_by_family.get(family),
10561059
)
10571060
if projections is None:
10581061
continue
@@ -1066,6 +1069,7 @@ def add_runtime_projection(
10661069
family_cache_dir=source.family_cache_dir,
10671070
family=family,
10681071
demand=demand,
1072+
demand_signature=demand_signature_by_family.get(family),
10691073
),
10701074
)
10711075
ast_families.remove(family)
@@ -1174,6 +1178,7 @@ def add_runtime_projection(
11741178
family=family,
11751179
demand=demand,
11761180
items=projections,
1181+
demand_signature=demand_signature_by_family.get(family),
11771182
)
11781183
add_runtime_projection(family, projections, projection_signature)
11791184
ast_families.remove(family)
@@ -1230,6 +1235,7 @@ def add_runtime_projection(
12301235
family=family,
12311236
demand=demand,
12321237
items=projections,
1238+
demand_signature=demand_signature_by_family.get(family),
12331239
)
12341240
)
12351241
else:
@@ -2221,6 +2227,15 @@ def extend_report_findings(
22212227
if family in report_family_demands
22222228
)
22232229
),
2230+
family_demand_signatures=(
2231+
()
2232+
if include_local_findings
2233+
else tuple(
2234+
(family, projection_manifest._demand_signature(family))
2235+
for family in missing_families
2236+
if family in report_family_demands
2237+
)
2238+
),
22242239
bundle_families=projection_manifest.projection_families,
22252240
)
22262241
)

nominal_refactor_advisor/ast_tools.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,8 @@ def store_cached_collected_family_items_for_source_signature(
20952095
) -> str | None:
20962096
"""Publish source-native compact facts under the existing cache identity."""
20972097

2098+
if family_cache_dir is None:
2099+
return None
20982100
return _store_cached_collected_family_items_for_identity(
20992101
cache_dir=family_cache_dir,
21002102
identity=_collected_family_cache_identity_for_source_signature(
@@ -2117,9 +2119,12 @@ def store_cached_demanded_collected_family_items_for_source_signature(
21172119
family: type[CollectedFamily[ShapeItemT]],
21182120
demand: object,
21192121
items: tuple[ShapeItemT, ...],
2122+
demand_signature: str | None = None,
21202123
) -> str | None:
21212124
"""Persist a focused view without publishing it as the complete family."""
21222125

2126+
if family_cache_dir is None:
2127+
return None
21232128
return _store_cached_collected_family_items_for_identity(
21242129
cache_dir=family_cache_dir,
21252130
identity=_collected_family_demand_cache_identity_for_source_signature(
@@ -2128,6 +2133,7 @@ def store_cached_demanded_collected_family_items_for_source_signature(
21282133
source_signature=source_signature,
21292134
family=family,
21302135
demand=demand,
2136+
demand_signature=demand_signature,
21312137
),
21322138
family=family,
21332139
items=items,

tests/test_analysis_cache.py

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,25 @@ def test_source_demand_projection_shard_is_filtered_and_not_cached_as_full(
28262826
)
28272827
role_family = role_surface_detectors.CompactRoleSurfaceModuleProjectionFamily
28282828
boundary_family = surface_detectors.CompactDistributedBoundaryModuleProjectionFamily
2829+
role_demand = role_surface_detectors.CompactRoleSurfaceProjectionDemand(
2830+
field_names=frozenset({"selected_values"}),
2831+
generic_axis_tokens=frozenset(),
2832+
generic_case_tokens=frozenset(),
2833+
minimum_generic_case_count=2,
2834+
)
2835+
boundary_demand = surface_detectors.CompactDistributedBoundaryProjectionDemand(
2836+
frozenset({"projected_axis_offsets"})
2837+
)
2838+
demand_signatures = (
2839+
(
2840+
role_family,
2841+
ast_tools_module.collected_family_demand_cache_signature(role_demand),
2842+
),
2843+
(
2844+
boundary_family,
2845+
ast_tools_module.collected_family_demand_cache_signature(boundary_demand),
2846+
),
2847+
)
28292848

28302849
def unexpected_ast_parse(self, paths):
28312850
del self, paths
@@ -2838,28 +2857,25 @@ def unexpected_ast_parse(self, paths):
28382857
"parsed_source_paths",
28392858
unexpected_ast_parse,
28402859
)
2860+
2861+
def unexpected_demand_signature(_demand: object) -> str:
2862+
raise AssertionError("worker must reuse the staged demand signature")
2863+
2864+
monkeypatch.setattr(
2865+
ast_tools_module,
2866+
"collected_family_demand_cache_signature",
2867+
unexpected_demand_signature,
2868+
)
28412869
result = analysis_module.build_compact_projection_shard(
28422870
analysis_module.CompactProjectionBuildRequest(
28432871
source=projection_source,
28442872
missing_families=(role_family, boundary_family),
28452873
config=DetectorConfig(),
28462874
family_demands=(
2847-
(
2848-
role_family,
2849-
role_surface_detectors.CompactRoleSurfaceProjectionDemand(
2850-
field_names=frozenset({"selected_values"}),
2851-
generic_axis_tokens=frozenset(),
2852-
generic_case_tokens=frozenset(),
2853-
minimum_generic_case_count=2,
2854-
),
2855-
),
2856-
(
2857-
boundary_family,
2858-
surface_detectors.CompactDistributedBoundaryProjectionDemand(
2859-
frozenset({"projected_axis_offsets"})
2860-
),
2861-
),
2875+
(role_family, role_demand),
2876+
(boundary_family, boundary_demand),
28622877
),
2878+
family_demand_signatures=demand_signatures,
28632879
)
28642880
)
28652881

0 commit comments

Comments
 (0)