Skip to content
Merged
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
28 changes: 28 additions & 0 deletions .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,34 @@
{
"file": "src/cloud-webdriver.ts",
"exports": ["CLOUD_WEBDRIVER_PROVIDERS"]
},
{
"file": "src/daemon/handlers/lease.ts",
"exports": ["handleLeaseCommands"]
},
{
"file": "src/daemon/handlers/session.ts",
"exports": ["handleSessionCommands"]
},
{
"file": "src/daemon/handlers/snapshot.ts",
"exports": ["handleSnapshotCommands"]
},
{
"file": "src/daemon/handlers/react-native.ts",
"exports": ["handleReactNativeCommands"]
},
{
"file": "src/daemon/handlers/record-trace.ts",
"exports": ["handleRecordTraceCommands"]
},
{
"file": "src/daemon/handlers/find.ts",
"exports": ["handleFindCommands"]
},
{
"file": "src/daemon/handlers/interaction.ts",
"exports": ["handleInteractionCommands"]
}
],
"usedClassMembers": ["name", "listActiveLeases", "delete", "values", "elapsedMs", "isExpired"],
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ jobs:
FALLOW_BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
run: pnpm check:fallow --base "$FALLOW_BASE"

- name: Check for production-unused exports
run: pnpm check:production-exports

coverage:
# Runs the full unit + provider-integration suites under coverage with
# thresholds, so a separate unit-tests job would rerun the same tests.
Expand Down
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ intentionally accepting a finding.
- `pnpm fallow:all` — full-tree summary, includes grandfathered legacy findings
- `pnpm fallow:baseline` — regenerate baselines (only to intentionally accept a finding)

Code quality (production exports): `pnpm check:production-exports` runs Fallow's native
production graph, which excludes test/story/dev files, and fails when a new export has no
production consumer. This includes the test-only-export bug class that shipped in #1199's first
revision, while also catching exports that are unreachable from every graph. Fallow's
`ignoreExportsUsedInFile` option in the gate's inherited config keeps exports with a real
same-file consumer out of this report without weakening the general Fallow audit. The checked-in
native baseline lives at `fallow-baselines/production-unused-exports.json`.

Fix a finding by wiring the export into production or removing the unnecessary export/code. For
an intentional test seam, explain why in a source comment and put
`// fallow-ignore-next-line unused-export` directly above the export. Run
`pnpm check:production-exports:baseline` only for a deliberate reviewed baseline migration or to
remove stale entries; additions accept new production-unreachable exports and should be rare.
Production usage reached only through dynamic property access remains invisible to a static
import graph, so register those exports in `.fallowrc.json` `ignoreExports` instead (as with the
daemon route handlers loaded through `typeof import()`).

Optional device selectors for tests:

