Skip to content

v1.0.0-rc.17

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 05 Oct 04:09
· 33 commits to main since this release

Latest five-day study: download the current signed study and Traditional Chinese instructions from the participant page. The study uses stable filenames and URLs: study.partcfg and participant instructions. The current questionnaire contains seven questions. Download and import the study again for each new setup; installing the APK alone does not update an imported study. Existing enrolled studies keep their original configuration. The dated 20261005 participant ZIP is a historical six-question snapshot, not the current study download.

This release improves participant disclosure, collection recovery, and verification of
five-day study exports. Physical-device admission checks and daily data return remain necessary;
these changes do not establish a completed 120-hour physical-device endurance run.

The RC14, RC15 and RC16 tags did not produce public releases because their CI gates failed. RC17
follows RC13 as the next public release candidate.

  • Application dependency construction and session initialization run in the background behind one
    explicit readiness boundary. Participant screens, Android results and study-entry intents,
    workers and receivers wait for the same initialized components. Unexpected initialization
    failures release waiters and show a neutral failure screen; they do not leave a permanent
    loading screen or expose incomplete components. Foreground-service notification and startup
    acknowledgement remain immediate, before waiting for the application, so recovery cannot
    deadlock with service startup. Existing recovery-required state and participant controls remain
    unchanged. This removes filesystem, KeyStore and client construction from process binding;
    it does not guarantee responsiveness under arbitrary device CPU starvation.

  • Interrupted runtime checkpoint writes can recover from an authenticated base and the complete
    authenticated commit log even when a staging snapshot was only partly written. Staging files are
    retired only after recovery succeeds. Invalid bases, authenticated conflicting documents, damaged
    retained commits and pending-input failures still stop recovery; process recovery remains paused
    until the participant explicitly resumes.

  • Limited traffic uses separate bounded flow queues in both directions before
    paced Layer-3 admission. Previously, waiting for uplink credit stopped TUN reads;
    sustained transfers could fill the kernel queue and stall TCP delivery even when
    their average rate passed. A downlink FIFO also let download data delay upload
    acknowledgements. Each direction now has a shared hard limit of 128 packets and
    64 KiB across 1024 fixed hash buckets, with byte-deficit scheduling.
    Uplink uses CoDel and capacity drops. Limited downlink admission never waits for
    queue capacity on a shared TCP processor: it removes the minimum required tail
    packets from the highest occupied-MTU score (ceil(backlog_bytes / 1500)),
    including the incoming packet in that decision. Equal scores rotate the
    resident tail selected for removal, so smaller resident single-packet queues
    cannot always reject a full-MTU newcomer. A strictly highest-score incoming
    backlog still loses its incoming tail. Scheduling remains byte based; admitting
    a large packet can require multiple small-packet drops, and this policy does
    not guarantee ACK priority or progress for every flow under arbitrary traffic.
    Its effective byte limit follows 100 ms of configured bandwidth,
    bounded by one MTU and 64 KiB; the consumer can hold one additional MTU.
    A completed limited enqueue yields to ready workers after releasing its locks,
    without waiting for the queue to drain. TCP explicitly uses Reno with SACK-based
    recovery and leaves RACK disabled; controlled duplex tests exposed repeated
    timeout/recovery cycles with the pinned stack's RACK mode after initial queue
    loss. This choice applies to every study profile and does not alter the signed
    rate settings. Congestion drops and retransmissions remain possible.
    Classification keys are temporary; flow identities and hashes are not recorded
    or exported. Counters include only admitted Layer-3 packets, including admitted
    retransmissions; downlink admission requires a successful TUN write. Unlimited
    profiles retain FIFO queue backpressure. Suspension, profile replacement and
    shutdown retain the admission fence, and queued packets use the current profile
    when delivered. Hash collisions and opaque traffic can share a bucket; strict
    per-flow fairness and lossless delivery are not guaranteed.

  • WorkManager initializes on demand with its existing default configuration. Its database is no
    longer opened by the eager startup provider, and constructing the action and upload adapters
    does not initialize it. Durable timer, action and upload scheduling still request the same
    application-wide WorkManager instance when needed.

  • Emulator throughput diagnostics can explicitly sample native counters, fixture write progress
    and kernel drop/retransmission counters, or run a bounded 300-second stress interval. Routine
    release gates retain their 60-second duration and original rate bounds, without periodic
    foreground diagnostic broadcasts changing the app's process priority.

  • Throughput gates also require each selected connection to make progress after a ten-second
    warmup: more than five consecutive complete one-second buckets without payload fails the
    measurement even if its aggregate rate passes. A simultaneous upload/download case checks
    actual Android-received download payload under the same fixed 512/512 kbps profile, with
    bounded start synchronization and the original rate bounds in both directions.
    A focused 64/64 kbps duplex run uses the corresponding signed fixture and the
    same rate and liveness bounds; the default release suite retains its 512 kbps case.

  • Emulator readiness waits for completed boot before querying ActivityManager and
    allows the stock SDK image to finish its initial HOME setup within the existing
    deadline. API 37 cleanup bounds console commands, terminates only the process
    owned by that runner, preserves the original failure status, and records whether
    the emulator and temporary AVD were actually removed.

  • Usage-event queries now check Usage Access and the unlocked-user state before and after each
    query, including an empty barrier flush. Lost access fails the collector without advancing its
    successful-query coverage, rather than recording an empty result as successful collection.

  • A paused study immediately posts a neutral, persistent reminder to open Particeps and check
    its status. Resume or study removal clears it. Notification delivery blocked by permissions or
    channel settings is retried during access reconciliation; it is not cached as delivered.
    Recovery remains paused until the participant explicitly resumes.

  • Participants who have started a study get one Study and my data entry, identical in every
    study arm, on the collection panel and on the access panel shown while required access is
    repaired. It restates the study, researcher contact, consent text and version, signing-key
    fingerprint, installation code and any assigned code, what each data category records and does
    not record with the Android access it uses, the upload terms, the fixed VPN paragraph for a study
    that may adjust transfer speed, and what Pause, Resume, Withdraw, and Delete local data do. It
    also shows the state, study day, planned end once the phone's clock is verified, collecting and
    paused time, the size and event count of an export made since Particeps last started, and local
    storage measured when the page opens. Both sizes are shown in 50 MB steps ("Less than 50 MB",
    "50–100 MB", and so on), and no byte count reaches the screen. The steps limit the bytes stored
    per event, which depend on the arm's automation through per-commit overhead, to what a 50 MB
    difference reveals. They do not hide when collection runs: the export's event count on this page
    and the running screen's live event count stay exact. It has no lifecycle control. The Details
    toggle is gone, and the signed configuration ID, which differs between study arms, is no longer
    shown anywhere.

  • Every setup step, from import through Ready, offers Decline and remove this study. After a
    confirmation it removes the study and setup progress through the local deletion path; Android
    access granted during setup stays on.

  • The paused-since time and an ended study's length come from the commit that entered that state,
    so later commits in the same state, such as upload acknowledgements, no longer move them.

  • Intervention notifications carry a fixed public version: the app name and "A research activity
    is available. Unlock your phone to see it." Android shows it in place of the researcher's title
    and message only when the lock screen is set to hide sensitive content; Android's default shows
    all content.

  • Data-category copy states what each category records and does not record and no longer quotes
    profile settings, such as sampling rates or poll intervals, that can differ between arms. The app
    category is "Particeps app activity". The fixed traffic-shaping paragraph is reworded to be true
    for both selected-app and all-app targets, the consent checkbox reads "data collection and
    sharing", and the consent upload sentence and the public participant page say that unsent data
    "can still be sent" after pausing or withdrawing.

  • Upload progress on the running screen and export phase progress are whole percentages. Batch
    counts are no longer shown, because how many commits a study makes depends on its automation.

  • Automatic upload begins at Start. Nothing is staged, scheduled, or sent during setup, and the
    first bundle begins at commit 1 and carries the setup commits with the first collection. If
    scheduling the upload chain fails after Start, Start keeps its result and the next Resume or
    access reconciliation retries it.

  • Gyroscope and accelerometer samples commit in batches through a window of up to 5 s of awake
    time when no automation in the signed study matches that sensor's events and the study has no
    sequence trigger or window_threshold trigger or condition. Otherwise every sample commits
    without waiting, as before. Observed time, values, sampling rate, and condition-epoch attribution
    are unchanged; committed_at can trail capture by up to 5 s, and for the accelerometer, which
    holds no wake lock, by any CPU suspend while a batch is open. Process death loses the samples
    since the sensor's last recorded one, inside the PROCESS_RECOVERY quality gap that recovery
    records. A safety pause, a phone clock or time-zone change while the study runs, and a clock
    change first seen after the deadline each drop up to 5 s of open-batch samples with no quality
    gap that names the sensor. The researcher guide and data dictionary give the analysis rules.

  • Callback collectors merge callbacks that are already queued into one observation and, without a
    window, never wait for more. When a desired resource would change only after a live batch's first
    event, the runtime records the events before it and the collector offers the rest under the next
    producer ordinal. A commit records each of the reducer's condition-timer intents in the
    reducer's order, as RC13 did, except those for a timer generation that the same commit armed
    and then retired or replaced, and only the recorded intents reach WorkManager. A merged batch
    that slides a window once per event therefore retires the prior timer once and schedules only
    the final one, and recovery of a running study, whose quality-gap reset re-arms each condition
    timer before the safety pause retires it, records one retirement per timer and leaves no
    wakeup for the re-armed generation.

  • A timer wakeup that the runtime rejects as stale, because it holds that timer at a later
    generation, now ends. RC13 retried it with a backoff that grows by 10 s per attempt, about 130
    attempts in the first day, until the timer was next removed, such as at the next pause.

  • Collector API: EmitBatchResult.Accepted gains recordedEvents, and CollectorContext gains
    requiresPromptCommits. SerializedCallbackCollector handles both; a collector that implements
    Collector directly and emits multi-event live batches must offer events.drop(recordedEvents)
    again under the next producer ordinal.

  • Cold start authenticates the retained commit log once. The encrypted store caches its engine key
    and commit-log byte totals, the runtime reuses per-commit digests and precomputes reducer state
    keys, timer identities, local times, literals, and thresholds, and the participant UI state is
    built only while the Activity is started.

  • A recovery reset now deletes the study's Android Keystore engine key. RC13's reset matched an
    alias prefix no key used and left the key in place.

  • A commit the store has made durable is always applied to the runtime's memory, even when the
    caller is cancelled during the append. Before, such a cancellation could leave every later commit
    rejected, with the study still shown as running, until the process restarted.

  • The researcher site's participant preview shows only the upload destination host, as the app
    does, and its fixed VPN paragraph is checked against the app's string resources.

