Skip to content

Rename the project to Particeps - #24

Merged
JacobLinCool merged 1 commit into
mainfrom
a/particeps-rename
Aug 6, 2026
Merged

Rename the project to Particeps#24
JacobLinCool merged 1 commit into
mainfrom
a/particeps-rename

Conversation

@JacobLinCool

@JacobLinCool JacobLinCool commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes #23.

Renames the entire project from Android Data Collector / ADC to Particeps — product, package identity, Protocol v1 wire names, artifact extensions, join URI, receiver contract, analysis package, Web authoring, researcher tooling, CI/release artifacts, and documentation — in one commit, so no revision of main claims to be Particeps while emitting ADC artifacts.

Naming contract

Was Now
Product Android Data Collector Particeps (PAR-ti-keps)
Gradle root project android-data-collector particeps
Application ID / Kotlin root package cool.linc.androiddatacollector cool.linc.particeps
Signed configuration .adccfg, ADCCFG01 .partcfg, PTCCFG01
Encrypted export .adcexp, ADCEXP01 .partexp, PTCEXP01
Join URI adc://join/v1 particeps://join/v1
Bundle format research-bundle-v1 particeps-research-bundle-v1
Upload media type application/vnd.adc.research-bundle application/vnd.particeps.research-bundle
Upload headers X-ADC-* X-Particeps-*
Python distribution / CLI adc-analysis particeps-analysis
Python import package adc_analysis particeps_analysis
Analysis key file adc-analysis-keys-v1 particeps-analysis-keys-v1
Release APK android-data-collector-<tag>.apk particeps-<tag>.apk

Additional ADC-derived identifiers found during implementation

The issue's contract asked for these to be added rather than silently retained:

  • On-device storage framing: ADCMET01/ADCTXN01/ADCEVT01/ADCACT01/ADCOUT01PTCMET01/PTCTXN01/PTCEVT01/PTCACT01/PTCOUT01, all still exactly eight ASCII bytes.
  • On-device filenames: events-NNNNNNNN.adcs.ptcs, .metadata.adc/.transaction.adc/active-study.adc.ptc. The suffix mirrors the magic in each file's header.
  • Corpus and format identities: adc-protocol-conformance-v1, adc-join-link-conformance-v1, adc-collector-catalog-v1, adc-ciphertext-inventory-v1, adc-parquet-dataset-v1, adc-quality-summary-v1, adc-validation-report-v1, adc-active-study-v1particeps-*.
  • Parquet column metadata keys adc.type/adc.unit/adc.meaning/adc.collector_id/adc.payload_type/adc.payload_schema_version/adc.clock_basisparticeps.*.
  • Key-ID derivation domains adc:signer-key-id:v1: / adc:export-key-id:v1:particeps:… (27 ASCII bytes each, was 21).
  • Keystore aliases, WorkManager unique work names and tags, HandlerThread names, staging-file prefixes, Gradle system properties (adc.repository.root, adc.appProjectDir), the browser locale key adc.locale, the Kotlin conformance package adc.conformance, and the npm package @adc/ciphertext-receiver.

Fresh-install boundary

The applicationId change makes this a different Android application. There is no upgrade, no migration, and no shared Keystore namespace: a pre-rename RC install must be uninstalled separately, and its studies, keys, encrypted segments, and staged upload bodies go with it. That is documented in the README, the participant guide, and as invariant 8 in the implementation contract — which also records why renaming the on-device names was safe in this commit and only in this commit.

The release signing key and certificate are unchanged.

Protocol v1

schema_version stays 1; there is no v2, no alias, no compatibility decoder, no converter. The complete conformance corpus was regenerated with node tools/generate_protocol_vectors.mjs — hand-editing it is not possible, since particeps-research-bundle-v1 is authenticated as HPKE info and AES-GCM associated data and is ten bytes longer than the name it replaces. The ADCCFG01/ADCEXP01 magics are length-preserving, so no binary offset moved.

The retired identity now has executable fail-closed coverage rather than merely being absent:

  • partcfg-retired-product-magic and bundle-retired-product-magic — valid frames with only the magic set back to ADCCFG01/ADCEXP01.
  • bundle-retired-bundle-format — an authenticated bundle whose inner format is research-bundle-v1, so only the format check can reject it.
  • join-retired-product-scheme — an otherwise-valid join link whose only defect is adc://.
  • Receiver rejection cases for X-ADC-Extra, X-ADC-Bundle-Format, the retired research-bundle-v1 value, and application/vnd.adc.research-bundle.
  • Web and Android import tests that overwrite the magic of an otherwise-valid artifact, so the tests prove identity rejection rather than only truncation rejection.

These are the only places old names survive, and each carries a comment marking it a retired-identity rejection fixture so a future sweep does not "fix" it.

Regenerated, not edited

  • protocol/v1/conformance-vectors.json
  • core/collector-api/.../ProtocolEventContracts.kt (tools/catalog.py generate-kotlin)
  • app/src/debug/res/raw/demo_study_envelope.txt — re-signed, because demo-study.json's researcher name is inside the Ed25519-signed canonical bytes
  • particeps-analysis/uv.lock

Two guards against decay

The rename exposed two things nothing in the tree was checking, and both now fail the build rather than relying on care:

  • tools/retired_identity_audit.py searches every tracked file for every retired spelling and fails on any match outside a reviewed allow-list that states, per file, why the old name must stay. It also pins applicationId/namespace to cool.linc.particeps and refuses any source reference to the retired namespace — which is the acceptance criterion "the boundary is documented and tested", expressed as something executable. Wired into ci.yml and release.yml, with its own unit tests.
  • The upload request vocabulary (media type, bundle format, seven routing header names) is the one part of Protocol v1 whose producer is Kotlin and whose only reader is TypeScript. Each side previously asserted against its own constants, which passes however either is spelled. It is now valid.upload_request in the shared corpus, and both sides assert against that. Both assertions were negative-checked: renaming one header on either side fails its suite.

