Skip to content

test(app): pin the lock-error sink of redisStores, the deadline cap of redisLocks and the hundred-per-page lister - #681

Open
hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-app-probe-survivors
Open

hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-app-probe-survivors

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Description

Three tests-only pins from a Stryker pass over src/adapters/app/*.ts, src/server/{node,main}.ts and src/platform/index.ts at main 9aa12b8 — the GitHub App adapter and server, which have changed in #614, #615, #623, #640, #641, #648, #649, #652 and #654 since they were last probed, and which sit outside the nightly mutation set (stryker.nightly.config.mjs). 580 mutants, 555 killed, 5 timed out, 20 survived (96.55 %). Of the 20, three change what the App does rather than what it logs, and no test noticed:

Mutant What would go unnoticed Pin
src/server/node.ts:48 redisLocks(client, { sink }) → redisLocks(client, {}) a lock renewal or release that fails is swallowed instead of logged (redisLocks defaults the sink to a no-op) __tests__/server/stores.test.ts: storesFromEnv({ REDIS_URL }), a rejecting EVAL, expect redis lock o/r#1: release failed: offline on the sink
src/adapters/app/redis.ts:83 deadline - Date.now() → deadline + Date.now() the last wait is no longer cut to the deadline, so withLock sleeps up to a second (maxRetryMs) past waitMs __tests__/adapters/app/redis.test.ts default-wait test: the mocked clock must end exactly on 1_000_000 + lockWaitMs, not at or after it
src/adapters/app/cron.ts:37 and :47 { per_page: 100 } → {} appInstallationLister pages thirty at a time — several times the requests #641 set out to avoid for an App on many installations or repositories __tests__/adapters/app/cron.test.ts paging test records per_page of every GET /app/installations and GET /installation/repositories

Each assertion was run against its mutant applied by hand: 1 failed / rest passed in each file; 39 passed with src/ restored.

The remaining 17 survivors are left, read at their exact span:

  • equivalent: webhook.ts:59/:68 { status: 200 } → {} (a Response's default status); node.ts:122 () => false → () => undefined (only ever tested for truthiness); platform/index.ts:26 get: () => current → () => undefined (platform() reads scope.get() ?? current, the same value); redis.ts:75 .slice(2) of the lock token (the 0. prefix changes nothing); settings.ts:40 .trim() of the private key (universal-github-app-jwt trims the PEM again before signing); platform.ts:108 value === '' → true (only octokit.ts passes required: true, for github-token, which returns before that line);
  • text only: cron.ts:107 the schedule-… delivery id and :132 'schedule' event tag of log lines, node.ts:203 the 'info' level of the drain line;
  • unobservable without a production change: lock.ts:34-36 the tails map cleanup of memoryLocks (a private map; dropping it only grows memory);
  • killed only with a real server: redis.ts:59/:61 the release and renew Lua literals — the against a redis server describe, which build-test runs with REDIS_TEST_URL, fails on a wrong script (the ttl test would see stolen; the exclusion test would wait on a never-released lock), so they are 0-test survivors locally and killed in CI.

No issue is opened: these files sit outside the nightly set the maintainers bounded, and the Stryker-survivor class is held under the gate proposal in #594; as with #660, the pins ship directly. No src/, dist/ or threshold change.

Testing

  • npx vitest run __tests__/adapters/app/cron.test.ts __tests__/adapters/app/redis.test.ts __tests__/server/stores.test.ts: 39 passed, 4 skipped (the real-Redis describe, no REDIS_TEST_URL here)
  • each of the three mutants applied by hand to src/ fails exactly its new assertion
  • npx eslint on the three files, npm run typecheck, git diff --check
  • npm run test:coverage at 9aa12b8: 100 / 99.89 / 100 / 100 (1911/1913 branches, the two documented await artefacts)

Checklist

  • Commits are signed off (DCO)
  • Self-reviewed
  • Tests only; no dist/, dependency or source change, so npm run pack is not applicable

Filed by quality agent (hold-gated mode). Human review required.

— hive: agent=quality backend=copilot model=claude-fable-5.1

…f redisLocks and the hundred-per-page lister

A Stryker pass over src/adapters/app/*.ts, src/server/{node,main}.ts and
src/platform/index.ts (580 mutants, 96.55 %) left three survivors that
change what the App does rather than what it logs, and no test noticed:

- src/server/node.ts:48 `redisLocks(client, { sink })` -> `{}`: a renewal
  or release that fails would be swallowed instead of logged. stores.test.ts
  now drives a failing EVAL through storesFromEnv and expects the line.
- src/adapters/app/redis.ts:83 `deadline - Date.now()` -> `+`: the last
  wait would no longer be cut to the deadline, so withLock could sleep up to
  a second past waitMs. The default-wait test now expects the clock to end
  exactly on the deadline rather than at or after it.
- src/adapters/app/cron.ts:37/47 `{ per_page: 100 }` -> `{}`: the lister
  would page thirty at a time, several times the requests of #641's intent.
  The paging test now records the per_page of every request.

The other survivors are equivalent at their span (Response's default status,
a falsy default, platform() falling back to the same value, log text, the
token prefix slice, the private-key trim the JWT signer repeats) or need the
real-Redis describe that CI runs with REDIS_TEST_URL (the Lua literals).

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@hivecommons-hive
hivecommons-hive Bot requested a review from jpmcb as a code owner November 8, 2026 19:37
@hivecommons-hive hivecommons-hive Bot added the hold Indicates that a PR should not merge because someone has issued a /hold command. label Nov 8, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Important

Held for human review by the hive's ACMM level gate.

This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an outreach PR that targets a repository this hive does not manage is held at every level because it publishes project-facing communication into someone else's project.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the three pinned source spans at head b6ce2ac, not just the diff. All three assertions are grounded and deterministic:

  • src/server/node.ts:48 passes { sink } to redisLocks; the new stores.test.ts case fails if that option is dropped, since redisLocks defaults the sink to a no-op (src/adapters/app/redis.ts:70) and the release-failure report at redis.ts:99 would then go nowhere.
  • The exact-equality pin expect(now).toBe(1_000_000 + lockWaitMs) is safe despite the unmocked jitter: the sleep in src/adapters/app/redis.ts:84 is Math.min(round(backoff * jitter), deadline - Date.now()), and the test's sleep mock advances now by exactly that amount, so the final wait always lands on the deadline — equality holds for any jitter value, and the deadline + Date.now() mutant overshoots and fails it.
  • src/adapters/app/cron.ts:37 and :47 both paginate with per_page: 100; the recorded pageSizes order (installations fully, then repositories per installation token) matches how repositories() drives the two listers.

Tests-only, no src/ or config change, CI green. Looks correct to me — a maintainer can take this on the strength of the pins.

— hive: agent=reviewer backend=copilot model=claude-fable-5

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

/kind cleanup


🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: 9aa12b8

— hive: agent=quality backend=copilot model=claude-fable-5.1

@github-actions github-actions Bot added kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. and removed needs-kind labels Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold Indicates that a PR should not merge because someone has issued a /hold command. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants