Skip to content

Commit c106fa1

Browse files
Staacksclaude
andcommitted
requireFill: exempt the first run that happened, not the first clock tick.
The gate skipped the analysis block when the observed container held too little, except on the first run - and "first run" was read off lastAnalysis, which holds the experiment time. That is exactly zero as long as an experiment has never been started, so before the first start every pass counted as the first one and the gate never engaged; the golden vector for the ruled semantics (spec/analysis.yml requireFill, decided 2026-08-24) is pinned in precisely that state and saw the block run twice. A pass that actually ran now sets analysisRan, and stopAllIO clears it again so the first run after the next start stays exempt. While measuring nothing changes: the experiment time was non-zero there, so the old test agreed with the new one. Before the first start, analysis on user input is now gated from the second pass on, which is what the rule says. The vector runs unskipped again: 117 of 117. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent af41209 commit c106fa1

2 files changed

Lines changed: 4 additions & 23 deletions

File tree

app/src/main/java/de/rwth_aachen/phyphox/PhyphoxExperiment.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ public List<Link> getHighlightedLinks() {
124124
double analysisSleep = 0.; //Pause between analysis cycles. At 0 analysis is done as fast as possible.
125125
DataBuffer analysisDynamicSleep = null;
126126
double lastAnalysis = 0.0; //This variable holds the system time of the moment the last analysis process finished. This is necessary for experiments, which do analysis after given intervals
127+
boolean analysisRan = false; //Whether an analysis pass has run since the experiment was opened or (re)started. The first run is exempt from the requireFill gate (spec/analysis.yml, decided 2026-08-24), and this cannot be read off lastAnalysis: that holds the experiment time, which is exactly zero as long as the experiment has never been started.
127128
double analysisTime; //This variable holds the experiment time of the moment the current analysis process started.
128129
double analysisLinearTime; //Same with the current system time
129130
boolean analysisOnUserInput = false; //Do the data analysis only if there is fresh input from the user.
@@ -327,7 +328,7 @@ public void processAnalysis(boolean measuring) {
327328
} else
328329
cycle = 0;
329330

330-
if (requireFill != null && lastAnalysis != 0) {
331+
if (requireFill != null && analysisRan) {
331332
int threshold = requireFillThreshold;
332333
if (requireFillDynamic != null && requireFillDynamic.getFilledSize() > 0)
333334
threshold = (int)requireFillDynamic.value;
@@ -392,6 +393,7 @@ public void processAnalysis(boolean measuring) {
392393
recordingUsed = true;
393394
newData = true; //We have fresh data to present.
394395
lastAnalysis = experimentTimeReference.getExperimentTime(); //Remember when we were done this time
396+
analysisRan = true; //A run that was gated above does not get here, so this marks a pass that actually happened
395397
}
396398

397399
//called by the main loop after everything is processed. Here we have to send all the analysis results to the appropriate views
@@ -441,6 +443,7 @@ public void stopAllIO() {
441443
experimentTimeReference.registerEvent(ExperimentTimeReference.TimeMappingEvent.PAUSE);
442444
event = experimentTimeReference.getLastMapping();
443445
lastAnalysis = 0.0;
446+
analysisRan = false; //The first run after the next start is exempt from the requireFill gate again
444447

445448
//Recording
446449
if (audioRecord != null && audioRecord.getState() == AudioRecord.STATE_INITIALIZED)

app/src/test/java/de/rwth_aachen/phyphox/AnalysisGoldenVectorTest.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,6 @@ public class AnalysisGoldenVectorTest {
4141

4242
private static final String VECTORS = "analysis/vectors";
4343

44-
//Cases whose failure has been reported and is waiting for a decision, skipped with the
45-
//finding so the rest of the corpus stays useful. An entry here is a report, not a fix: it
46-
//states what the app does and why that differs from what the case pins, and it goes away
47-
//when the divergence is resolved. Never add one to make a red case quiet.
48-
private static final Map<String, String> REPORTED = new LinkedHashMap<String, String>() {{
49-
put("execution/requirefill-first-run-exempt.phyphox",
50-
"the app exempts the first run through the experiment clock - processAnalysis "
51-
+ "gates on \"requireFill != null && lastAnalysis != 0\", and lastAnalysis "
52-
+ "holds the experiment time, which stays exactly 0 while an experiment "
53-
+ "has never been started. So in the never-started state this case pins, "
54-
+ "EVERY pass is exempt and the second cycle appends again (out holds "
55-
+ "1, 2, 1, 2). Once the experiment has been started the gate behaves as "
56-
+ "ruled. Fixing it means keying the exemption on a run having happened "
57-
+ "rather than on the clock, which changes what analysis-on-user-input "
58-
+ "does before the first start - a production change, so reported rather "
59-
+ "than made here.");
60-
}};
61-
6244
private final String relativePath;
6345

6446
public AnalysisGoldenVectorTest(String relativePath) {
@@ -97,10 +79,6 @@ public void matchesGoldenVector() throws Exception {
9779
+ " > supported " + PhyphoxFile.phyphoxFileVersion + " - skipped.",
9880
CorpusTestEnvironment.versionAtMostSupported(declared));
9981

100-
for (Map.Entry<String, String> reported : REPORTED.entrySet())
101-
assumeTrue("Reported to phyphox-docs: " + reported.getValue(),
102-
!relativePath.endsWith(reported.getKey()));
103-
10482
JSONObject expected = readJson(new File(corpus,
10583
relativePath.substring(0, relativePath.length() - ".phyphox".length()) + ".expected.json"));
10684

0 commit comments

Comments
 (0)