- `ANDROID_DEVICE=Pixel_9_Pro_XL` or `ANDROID_SERIAL=emulator-5554`
Expand Down
130 changes: 130 additions & 0 deletions fallow-baselines/production-unused-exports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"unused_files": [],
"unused_exports": [
"src/cli/parser/args.ts:parseArgs",
"src/cli/parser/command-suggestions.ts:listCommandAliasSuggestionEntries",
"src/cloud-webdriver/aws-device-farm.ts:getAwsDeviceFarmWebDriverCapabilities",
"src/cloud-webdriver/aws-device-farm.ts:createAwsDeviceFarmWebDriverRuntime",
"src/cloud-webdriver/browserstack.ts:getBrowserStackWebDriverCapabilities",
"src/cloud-webdriver/browserstack.ts:createBrowserStackWebDriverRuntime",
"src/commands/capture/index.ts:alertCliReader",
"src/commands/capture/index.ts:alertDaemonWriter",
"src/commands/capture/index.ts:diffCliReader",
"src/commands/capture/index.ts:screenshotCliReader",
"src/commands/capture/index.ts:screenshotDaemonWriter",
"src/commands/capture/index.ts:settingsCliReader",
"src/commands/capture/index.ts:settingsDaemonWriter",
"src/commands/capture/index.ts:snapshotCliReader",
"src/commands/capture/index.ts:waitCliReader",
"src/commands/capture/index.ts:waitDaemonWriter",
"src/commands/command-metadata.ts:listCommandMetadataNames",
"src/commands/command-surface.ts:listExecutableCommandNames",
"src/commands/index.ts:ref",
"src/commands/index.ts:selector",
"src/commands/index.ts:commands",
"src/commands/interaction/runtime/selector-read.ts:selector",
"src/commands/interaction/runtime/selector-read.ts:ref",
"src/core/command-descriptor/registry.ts:listDescriptorCatalogCommandNames",
"src/core/command-descriptor/registry.ts:listDescriptorDispatchCommandNames",
"src/core/command-descriptor/registry.ts:listCapabilityCheckedCommandNames",
"src/core/command-descriptor/registry.ts:listCommandResponseDataTransforms",
"src/core/dispatch.ts:listRegisteredDispatchCommandNames",
"src/core/platform-plugin/plugin.ts:registeredPlatforms",
"src/core/scroll-gesture.ts:buildSwipeGesturePlan",
"src/daemon/app-log.ts:APP_LOG_PID_FILENAME",
"src/daemon/app-log.ts:cleanupStaleAppLogProcesses",
"src/daemon/app-log.ts:assertAndroidPackageArgSafe",
"src/daemon/app-log.ts:buildAppleLogPredicate",
"src/daemon/app-log.ts:buildIosDeviceConsoleLaunchArgs",
"src/daemon/app-log.ts:buildIosSimulatorLogStreamArgs",
"src/daemon/client/daemon-client.ts:computeDaemonCodeSignature",
"src/daemon/client/daemon-client.ts:downloadRemoteArtifact",
"src/daemon/client/daemon-client.ts:cleanupFailedDaemonStartupMetadata",
"src/daemon/client/daemon-client.ts:resolveDaemonStartupHint",
"src/daemon/client/daemon-client.ts:canConnectSocket",
"src/daemon/client/daemon-client.ts:resolveDaemonRequestTimeoutMs",
"src/daemon/client/daemon-client.ts:shouldResetDaemonAfterRequestTimeout",
"src/daemon/handlers/find.ts:parseFindArgs",
"src/daemon/handlers/snapshot-capture.ts:buildSnapshotVisibility",
"src/daemon/lease-context.ts:buildLeaseDiagnosticsContext",
"src/daemon/runtime-hints.ts:resolveRuntimeTransportHints",
"src/kernel/contracts.ts:daemonCommandRequestSchema",
"src/kernel/contracts.ts:leaseAllocateSchema",
"src/kernel/contracts.ts:leaseHeartbeatSchema",
"src/kernel/contracts.ts:leaseReleaseSchema",
"src/kernel/device.ts:isPlatform",
"src/platforms/android/multitouch-helper.ts:resetAndroidMultiTouchHelperInstallCache",
"src/platforms/android/perf-frame.ts:parseAndroidFramePerfSample",
"src/platforms/android/perf.ts:parseAndroidFramePerfSample",
"src/platforms/android/snapshot-helper-artifact.ts:prepareAndroidSnapshotHelperArtifactFromManifestUrl",
"src/platforms/android/snapshot-helper-capture.ts:parseAndroidSnapshotHelperXml",
"src/platforms/android/snapshot-helper-install.ts:resetAndroidSnapshotHelperInstallCache",
"src/platforms/android/snapshot-helper-session.ts:resetAndroidSnapshotHelperSessions",
"src/platforms/android/snapshot-helper.ts:prepareAndroidSnapshotHelperArtifactFromManifestUrl",
"src/platforms/android/snapshot-helper.ts:verifyAndroidSnapshotHelperArtifact",
"src/platforms/android/snapshot-helper.ts:parseAndroidSnapshotHelperOutput",
"src/platforms/android/snapshot-helper.ts:parseAndroidSnapshotHelperXml",
"src/platforms/android/snapshot-helper.ts:resetAndroidSnapshotHelperSessions",
"src/platforms/android/snapshot-helper.ts:resolveAndroidSnapshotHelperSessionRequestTimeoutMs",
"src/platforms/android/snapshot-helper.ts:resetAndroidSnapshotHelperInstallCache",
"src/platforms/apple/core/app-resolution.ts:maybeResolveIosDevicectlHint",
"src/platforms/apple/core/apps.ts:shouldFallbackToRunnerForIosScreenshot",
"src/platforms/apple/core/apps.ts:shouldRetryIosSimulatorScreenshot",
"src/platforms/apple/core/devices.ts:createLocalAppleToolProvider",
"src/platforms/apple/core/devices.ts:withAppleToolProvider",
"src/platforms/apple/core/runner/runner-artifact.ts:ensureXctestrun",
"src/platforms/apple/core/runner/runner-client.ts:isRetryableRunnerError",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerEarlyExitHint",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerBuildFailureHint",
"src/platforms/apple/core/runner/runner-client.ts:shouldRetryRunnerConnectError",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerDestination",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerBuildDestination",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerMaxConcurrentDestinationsFlag",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerSigningBuildSettings",
"src/platforms/apple/core/runner/runner-client.ts:resolveRunnerBundleBuildSettings",
"src/platforms/apple/core/runner/runner-client.ts:assertSafeDerivedCleanup",
"src/platforms/apple/core/runner/runner-recycle-ledger.ts:resetRunnerRecycleLedgerForTests",
"src/platforms/apple/core/runner/runner-transport.ts:clearDeviceTunnelIpCache",
"src/platforms/apple/core/runner/runner-xctestrun.ts:ensureXctestrun",
"src/platforms/apple/core/runner/runner-xctestrun.ts:findXctestrun",
"src/platforms/apple/core/runner/runner-xctestrun.ts:scoreXctestrunCandidate",
"src/platforms/apple/core/runner/runner-xctestrun.ts:xctestrunReferencesProjectRoot",
"src/platforms/apple/core/runner/runner-xctestrun.ts:acquireRunnerXctestrunCacheLock",
"src/platforms/apple/core/runner/runner-xctestrun.ts:resolveRunnerCacheMetadataPath",
"src/platforms/apple/core/runner/runner-xctestrun.ts:shouldDeleteRunnerDerivedRootEntry",
"src/platforms/apple/core/runner/runner-xctestrun.ts:writeRunnerCacheMetadata",
"src/platforms/apple/core/runner/runner-xctestrun.ts:resolveRunnerPerformanceBuildSettings",
"src/platforms/apple/core/runner/runner-xctestrun.ts:resolveRunnerSandboxBuildArgs",
"src/platforms/apple/core/runner/runner-xctestrun.ts:resolveXcodebuildSimulatorDeviceSetPath",
"src/platforms/apple/core/screenshot.ts:prepareSimulatorStatusBarForScreenshot",
"src/platforms/install-source.ts:ARCHIVE_EXTENSIONS",
"src/platforms/linux/linux-env.ts:resetInputToolCache",
"src/provider-device-runtime.ts:setActiveProviderDeviceRuntimes",
"src/remote/remote-config.ts:resolveRemoteConfigPath",
"src/utils/ttl-memo.ts:resetAllProcessMemosForTests"
],
"unused_types": [],
"private_type_leaks": [],
"unused_dependencies": [],
"unused_dev_dependencies": [],
"circular_dependencies": [],
"re_export_cycles": [],
"unused_optional_dependencies": [],
"unused_enum_members": [],
"unused_class_members": [],
"unresolved_imports": [],
"unlisted_dependencies": [],
"duplicate_exports": [],
"type_only_dependencies": [],
"test_only_dependencies": [],
"boundary_violations": [],
"boundary_coverage_violations": [],
"boundary_call_violations": [],
"policy_violations": [],
"stale_suppressions": [],
"unused_catalog_entries": [],
"empty_catalog_groups": [],
"unresolved_catalog_references": [],
"unused_dependency_overrides": [],
"misconfigured_dependency_overrides": []
}
8 changes: 8 additions & 0 deletions fallow-production-exports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
"extends": ["./.fallowrc.json"],
"ignoreExportsUsedInFile": true,
"rules": {
"unused-exports": "warn"
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@
"check:fallow": "fallow audit",
"check:layering": "node --experimental-strip-types --test scripts/layering/model.test.ts && node --experimental-strip-types scripts/layering/check.ts",
"check:layering:baseline": "node --experimental-strip-types scripts/layering/check.ts --update-baseline",
"check:production-exports": "fallow dead-code --config fallow-production-exports.json --production --unused-exports --baseline fallow-baselines/production-unused-exports.json --fail-on-issues",
"check:production-exports:baseline": "fallow dead-code --config fallow-production-exports.json --production --unused-exports --save-baseline fallow-baselines/production-unused-exports.json --summary",
"check:quick": "pnpm lint && pnpm typecheck",
"sync:mcp-metadata": "node scripts/sync-mcp-metadata.mjs",
"check:mcp-metadata": "node scripts/sync-mcp-metadata.mjs --check",
"version": "node scripts/sync-mcp-metadata.mjs && git add server.json",
"check:tooling": "pnpm lint && pnpm typecheck && pnpm check:layering && pnpm check:mcp-metadata && pnpm build",
"check:tooling": "pnpm lint && pnpm typecheck && pnpm check:layering && pnpm check:production-exports && pnpm check:mcp-metadata && pnpm build",
"check:unit": "pnpm test:unit && pnpm test:smoke",
"check": "pnpm check:tooling && pnpm check:fallow && pnpm check:unit",
"prepack": "pnpm check:mcp-metadata && pnpm build:all && pnpm package:apple-runner:npm && pnpm package:android-snapshot-helper:npm && pnpm package:android-multitouch-helper:npm",
Expand Down
Loading