The Quality Hunt

A session chronicle of The Quality Hunt.

Act I · Bug Fix

The Cancel-at Mending

Odin

Whats the url on vercel for that db can i view the data there?

Bug Fixed

Stripe portal cancellations set cancel_at (a timestamp) instead of cancel_at_period_end (a boolean). The membership route backfill only checked the boolean, so cancellation state never appeared on the frontend Settings page.

Aligned all three Stripe subscription handlers to check both cancel_at_period_end and cancel_at !== null. When cancel_at is present, it takes priority as the currentPeriodEnd date — this is the actual cancellation timestamp the portal writes.

Three locations made consistent: webhook.ts buildEntitlementFromSubscription, webhook/route.ts handleSubscriptionUpdated, and membership/route.ts backfill path.

// Before: only checked the boolean
cancelAtPeriodEnd = sub.cancel_at_period_end;

// After: portal uses cancel_at timestamp cancelAtPeriodEnd = sub.cancel_at_period_end || sub.cancel_at !== null; currentPeriodEnd = sub.cancel_at ? new Date(sub.cancel_at * 1000).toISOString() : sub.items.data[0] ? new Date(sub.items.data[0].current_period_end * 1000).toISOString() : new Date().toISOString();

✎ src/app/api/stripe/membership/route.ts

Act II · Bug Fix

The Protocol Correction

Odin

hmmm stripe redirect on checkout choked now. why did it try to go to https://localhost:9653 TLS isn't up locally

Bug Fixed

vercel dev sets VERCEL_URL but runs plain HTTP. The checkout and portal routes blindly prefixed https://, breaking Stripe redirects when developing locally.

Added a VERCEL_ENV check to both checkout and portal routes. When VERCEL_ENV === "development" (local vercel dev), the base URL uses http://. Preview and Production deployments continue using https://.

const baseUrl = process.env.APP_BASE_URL
  ?? (process.env.VERCEL_URL
    ? (process.env.VERCEL_ENV === "development"
      ? `http://${process.env.VERCEL_URL}`
      : `https://${process.env.VERCEL_URL}`)
    : "http://localhost:9653");
✎ src/app/api/stripe/checkout/route.ts ✎ src/app/api/stripe/portal/route.ts

Act III · Issue Filing

The Issue Harvest

Odin

We need bigger fonts. file a bug to do a UX update. Stripe platform is so much easier to read. We need to keep our style but bigger size by default.

Odin walked through the live app, identifying UX issues and feature requests as they appeared. Each observation was immediately filed as a GitHub Issue with screenshots, reproduction steps, and acceptance criteria. Eight issues filed in rapid succession, covering readability, button feedback, layout, and visual design.

#TitleType
#149Increase base font sizes for readabilityUX
#150Add hover/click feedback to buttonsUX
#151Redesign Settings page layoutUX
#152Howl panel vertical alignment with card gridUX
#153Assign runes to issuers + bank logosUX
#154Howl panel overlaps user menuBug
#155Stripe test coverage gapsTest
#156Logged-out empty state overbusyUX

Act IV · Triage

The Triage Walk

Odin

Lets walk through them 1 by 1 and determine which are still applicable

Walked through every on-disk bug: 6 Stripe security findings, 9 Google API security findings, 3 import QA defects, and 7 Sprint 3 gap items. Each was checked against current code to determine if still applicable.

Of ~25 items examined: 10 already fixed, 3 not applicable, 7 won't-do (accepted design decisions), and 5 filed as new issues.

SourceItemsVerdict
Stripe SEV-001Secrets in worktree .env.localStale — worktree deleted, never in git
Stripe SEV-002Origin header in redirectsFixed this session
Stripe SEV-003CSP missing Stripe domainsAlready fixed
Stripe SEV-004–006Rate limiter, dedup, anon checkoutWon't do / not applicable
Google SEV-001–003Open redirect, headers, rate limitingAll fixed
Google SEV-005LLM prompt injection via CSVFiled as #157
Google SEV-004,006–009Picker key, Drive token, error fwd, etc.Design decisions / fixed / skip
Import DEF-001–003Success step, aria-labels, CSV msgAll fixed
Sprint 3 gaps4 remaining gapsFiled as #158–#161

Act V · Process

The Template Pact

Odin

ok now lets develop a template for issues being filed in GH and update everyone's instructions to use it when needed.

Analyzed existing issues to extract common patterns, then created a unified GitHub Issue template. Title format: [Type] [Priority]: Short description. Types: Bug, Feature, UX, Security, Test. Priorities: P1-Critical through P4-Low.

Template includes structured sections: Problem, Screenshots, Expected Behavior, Affected Code, Reproduction Steps, Acceptance Criteria, and Notes.

# Title format
[Bug] [P1]: Howl panel overlaps top-right user menu
[Feature] [P3]: Add financial sort options to Valhalla
[UX] [P2]: Increase base font sizes for readability
[Security] [P2]: LLM prompt injection via CSV content
[Test] [P2]: Stripe cancellation state coverage gaps
✦ .github/ISSUE_TEMPLATE/issue.md

Act VI · Tooling

The Label Forge

Odin

How can we change how things are filed so that i can use severity and type filters?

Created the Fenrir Ledger Triage GitHub Projects board. Added all 22 open issues. Created structured labels for filtering: type:bug, type:ux, type:feature, type:security, type:test for types, and P1-critical through P4-low for priorities.

Spawned 4 subagents in parallel to reformat all 21 existing issue titles to the [Type] [Priority]: convention and apply correct labels. All 22 issues updated.

PriorityCountIssues
P2-high6#146, #147, #148, #154, #155, #157
P3-medium10#126, #131, #145, #149, #150, #151, #153, #156, #158, #160, #161
P4-low6#132, #133, #152, #159, #162

Act VII · Agent Binding

The Agent Binding

Odin

File them as feature requests in GH. Update the team norms to file all issues in GH from now on. Ensure Loki and FiremanDecko have this in their prompts.

Updated three agent/config files with the new issue tracking workflow. Loki now files GitHub Issues for every defect found during QA, includes the full template, and hands off to FiremanDecko with the issue URL. FiremanDecko references issue numbers in branches and PRs, uses Fixes #N for auto-close on merge.

Both agents instructed to add every new issue to the project board: gh project item-add 1 --owner declanshanaghy --url <issue-url>.

Team Norm — GitHub-First Issue Tracking

All defects, bugs, features, and security issues MUST be tracked as GitHub Issues. On-disk QA verdicts and security reports are supplementary documentation, not the source of truth. A defect without a GitHub Issue is an untracked defect. Untracked defects get lost.

✎ .claude/agents/loki.md ✎ .claude/agents/fireman-decko.md ♢ memory/team-norms.md

Act VIII · Delivery

The Push & the Hunt

Odin

ok lets commit everything

Two clean commits on fix/stripe-subscription-state: the first for Stripe bug fixes (cancel_at handling + protocol fix), the second for process improvements (consolidated dev scripts, issue template, agent prompt updates). Pushed and created PR #163.

Playwright tests failing on CI — Loki spawned in the background to investigate and fix.

  • d5700b1 — fix: handle Stripe cancel_at for portal cancellations and fix local dev redirect
  • b7a84af — chore: consolidate dev scripts, add issue template, update agent prompts
✎ 6 files (Stripe fixes) ✎ 7 files (process/tooling)
Session Ledger
Bugs fixed
2
Issues filed
14
Items triaged
25
Team norms added
1