Experiment record
SwitchBot five-minute Raw collection: diagnosing minute-04 gaps and reducing ScriptLock contention
A completed verification of a recurring SwitchBot five-minute Raw gap pattern concentrated near minute 04 of each hour. After shortening shared ScriptLock scope and moving API acquisition before persistence locking, post-change Raw contained all 34 expected minute-04 observations and all 411 expected five-minute cycles.
Summary
AIEL-2026-0007 investigated a recurring five-minute Raw collection failure in which missing SwitchBot observations were concentrated near minute 04 of each hour.
The retained pre-change Apps Script source contained a concrete failure mechanism: SwitchBotPower tried to acquire a shared ScriptLock before calling the SwitchBot API, and an invocation could return after a 20-second lock timeout without recording an observation. The same Apps Script project also contained a gas-side path that held the shared lock across a longer processing section.
The collector was changed so that SwitchBot API acquisition occurs before persistence locking, the API acquisition time becomes the observation timestamp, and the lock is held only around the short write section. The gas-side path was likewise changed so the shared lock is no longer held across the entire refresh operation.
Post-change validation used the five-minute Raw only. Over approximately 34 hours, minute-04 acquisition was 34/34 = 100% and all expected five-minute cycles were present at 411/411. Missing cycles, delayed-save markers, post-gap-observation markers, and intervals longer than seven minutes were all 0.
One duplicate observation occurred about 38.5 seconds after the preceding observation. Existing duplicate protection excluded it from accumulation, and the abnormal-interval cross-check found no recurrence pattern.
The result is COMPLETED / SUCCESS for the targeted minute-04 missingness problem.
Background
Before the change, the SwitchBot path was effectively:
scheduled invocation → acquire shared ScriptLock → SwitchBot API acquisition → write Raw
If the shared lock was unavailable for 20 seconds, the invocation could end before the API call. This creates a silent Raw gap because observation itself never occurs.
For periodic collectors, this distinction matters: persistence contention should not become an acquisition failure when external observation can be performed independently. Separating acquisition from persistence preserves when the external state was actually observed and lets storage contention be handled separately.
The source establishes this failure mechanism directly. The attribution of the concentrated minute-04 pattern to long-held shared ScriptLock contention is classified as INFERRED, high confidence, because no direct lock trace was retained for every individual historical missing slot. The inference is supported by the verified mechanism and the disappearance of the pattern after the lock-scope redesign.
Methods
- Review the pre-change Apps Script control flow and identify the lock-before-observation early-return path.
- Move SwitchBot API acquisition outside the lock, fix observation time at API acquisition, and keep the lock only around persistence. Reduce the gas-side whole-process lock to the write section as well.
- Preserve existing Raw rows and continue normal five-minute collection.
- Validate the post-change Raw for expected five-minute cycles, minute-04 observations, missing cycles, duplicate intervals, delayed-save markers, post-gap-observation markers, and intervals longer than seven minutes.
Daily aggregates were not used for the completion decision.
The separate daily usage-time issue is outside this Experiment:
electricity-accumulation eligibility time ≠ observation coverage ≠ power-on usage time
Those quantities require a separate semantic design and validation exercise.
Experiment Log
Pre-change control flow
The retained SwitchBotPower logic acquired ScriptLock before SwitchBot API acquisition. If the lock was not obtained within 20 seconds, the invocation could return without a Raw observation.
Collector change
The revised SwitchBot path became:
scheduled invocation → SwitchBot API acquisition + acquisition timestamp → short persistence lock → Raw write
The gas-side refresh path also stopped holding the same shared lock across the whole processing operation and retained locking only for the write section.
Post-change Raw verification
| Check | Result |
|---|---|
| Expected minute-04 observations | 34 |
| Acquired minute-04 observations | 34 |
| Minute-04 success rate | 100% |
| Expected five-minute cycles | 411 |
| Observed five-minute cycles | 411 |
| Missing cycles | 0 |
| Delayed-save markers | 0 |
| Post-gap-observation markers | 0 |
| Intervals > 7 min | 0 |
| Duplicate observations | 1 isolated event |
The duplicate occurred about 38.5 seconds after the preceding observation. It was excluded from accumulation by the existing duplicate defense and did not form a recurring pattern.
Conclusion
The pre-change source verifies a failure mechanism in which shared ScriptLock contention could terminate a scheduled SwitchBot collection before API acquisition and leave no Raw observation. The redesign removed API acquisition from that lock dependency, preserved acquisition time as observation time, and shortened the shared lock scope on the relevant SwitchBot and gas-side paths.
In the approximately 34-hour post-change Raw window, minute-04 acquisition was 34/34 and total five-minute coverage was 411/411, with zero missing cycles, zero delayed-save markers, zero post-gap-observation markers, and zero intervals longer than seven minutes. The only duplicate was an isolated event safely excluded from accumulation.
The verified failure mechanism and the matching pre/post behavior support long-held shared ScriptLock contention as the primary cause of the targeted minute-04 gaps. Because individual historical gaps do not have retained direct lock traces, that causal attribution remains INFERRED rather than directly observed. The repair is VERIFIED effective for the tested failure pattern and validation window.
The experiment therefore closes as COMPLETED / SUCCESS.
Evidence summary
The Evidence States for the information obtained in this Experiment are as follows.
See Evidence State for the shared definitions.
| Recorded content | Evidence State | Basis |
|---|---|---|
The old SwitchBot path could time out on ScriptLock before API acquisition and leave no Raw observation | VERIFIED | retained source review |
| The revised SwitchBot path acquires the API observation before the persistence lock and uses acquisition time as observation time | VERIFIED | retained revised source |
| The gas-side shared lock was reduced from whole-process scope to the write section | VERIFIED | retained revised source |
| Post-change minute-04 coverage was 34/34 and total five-minute coverage was 411/411, with zero missing cycles | VERIFIED | retained Raw |
| Delayed-save markers, post-gap markers, and >7-minute intervals were all zero | VERIFIED | retained Raw |
| One duplicate occurred about 38.5 seconds after the preceding observation and was safely excluded from accumulation | OBSERVED | retained Raw |
Long-held shared ScriptLock contention was the primary cause of the concentrated minute-04 gaps | INFERRED | verified failure mechanism + pre/post Raw behavior |
Operational implications
For a periodic Apps Script collector, a persistence lock should not determine whether an external observation is acquired when those stages can be separated. Acquiring and timestamping the external observation first, then applying a short persistence lock, reduces the chance that storage contention becomes a silent acquisition gap.
This result is bounded to the tested architecture and failure pattern; it does not imply that every future missing sample must be lock-related.
The daily usage-time redesign is a separate planned follow-up. It should derive power-on usage time from the Raw power-state series and keep electricity-accumulation eligibility time, observation coverage, and power-on usage time as distinct quantities.
Machine-readable experiment record
A machine-readable canonical record of this Experiment is published as JSON.
AIEL-2026-0007 experiment.json
Related experiments
AIEL-2026-0001 used an independent five-minute Google Apps Script collection path while investigating SwitchBot OpenAPI stale-status behavior. AIEL-2026-0007 addresses a different failure layer: collector-side missingness caused by observation/persistence lock coupling.