Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ This directory contains the CI/CD workflows for the Letterbox project. The workf

**Jobs:**
- **lint-and-test**: Runs Rust format checks, Rust tests, Android lint, and Android unit tests
- **build**: Builds debug and release APKs with native libraries for all architectures
- **build**: Builds staging debug and prod release APKs with native libraries for all architectures

**Outputs:**
- `debug-artifact-name`: Name of the uploaded debug APK artifact
- `release-artifact-name`: Name of the uploaded release APK artifact
- `test-artifact-name`: Name of the uploaded staging debug APK artifact
- `prod-release-artifact-name`: Name of the uploaded prod release (unsigned) APK artifact

### 2. `android-ui.yml` - Android UI Tests
**Trigger:** On completion of the Build workflow (via `workflow_run`).
Expand Down Expand Up @@ -120,13 +120,21 @@ The `android-ui.yml` workflow runs instrumented tests using Gradle Managed Devic

```bash
# Run UI tests locally
./gradlew pixel7Api34DebugAndroidTest
./gradlew pixel7Api34StagingDebugAndroidTest
```

Test files are located in `app/src/androidTest/java/com/btreemap/letterbox/`:
Test files are located in `app/src/androidTest/java/org/joefang/letterbox/`:
- `HomeScreenTest.kt` - Core UI element tests
- `NavigationTest.kt` - Navigation flow tests
- `BackNavigationTest.kt` - Back navigation behavior tests
- `AccessibilityTest.kt` - Accessibility compliance tests
- `EmailDetailScreenTest.kt` - Email detail screen tests
- `EmailOpeningE2ETest.kt` - End-to-end email opening tests
- `AttachmentInteractionE2ETest.kt` - Attachment interaction tests
- `HistoryFeaturesE2ETest.kt` - History feature tests
- `LinkHandlingE2ETest.kt` - Link handling tests
- `CloudflareTermsConsentE2ETest.kt` - Cloudflare consent flow tests
- `ImageProxyIntegrationTest.kt` - Image proxy integration tests

## Artifact Retention Policies

Expand Down
9 changes: 9 additions & 0 deletions .jules/atlas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Atlas Journal — Critical Learnings

## 2026-02-27 - Package path mismatch pattern
**Learning:** The Android package is `org.joefang.letterbox` (see `app/build.gradle.kts` applicationId), but the GitHub org is `BTreeMap`. Documentation that references file paths may use the wrong package path (e.g., `com/btreemap/letterbox` instead of `org/joefang/letterbox`). Always verify package paths against the actual `applicationId` in `build.gradle.kts`.
**Action:** When auditing docs that reference Java/Kotlin file paths, cross-check against `applicationId` in `app/build.gradle.kts` and the actual directory structure.

## 2026-02-27 - Cargo workspace has two crates, not one
**Learning:** The Cargo workspace includes both `rust/letterbox-core` and `rust/letterbox-proxy`. Documentation and CI both build/test these independently. Any doc claiming to describe the Rust workspace should mention both crates.
**Action:** When auditing Rust-related docs, verify all workspace members from `Cargo.toml` are mentioned.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ Letterbox is an Android application built with Jetpack Compose that opens and in

- `app/`: Android application module, Compose UI, Room data layer, UniFFI bindings, and Gradle tasks to build native artifacts.
- `rust/letterbox-core/`: Rust library that parses emails with `mail-parser` and exposes UniFFI bindings for Kotlin/Android.
- `rust/letterbox-proxy/`: Rust library implementing a privacy-preserving image proxy using Cloudflare WARP.
- `docs/`: Project documentation (architecture, troubleshooting, versioning, signing, and more).
- `gradle/`, `build.gradle.kts`, `settings.gradle.kts`: Gradle wrapper and version catalog configuration for the Android project.
- `Cargo.toml`: Rust workspace definition pointing to `rust/letterbox-core`.
- `Cargo.toml`: Rust workspace definition for `rust/letterbox-core` and `rust/letterbox-proxy`.
- `LICENSE`: MIT license for the project.

## Quickstart
Expand Down
134 changes: 134 additions & 0 deletions scripts/check-doc-drift.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
# check-doc-drift.sh — Detect documentation drift for key CI/workflow claims.
#
# Usage: ./scripts/check-doc-drift.sh
#
# Exits 0 if all checks pass, 1 if any drift is detected.
# Run this locally or in CI to prevent docs from silently going stale.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WORKFLOWS_README="$REPO_ROOT/.github/workflows/README.md"
ROOT_README="$REPO_ROOT/README.md"
BUILD_YML="$REPO_ROOT/.github/workflows/build.yml"
UI_YML="$REPO_ROOT/.github/workflows/android-ui.yml"
CARGO_TOML="$REPO_ROOT/Cargo.toml"
ANDROID_TEST_DIR="$REPO_ROOT/app/src/androidTest/java/org/joefang/letterbox"

ERRORS=0

fail() {
echo "❌ DRIFT: $1"
ERRORS=$((ERRORS + 1))
}

pass() {
echo "✅ $1"
}

echo "=== Documentation Drift Check ==="
echo ""

# --- 1. Workflow output names in workflows README must match build.yml ---
echo "--- Checking build.yml output names in workflows README ---"

for output_name in "test-artifact-name" "prod-release-artifact-name"; do
if grep -qF "$output_name" "$BUILD_YML" && grep -qF "$output_name" "$WORKFLOWS_README"; then
pass "Workflow output '$output_name' found in both build.yml and workflows README"
elif ! grep -qF "$output_name" "$BUILD_YML"; then
fail "Workflow output '$output_name' referenced in README but not in build.yml"
else
fail "Workflow output '$output_name' exists in build.yml but missing from workflows README"
fi
done

# Check for stale output names that no longer exist in build.yml
# Use word-boundary-aware matching to avoid false positives from substrings
for stale_name in "debug-artifact-name" "release-artifact-name"; do
# Match the stale name as a standalone backtick-delimited identifier (e.g. `debug-artifact-name`)
if grep -qP '(?<!\w)'"$stale_name"'(?!\w)' "$WORKFLOWS_README" && ! grep -qP '(?<!\w)'"$stale_name"'(?!\w)' "$BUILD_YML"; then
fail "Stale output name '$stale_name' found in workflows README but not in build.yml"
fi
done

echo ""

# --- 2. UI test command in workflows README must match android-ui.yml ---
echo "--- Checking UI test command ---"

# Extract the Gradle task from android-ui.yml
UI_TASK=$(grep -oP '\./gradlew \K\S+' "$UI_YML" | head -1)
if [ -n "$UI_TASK" ]; then
if grep -qF "$UI_TASK" "$WORKFLOWS_README"; then
pass "UI test task '$UI_TASK' matches in workflows README"
else
fail "UI test task in android-ui.yml is '$UI_TASK' but not found in workflows README"
fi
else
fail "Could not extract UI test task from android-ui.yml"
fi

echo ""

# --- 3. Test file path in workflows README must use correct package ---
echo "--- Checking androidTest file path ---"

if [ -d "$ANDROID_TEST_DIR" ]; then
if grep -qF "org/joefang/letterbox" "$WORKFLOWS_README"; then
pass "Correct package path 'org/joefang/letterbox' in workflows README"
else
fail "Workflows README does not reference correct test path 'org/joefang/letterbox'"
fi
# Check for stale wrong package path
if grep -qF "com/btreemap/letterbox" "$WORKFLOWS_README"; then
fail "Stale package path 'com/btreemap/letterbox' found in workflows README"
fi
else
fail "Android test directory not found at expected path: $ANDROID_TEST_DIR"
fi

echo ""

# --- 4. All androidTest .kt files should be listed in workflows README ---
echo "--- Checking androidTest file listing ---"

if [ -d "$ANDROID_TEST_DIR" ]; then
for kt_file in "$ANDROID_TEST_DIR"/*.kt; do
kt_filename=$(basename "$kt_file")
if grep -qF "$kt_filename" "$WORKFLOWS_README"; then
pass "Test file '$kt_filename' listed in workflows README"
else
fail "Test file '$kt_filename' exists but is not listed in workflows README"
fi
done
fi

echo ""

# --- 5. Cargo workspace members in README must match Cargo.toml ---
echo "--- Checking Cargo workspace members in README ---"

# Extract workspace members from Cargo.toml
CARGO_MEMBERS=$(grep -oP '"rust/[^"]+"' "$CARGO_TOML" | tr -d '"')
for member in $CARGO_MEMBERS; do
crate_name=$(basename "$member")
if grep -qF "$member" "$ROOT_README"; then
pass "Workspace member '$member' mentioned in README"
else
fail "Workspace member '$member' from Cargo.toml not mentioned in README"
fi
done

echo ""

# --- Summary ---
echo "=== Summary ==="
if [ "$ERRORS" -eq 0 ]; then
echo "All documentation checks passed! ✅"
exit 0
else
echo "$ERRORS drift issue(s) detected. ❌"
echo "Please update the documentation to match the repo source of truth."
exit 1
fi
Loading