Analysis tools (no app change):

  • Authenticated bundle JSON, commit reassembly and replay now use streaming reads and private
    SQLite staging rather than keeping the complete commit history in memory. The pipeline verifies
    the whole participant chain before publishing Parquet, bounds individual commit and JSON tokens,
    and removes temporary plaintext on handled failures. Metadata still grows with participants,
    epochs and actions; this is not a constant-memory guarantee for every input.

  • Materialization retains successful usage-query coverage and hashes its quality summary in the
    dataset manifest. The new usage-report command verifies that dataset and reports foreground
    intervals, resumed events, censoring and coverage before, during and after the 12:00–17:00
    reference window. Missing collection is not counted as zero use. Traffic receipts and snapshots
    produce a separate report of applied limited, unlimited and unknown intervals; these intervals
    are not evidence of achieved network speed or a causal treatment effect.

  • Before this change, no export from RC13 could be verified or analyzed, including the running
    five-day pilot's, with either RC13's or this tree's offline tools. Decryption succeeded and the
    files are intact, but verification stopped at commit 1. researcher-tools decrypt failed with
    "Automation checkpoint reducer cursor diverges from commit" and wrote no output,
    particeps-analysis failed with "automation checkpoint has an incomplete desired resource
    vector", and the researcher site's Read step reported the bundle unreadable. Past commit 1, the
    tools also rejected shapes that RC13 writes in normal use:

    • the usage-events cursor stored at a barrier flush;
    • the usage-events checkpoint that recovery drops;
    • the CANCELLED and LIFECYCLE_ENDED timer retirements at a window barrier and at the deadline
      stop;
    • a recovery that closes the epoch without a traffic-shaping audit, or in the new boot after a
      reboot;
    • deadline-timer events that carry the epoch being closed;
    • the deadline that a Complete or Withdraw from RUNNING retires;
    • usage-events coverage that starts a few milliseconds before its epoch;
    • a survey requested at the 17:00 barrier and answered in the next epoch;
    • the timer events of RC13's recovery commits.

    A chain that passed verification still could not be written: the Parquet sink failed on
    json_string fields and on payload fields named condition_epoch_id or source_id.

  • protocol/v1/README.md now specifies what RC13 writes, with no branching on the producer's
    client version, and the same rules accept this build's exports. Each rule is relaxed only as far
    as the observed shapes require. particeps-analysis enforces every rule. The Kotlin verifier and
    the researcher site's bundle reader do not replay the reducer and enforce the subset that needs no
    replay, which the protocol's Conformance section lists: for example the reducer cursor's bounds,
    the complete checkpoint upsert, one PROCESS_RECOVERY gap per recovery, and a recovery close at
    the recovery instant. A bundle that researcher-tools decrypt verifies can therefore still be
    quarantined by the analyzer, which names the rule, for example for a timer rendering or a
    deadline that only a replay can check.

  • The rules also accept RC13 shapes that come from platform failures and that no pilot export is
    known to contain yet: a pause or barrier in the same millisecond as a usage-events poll, whose
    flush covers the empty interval [t, t); a safety pause after the VPN is revoked or replaced,
    whose boundary audit cannot read the traffic counters and so records none; a stop whose resource
    release fails, which safety-pauses the PAUSING study and leaves it PAUSED without a deadline
    until Resume re-arms it; a process death while PAUSING, whose recovery re-arms the deadline; and
    a reboot without trusted UTC, whose recovery commit keeps the previous boot's clock anchor as
    committed_at. Each is reproduced by a checked-in RC13 export.

  • The recovery close is bound exactly. An epoch event's boundary must equal its observed time, and
    a recovery close must lie at the recovery instant, the time of its PROCESS_RECOVERY gap. Only
    that close may lie in a boot other than the activation's.

  • Parquet output renames six payload fields that share a name with a provenance or partition
    column to payload_<name>, as the data dictionary lists, and each json_string column holds the
    authenticated wire text.

  • An interventions.v1 row's source_condition_epoch_id is now the epoch in which its
    ACTION_REQUESTED was recorded, bound by the occurrence identity, instead of the epoch that
    contains its scheduled time. A survey requested at the 17:00 barrier therefore belongs to the
    closing epoch, not to the next one in which it is answered.

  • quality-summary.json lists each participant's condition epochs with their preparation bound,
    activation, and deactivation. Usage-events rows may begin at the preparation bound, before the
    epoch's resources were confirmed; exclude rows before activated_at to keep only time under the
    applied condition.

  • Eleven real exports are checked in under particeps-analysis/tests/fixtures/runtime-bundles/:
    ten from RC13 and one from this build, all encrypted to the public demonstration key. The Kotlin
    verifier and the site's reader must accept every one and each retained range that starts at a
    recovery or an epoch boundary, and particeps-analysis must also materialize each to Parquet.
    CI also runs this tree's runtime through a pilot-shaped week and passes its exports to both. That
    week includes barriers, pauses, a survey, process death, a reboot, clock changes, and the
    deadline stop. A change to the published pilot configuration now also runs the Android CI
    workflow, whose real-runtime test reads it.

  • The RC13 export-verification correction itself needs no phone update. It does not require a
    different event-source registry, bundle format, or reducer; existing RC13 exports verify as they are. Keep the original .partexp files and
    analyze them with this tree's particeps-analysis and researcher-tools. Keep the pilot phones
    on RC13 until the pilot ends: the fix is in the offline tools only.

