Skip to content

fix: repair silently failing selector tests, guard premature campaign completion, build for the target arch - #12

Open
threechord82 wants to merge 3 commits into
miwidot:mainfrom
threechord82:fix/build-tests-completion
Open

fix: repair silently failing selector tests, guard premature campaign completion, build for the target arch#12
threechord82 wants to merge 3 commits into
miwidot:mainfrom
threechord82:fix/build-tests-completion

Conversation

@threechord82

@threechord82 threechord82 commented Jul 26, 2026

Copy link
Copy Markdown

Three independent fixes I've been carrying downstream while running this on a
Raspberry Pi. Separate commits, so feel free to take them individually.

1. fix(test): four selector tests have been failing silently

Since the v2.0 switch to the persisted-hash GameDirectory query, production
passes the game's URL slug to GetGameStreamsDropsEnabled, while the test
fixtures in selector_test.go are keyed by display name. The fake source
returns no streams, buildPool produces an empty pool, and four tests fail:

  • TestBuildPool_UnrestrictedCampaign
  • TestBuildPool_DirectoryQueriedOncePerGame
  • TestSelect_WantedGamesForcesNonClosestExpiry
  • TestSelect_SkipChannelsExcludesFromPool

go test ./... on current main reproduces this. fakeStreamSource now falls
back to matching SlugFromGameName(fixtureKey) against the requested slug and
counts the call under the fixture key, so the "queried once per game"
assertion keeps working. Fixtures stay readable, no production code touched.

After this commit go test ./... is green again.

2. fix(drops): campaign marked completed while it still had drops left

autoClaimWith() wrote a campaign to completed_campaigns as soon as every
drop it could see was claimed. Twitch sometimes omits
requiredMinutesWatched for a campaign's later drops, so after claiming drop
3 of 5 the loop concludes "everything claimed", the campaign is filtered out
permanently, and the remaining two drops are abandoned mid-progress. Observed
here on a 5-tier Marble Day campaign.

Completion now additionally requires:

  • !c.InInventory — while Twitch still lists the campaign as in-progress
    there is more to farm. This is the same anchor
    MarkCompletedIfFinishedExternally already trusts, so both paths now agree.
  • claimedSeen > 0 — a campaign whose metadata glitched to "nothing
    watchable" can't complete itself without a single observed claim.

No farming loop is introduced by waiting: a genuinely finished campaign that's
still in the inventory is skipped by the selector anyway (no drop reports
IsEarnable) and gets marked on a later cycle once Twitch drops it from the
in-progress list.

3. build: image only ever built for amd64

The Dockerfile hard-codes GOARCH=amd64, so the image can't run on arm64 —
Raspberry Pi, Apple Silicon, arm64 VPS. The release workflow already ships a
twitchpoint-linux-arm64 binary, so the Docker image was the last place still
pinned. I've been patching this line locally on every update.

GOOS/GOARCH now come from TARGETOS/TARGETARCH, which BuildKit sets
automatically, with ${VAR:-…} defaults so nothing changes for existing
builds:

build command result
docker build on x86-64 amd64 — unchanged
builder that sets neither var falls back to linux/amd64
docker build on arm64 native arm64 image
docker buildx build --platform linux/amd64,linux/arm64 multi-arch image

The builder stage is pinned to --platform=$BUILDPLATFORM so the Go toolchain
keeps running natively and cross-compiles, rather than the whole build stage
being emulated through QEMU (painfully slow for Go).

Testing

  • go test ./... — green with commit 1 (red on main before it)
  • go build ./... — clean
  • Built and deployed as an arm64 image on a Pi 4 (Debian 13); v2.1.7 running
    with these three commits, drops and points mining working

Summary by CodeRabbit

  • Bug Fixes

    • Improved campaign completion detection to avoid marking campaigns complete when drop information is incomplete or inconsistent.
    • Improved multi-architecture container builds, supporting binaries for different operating systems and CPU architectures while preserving existing defaults.
  • Tests

    • Updated stream-selection test coverage to reflect game slug-based lookups.