Verification

  • ./gradlew test testDebugUnitTest lintDebug assembleDebug assembleRelease — pass
  • Kotlin vectors: :core:export:test --tests particeps.conformance.ProtocolConformanceTest — pass
  • python3 tools/catalog.py check, tools/catalog_parity.py, tools/validate_protocol_vectors.py, tools/collector_assurance.py, tools/tests — pass
  • Web check + test + shared TypeScript conformance + generate_protocol_vectors.mjs --check — pass
  • Receiver typecheck + unit + workerd — pass
  • Analysis ruff check + full offline pipeline suite — pass
  • python3 tools/retired_identity_audit.py — pass (16 reviewed exceptions)
  • Emulator (Pixel_10_Pro, API 37): :core:storage:connectedDebugAndroidTest + :app:connectedDebugAndroidTest — 10/10 pass
  • web pnpm run e2e (browser authoring → signed .partcfg → the app's own Kotlin verifier accepts it) — pass. pnpm run e2e:units — pass. pnpm run e2e:one-line fails on seven collector-description strings, which main fails identically; unrelated and pre-existing.

Not in this PR

  • Renaming the GitHub repository to particeps (do it after merge; badges, links, and the Pages BASE_PATH are already prepared for the new URL).
  • The post-rename release candidate tag.
  • CITATION.cff version/date-released, which are intentionally absent until the first post-rename tag.

@changeset-bot

changeset-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f90b7cd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Replace the Android Data Collector / ADC identity everywhere it is maintained:
the product name, the Gradle root project, the Android applicationId and Kotlin
root package, the Protocol v1 wire names, the artifact extensions, the join URI,
the receiver contract, the offline analysis package, Web authoring, researcher
tooling, CI and release artifacts, and the documentation. One commit, so no
revision of main claims to be Particeps while emitting ADC artifacts.

Protocol v1 keeps schema_version 1 and gains no second dialect. PTCCFG01 and
PTCEXP01 replace ADCCFG01 and ADCEXP01 at the same eight bytes, so no binary
offset moves; particeps-research-bundle-v1 replaces research-bundle-v1 and is
ten bytes longer, and because it is authenticated as HPKE info and AES-GCM
associated data the whole conformance corpus was regenerated rather than
edited. The retired identity now has executable fail-closed coverage in Kotlin,
TypeScript, and Python rather than merely being absent: retired magics, the
retired bundle format, the retired join scheme, retired routing headers, and
the retired media type each have a hostile vector or rejection test, and every
surviving old literal carries a comment saying so.

The implementation surfaced ADC-derived identifiers the issue's contract did
not list, and they are renamed here rather than silently retained: the
on-device frame magics and file suffixes, the corpus and dataset format
identities, the Parquet column metadata keys, the key-ID derivation domains,
the Keystore aliases, the WorkManager work names and tags, the Gradle system
properties, the browser locale key, the Kotlin conformance package, and the
receiver's npm package name.

Moving applicationId to cool.linc.particeps makes this a different Android
application. There is no upgrade, no migration, and no shared Keystore
namespace; a pre-rename install is removed separately and its studies, keys,
encrypted segments, and staged upload bodies go with it. That boundary is what
made renaming the on-device names safe, and it is recorded in the README, the
participant guide, and invariant 8 of the implementation contract so a later
reviewer does not lift one of those renames out of context. The release signing
key and certificate are unchanged.

Two guards keep the rename from decaying. tools/retired_identity_audit.py fails
the build on any retired spelling outside a reviewed, reasoned allow-list, and
pins the applicationId, so the fresh-install boundary is tested and not only
documented. The upload request vocabulary — media type, bundle format, and the
seven routing header names — is now a shared corpus fixture that the Kotlin
emitter and the TypeScript receiver each assert against, because it was the one
part of the wire contract whose producer and only reader could be renamed
independently without any test noticing.

Regenerated rather than edited: the conformance corpus, the collector-catalog
Kotlin contract, the demo signed envelope (the researcher name it carries is
inside the Ed25519-signed canonical bytes), and the analysis lockfile.

Closes #23.
@JacobLinCool

Copy link
Copy Markdown
Owner Author

Emulator validation

Pixel_10_Pro AVD, API 37, on the merged tree at f90b7cd.

:core:storage:connectedDebugAndroidTest + :app:connectedDebugAndroidTest
  Pixel_10_Pro(AVD) - 17   Tests 10/10 completed. (0 skipped) (0 failed)
  BUILD SUCCESSFUL

Identity, checked on the device rather than in the source:

$ adb shell pm list packages | grep -iE 'particeps|androiddatacollector'
package:cool.linc.particeps

$ aapt2 dump badging app-debug.apk | grep -E '^package|application-label:'
package: name='cool.linc.particeps' versionName='1.0.0-dev'
application-label:'Particeps'

The join scheme is routable under the new name and unroutable under the old one — the retired
scheme fails closed at Android's own resolution layer, before any of our code runs:

$ cmd package resolve-activity --brief -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE -d 'particeps://join/v1?artifact=x&sha256=y&signer_fingerprint=z'
cool.linc.particeps/.MainActivity

$ cmd package resolve-activity --brief -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE -d 'adc://join/v1?artifact=x&sha256=y&signer_fingerprint=z'
No activity found

The launcher, the header before any study is imported, and the app label all read Particeps;
header_no_study is now @string/app_name rather than a second name for the product.

Loading the demo study on the device verifies the regenerated signed envelope end to end: the
setup flow opens on "Modular sensing demonstration" with researcher "Particeps maintainers", which
is the string that sits inside the Ed25519-signed canonical bytes and therefore required re-signing
rather than editing.

Not yet done, and deliberately so

Renaming the GitHub repository, and the post-rename release candidate tag. Both belong after this
merges — #23 asks for the repository rename only once main carries a tree that is ready for the
new URL, and docs/maintainers/release.md now carries the ordered checklist for finishing the
cutover.

@JacobLinCool
JacobLinCool merged commit 6703bc3 into main Aug 6, 2026
5 checks passed
@JacobLinCool
JacobLinCool deleted the a/particeps-rename branch August 6, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rename the entire project to Particeps before v1.0.0

1 participant