Skip to content

πŸ“Š Mutation testing β€” weekly baselineΒ #591

Description

@github-actions

Score: 63.9% (↓ -1.5 vs prior)

Per-shard breakdown

Shard Score Killed Survived No cov Timeout Errors Total
db 10.5% 55 412 52 4 412 935
hardware-lib 67.6% 1518 538 181 7 893 3161
homekit 62.1% 282 163 9 0 201 681
hooks 73.5% 866 289 23 1 497 1702
server 59.1% 1393 596 368 2 1679 5082
services-scheduler 73.0% 548 184 16 3 251 1004
streaming 75.5% 870 210 61 12 392 1559
  • HTML reports: attached as mutation-report-<shard> artifacts on run 28284145339.
  • Hit list artifact: mutation-hitlist on the same run.
  • Last updated: 2026-06-27T09:55:43.143Z (commit 9a2418b, trigger: schedule).

This issue is updated automatically by .github/workflows/mutation.yml on each scheduled / manual mutation run. Do not edit the body β€” it will be overwritten. Comment freely to track work on surviving mutants.


Mutation testing β€” hit list

Score: 63.9% Β· Total mutants: 14124

Status Count
Killed 5532
Survived 2392
NoCoverage 710
Timeout 29
CompileError 4324
RuntimeError 1
Ignored 1136

Surviving mutants by file (82 files, top 50 mutants shown)

For each entry below: the mutator type tells you what Stryker changed, the snippet shows where, and "expected test" is the most likely location to add a killing assertion. A killing test must fail when the mutation is applied.

src/db/schema.ts β€” 194 surviving

Expected test file: src/db/tests/schema.test.ts

StringLiteral at line 8
     7 | 