Four selector tests have been failing silently since the v2.0 switch to the
persisted-hash GameDirectory query: production now passes the game's URL slug
to GetGameStreamsDropsEnabled, while the test fixtures are keyed by display
name. The fake returned no streams, so buildPool produced an empty pool and
the assertions never had anything to work with.

Affected: TestBuildPool_UnrestrictedCampaign,
TestBuildPool_DirectoryQueriedOncePerGame,
TestSelect_WantedGamesForcesNonClosestExpiry,
TestSelect_SkipChannelsExcludesFromPool.

The fake now falls back to matching SlugFromGameName(fixtureKey) against the
requested slug, and counts the call under the fixture key so the
"queried once per game" assertion keeps working. Fixtures stay readable
(display names), no production code touched.
autoClaimWith() marked a campaign completed as soon as every drop it could
see was claimed. Twitch sometimes omits requiredMinutesWatched for a
campaign's later drops, so after claiming drop 3 of 5 the loop sees
"everything claimed", writes the campaign to completed_campaigns, and the
selector filters it out permanently — the remaining two drops are abandoned
mid-progress. Observed on a 5-tier Marble Day campaign.

Completion now additionally requires:

  - !c.InInventory — while Twitch still lists the campaign as in-progress
    there is more to farm. This is the same anchor
    MarkCompletedIfFinishedExternally already trusts, so the two paths agree.
  - claimedSeen > 0 — a campaign whose metadata glitched to "nothing
    watchable" cannot complete itself without a single observed claim.

No farming loop is introduced by waiting: a genuinely finished campaign that
is still in the inventory is skipped by the selector anyway (no drop reports
IsEarnable), and gets marked on a later cycle once Twitch drops it from the
in-progress list.
The Dockerfile hard-coded GOARCH=amd64, so the image could only ever run on
x86-64 — building on or for arm64 (Raspberry Pi, Apple Silicon, arm64 servers)
produced an amd64 binary that fails to start. The release workflow already
publishes a twitchpoint-linux-arm64 binary, so the Docker image was the only
place still pinned.

GOOS/GOARCH now come from TARGETOS/TARGETARCH, which BuildKit sets
automatically. Behaviour is unchanged for existing builds:

  - plain `docker build` on x86-64  → TARGETARCH=amd64, same output as before
  - a builder that sets nothing     → falls back to linux/amd64 via ${VAR:-…}
  - `docker build` on arm64         → native arm64 image, no patching needed
  - `docker buildx build --platform linux/amd64,linux/arm64` → multi-arch image

The builder stage is pinned to --platform=$BUILDPLATFORM so the Go toolchain
keeps running natively and cross-compiles, instead of the whole build stage
being emulated through QEMU (which is very slow for Go builds).
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 41a35f40-e9ca-4cf8-be20-72378fabf4bd

📥 Commits

Reviewing files that changed from the base of the PR and between 53570ec and e70ea56.

📒 Files selected for processing (3)
  • Dockerfile
  • internal/drops/inventory.go
  • internal/drops/selector_test.go

📝 Walkthrough

Walkthrough

The Docker builder now supports target-platform compilation while preserving Linux amd64 defaults. Drop auto-claim completion uses observed claimed-drop state and excludes inventory campaigns. The stream-source test double now resolves game slugs to fixture names.

Changes

Cross-platform Docker builds

Layer / File(s) Summary
Target-driven Docker compilation
Dockerfile
The builder runs on $BUILDPLATFORM, and go build uses configurable TARGETOS and TARGETARCH values with Linux amd64 defaults.

Drop completion tracking

Layer / File(s) Summary
Claim tracking and slug-based stream lookup
internal/drops/inventory.go, internal/drops/selector_test.go
Auto-claim evaluation counts pre-claimed and newly claimed drops before completing campaigns, while the fake stream source accepts game slugs and records calls by resolved fixture name.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: miwidots

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the three main changes: selector test repair, campaign completion guard, and target-arch Docker builds.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant