| type | Reference | |||||
|---|---|---|---|---|---|---|
| title | Agent command policy | |||||
| description | Canonical allowlist for agent shell commands — Gradle, scripts, emulator, and validation. Supersedes improvised diagnostics. | |||||
| tags |
|
|||||
| timestamp | 2026-07-31 00:00:00 UTC |
Single source for which shell commands agents may run in this repo. E2e is a subset of this policy; running e2e § e2e agent rule adds e2e-specific prohibitions.
If a command is not listed here (or linked from here as canonical), do not run it — including “diagnostic probes” suggested by log output, module READMEs, or Gradle task help.
- Run only commands in the registry below (repo root unless noted).
- Prefer
./scripts/build.shfor the CI-equivalent unit build/test path (step list: Android CI). Do not invent alternate Gradle task graphs that skipcheckstyleor re-include:e2eTestunit tests in the unit CI path.build.shis the unit path only — lint and e2e are separate gates with their own workflows, so a greenbuild.shis not a green CI. - When a canonical command fails: read the full output, fix product code (or environment prerequisites), re-run the same command. Do not switch invocation style.
- Do not infer alternate commands from error strings — see known traps.
- Subagents (Task, explore, orchestrator): same rule — paste the handoff block into every FirebaseUI-Android task prompt.
| Intent | Command | Never use instead |
|---|---|---|
| Full CI unit path (assemble + checkstyle + unit tests) | ./scripts/build.sh |
Ad-hoc ./gradlew clean assembleDebug test without checkstyle; inventing a different exclusion set |
| Unit tests (all library modules; exclude e2eTest) | ./gradlew testDebugUnitTest -x :e2eTest:testDebugUnitTest |
Bare ./gradlew test (pulls wrong tasks / e2e); IDE-only as the agent gate |
Unit tests (one module with a real src/test suite) |
./gradlew :<module>:testDebugUnitTest (e.g. :auth:testDebugUnitTest, :firestore:…, :storage:…) |
:common:testDebugUnitTest / :database:testDebugUnitTest as “green” evidence (empty suites — empty unit-suite trap); full suite when only one module changed as a substitute for the CI path at handoff |
| Assemble one module (when no JVM unit suite) | ./gradlew :<module>:assembleDebug (e.g. :database, :common) |
Treating empty testDebugUnitTest as validation |
| Checkstyle (Java only) | ./gradlew checkstyle |
Invented ktlint/detekt entrypoints; treating a green checkstyle as style coverage for Kotlin sources (Kotlin blind spot) |
Android Lint (all gated modules) — not in build.sh, own workflow |
./gradlew lintAll |
Bare ./gradlew lint / lintDebug (pulls :app and :e2eTest, which declare no lint { } block yet); assuming a green build.sh covered lint |
| Android Lint (one module) | ./gradlew :<module>:lintDebug (:proguard-tests uses lintRelease) |
Editing Kotlin in a gated module without re-running lint |
| Accept new lint debt (needs a human decision) | ./gradlew :auth:updateLintBaseline |
Running this to make a red build green — see lint baseline trap |
| Assemble debug | ./gradlew assembleDebug |
Module-scoped assemble as the only CI substitute at handoff |
| Install demo app | ./gradlew :app:installDebug |
Manual APK sideload scripts |
| Start Auth emulator (e2e prerequisite) | ./scripts/start-firebase-emulator.sh |
Bare firebase emulators:start with invented flags/ports; starting Firestore/Database emulators “just in case” |
| E2e suite | ./gradlew e2eTest (emulator already up) |
./gradlew :e2eTest:testDebugUnitTest as a silent substitute without understanding the custom task; inventing Espresso/connectedCheck for this suite |
| CI failure logs | ./scripts/print_build_logs.sh |
Truncating Gradle logs / guessing from partial output |
| Local Maven publish (optional local verify only) | ./gradlew :library:prepareArtifacts publishToMavenLocal |
Treating this as the Maven Central release procedure (releasing.md owns release); remote publish unless the user explicitly requested a release |
| Validation sequence | validation checklist | Partial one-off task lists that omit checkstyle or the e2e exclusion |
- JDK 21+ (CI uses Temurin 21) — CONTRIBUTING.md.
- Android SDK with min API aligned to
Config.SdkVersions.mininbuildSrc. - E2e also needs Node.js, npm, firebase-tools, and jq (script preflights firebase/node/npm;
jqis required to parsee2eTest/.firebaserc/firebase.jsonbut is not preflight-checked — running e2e).
./scripts/build.sh copies library/google-services.json → app/ and proguard-tests/. Prefer the script over hand-copying. Replace library/google-services.json only when intentionally pointing the demo/proguard modules at a different Firebase project.
- Re-run from repo root with the same canonical command (full log — do not truncate). On CI-shaped failures, also run
./scripts/print_build_logs.sh. - Fix product code or missing prerequisites (JDK, SDK, emulator online).
- Re-run the same command.
- Do not “verify tooling” with invented Gradle flags, alternate tasks, or skipping checkstyle/lint.
| Command / pattern | Why |
|---|---|
Improvised ./gradlew … graphs not in the registry or validation checklist |
Wrong task / cwd / exclusions; invents CI that does not match .github/workflows |
Including :e2eTest:testDebugUnitTest in the unit CI path without an emulator |
E2e suite expects Auth emulator; unit CI explicitly excludes it (scripts/build.sh) |
Bare firebase emulators:start with custom ports |
Ports and project ID come from e2eTest/firebase.json / .firebaserc via the start script |
connectedAndroidTest / device Espresso as a substitute for e2eTest |
Canonical e2e is Robolectric + emulator via ./gradlew e2eTest |
Invented formatters (ktlintFormat, random spotlessApply) as the style gate |
Canonical gates are ./gradlew checkstyle (Java) and ./gradlew lintAll (everything else) |
updateLintBaseline to clear a lint failure you introduced |
The baseline records pre-existing debt only — see lint baseline trap |
| Publishing to Maven Central / Sonatype unless the user explicitly requested a release | Release process is human-gated — repo tooling |
- Unit CI runs
testDebugUnitTest -x :e2eTest:testDebugUnitTest. - E2e CI starts the Auth emulator, then runs the custom Gradle task
e2eTest(registered ine2eTest/build.gradle.kts), not a connected device suite. - Running
:e2eTest:testDebugUnitTestwithout the emulator is not the CI e2e path.
:commonhas no test source set.:databasehas onlyandroidTest(nosrc/test)../gradlew :common:testDebugUnitTest/:database:testDebugUnitTestcan exit 0 with zero tests — that is not validation evidence.- Modules with real JVM unit suites today:
:auth,:firestore,:storage(and:e2eTestvia the custome2eTesttask, not the unit CI path). - Instrumented
connectedAndroidTestis forbidden as an Auth e2e substitute and is not an allowlisted database/firestore gate (not run inandroid.yml). Module matrix: validation checklist.
- Root
build.gradle.ktsscopes thecheckstyletask withinclude("**/*.java"). :auth,:appand:e2eTestare Kotlin../gradlew checkstyleinspects zero files there and exits 0.- A green
checkstyleon a Kotlin-only diff is not evidence of anything../gradlew lintAllis the gate that reads Kotlin (via UAST).
- Observed once:
Unexpected failure during lint analysis of Bean.java (this is a bug in lint…), aFileNotFoundExceptionon a:databaseannotation-processor output underbuild/generated/ap_generated_sources/. It did not reproduce on an immediate re-run. - It is a race between annotation-processor regeneration and lint analysis that
--rerun-tasksmakes possible. Re-run the same command before investigating; treat a single red--rerun-tasksrun naming a module you did not touch as suspect, not as a finding. - Plain
./gradlew lintAll(no--rerun-tasks) has not shown it.
auth/lint-baseline.xmlsuppresses 180 pre-existing findings (localization: CPRN-432; Compose: CPRN-436). It is the only baseline in the repo — every other gated module is clean and declares nobaseline.warningsAsErrors = trueandabortOnError = truein every gated module, so a new finding fails the build hard. That is the point.- Running
updateLintBaselineto absorb a finding your change introduced defeats the gate. Fix the code instead; regenerating the baseline is a human decision tied to a tracked issue. - A baseline's
file=paths are recorded relative to the module that produced them, andupdateLintBaselinerewrites the whole file per module — so a shared baseline silently misbehaves in both directions. The oldlibrary/quality/lint-baseline.xmlhad one entry (src/main/AndroidManifest.xml) that matched any module's manifest and one (auth/src/main/res/...) recorded root-relative that matched none, which is why every module reportedLintBaselineFixed. Keep baselines per module.
- .github/PULL_REQUEST_TEMPLATE.md mentions
./gradlew check(stale vs current CI). - Agents: treat
./scripts/build.shas the CI-matching unit path — Android CI. Full handoff (including e2e when Auth UI touched): validation checklist.
- See Android CI §
build.sh—proguard-tests:buildis commented out; green unit CI does not prove ProGuard/R8.
- Locally,
./scripts/start-firebase-emulator.shruns the emulator in the foreground (blocking). Start it in a separate terminal (or backgrounded shell the agent can leave running), then run./gradlew e2eTestin another. - In CI (
CIset), the script backgrounds the emulator and waits untilFIREBASE_AUTH_EMULATOR_URLresponds.
Paste into Task / explore / work-queue prompts:
FirebaseUI-Android agent command policy: okf-bundle/testing/agent-command-policy.md ONLY.
Unit CI path: ./scripts/build.sh (or the exact gradle tasks it runs) — never invent alternate graphs.
Unit tests: ./gradlew testDebugUnitTest -x :e2eTest:testDebugUnitTest OR ./gradlew :<module>:testDebugUnitTest only for modules with src/test (auth/firestore/storage). Never treat :common/:database testDebugUnitTest as evidence (empty suites).
Style: ./gradlew checkstyle (Java only — it inspects zero files in Kotlin modules) AND ./gradlew lintAll (Android Lint, covers Kotlin; separate workflow, NOT run by build.sh). Do not invent ktlint/detekt entrypoints.
Never run updateLintBaseline to silence a failure you caused; the baseline is pre-existing debt only.
E2e: ./scripts/start-firebase-emulator.sh then ./gradlew e2eTest — okf-bundle/testing/running-e2e.md.
Never: bare firebase emulators:start with invented ports; connectedCheck as e2e substitute; Maven Central publish unless user asked.
On failure: fix product code / prerequisites, re-run the same canonical command; use ./scripts/print_build_logs.sh for CI-shaped failures.
Gate close / push: return validation evidence package from okf-bundle/testing/validation-checklist.md — required before commit or publication (okf-bundle/testing/change-authoring-workflow.md#validation-evidence-blocking).
| Topic | Owner |
|---|---|
| E2e commands, emulator, narrowing | running-e2e.md |
| Handoff validation sequence | validation-checklist.md |
| Work types and gates | change-authoring-workflow.md |
| Doc / commit policy | documentation-policy.md |
| CI job shape | ci-workflows/index.md |