chore: remove dead type re-exports, prune stale suppressions, gate unused-types (#1364)

* chore: remove dead type re-exports and gate unused-types

Clears the 72 `unused-types` findings left by #1363 and flips
`rules.unused-types` from `warn` to `error` so new ones cannot creep in.
Every fallow detector is now at zero.

71 of the findings were re-export lines (`export type { X } from './y.ts'`
with no importer of X through that path); one was a direct declaration
(`HelpTopicName`, zero references anywhere).

Removing them cascaded, which is the point: imports that existed only to
feed a re-export became unused (8 of them, caught by `noUnusedLocals`), and
clearing those exposed a further chain through `command-projection.ts` ->
`batch/index.ts` -> `batch/projection.ts`. Also updated a comment in
`batch-policy.ts` that described the `command-surface.ts` re-export path
this removes, and dropped two `export type {}` husks left where every name
in a block was dead.

One finding was NOT what it looked like: fallow flagged `DebugSymbolsOptions`
and `DebugSymbolsResult` in `apple/core/debug-symbols/types.ts`, but removing
them broke `apple/core/debug-symbols.ts`, which re-exported them from there.
Both ends were dead — every real consumer imports from
`contracts/debug-symbols.ts` — so the fix was removing the intermediate
re-export too, not restoring the leaf.

Safety: the published type surface is unchanged. All 11 entry points in
package.json#exports export exactly the same names before and after. Two
chunk files differ only because `AndroidSnapshotBackendMetadata` relocated
between internal code-splitting chunks, which is not a consumer-visible
boundary.

* chore: prune fallow suppressions that no longer suppress anything

The whole point of this arc was that fallow looked clean mainly because of
its own ignore list, so the list itself deserved an audit. Emptying
`ignoreExports` and re-running shows most entries no longer match a real
finding: 20 blocks collapse to 5, with no change in what either fallow
invocation reports.

Removed 8 fully-stale blocks. They went stale for three different reasons:
- code moved (`assertSafeDerivedCleanup` is exported from runner-cache.ts,
  not the runner-xctestrun.ts the suppression named),
- the exports became genuinely used (apps.ts, runner-contract.ts,
  runner-session.ts, cloud-webdriver.ts, the test-utils fixtures),
- and `installAndroidInstallablePath` was suppressed in two places at once.

`app-lifecycle.ts` needed a code fix rather than a suppression: it
re-exported three `parseAndroid*` helpers from app-parsers.ts that nothing
imports through it, so the re-export is dropped and the block goes away.
The two type re-exports on that statement ARE consumed and stay.

The seven `src/daemon/handlers/*` blocks are KEPT, collapsed into one
documented glob. They are not stale: those handlers are reached only
through the dynamic `import()` table in request-handler-chain.ts, which the
--production analysis behind `check:production-exports` cannot follow. A
first pass removed them because the staleness probe only exercised the
default config; the repo runs fallow twice, and `check:production-exports`
caught it.
This commit is contained in:
Michał Pierzchała
2026-07-22 18:17:59 +02:00
committed by GitHub
parent c0fc822e80
commit 317469f35a
33 changed files with 29 additions and 223 deletions
+9 -102
View File
@@ -36,12 +36,6 @@
"@theme"
],
"ignoreExports": [
{
"file": "src/__tests__/test-utils/index.ts",
"exports": [
"*"
]
},
{
"comment": "Authoritative supported-command list; sole consumer is the conformance oracle (scripts/maestro-conformance, an ignored tooling tree).",
"file": "src/compat/maestro/program-ir-command-parser.ts",
@@ -50,102 +44,15 @@
]
},
{
"file": "src/__tests__/test-utils/device-fixtures.ts",
"exports": [
"LINUX_DEVICE",
"ANDROID_TV_DEVICE",
"TVOS_SIMULATOR"
]
},
{
"file": "src/platforms/android/app-lifecycle.ts",
"exports": [
"parseAndroidForegroundApp",
"parseAndroidLaunchablePackages",
"parseAndroidUserInstalledPackages",
"installAndroidInstallablePath"
]
},
{
"file": "src/platforms/android/index.ts",
"exports": [
"installAndroidInstallablePath"
]
},
{
"file": "src/platforms/apple/core/apps.ts",
"exports": [
"listSimulatorApps",
"uninstallIosApp"
]
},
{
"file": "src/platforms/apple/core/runner/runner-contract.ts",
"exports": [
"resolveRunnerEarlyExitHint"
]
},
{
"file": "src/platforms/apple/core/runner/runner-session.ts",
"exports": [
"stopAllIosRunnerSessions"
]
},
{
"file": "src/platforms/apple/core/runner/runner-xctestrun.ts",
"exports": [
"resolveRunnerBuildDestination",
"resolveRunnerAppBundleId",
"resolveRunnerSigningBuildSettings",
"resolveRunnerBundleBuildSettings",
"assertSafeDerivedCleanup"
]
},
{
"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",
"comment": "Daemon route handlers are reached only through the dynamic `import()` table in request-handler-chain.ts, which --production analysis cannot follow to a consumer.",
"file": "src/daemon/handlers/{lease,session,snapshot,react-native,record-trace,find,interaction}.ts",
"exports": [
"handleLeaseCommands",
"handleSessionCommands",
"handleSnapshotCommands",
"handleReactNativeCommands",
"handleRecordTraceCommands",
"handleFindCommands",
"handleInteractionCommands"
]
},
@@ -183,7 +90,7 @@
"isExpired"
],
"rules": {
"unused-types": "warn",
"unused-types": "error",
"duplicate-exports": "off"
},
"production": {
+2 -3
View File
@@ -10,9 +10,8 @@ import { AppError } from './kernel/errors.ts';
* literal `batchable`. Extracting the entries whose `batchable` is `true` and
* indexing their `name` reconstructs this union from the same single source the
* runtime allowlist below is built from — no hand-maintained list to drift. The
* downstream contracts (`BatchCommandName`, re-exported from `command-surface.ts`,
* and the `satisfies readonly DaemonCommandName[]` guard in
* `commands/batch/projection.ts`) are still enforced by `tsc`.
* downstream contracts (`BatchCommandName` in `commands/batch/projection.ts` and
* its `satisfies readonly DaemonCommandName[]` guard) are still enforced by `tsc`.
*/
export type StructuredBatchCommandName = Extract<
(typeof commandDescriptors)[number],
+3 -4
View File
@@ -1,6 +1,6 @@
import type { CliCommandName } from '../command-catalog.ts';
import { listCommandMetadata } from '../commands/command-metadata.ts';
import type { CommandSchema, CommandSchemaOverride } from './types.ts';
import type { CommandSchema } from './types.ts';
import { getCliCommandOverride, getSchemaOnlyCliCommandSchema } from './command-overrides.ts';
import { getFlagDefinition, getFlagDefinitions } from '../commands/cli-grammar/flag-registry.ts';
import {
@@ -9,13 +9,12 @@ import {
} from '../commands/cli-grammar/flag-groups.ts';
import {
type CliFlags,
type DaemonExcludedCliFlag,
type FlagDefinition,
type FlagKey,
} from '../commands/cli-grammar/flag-types.ts';
export type { CliFlags, DaemonExcludedCliFlag, FlagDefinition, FlagKey };
export type { CommandSchema, CommandSchemaOverride };
export type { CliFlags, FlagDefinition, FlagKey };
export type { CommandSchema };
export { getFlagDefinition, getFlagDefinitions, GLOBAL_FLAG_KEYS };
const COMMAND_SCHEMA_BASES = new Map<string, CommandSchema>(
+1 -5
View File
@@ -10,11 +10,7 @@ import { replayCommand } from './replay.ts';
import { screenshotCommand, diffCommand } from './screenshot.ts';
import type { ClientCommandHandlerMap, ClientCommandParams } from './router-types.ts';
export type {
ClientCommandHandler,
ClientCommandHandlerMap,
ClientCommandParams,
} from './router-types.ts';
export type { ClientCommandParams } from './router-types.ts';
const dedicatedCliCommandHandlers = {
connect: connectCommand,
-2
View File
@@ -1097,8 +1097,6 @@ Report:
},
} as const satisfies Record<string, { summary: string; body: string }>;
export type HelpTopicName = keyof typeof HELP_TOPICS;
function formatCommandListArg(commandName: string, schema: CommandSchema, arg: string): string {
const optional = arg.endsWith('?');
const name = optional ? arg.slice(0, -1) : arg;
-1
View File
@@ -47,7 +47,6 @@ export const batchCommandFamily = defineCommandFamilyFromFacets({
});
export { createBatchDaemonWriter };
export type { BatchCommandName } from './projection.ts';
function toBatchOptions(input: BatchInput): BatchRunOptions {
return {
-2
View File
@@ -34,8 +34,6 @@ import type {
} from '../../runtime-types.ts';
import { now } from '../../runtime-common.ts';
export type { SnapshotDiffLine, SnapshotDiffSummary } from '../../../snapshot/snapshot-diff.ts';
export type SnapshotCommandResult = {
nodes: SnapshotNode[];
truncated: boolean;
+1 -1
View File
@@ -1,6 +1,6 @@
import type { CliFlags } from '../../contracts/cli-flags.ts';
export type { CliFlags, DaemonExcludedCliFlag } from '../../contracts/cli-flags.ts';
export type { CliFlags } from '../../contracts/cli-flags.ts';
export type FlagKey = keyof CliFlags;
type FlagType = 'boolean' | 'int' | 'enum' | 'string' | 'booleanOrString';
+1 -5
View File
@@ -1,9 +1,7 @@
import type { InteractionTarget, InternalRequestOptions } from '../../client/client-types.ts';
import type { InternalRequestOptions } from '../../client/client-types.ts';
import type { CommandFlags } from '../../core/dispatch-context.ts';
import type { CliFlags } from './flag-types.ts';
import type { ClickButton } from '../../core/click-button.ts';
import type { DecodedFillTarget } from '../../core/interaction-positionals.ts';
import type { WaitParsed } from '../../core/wait-positionals.ts';
export type DaemonCommandRequest = {
command: string;
@@ -88,5 +86,3 @@ export type SelectionOptions = {
export type CliInput = Record<string, unknown>;
export type CliReader = (positionals: string[], flags: CliFlags) => CliInput;
export type DaemonWriter = (input: CommandInput) => DaemonCommandRequest;
export type { DecodedFillTarget, InteractionTarget, WaitParsed };
+1 -3
View File
@@ -1,4 +1,4 @@
import { createBatchDaemonWriter, type BatchCommandName } from './batch/index.ts';
import { createBatchDaemonWriter } from './batch/index.ts';
import type { CommandInput, DaemonCommandRequest, DaemonWriter } from './cli-grammar/types.ts';
import { findCommandMetadata } from './command-metadata.ts';
import { readMetadataCommandFlags } from './command-flags.ts';
@@ -12,8 +12,6 @@ const daemonWriters: Record<string, DaemonWriter> = {
export type DaemonCommandName = keyof typeof daemonWriters;
export type { BatchCommandName };
function prepareBatchDaemonCommandRequest(
command: string,
input: CommandInput,
+1 -2
View File
@@ -1,11 +1,10 @@
import type { AgentDeviceClient } from '../client/client-types.ts';
import { listCommandFamilyDefinitions, type CommandFamilyDefinition } from './family/registry.ts';
import type { BatchCommandName } from './command-projection.ts';
import type { CommandName } from './command-metadata.ts';
const commandSurface = listCommandFamilyDefinitions();
export type { BatchCommandName, CommandName };
export type { CommandName };
type CommandDefinitionFor<Name extends CommandName> = Extract<
CommandFamilyDefinition,
+1 -8
View File
@@ -44,14 +44,7 @@ import {
type SystemCommands,
} from './system/runtime/index.ts';
export type {
BoundRuntimeCommand,
CommandResult,
DiffSnapshotCommandOptions,
RuntimeCommand,
ScreenshotCommandOptions,
SnapshotCommandOptions,
} from './runtime-types.ts';
export type { ScreenshotCommandOptions } from './runtime-types.ts';
export type AgentDeviceCommands = {
capture: CaptureCommands;
@@ -35,14 +35,12 @@ export { focusCommand, longPressCommand, scrollCommand } from './gestures.ts';
export type {
FocusCommandOptions,
FocusCommandResult,
GestureDirection,
LongPressCommandOptions,
LongPressCommandResult,
ScrollCommandOptions,
ScrollCommandResult,
ScrollTarget,
} from './gestures.ts';
export type { InteractionTarget, PointTarget, ResolvedInteractionTarget } from './resolution.ts';
export type { InteractionTarget } from './resolution.ts';
export type PressCommandOptions = CommandContext &
RepeatedInput & {
@@ -48,7 +48,7 @@ import {
type ReplayTargetGuardDenotation,
} from '../../../replay/target-identity-node.ts';
export type { InteractionTarget, PointTarget, ResolvedInteractionTarget };
export type { InteractionTarget, ResolvedInteractionTarget };
/**
* ADR 0012 migration step 4, post-resolution guard: the LOCAL identity AND
+1 -5
View File
@@ -61,11 +61,7 @@ import type {
MaestroPublicOperation,
} from './daemon-runtime-public-operation.ts';
export type { DaemonMaestroRuntimeDependencies } from './daemon-runtime-port-observation.ts';
export type {
CreateDaemonMaestroRuntimeOperationsOptions,
DaemonMaestroRuntimeBaseRequest,
} from './daemon-runtime-port-support.ts';
export type { CreateDaemonMaestroRuntimeOperationsOptions } from './daemon-runtime-port-support.ts';
function createDaemonMaestroRuntimeParts(options: CreateDaemonMaestroRuntimeOperationsOptions): {
operations: MaestroRuntimeOperations;
@@ -42,8 +42,6 @@ const IOS_DEVICE_RECORD_MIN_FPS = 1;
const IOS_DEVICE_RECORD_MAX_FPS = 120;
const IOS_SIMULATOR_RECORDING_TAIL_SETTLE_MS = 350;
export type { RecordTraceDeps, RecordingBase } from './record-trace-types.ts';
type StartRecordingParams = {
req: DaemonRequest;
sessionName: string;
+1 -2
View File
@@ -8,12 +8,11 @@ import {
findMissingProxyLeaseFields,
isProxyLeaseScope,
leaseScopeFromRequest,
type LeaseDiagnosticsContext,
type LeaseScope,
} from '../core/lease-scope.ts';
export { DEFAULT_PROXY_LEASE_TTL_MS, findMissingProxyLeaseFields, isProxyLeaseScope };
export type { LeaseDiagnosticsContext, LeaseScope };
export type { LeaseScope };
export type SessionLease = {
tenantId: string;
-4
View File
@@ -34,13 +34,9 @@ import type {
import type { AudioProbeSource } from '../audio-probe-result.ts';
import type { SnapshotDiagnosticsState } from '../snapshot-diagnostics.ts';
export type {
ReplaySuiteAttemptFailure,
ReplaySuiteResult,
ReplaySuiteTestFailed,
ReplaySuiteTestPassed,
ReplaySuiteTestResult,
ReplaySuiteTestSkipped,
ReplaySuiteTestSkipReason,
} from '../contracts/replay.ts';
export type DaemonInstallSource = PublicDaemonInstallSource;
-7
View File
@@ -1,12 +1,5 @@
export type { AppErrorCode } from './errors.ts';
export { defaultHintForCode, normalizeError } from './errors.ts';
export type {
DebugSymbolsCrashFrame,
DebugSymbolsCrashSummary,
DebugSymbolsImage,
DebugSymbolsOptions,
DebugSymbolsResult,
} from '../contracts/debug-symbols.ts';
import type { PlatformSelector } from './device.ts';
export type SessionRuntimeHints = {
+1 -4
View File
@@ -34,10 +34,7 @@ type ResolvedMetroKind = Exclude<MetroPrepareKind, 'auto'>;
type EnvSource = NodeJS.ProcessEnv | Record<string, string | undefined>;
type RepackBundlerKind = 'rspack' | 'webpack';
export type {
CompanionTunnelScope,
MetroBridgeScope,
} from '../client/client-companion-tunnel-contract.ts';
export type { MetroBridgeScope } from '../client/client-companion-tunnel-contract.ts';
type PackageManagerConfig = {
command: string;
+1 -7
View File
@@ -28,13 +28,7 @@ import {
type AndroidForegroundApp,
} from './app-parsers.ts';
export {
parseAndroidForegroundApp,
parseAndroidLaunchablePackages,
parseAndroidUserInstalledPackages,
type AndroidBlockingDialogFocus,
type AndroidForegroundApp,
} from './app-parsers.ts';
export type { AndroidBlockingDialogFocus, AndroidForegroundApp } from './app-parsers.ts';
const ALIASES: Record<string, { type: 'intent' | 'package'; value: string }> = {
settings: { type: 'intent', value: 'android.settings.SETTINGS' },
-1
View File
@@ -6,7 +6,6 @@ import { parseAndroidFramePerfSample, type AndroidFramePerfSample } from './perf
export {
ANDROID_FRAME_SAMPLE_DESCRIPTION,
ANDROID_FRAME_SAMPLE_METHOD,
type AndroidFrameDropWindow,
type AndroidFramePerfSample,
} from './perf-frame-parser.ts';
+1 -11
View File
@@ -5,14 +5,4 @@ export {
stopAndroidSimpleperfProfile,
writeAndroidSimpleperfReport,
} from './perf-native-simpleperf.ts';
export type {
AndroidNativePerfKind,
AndroidNativePerfOptions,
AndroidNativePerfFrameHealthSummary,
AndroidNativePerfSession,
AndroidNativePerfStartResult,
AndroidNativePerfStopResult,
AndroidNativePerfStopSummary,
AndroidNativePerfType,
AndroidSimpleperfReportResult,
} from './perf-native-types.ts';
export type { AndroidNativePerfKind, AndroidNativePerfSession } from './perf-native-types.ts';
-6
View File
@@ -16,8 +16,6 @@ export {
ANDROID_FRAME_SAMPLE_METHOD,
resetAndroidFramePerfStats,
sampleAndroidFramePerf,
type AndroidFrameDropWindow,
type AndroidFramePerfSample,
} from './perf-frame.ts';
export {
cleanupAndroidNativePerfSession,
@@ -28,10 +26,6 @@ export {
writeAndroidSimpleperfReport,
type AndroidNativePerfKind,
type AndroidNativePerfSession,
type AndroidNativePerfStartResult,
type AndroidNativePerfStopResult,
type AndroidNativePerfType,
type AndroidSimpleperfReportResult,
} from './perf-native.ts';
export const ANDROID_CPU_SAMPLE_METHOD = 'adb-shell-dumpsys-cpuinfo';
@@ -1,5 +1,4 @@
import type { AndroidAdbExecutor, AndroidAdbProvider } from './adb-executor.ts';
import type { AndroidSnapshotBackendMetadata } from './snapshot-types.ts';
export type AndroidSnapshotHelperTransport = 'instrumentation' | 'persistent-session';
export type AndroidSnapshotCaptureMode = 'interactive-windows' | 'active-window';
@@ -99,5 +98,3 @@ export type AndroidSnapshotHelperOutput = {
xml: string;
metadata: AndroidSnapshotHelperMetadata;
};
export type { AndroidSnapshotBackendMetadata };
-4
View File
@@ -15,11 +15,7 @@ export { ANDROID_SNAPSHOT_HELPER_WAIT_FOR_IDLE_TIMEOUT_MS } from './snapshot-hel
export type {
AndroidAdbExecutor,
AndroidSnapshotHelperArtifact,
AndroidSnapshotHelperCaptureOptions,
AndroidSnapshotHelperInstallPolicy,
AndroidSnapshotHelperInstallResult,
AndroidSnapshotHelperManifest,
AndroidSnapshotHelperMetadata,
AndroidSnapshotHelperOutput,
} from './snapshot-helper-types.ts';
export type { AndroidSnapshotBackendMetadata } from './snapshot-types.ts';
@@ -7,14 +7,6 @@ import { resolveAppleTools, symbolicateAddresses } from './debug-symbols/symboli
import type { DebugSymbolsOptions, DebugSymbolsResult } from '../../../contracts/debug-symbols.ts';
import { AppError } from '../../../kernel/errors.ts';
export type {
DebugSymbolsCrashFrame,
DebugSymbolsCrashSummary,
DebugSymbolsImage,
DebugSymbolsOptions,
DebugSymbolsResult,
} from './debug-symbols/types.ts';
const MAX_CRASH_ARTIFACT_BYTES = 64 * 1024 * 1024;
export async function symbolicateCrashArtifact(
@@ -1,9 +1,6 @@
export type {
DebugSymbolsCrashFrame,
DebugSymbolsCrashSummary,
DebugSymbolsImage,
DebugSymbolsOptions,
DebugSymbolsResult,
} from '../../../../contracts/debug-symbols.ts';
export type AppleImage = {
@@ -9,7 +9,6 @@ export {
} from './runner-artifact.ts';
export {
markRunnerXctestrunArtifactBadForRun,
type ExistingXctestrunState,
type RunnerXctestrunCacheKind,
} from './runner-cache.ts';
export {
@@ -17,6 +16,5 @@ export {
resolveExpectedRunnerCacheMetadata,
resolveRunnerAppBundleId,
resolveRunnerDerivedPath,
type RunnerXctestrunCacheMetadata,
} from './runner-cache-metadata.ts';
export { acquireXcodebuildSimulatorSetRedirect } from './runner-device-set.ts';
-5
View File
@@ -1,6 +1 @@
export type {
RemoteConfigProfile,
RemoteConfigProfileOptions,
ResolvedRemoteConfigProfile,
} from './remote-config-schema.ts';
export { resolveRemoteConfigProfile } from './remote-config-core.ts';
-3
View File
@@ -10,12 +10,9 @@ import type {
export type {
AgentDeviceRuntime,
AgentDeviceRuntimeConfig,
CommandClock,
CommandContext,
CommandPolicy,
CommandSessionRecord,
CommandSessionStore,
DiagnosticsSink,
} from './runtime-contract.ts';
export type AgentDevice = AgentDeviceRuntime & BoundAgentDeviceCommands;
@@ -5,8 +5,6 @@ import { findConnectedMaskComponents } from './screenshot-diff-components.ts';
import { splitLargeDiffRegions } from './screenshot-diff-region-split.ts';
import type { MutableDiffRegion } from './screenshot-diff-region-types.ts';
export type { MutableDiffRegion } from './screenshot-diff-region-types.ts';
type ScreenshotDiffColor = {
r: number;
g: number;
+2 -2
View File
@@ -1,5 +1,5 @@
export type { Selector, SelectorChain } from './arguments.ts';
export type { SelectorDiagnostics, SelectorResolution, SelectorChainMatchList } from './resolve.ts';
export type { Selector } from './arguments.ts';
export type { SelectorDiagnostics, SelectorResolution } from './resolve.ts';
export {
parseSelectorChain,