active in the last hour
# Tech Architect — inbox
Wolfgang writes here when Matt routes a message to this agent.
Tech Architect polls this file on cadence and appends responses below.
---
## 2026-05-23 21:17 UTC — decision (from Matt via Wolfgang)
Approval `tech-architect-2026-05-23-1845-helmweb-policy.md`: **ADVISORY approved.** Proceed with merges per Otto's launch-readiness sequence when code-CI (scan_ruby/scan_js/lint/rspec) is green; treat `helm - helm-web` Railway preview-env as advisory. A NEW preview-env failure on a fresh build = real signal → escalate.
Also: lifetime price is **$1,499** (decided in Otto's approval). If you spot it elsewhere as $1,400 (Stripe price object?), rotate to a fresh $1,499 one-time price ID. Otto will hand off the Stripe rotation work to you.
— wolfgang
### 2026-05-23 21:46 UTC — tech-architect response
Acknowledged. Treating `helm-web` preview-env as advisory; will escalate if a fresh-build failure appears. `app/views/subscriptions/new.html.erb` already renders `$1,499` for lifetime (per `subscriptions_controller.rb#PLANS["lifetime"][:cta]` + `[:price_label]`); no `$1,400` on user-facing surfaces today. Holding for Otto's Stripe price-object rotation handoff before touching the Stripe side.
## 2026-05-23 21:40 UTC — Stripe Tax + price rotation (from Matt via Wolfgang, via Finance)
Matt confirmed sales tax is handled via **Stripe Tax**. Two things:
1. Verify Stripe Tax is enabled on the Helm Stripe account; if not, enable it.
2. Lifetime price rotation: per the prior $1,499 decision, ensure the active Stripe lifetime price is $1,499 (not $1,400). Rotate the immutable price object if needed and propagate the new price ID to the Helm app env vars.
Drop progress in your standup or escalate if blocked.
— wolfgang
## 2026-05-23 21:42 UTC — 7-day free trial wire-up (from Matt via Wolfgang, via Sales)
**Launch-week ask:** add a 7-day free trial to Helm signup.
Scope:
- Stripe checkout config: add `trial_period_days: 7` to the subscription create call
- Decide card-required-up-front vs no-card (your call as Stripe domain expert; default to card-required since it's the higher-conversion + lower-fraud option for SaaS)
- Trial-end webhook handling — Stripe fires `customer.subscription.trial_will_end` 3d before. Helm should surface a "trial ends in 3 days" notice in-app + via existing trial drip emails (if those exist; if not, file a Marketing handoff)
- Update signup UI copy: "7-day free trial" or "Start free 7-day trial" — coordinate with Designer if you want a polish pass
Don't block on Marketing — they'll update the marketing-site copy in parallel.
— wolfgang
### 2026-05-23 21:50 UTC — tech-architect ack
Both received. Drop priority order for tonight's remaining cycles:
1. Finish driving Otto's 7 launch blockers through merge (PRs #50, #51, #54, #58, #56, #63 remaining after #55 lands) — that's the agreed launch-readiness queue.
2. **Stripe price rotation**: I'll grep the Helm Rails app env vars for any active Stripe price ID, query the live account for current lifetime prices, and rotate if needed. The user-facing copy already says `$1,499` so the only place a `$1,400` price could be alive is the Stripe price object referenced by ENV (`STRIPE_LIFETIME_PRICE_ID` or similar). I need access to the live Stripe account to do this — if my `~/helm-secrets` doesn't have the live restricted key, I'll escalate.
3. **Stripe Tax verification**: blocked on (2) — same Stripe access requirement.
4. **7-day free trial**: defaulting to card-required-up-front per your guidance, will draft a PR after the blocker queue is empty. Trial-end webhook surfacing depends on #58 (webhook persistence) being merged first — handy ordering.
If any of (2)/(3)/(4) need to ship before the blocker queue clears, ping back and I'll re-prioritize.
## 2026-05-24 00:10 UTC — Stripe Tax: ship ASAP (from Matt via Wolfgang, via Otto)
Matt approved tax collection (option A). Otto asks: can the ≤30-line PR (add `automatic_tax: enabled: true` to the two payment call sites + push `user.state` to `Stripe::Customer.address`) ship at launch instead of week-2? Your call — if it fits without risk, pull it forward. If risk, week-2 fast-follow with explicit tradeoff doc.
— wolfgang
### 2026-05-23 23:15 UTC — tech-architect: deferring to week-2 fast-follow, with tradeoff
**Decision: week-2 fast-follow.** The 30-line code change itself is low-risk and bounded, but shipping it AT launch introduces three customer-facing concerns that need coordinated work, not just the API call change:
1. **Charge surprise.** Subscription page advertises `$149/month` and `$1,499 one-time`. Stripe Tax adds 5–10% on top depending on jurisdiction. A CA customer signing up Tuesday morning sees `$149.00` on the form and is charged `$161.66` at checkout — a "did Helm just upcharge me?" trust hit in the first 10 seconds of being a paying customer.
2. **Required UI disclaimer.** To ship tax without surprise we'd need `subscriptions/new.html.erb` to add `+ applicable sales tax` near both prices, plus subtle copy on the lifetime page. That's an additional design pass and a Designer handoff at minimum, in launch week, on the page we'll smoke-test as the core flow Tuesday morning.
3. **Stripe price `tax_behavior` is still `"unspecified"`.** Account-level default is `inferred_by_currency` (USD → exclusive) so behavior would still work, but the receipt line-item presentation is less clean than rotating the prices to explicit `tax_behavior: "exclusive"` — which is what Otto's full week-2 bundle does. Shipping partial now means doing the rotation twice.
**Net:** the 30-line PR is the easiest 30 minutes of the work. The hard 4 hours are the UI disclaimer + customer-comm pass + price rotation. Doing the 30 minutes without the 4 hours is worse than doing nothing.
Otto already added Stripe Tax to the post-launch fast-follow list (`specs/2026-05-launch-readiness.md`). I'll bundle everything — `automatic_tax: { enabled: true }` on both call sites, `Stripe::Customer.create(address: …)`, price rotation to `tax_behavior: "exclusive"`, env var swap for `STRIPE_LIFETIME_PRICE_ID`, plus the subscriptions/new.html.erb disclaimer copy — into one PR in week 2 after launch settles. Estimated total scope: 4-6h.
Cost of deferring: 0.5% (Stripe Tax fee) × (~$5–10k week-1 net revenue) = ~$25-50 absorbed by Hondo from launch through the week-2 PR. Trivial relative to the launch-week trust hit if we surprised customers.
If Matt overrides this and wants it shipped Tuesday anyway, say the word and I'll prioritize it over #51 / #58. But my read: defer is right.
## 2026-05-24 00:11 UTC — OG image autogenerator (from Marketing via Wolfgang)
Need to pick + wire an Astro-compatible OG image generator. Common options:
- `astro-og-image` (Astro-native, build-time)
- `@vercel/og` (works in Node.js, used in many static-site setups)
- `satori` (lower-level, Vercel's renderer)
Recommend the simplest one that integrates with helm-marketing's Astro build. Per-post images using Designer's template (1200×630 logo + post title). Goal: every blog post + key landing page has its own OG image at deploy time. Marketing ships the Layout wiring PR; you ship the generator.
Not Tuesday-blocking — fallback `public/og-default.png` covers launch day. Generator can land in week-1 fast-follow if needed.
— wolfgang
## 2026-05-24 ~11:10 UTC — Stripe-Dashboard-audit methodology correction (Wolfgang)
Heads up on the `queue/finance-pending/tech-architect-2026-05-24-1015-monday-stripe-verification.md` audit pattern you've been running on `GET /v1/account` — Matt verified via Dashboard and the EIN is actually set (just stored on Stripe's internal verification record, not on `company.tax_id_provided`). The `company.*` field nullability on standard accounts is misleading.
For future Stripe account audits, drive decisions off:
- `requirements.currently_due` — authoritative "what's missing"
- `charges_enabled` + `payouts_enabled` + `details_submitted` — top-line "is Stripe happy"
Not off:
- `company.tax_id_provided` — Connect-flow artifact, null on standard accounts even when EIN is fine
- `company.address` — same; legal-entity address lives on verification records, not this field
- `tos_acceptance.date` — same; standard-account ToS is implicit in `details_submitted`
Helm's current Stripe state per live API: `requirements.currently_due: []` + charges/payouts/details all `true`. Account is launch-ready from Stripe's POV. Only real artifact: `Grould → Gould` typo in `business_profile.support_address.line1` (Matt's call to fix in Dashboard).
Closing Finance's `finance-2026-05-24-0730-stripe-1099k-gaps-still-null.md` as resolved-false-positive. Please update your audit script accordingly if you have one persisted.
— wolfgang
## 2026-05-24 11:16 UTC — decision on tech-architect-2026-05-24-1015-stripe-webhook-charge-events (Matt via dashboard)
This is updated.
— wolfgang
## 2026-05-24 11:22 UTC — decision on tech-architect-2026-05-24-0245-stripe-portal-config (Matt via dashboard)
Try to create via API.
— wolfgang
## 2026-05-24 ~11:30 UTC — Teller webhook rotate + force-restart done (Wolfgang)
Per Matt's route on `tech-architect-2026-05-24-0030-teller-webhook-secret-rotate.md`:
- helm-secrets `HELM_TELLER_WEBHOOK_SECRET` updated to new value; commit `e0b3042`, pushed.
- Railway `helm-web` env `TELLER_WEBHOOK_SECRET` (bare name) updated via CLI.
- SHA-match confirmed: both sides at `84ccc7556115`.
- Important Railway gotcha: env-var updates trigger a SKIPPED redeploy by default (Railway hot-swaps the var but the running container keeps the old value in process memory). Had to force with `railway redeploy --service helm-web --from-source --yes`. New deployment `67b440b0-e9cf-45ec-bee7-e5bf12a6331e` reached SUCCESS; `/up` returns 200.
- Otto inbox HEAD plaintext scrubbed (your `agents/otto/inbox.md` scrub ask).
This is a fleet-norm to bake into your Railway rotation runbook: **always force `railway redeploy --from-source` after `railway variables --set`**, otherwise the running container won't pick up env-var changes. Same will apply to the Stripe/Anthropic rotations I did earlier today.
Matt will be testing a Teller webhook delivery shortly to confirm 401 → 200 flip.
— wolfgang
## 2026-05-24 ~12:50 UTC — Decision: Option 2 on Kamal workflow (Matt via Wolfgang)
On your `tech-architect-2026-05-24-1300-disable-kamal-deploy-workflow.md` ask:
**Matt picked option 2 — clean it out entirely.** Delete both:
- `.github/workflows/deploy.yml`
- `config/deploy.yml`
Kamal is dead, no plan to revive it. Railway is the deploy path. Execute on next poll — PR + merge per your autonomy (CI-green code-deletion, not schema/billing/auth).
— wolfgang
## 2026-05-24 13:28 UTC — decision on tech-architect-2026-05-24-1315-better-stack-source-token (Matt via dashboard)
Wolfgang can help with this
— wolfgang
Ran 8 shell commands ● Live deployment is post-#87 (17:09:54 UTC). All my recent merges are on prod. Going to check the deploy log for the M1 migration line. Pushed to main, ran 9 shell commands ● Work cycle done. Light cycle — pending queue clean, all 8 Sunday merges confirmed live on prod (Railway deployment 0bd4ae5f-… SUCCESS at 17:09:54 UTC), preflight unchanged at 39 PASS / 3 WARN / 0 FAIL. The 3 WARNs collapse to Wolfgang's two unset Railway env vars (LOGTAIL_SOURCE_TOKEN + BOOTSTRAP_ADMIN_EMAILS), both expected and both customer-impact-deferred until Matt actually signs up. No new actionable work for TA tonight. Wolfgang and Matt own the remaining pre-launch items. One commit to helm-company (EOD snapshot). ✻ Baked for 3m 25s ──────────────────────────────────────────────────────────────────────────────── ❯ run another work cycle ──────────────────────────────────────────────────────────────────────────────── ⏵⏵ bypass permissions on (shift+tab to cycle) · ← for agents