Skip to content
Open
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
111 changes: 111 additions & 0 deletions .github/workflows/canvas-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Native Canvas Stall Audit

on:
pull_request:
paths:
- 'ios/**'
- 'src/**'
- 'app/**'
- 'vendor/**'
- 'package*.json'
- 'scripts/ci/**'
- 'scripts/ios/**'
- '.github/workflows/canvas-audit.yml'
workflow_dispatch:

permissions:
contents: read

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
canvas-interaction-audit:
name: iPad canvas interaction stall audit
runs-on: macos-15
timeout-minutes: 60
env:
IOS_SIMULATOR_FAMILY: ipad
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci --legacy-peer-deps
- run: node --test scripts/ci/verify-canvas-audit.test.mjs
- name: Select compatible native audit toolchain
run: echo "DEVELOPER_DIR=$(python3 scripts/ci/select-ios-toolchain.py)" >> "$GITHUB_ENV"
- name: Install iOS pods
run: pod install --project-directory=ios
- name: Resolve iPad simulator
run: echo "IOS_SIMULATOR_DESTINATION=$(node scripts/ci/resolve-ios-simulator.mjs)" >> "$GITHUB_ENV"
- name: Record toolchain and host conditions
run: |
xcodebuild -version
uname -m
uptime
xcrun simctl list runtimes
- name: Build native interaction tests
run: |
UITEST_FORCE_BUNDLING=1 xcodebuild build-for-testing \
-workspace ios/OpenNotes.xcworkspace -scheme OpenNotesIntegrity \
-derivedDataPath /tmp/opennotes-ui-deriveddata \
-destination "$IOS_SIMULATOR_DESTINATION" -parallel-testing-enabled NO \
ONLY_ACTIVE_ARCH=YES IPHONEOS_DEPLOYMENT_TARGET=15.1 COMPILER_INDEX_STORE_ENABLE=NO
- name: Seed owned 100-page lecture fixtures
run: |
simulator_id="${IOS_SIMULATOR_DESTINATION##*id=}"
python3 -c 'import subprocess,sys; subprocess.run(["xcrun", "simctl", "bootstatus", sys.argv[1], "-b"], check=True, timeout=180)' "$simulator_id"
xcrun simctl install "$simulator_id" /tmp/opennotes-ui-deriveddata/Build/Products/Release-iphonesimulator/OpenNotes.app
python3 scripts/seed-native-audit.py "$simulator_id"
- name: Run real native interaction workloads
id: interaction_workloads
run: |
xcodebuild test-without-building \
-workspace ios/OpenNotes.xcworkspace -scheme OpenNotesIntegrity \
-derivedDataPath /tmp/opennotes-ui-deriveddata \
-destination "$IOS_SIMULATOR_DESTINATION" -parallel-testing-enabled NO \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDensePagesAndKeyboardInteractionAudit \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDensePanZoomInteractionAudit \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDenseWritingDuringAutosaveInteractionAudit \
-only-testing:OpenNotesUITests/NotebookInteractionUITests/testStrokeCrossesPageBoundary \
-only-testing:OpenNotesUITests/NotebookInteractionUITests/testCrossPageAssetHistory \
-only-testing:OpenNotesUITests/NotebookInteractionUITests/testInvalidNativePayloadShowsRecoveryWithoutOverwritingNote \
-collect-test-diagnostics never
- name: Verify persisted lecture content
run: |
simulator_id="${IOS_SIMULATOR_DESTINATION##*id=}"
python3 -c 'import subprocess,sys; subprocess.run(["xcrun", "simctl", "bootstatus", sys.argv[1], "-b"], check=True, timeout=180)' "$simulator_id"
python3 scripts/verify-native-audit.py "$simulator_id"
- name: Validate native responsiveness and render budgets
id: canvas_budgets
if: always()
run: |
python3 scripts/ci/collect-canvas-audits.py "$RUNNER_TEMP/canvas-audit-reports"
node scripts/ci/verify-canvas-audit.mjs "$RUNNER_TEMP/canvas-audit-reports"
- name: Profile interactions that missed the budgets
if: ${{ failure() && steps.interaction_workloads.outcome == 'success' && steps.canvas_budgets.outcome == 'failure' }}
run: |
python3 scripts/ci/sample-canvas-process.py OpenNotes "$RUNNER_TEMP/canvas-audit-profiles" &
profile_pid=$!
trap 'kill "$profile_pid" 2>/dev/null || true; wait "$profile_pid" || true' EXIT
xcodebuild test-without-building \
-workspace ios/OpenNotes.xcworkspace -scheme OpenNotesIntegrity \
-derivedDataPath /tmp/opennotes-ui-deriveddata \
-destination "$IOS_SIMULATOR_DESTINATION" -parallel-testing-enabled NO \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDensePagesAndKeyboardInteractionAudit \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDensePanZoomInteractionAudit \
-only-testing:OpenNotesUITests/NotebookStallUITests/testDenseWritingDuringAutosaveInteractionAudit \
-collect-test-diagnostics never
- name: Preserve audit evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: canvas-interaction-audit
path: |
/tmp/opennotes-ui-deriveddata/Logs/Test
${{ runner.temp }}/canvas-audit-reports
${{ runner.temp }}/canvas-audit-profiles
if-no-files-found: warn
retention-days: 7
Loading
Loading