Application update from v1.0.0-rc.13: install the signed RC17 APK over the existing
app without uninstalling or clearing its data; it does not change the application ID.

Local studies and exported data: there is no local-store migration, mandatory reset,
event-source-registry change, or bundle-format change from RC13: the runtime document layout and
the PTCRUN03, PTCPND03, and PTCENG03 frames are unchanged. Existing signed configurations stay
valid and do not need to be re-signed. Reopen the app after updating, complete normal recovery and
access checks, and explicitly Resume the study.

  • A study already started keeps its upload chain, re-armed at every process start as before. RC13
    armed automatic upload at import and could stage and send setup commits before Start. For a study
    still in setup when the phone updates, a leftover RC13 upload job now ends without sending, a
    bundle RC13 staged waits and is sent after Start under its original bundle ID, and setup commits
    RC13 already delivered stay delivered. When the phone holds an acknowledgement for them, the
    decline confirmation says that setup records were already sent and that declining does not take
    them back.
  • The update keeps the existing notification channels and any settings the participant changed. It
    does not change a channel's lock-screen setting; the fixed public version applies to each
    intervention notification this build posts.
  • The 5 s window applies to an existing signed configuration that meets its conditions as soon as
    the updated app runs it, including a study already under way. From then on, those sensors'
    committed_at values and the losses described above follow the windowed rules. A configuration
    whose automation matches the sensor, or that has any sequence or window state, keeps per-sample
    commits.
  • Participants who consented under RC13 read RC13's consent-screen wording; the new wording appears
    on the consent screen and on Study and my data after the update.
  • Collector code outside this repository that constructs EmitBatchResult.Accepted or
    CollectorContext must pass the new recordedEvents or requiresPromptCommits argument before
    it compiles against this tree.
  • Verify and materialize bundles from this build, and from RC13, with this tree's
    particeps-analysis and researcher-tools. For the same reduced inputs, both builds record the
    same condition-timer events for every commit in which no timer generation is armed and then
    retired or replaced before the commit ends. That includes every commit that reduces a single
    input, such as Start, Resume, or a one-event observation. Only a commit that reduces several
    inputs can differ: an observation or barrier whose events change a window_threshold or
    held_for timer more than once; a pause, completion, or withdrawal whose flushed events re-armed
    a timer that the stop then retires; recovery of a study left ACTIVATING or RUNNING, as after
    an app update, process death, or reboot while it runs, whose quality-gap reset re-arms each
    condition timer its still-active conditions need and whose safety pause retires it in the same
    commit; or a phone clock or time-zone change first seen after the deadline, which does the same
    before completing. For such a commit RC13 records every intent, the complete rendering: a
    TIMER_SCHEDULED for every generation it armed and, when the timer existed before the commit, a
    repeated TIMER_RETIRED for each retired generation. This build records the net rendering: that
    prior timer's retirement once and the resulting timer's schedule once. Protocol v1 admits exactly
    these two renderings for each commit and rejects a mixture, so this tree's tools accept RC13
    chains, chains from this build, and a chain started under RC13 and continued on this build. The
    five-day pilot's automation uses only study_local_window and study_session_active conditions,
    so its RC13 commits can differ only at such a stop, recovery, or late clock change; every RC13
    recovery of the running pilot is such a commit, because its resource bindings keep a window timer
    armed throughout the study. This build also groups inputs differently: it merges queued callbacks
    into one observation and splits a live batch at its first resource-changing event, so for
    automation that matches collector events the two builds need not make the same commits from the
    same callbacks.
  • Each RC13 recovery of a running study left a WorkManager wakeup for every condition timer it
    re-armed and retired. One whose target passes while the study runs retries until the next pause
    under RC13; after the update it ends at its next attempt.

Fresh install: install the signed RC17 APK, then scan a research-team QR code or import
its signed study file. Review the study and data collection, provide consent, complete required
access setup, and explicitly Start.

Verification scope: publication requires this tag's own Android 14 and Android 17 device gates,
Web/receiver/analysis checks, native race gate, release build and signing/packaging verification.
Earlier candidates' passing checks do not override a failure in this run. A complete 120-hour
physical-device endurance study has not been performed; per-device admission and daily readable
exports remain necessary.