>    8 | export const deviceSettings = sqliteTable('device_settings', {
     9 |   id: integer('id').primaryKey().$defaultFn(() => 1), // Singleton

+ (mutation): ""
StringLiteral at line 9
     8 | export const deviceSettings = sqliteTable('device_settings', {
>    9 |   id: integer('id').primaryKey().$defaultFn(() => 1), // Singleton
    10 |   timezone: text('timezone').notNull().default('America/Los_Angeles'),

+ (mutation): ""
StringLiteral at line 10
     9 |   id: integer('id').primaryKey().$defaultFn(() => 1), // Singleton
>   10 |   timezone: text('timezone').notNull().default('America/Los_Angeles'),
    11 |   temperatureUnit: text('temperature_unit', { enum: ['F', 'C'] })

+ (mutation): ""
StringLiteral at line 10
     9 |   id: integer('id').primaryKey().$defaultFn(() => 1), // Singleton
>   10 |   timezone: text('timezone').notNull().default('America/Los_Angeles'),
    11 |   temperatureUnit: text('temperature_unit', { enum: ['F', 'C'] })

+ (mutation): ""
StringLiteral at line 11
    10 |   timezone: text('timezone').notNull().default('America/Los_Angeles'),
>   11 |   temperatureUnit: text('temperature_unit', { enum: ['F', 'C'] })
    12 |     .notNull()

+ (mutation): ""
StringLiteral at line 14
    13 |     .default('F'),
>   14 |   rebootDaily: integer('reboot_daily', { mode: 'boolean' })
    15 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 16
    15 |     .notNull()
>   16 |     .default(false),
    17 |   rebootTime: text('reboot_time').default('03:00'), // HH:mm format

+ (mutation): true
StringLiteral at line 17
    16 |     .default(false),
>   17 |   rebootTime: text('reboot_time').default('03:00'), // HH:mm format
    18 |   primePodDaily: integer('prime_pod_daily', { mode: 'boolean' })

+ (mutation): ""
StringLiteral at line 17
    16 |     .default(false),
>   17 |   rebootTime: text('reboot_time').default('03:00'), // HH:mm format
    18 |   primePodDaily: integer('prime_pod_daily', { mode: 'boolean' })

+ (mutation): ""
StringLiteral at line 18
    17 |   rebootTime: text('reboot_time').default('03:00'), // HH:mm format
>   18 |   primePodDaily: integer('prime_pod_daily', { mode: 'boolean' })
    19 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 20
    19 |     .notNull()
>   20 |     .default(false),
    21 |   primePodTime: text('prime_pod_time').default('14:00'), // HH:mm format

+ (mutation): true
StringLiteral at line 21
    20 |     .default(false),
>   21 |   primePodTime: text('prime_pod_time').default('14:00'), // HH:mm format
    22 |   ledNightModeEnabled: integer('led_night_mode_enabled', { mode: 'boolean' })

+ (mutation): ""
StringLiteral at line 21
    20 |     .default(false),
>   21 |   primePodTime: text('prime_pod_time').default('14:00'), // HH:mm format
    22 |   ledNightModeEnabled: integer('led_night_mode_enabled', { mode: 'boolean' })

+ (mutation): ""
StringLiteral at line 22
    21 |   primePodTime: text('prime_pod_time').default('14:00'), // HH:mm format
>   22 |   ledNightModeEnabled: integer('led_night_mode_enabled', { mode: 'boolean' })
    23 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 24
    23 |     .notNull()
>   24 |     .default(false),
    25 |   ledDayBrightness: integer('led_day_brightness').notNull().default(100), // 0-100

+ (mutation): true
StringLiteral at line 26
    25 |   ledDayBrightness: integer('led_day_brightness').notNull().default(100), // 0-100
>   26 |   ledNightBrightness: integer('led_night_brightness').notNull().default(0), // 0-100
    27 |   ledNightStartTime: text('led_night_start_time').default('22:00'), // HH:mm format

+ (mutation): ""
StringLiteral at line 25
    24 |     .default(false),
>   25 |   ledDayBrightness: integer('led_day_brightness').notNull().default(100), // 0-100
    26 |   ledNightBrightness: integer('led_night_brightness').notNull().default(0), // 0-100

+ (mutation): ""
StringLiteral at line 27
    26 |   ledNightBrightness: integer('led_night_brightness').notNull().default(0), // 0-100
>   27 |   ledNightStartTime: text('led_night_start_time').default('22:00'), // HH:mm format
    28 |   ledNightEndTime: text('led_night_end_time').default('07:00'), // HH:mm format

+ (mutation): ""
StringLiteral at line 27
    26 |   ledNightBrightness: integer('led_night_brightness').notNull().default(0), // 0-100
>   27 |   ledNightStartTime: text('led_night_start_time').default('22:00'), // HH:mm format
    28 |   ledNightEndTime: text('led_night_end_time').default('07:00'), // HH:mm format

+ (mutation): ""
StringLiteral at line 28
    27 |   ledNightStartTime: text('led_night_start_time').default('22:00'), // HH:mm format
>   28 |   ledNightEndTime: text('led_night_end_time').default('07:00'), // HH:mm format
    29 |   // Global wall-clock safety cap: if a side has been powered for this many

+ (mutation): ""
StringLiteral at line 28
    27 |   ledNightStartTime: text('led_night_start_time').default('22:00'), // HH:mm format
>   28 |   ledNightEndTime: text('led_night_end_time').default('07:00'), // HH:mm format
    29 |   // Global wall-clock safety cap: if a side has been powered for this many

+ (mutation): ""
StringLiteral at line 37
    36 |   // middleware to gate a hashed-credential round-trip yet.
>   37 |   mqttEnabled: integer('mqtt_enabled', { mode: 'boolean' }),
    38 |   mqttUrl: text('mqtt_url'),

+ (mutation): ""
StringLiteral at line 32
    31 |   // off. NULL = disabled. Independent of per-side bed-exit auto-off.
>   32 |   globalMaxOnHours: integer('global_max_on_hours'),
    33 |   // MQTT bridge configuration. NULL on every field falls back to the

+ (mutation): ""
StringLiteral at line 38
    37 |   mqttEnabled: integer('mqtt_enabled', { mode: 'boolean' }),
>   38 |   mqttUrl: text('mqtt_url'),
    39 |   mqttUsername: text('mqtt_username'),

+ (mutation): ""
StringLiteral at line 39
    38 |   mqttUrl: text('mqtt_url'),
>   39 |   mqttUsername: text('mqtt_username'),
    40 |   mqttPassword: text('mqtt_password'),

+ (mutation): ""
StringLiteral at line 40
    39 |   mqttUsername: text('mqtt_username'),
>   40 |   mqttPassword: text('mqtt_password'),
    41 |   mqttTopicPrefix: text('mqtt_topic_prefix'),

+ (mutation): ""
StringLiteral at line 41
    40 |   mqttPassword: text('mqtt_password'),
>   41 |   mqttTopicPrefix: text('mqtt_topic_prefix'),
    42 |   mqttHaDiscovery: integer('mqtt_ha_discovery', { mode: 'boolean' }),

+ (mutation): ""
StringLiteral at line 42
    41 |   mqttTopicPrefix: text('mqtt_topic_prefix'),
>   42 |   mqttHaDiscovery: integer('mqtt_ha_discovery', { mode: 'boolean' }),
    43 |   mqttTlsEnabled: integer('mqtt_tls_enabled', { mode: 'boolean' }),

+ (mutation): ""
StringLiteral at line 43
    42 |   mqttHaDiscovery: integer('mqtt_ha_discovery', { mode: 'boolean' }),
>   43 |   mqttTlsEnabled: integer('mqtt_tls_enabled', { mode: 'boolean' }),
    44 |   // When true, accept self-signed broker certs (sets rejectUnauthorized:false).

+ (mutation): ""
StringLiteral at line 47
    46 |   // per ADR 0019 β€” tlsEnabled alone keeps strict cert verification.
>   47 |   mqttTlsInsecure: integer('mqtt_tls_insecure', { mode: 'boolean' }),
    48 |   // HomeKit bridge is opt-in. When true, instrumentation publishes the

+ (mutation): ""
StringLiteral at line 50
    49 |   // hap-nodejs bridge with HeaterCooler/OccupancySensor/Switch accessories.
>   50 |   homekitEnabled: integer('homekit_enabled', { mode: 'boolean' })
    51 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 52
    51 |     .notNull()
>   52 |     .default(false),
    53 |   // Pump-stall safety guard (ADR 0022): a side whose pump RPM stays under the

+ (mutation): true
StringLiteral at line 58
    57 |   // on missing data. Auto-recovery is separately opt-in.
>   58 |   pumpStallProtectionEnabled: integer('pump_stall_protection_enabled', { mode: 'boolean' })
    59 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 60
    59 |     .notNull()
>   60 |     .default(false),
    61 |   pumpStallRpmThreshold: integer('pump_stall_rpm_threshold').notNull().default(500),

+ (mutation): true
StringLiteral at line 62
    61 |   pumpStallRpmThreshold: integer('pump_stall_rpm_threshold').notNull().default(500),
>   62 |   pumpStallDwellSamples: integer('pump_stall_dwell_samples').notNull().default(2),
    63 |   pumpStallAutoRecoveryEnabled: integer('pump_stall_auto_recovery_enabled', { mode: 'boolean' })

+ (mutation): ""
StringLiteral at line 61
    60 |     .default(false),
>   61 |   pumpStallRpmThreshold: integer('pump_stall_rpm_threshold').notNull().default(500),
    62 |   pumpStallDwellSamples: integer('pump_stall_dwell_samples').notNull().default(2),

+ (mutation): ""
StringLiteral at line 63
    62 |   pumpStallDwellSamples: integer('pump_stall_dwell_samples').notNull().default(2),
>   63 |   pumpStallAutoRecoveryEnabled: integer('pump_stall_auto_recovery_enabled', { mode: 'boolean' })
    64 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 65
    64 |     .notNull()
>   65 |     .default(false),
    66 |   pumpStallRecoveryRpm: integer('pump_stall_recovery_rpm').notNull().default(1500),

+ (mutation): true
StringLiteral at line 66
    65 |     .default(false),
>   66 |   pumpStallRecoveryRpm: integer('pump_stall_recovery_rpm').notNull().default(1500),
    67 |   pumpStallRecoverySamples: integer('pump_stall_recovery_samples').notNull().default(3),

+ (mutation): ""
StringLiteral at line 67
    66 |   pumpStallRecoveryRpm: integer('pump_stall_recovery_rpm').notNull().default(1500),
>   67 |   pumpStallRecoverySamples: integer('pump_stall_recovery_samples').notNull().default(3),
    68 |   // Autopilot global kill-switch. When false, the AutomationEngine evaluates

+ (mutation): ""
StringLiteral at line 72
    71 |   // so the kill-switch survives reboot.
>   72 |   autopilotEnabled: integer('autopilot_enabled', { mode: 'boolean' })
    73 |     .notNull()

+ (mutation): ""
BooleanLiteral at line 74
    73 |     .notNull()
>   74 |     .default(true),
    75 |   createdAt: integer('created_at', { mode: 'timestamp' })

+ (mutation): false
StringLiteral at line 75
    74 |     .default(true),
>   75 |   createdAt: integer('created_at', { mode: 'timestamp' })
    76 |     .notNull()

+ (mutation): ""
StringLiteral at line 78
    77 |     .default(sql`(unixepoch())`),
>   78 |   updatedAt: integer('updated_at', { mode: 'timestamp' })
    79 |     .notNull()

+ (mutation): ""
StringLiteral at line 77
    76 |     .notNull()
>   77 |     .default(sql`(unixepoch())`),
    78 |   updatedAt: integer('updated_at', { mode: 'timestamp' })

+ (mutation): ``
StringLiteral at line 80
    79 |     .notNull()
>   80 |     .default(sql`(unixepoch())`),
    81 | })

+ (mutation): ``
StringLiteral at line 83
    82 | 
>   83 | export const sideSettings = sqliteTable('side_settings', {
    84 |   side: text('side', { enum: ['left', 'right'] }).primaryKey(),

+ (mutation): ""
StringLiteral at line 84
    83 | export const sideSettings = sqliteTable('side_settings', {
>   84 |   side: text('side', { enum: ['left', 'right'] }).primaryKey(),
    85 |   name: text('name').notNull(), // Must be provided explicitly during insert

+ (mutation): ""
StringLiteral at line 85
    84 |   side: text('side', { enum: ['left', 'right'] }).primaryKey(),
>   85 |   name: text('name').notNull(), // Must be provided explicitly during insert
    86 |   awayMode: integer('away_mode', { mode: 'boolean' }).notNull().default(false),

+ (mutation): ""
StringLiteral at line 86
    85 |   name: text('name').notNull(), // Must be provided explicitly during insert
>   86 |   awayMode: integer('away_mode', { mode: 'boolean' }).notNull().default(false),
    87 |   alwaysOn: integer('always_on', { mode: 'boolean' }).notNull().default(false),

+ (mutation): ""

…and 2342 more surviving mutants not shown. See the HTML report for the full list.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions