Prediction Assistant
Notes
Doc 2
-
ISS Rails Architecture
arch-railsISS Rails Architecture
Framework
Ruby on Rails 8 — full-stack monolith serving both the public landing page and the authenticated client management app. The same codebase powers the marketing site at
intelligentstaffingsystems.aiand the iOS app via Turbo Native.Asset Pipeline
Propshaft — Rails 8 default asset pipeline. No Sprockets, no Node build step. CSS is served from
app/assets/stylesheets/. JavaScript uses import maps.Mobile Delivery
Turbo Native — the iOS app wraps the Rails backend in a native shell. Interface changes deploy by pushing to Rails; no App Store resubmission required for UI updates. The companion iOS repo consumes the same endpoints and views.
Authentication
Keycloak OIDC — all authentication is handled by a self-hosted Keycloak instance. The Rails app is an OIDC relying party. Three roles are enforced:
prospect,client, andadmin. Session management flows through Keycloak; the app never stores passwords.Testing
Minitest — endpoint-first controller tests with no system/browser tests. Keycloak sessions are stubbed per role in the test helper. Tests run inside Docker via
docker compose run web rails test. CI gates PRs on the full test suite.Development Environment
Docker-based — the web image is pulled from Harbor (no local Dockerfile build). Local dev runs via
docker compose upon port 9999. Production runs on port 3000 per the platform port convention.Key Directories
app/controllers/— request handling; auth gating viabefore_actionapp/views/— ERB templates; tab-based navigation for the authenticated appapp/assets/stylesheets/— Propshaft CSS (forms, pages, navigation)config/routes.rb— route definitions; landing page, leads, dashboard, messagingtest/— Minitest suite; controller tests stub Keycloak sessions
-
Validation: #1 Rails scaffold + Kalshi API client
validation-1-2026-07-03Ticket
#1 Rails app scaffold with Kalshi API client (5pt, Sprint 1)
Shipped: Rails 8 scaffold with KalshiClient service using RSA-PSS authentication, rate limiting, and market/portfolio/order endpoints.
Environment
Local development — this is a scaffold ticket. Production deployment is Sprint 2 scope (Kustomize #9, CI/CD #11). Validation covers code correctness, test suite, and app boot.
Checks
# Criterion How to Verify Result Evidence 1 Rails app structure exists Check for Gemfile, config/application.rb, app/ directories PASS Standard Rails 8 structure: controllers, jobs, models, services directories present 2 App boots cleanly bin/rails runner "puts 'OK'"PASS Prints OK with no errors 3 Test suite passes bin/rails testPASS 20 tests, 50 assertions, 0 failures, 0 errors 4 KalshiClient RSA-PSS auth Test round-trip RSA-PSS signature verify PASS Tests cover signature generation + verification, auth headers (KALSHI-ACCESS-KEY, KALSHI-ACCESS-TIMESTAMP, KALSHI-ACCESS-SIGNATURE), credential validation raises AuthenticationError 5 API endpoint coverage Review KalshiClient methods PASS Markets (markets, market, orderbook), portfolio (balance), orders (create_order), exchange status. Generic get/post for extensibility. 6 Rate limiting Test rate limit enforcement PASS Sliding-window rate limiting: 20 read/sec, 10 write/sec per Kalshi Basic tier 7 Error handling Test 401/429/5xx responses PASS Tests cover authentication errors, rate limit responses, and server errors Verdict
PASS — all 7 checks green. Scaffold is complete and functional. Production deployment validation will occur under Sprint 2 tickets (#9 Kustomize, #11 CI/CD).
Discovered Issues
None. The
eventsendpoint is not a dedicated method but accessible via genericget— adequate for scaffold scope.
Review 66
-
Review: Add Ingress/TLS + wire Keycloak env vars for production deploy
review-1812-2026-07-05-r2Verdict: APPROVED
Re-review after refinements requested by review-1812-2026-07-05 (NEEDS_REFINEMENT). All 7 previous findings resolved.
Previous Findings Resolution
- [x] Missing Lineage section -- NOW ADDED with upstream (pal-e-services#173 tofu apply) and downstream (#93 verify site live)
- [x] Missing Acceptance Criteria -- NOW ADDED with 6 verifiable conditions
- [x] Keycloak env var placement unspecified -- NOW CLARIFIED: ConfigMap for KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID; Secret for KEYCLOAK_CLIENT_SECRET
- [x] redirect-middleware.yaml unclear -- NOW ANNOTATED as conditional ("only if needed; Tailscale funnels may handle HTTPS redirect natively")
- [x] Undocumented tofu apply dependency -- NOW IN LINEAGE as upstream blocker
- [x] [SCOPE] Create arch-k8s-deploy note -- NOW EXISTS in pal-e-docs (comprehensive k8s deployment architecture)
- [x] [SCOPE] Create arch-keycloak note -- NOW EXISTS in pal-e-docs (Keycloak OIDC architecture)
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- present (upstream: pal-e-services#173, downstream: #93, sprint: 12)
- [x] Repo -- prediction-assistant
- [x] User Story -- present
- [x] Context -- present, includes Keycloak env var placement and ingress clarification
- [x] File Targets -- 7 targets (3 new, 4 existing)
- [x] Feature Flag -- None (acceptable for infra work)
- [x] Acceptance Criteria -- 6 items, all verifiable
- [x] Test Expectations -- 3 items
- [x] Constraints -- present
- [x] Checklist -- present (Code complete checked)
- [x] Related -- present
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: platform-setup, role: Developer)
- [x] arch:k8s-deploy label -- Kubernetes Deployment
- [x] arch note verified -- arch-k8s-deploy exists in pal-e-docs (created 2026-07-03, comprehensive with diagram, directory structure, components)
- [x] arch:keycloak label -- Keycloak OIDC
- [x] arch note verified -- arch-keycloak exists in pal-e-docs (client pattern, config location, Terraform-managed)
- [x] Forgejo issue -- ldraney/prediction-assistant#105, closed (consistent with validation column -- implementation merged)
File Targets
- [x] k8s/overlays/prod/ingress.yaml (new) -- verified: does not exist, correctly marked as new
- [x] k8s/overlays/prod/cluster-issuer.yaml (new) -- verified: does not exist, correctly marked as new
- [x] k8s/overlays/prod/redirect-middleware.yaml (new, conditional) -- verified: does not exist. Now annotated as conditional on Tailscale funnel behavior. Previous concern RESOLVED.
- [x] k8s/overlays/prod/kustomization.yaml -- verified: exists (73 lines, has image pin, patches, labels). New resources will need adding.
- [x] k8s/base/configmap.yaml -- verified: exists with RAILS_ENV, RAILS_LOG_TO_STDOUT, RAILS_SERVE_STATIC_FILES, RAILS_MAX_THREADS, PORT. No Keycloak vars present (confirms gap).
- [x] k8s/base/deployment.yaml -- verified: exists with envFrom configMapRef and individual secretKeyRef entries (DATABASE_URL, SECRET_KEY_BASE, KALSHI_*). No Keycloak env vars. Pattern clear for adding KEYCLOAK_CLIENT_SECRET as another secretKeyRef.
- [x] k8s/base/worker-deployment.yaml -- verified: exists with same env pattern as deployment.yaml. No Keycloak env vars.
Repo Placement
OK -- issue filed on ldraney/prediction-assistant. All 7 file targets within prediction-assistant repo k8s/ directory. Single repo.
Dependencies
- Upstream (documented): pal-e-services#173 "tofu apply" (board item 1772, todo column, sprint:12) -- provisions prediction-assistant-secrets with KEYCLOAK_CLIENT_SECRET. Documented in Lineage. RESOLVED from previous review.
- Downstream (documented): prediction-assistant#93 "Verify prediction-assistant.com is live" (board item 1774, todo column, sprint:12). Documented in Lineage.
- Transitive (implicit, not blocking): pal-e-services#171 "Add Keycloak realm + OIDC client" (board item 1768, validation column, sprint:11) -- realm must exist before env vars are meaningful. Covered transitively through #173.
Acceptance Criteria
6 criteria, all verifiable:
- [x] AC1: "Tailscale Ingress resource created and assigned hostname" -- verifiable via kustomize build output
- [x] AC2: "HTTPS redirect applied" -- annotated with flexibility (funnel config OR middleware). Verifiable by checking resource/annotation presence.
- [x] AC3: "Keycloak env vars wired: ConfigMap for KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID" -- verifiable by inspecting configmap.yaml
- [x] AC4: "KEYCLOAK_CLIENT_SECRET wired from prediction-assistant-secrets Secret" -- verifiable by checking deployment manifest for secretKeyRef
- [x] AC5: "Pods can start with all required env vars present" -- post-deploy verification, reasonable
- [x] AC6: "kustomize build k8s/overlays/prod/ succeeds" -- verifiable by agent
Keycloak env vars cross-verified against app code: omniauth.rb, sessions_controller.rb, and keycloak_admin_service.rb all reference the same 4 env vars (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET). Issue correctly identifies all 4 with appropriate ConfigMap/Secret separation.
Blast Radius
- ConfigMap changes via envFrom propagate to both web and worker deployments -- both listed as file targets. Covered.
- Adding Keycloak vars to base/ affects both prod and dev overlays. Dev overlay could need different Keycloak URL/realm. Minor future concern -- not a blocker for this ticket.
- No sibling services in this repo.
- Existing env var pattern (individual secretKeyRef entries) is well-established -- adding KEYCLOAK_CLIENT_SECRET follows the same pattern as DATABASE_URL, SECRET_KEY_BASE, and KALSHI_* keys.
Decomposition Assessment
7 file targets in 1 repo, 6 acceptance criteria. AC count is 1 over the >5 threshold, but ACs 5 and 6 are verification steps (not independent work items). Actual work items: create ingress.yaml, add 3 vars to configmap, add secretKeyRef to 2 deployments, update kustomization resources. All follow existing patterns. Estimated agent work: 3-4 minutes. No decomposition needed.
Recommendation
No action needed. All previous NEEDS_REFINEMENT findings resolved. Scope is solid, traceability complete (including backing arch notes), file targets verified, dependencies documented, acceptance criteria clear and testable.
-
Review: Bootstrap salt-minion on edge-proxy (Hetzner VPS)
review-1813-2026-07-05-r2Verdict: APPROVED
Re-review of board item #1813. Previous review (
review-1813-2026-07-05) found 2 issues: 5 missing bug template sections and missingarch-edge-proxyarchitecture note. Both are now resolved.Template Completeness
Issue type: Bug. Checked against
template-issue-bug.- [x] Type -- present ("Bug")
- [x] Lineage -- present ("Blocks pal-e-platform#516... Standalone discovery during prediction-assistant S11 deploy")
- [x] Repo -- present ("ldraney/pal-e-platform")
- [x] What Broke -- present as "Problem" (semantically equivalent, header name differs slightly)
- [x] Repro Steps -- present (salt test.ping + salt-minion --version commands)
- [x] Expected Behavior -- present (test.ping returns True, salt-apply works)
- [x] Environment -- present (Hetzner CPX11, Debian 12, Tailscale 100.72.199.14)
- [x] Acceptance Criteria -- present (3 criteria)
- [x] Related -- present (blocks listed)
Extra sections: Impact (useful), Solution (useful). All 9 required Bug template sections are present.
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified --
platform-setupentry exists in project-prediction-assistant user-stories section (Developer role, "CI/CD push-to-deploy in under 10 minutes") - [x] arch:edge-proxy label -- edge proxy component
- [x] arch note verified --
arch-edge-proxynote exists in pal-e-docs (architecture type, active status, pal-e-platform project). Comprehensive content including diagram, components table, provisioning flow, and "Known Gap: Salt-Minion Not Bootstrapped" section - [x] Forgejo issue -- ldraney/pal-e-platform#521, closed (status:approved label)
File Targets
- [x]
terraform/modules/hetzner-edge/cloud-init.yaml-- verified: exists, contains only Tailscale + Caddy bootstrap (no salt-minion), confirms issue claim - [x]
salt/bootstrap.sh-- verified: exists, is Arch-only (uses paru, hardcodesMINION_ID="archbox"), confirms issue claim - [x]
salt/states/top.sls-- verified: line 23 references'edge-proxy'with caddy state assignment - [x]
salt/pillar/top.sls-- verified: line 22 references'edge-proxy'
Repo Placement
OK. Issue filed on
ldraney/pal-e-platform, fix targets files inpal-e-platform(cloud-init.yaml and/or bootstrap script). Board item is onboard-prediction-assistantas a cross-project dependency -- acceptable since this blocks prediction-assistant deployment.Dependencies
- Blocks: pal-e-platform#516 (Apply Caddy salt state) -- board item #1771, currently in
validationcolumn - Blocks: prediction-assistant#93 (Verify prediction-assistant.com is live) -- board item #1774, currently in
todocolumn - Sprint: 12 (deploy + verify)
- pal-e-services#173 (tofu apply) in
todois also S12 work, not directly dependent but same sprint
Forgejo issue is now closed with
status:approved, indicating implementation has merged. Board item is invalidationcolumn awaiting post-merge verification.Acceptance Criteria
3 ACs, all clear and testable:
- AC1: Salt-minion installed on edge-proxy via IaC -- verifiable by code review of cloud-init or bootstrap script
- AC2:
salt edge-proxy test.pingreturns True -- requires SSH to archbox for verification - AC3:
make salt-applysucceeds for edge-proxy -- requires SSH to archbox
AC2 and AC3 are integration-level checks requiring remote execution. An agent can implement the code changes but verification requires SSH access to archbox.
Blast Radius
salt/bootstrap.shis Arch-only. If a Debian bootstrap path is added, future Debian hosts would benefit. No other Debian minions currently intop.sls.- Any future Hetzner VPS would have the same cloud-init gap if not updated.
arch-edge-proxynote documents the gap under "Known Gap: Salt-Minion Not Bootstrapped" -- good traceability.
Decomposition Assessment
2 primary file targets in 1 repo. 3 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendations
No action needed. Both issues from the previous review have been resolved:
- All 5 missing Bug template sections (Lineage, Repo, Repro Steps, Expected Behavior, Environment) are now present in the Forgejo issue body.
- The
arch-edge-proxyarchitecture note now exists with comprehensive documentation of the edge proxy component, including the known salt-minion gap.
-
Review: Bootstrap salt-minion on edge-proxy (Hetzner VPS)
review-1813-2026-07-05Verdict: NEEDS_REFINEMENT
Template Completeness
Issue type: Bug. Checked against
template-issue-bug.- [x] Type -- present ("Bug")
- [ ] Lineage -- MISSING
- [ ] Repo -- MISSING
- [x] What Broke -- present as "Problem" (semantically equivalent, header name differs)
- [ ] Repro Steps -- MISSING
- [ ] Expected Behavior -- MISSING
- [ ] Environment -- MISSING
- [x] Acceptance Criteria -- present (3 criteria)
- [x] Related -- present (blocks listed)
Extra sections in issue not in template: Impact (useful), Solution (useful). 5 of 9 required Bug template sections are missing or misnamed.
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified --
story-prediction-assistant-platform-setupexists in pal-e-docs (user-story type, active) - [x] arch:edge-proxy label -- edge proxy component
- [ ] arch note MISSING -- [SCOPE] Create architecture note
arch-edge-proxyfor the Hetzner VPS edge-proxy component - [x] Forgejo issue -- ldraney/pal-e-platform#521, open
File Targets
- [x]
terraform/modules/hetzner-edge/cloud-init.yaml-- verified: exists, contains only Tailscale + Caddy bootstrap (no salt-minion), confirms issue claim - [x]
salt/bootstrap.sh-- verified: exists, is Arch-only (uses paru, hardcodesMINION_ID="archbox"), confirms issue claim - [x]
salt/states/top.sls-- verified: referencesedge-proxywithcaddystate assignment - [x]
salt/pillar/top.sls-- verified: referencesedge-proxy
Repo Placement
OK. Issue filed on
ldraney/pal-e-platform, fix targets files inpal-e-platform(cloud-init.yaml and/or bootstrap script). Board item is onboard-prediction-assistantas a cross-project dependency -- acceptable since this blocks prediction-assistant deployment.Dependencies
- Blocks: pal-e-platform#516 (Apply Caddy salt state) -- board item #1771, currently in
validationcolumn - Blocks: prediction-assistant#93 (Verify prediction-assistant.com is live) -- board item #1774, currently in
todocolumn - Sprint: 12 (deploy + verify)
- pal-e-services#173 (tofu apply) in
todois also S12 work, not directly dependent but same sprint
Note: #1771 (pal-e-platform#516) is in the
validationcolumn, suggesting it was merged but validation found the salt-minion prerequisite missing. This is consistent with the bug classification.Acceptance Criteria
3 ACs, all clear and testable:
- AC1: Salt-minion installed via IaC -- verifiable by code review of cloud-init or bootstrap script
- AC2:
salt edge-proxy test.pingreturns True -- requires SSH to archbox for verification - AC3:
make salt-applysucceeds for edge-proxy -- requires SSH to archbox; notemake salt-applycurrently runssalt-call state.apply(local), notsalt 'edge-proxy' state.apply(remote). May need a targeted salt command instead.
AC2 and AC3 are integration-level checks requiring remote execution. An agent can implement the code changes but may not be able to verify these without SSH access to archbox.
Blast Radius
salt/bootstrap.shis Arch-only. If a Debian bootstrap path is added, future Debian hosts would benefit. No other Debian minions currently intop.sls.lucass-macbook-air-1is also intop.slswithmac-agentstate -- different OS, separate concern.- Any future Hetzner VPS would have the same cloud-init gap if not updated.
Decomposition Assessment
2 primary file targets in 1 repo. 3 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendations
- [BODY] Add missing Bug template sections or restructure to match
template-issue-bug: add Lineage (e.g., "Standalone -- discovered during S12 deploy validation"), Repo (ldraney/pal-e-platform), Repro Steps (e.g., "1. SSH to archbox, 2. Runsalt edge-proxy test.ping, 3. Observe: minion not found"), Expected Behavior ("salt-minion running on edge-proxy, test.ping returns True"), Environment (Hetzner Debian 12, salt master on archbox at 100.110.151.59) - [SCOPE] Create architecture note
arch-edge-proxyfor the Hetzner VPS edge-proxy component. Multiple board items referencearch:edge-proxy(items #1692, #1726, #1771, #1813) but no backing arch note exists.
-
Review: Add Ingress/TLS + wire Keycloak env vars for production deploy
review-1812-2026-07-05Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [ ] Lineage — MISSING
- [x] Repo — prediction-assistant
- [x] User Story — present
- [x] Context — present
- [x] File Targets — 7 targets (3 new, 4 existing)
- [x] Feature Flag — None (acceptable for infra work)
- [ ] Acceptance Criteria — MISSING (only Test Expectations present)
- [x] Test Expectations — present (3 items)
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present (Blocks #93, Sprint 12)
Traceability
- [x] story:platform-setup label — Platform Setup
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:k8s-deploy label — k8s deployment component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-k8s-deploy for component k8s-deploy
- [x] arch:keycloak label — Keycloak auth component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-keycloak for component keycloak
- [x] Forgejo issue — ldraney/prediction-assistant#105, open
File Targets
- [x] k8s/overlays/prod/ingress.yaml (new) — verified: does not exist, correctly marked as new
- [x] k8s/overlays/prod/cluster-issuer.yaml (new) — verified: does not exist, correctly marked as new
- [ ] k8s/overlays/prod/redirect-middleware.yaml (new) — ISSUE: resource type unclear. "Middleware" is a Traefik CRD concept. Issue does not specify which ingress controller is in use or what k8s resource kind this file should contain
- [x] k8s/overlays/prod/kustomization.yaml — verified: exists, currently has image pin, patches, and labels. New resources must be added to the resources list
- [x] k8s/base/configmap.yaml — verified: exists with RAILS_ENV, RAILS_LOG_TO_STDOUT, RAILS_SERVE_STATIC_FILES, RAILS_MAX_THREADS, PORT. No Keycloak vars present (confirms the gap)
- [x] k8s/base/deployment.yaml — verified: exists with envFrom configMapRef and secret env vars (DATABASE_URL, SECRET_KEY_BASE, KALSHI_*). No Keycloak env vars present
- [x] k8s/base/worker-deployment.yaml — verified: exists with same env pattern as deployment.yaml. No Keycloak env vars present
Repo Placement
OK — issue filed on ldraney/prediction-assistant. All 7 file targets are within the prediction-assistant repo k8s/ directory.
Dependencies
- Documented: Blocks #93 "Verify prediction-assistant.com is live" (todo column, sprint:12)
- Undocumented: Depends on pal-e-services#173 "tofu apply — provision prediction-assistant infra" (board item 1772, todo column, sprint:12). The Keycloak env vars reference secrets (KEYCLOAK_CLIENT_SECRET at minimum) that must be provisioned by Terraform before pods can start with correct auth. This dependency is not documented in the issue.
- Related: pal-e-services#171 "Add Keycloak realm + OIDC client" (validation column, sprint:11) — the Keycloak realm and OIDC client must exist before these env vars are meaningful.
Acceptance Criteria
No ### Acceptance Criteria section exists. The Test Expectations section provides partial coverage but is insufficient:
- "kustomize build k8s/overlays/prod/ succeeds" — verifiable by agent
- "Ingress routes prediction-assistant.com to service" — only verifiable post-deploy, not by agent
- "Keycloak env vars present in pod specs" — verifiable via kustomize build output, but does not specify WHICH vars
Missing criteria:
- Which specific Keycloak env vars must appear: KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_URL, KEYCLOAK_REALM (per config/initializers/omniauth.rb)
- KEYCLOAK_CLIENT_SECRET must come from a Secret (not ConfigMap) — security constraint not stated
- TLS certificate provisioning verified (ClusterIssuer references valid issuer)
- HTTP-to-HTTPS redirect behavior
Blast Radius
- ConfigMap changes via envFrom propagate to both web and worker deployments — both are listed as file targets, so this is covered
- Adding Keycloak env vars to base/ affects both prod and dev overlays. If dev should use different Keycloak settings (different realm URL, different client), the issue should specify overlay-level overrides
- No sibling services in this repo to check for similar patterns
Decomposition Assessment
7 file targets in 1 repo, 3 test expectations, estimated agent work ~3-5 minutes. No decomposition needed.
Recommendation
[BODY]Add ### Acceptance Criteria section with verifiable conditions: "kustomize build output contains KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_URL, KEYCLOAK_REALM in pod specs", "KEYCLOAK_CLIENT_SECRET sourced from Secret not ConfigMap", "Ingress host is prediction-assistant.com", "TLS secretName references cert-manager Certificate"[BODY]Add ### Lineage section (e.g., "Standalone — discovered during deployment audit")[BODY]Specify which Keycloak env vars (KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_URL, KEYCLOAK_REALM per config/initializers/omniauth.rb) and whether each goes in ConfigMap or Secret (KEYCLOAK_CLIENT_SECRET MUST be a Secret)[BODY]Clarify what k8s resource type redirect-middleware.yaml represents (Traefik Middleware CRD? Ingress annotation? Something else?) and which ingress controller is in use[BODY]Document dependency on tofu apply (pal-e-services#173) for k8s secrets provisioning[SCOPE]Create architecture note arch-k8s-deploy for component k8s-deploy[SCOPE]Create architecture note arch-keycloak for component keycloak
-
Review: Scaffold Turbo Native iOS app (re-review)
review-1775-2026-07-05-r2Verdict: APPROVED
Re-review of board item #1775. Previous review (
review-1775-2026-07-05) found one[SCOPE]issue: arch-ios note was scoped only to landscaping-assistant. That has been resolved.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, modeled after landscaping-assistant-ios
- [x] Repo -- ldraney/prediction-assistant-ios
- [x] User Story -- present
- [x] Context -- present
- [x] File Targets -- 15 files to create, 1 exclusion
- [x] Feature Flag -- "none" (correct for iOS scaffold)
- [x] Acceptance Criteria -- 5 criteria
- [x] Test Expectations -- present with run command
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:app-experience label -- App Experience
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:ios label -- iOS / Turbo Native
- [x] arch note verified --
arch-iosnote exists in pal-e-docs, now cross-project with "Projects Using This Pattern" section covering both landscaping-assistant-ios and prediction-assistant-ios. Hasprediction-assistanttag. - [x] Forgejo issue -- ldraney/prediction-assistant-ios#2, open
File Targets
- [x]
project.yml-- verified: matches landscaping-assistant-ios - [x]
PredictionAssistant/AppDelegate.swift-- verified: matches LandscapingAssistant/AppDelegate.swift - [x]
PredictionAssistant/SceneDelegate.swift-- verified: matches LandscapingAssistant/SceneDelegate.swift - [x]
PredictionAssistant/Info.plist-- verified: matches LandscapingAssistant/Info.plist - [x]
PredictionAssistant/Assets.xcassets/-- verified: matches LandscapingAssistant/Assets.xcassets/ - [x]
fastlane/Appfile-- verified: exists in reference repo - [x]
fastlane/Fastfile-- verified: exists in reference repo - [x]
fastlane/Deliverfile-- verified: exists in reference repo - [x]
fastlane/metadata/-- verified: exists in reference repo with review_information/, en-US/, copyright.txt - [x]
fastlane/rating_config.json-- verified: exists in reference repo - [x]
build-testflight.sh-- verified: exists in reference repo - [x]
scripts/export-certs.sh-- verified: exists in reference repo - [x]
scripts/fix-keychain.sh-- verified: exists in reference repo - [x]
scripts/import-ci-keychain.sh-- verified: exists in reference repo - [x]
.gitignore-- verified: exists in reference repo
Target repo (prediction-assistant-ios) confirmed to contain only README.md currently. All 15 file targets verified against the landscaping-assistant-ios reference repo tree.
Repo Placement
OK. Forgejo issue filed on ldraney/prediction-assistant-ios. Board item links to the same. All work is in one repo. No cross-repo concerns.
Dependencies
- #1774 "Verify prediction-assistant.com is live" (sprint:12, backlog) -- direct prerequisite. Issue Lineage states "prediction-assistant.com must be live first." Sprint ordering is correct (S12 before S13).
- #1772 "tofu apply -- provision prediction-assistant infra" (sprint:12, backlog) -- upstream of #1774.
- #1776 "TestFlight beta build on MacBook" (sprint:13, backlog) -- downstream, depends on this ticket completing first.
Sprint ordering (S12 infra, then S13 iOS) is correct. Dependencies are implied by sprint labels and the Lineage section but not explicitly listed in the issue body. Acceptable given the Lineage statement.
Acceptance Criteria
5 criteria, all testable:
- AC 1-2: xcodegen + Xcode build -- verifiable locally with the provided run command
- AC 3: App loads prediction-assistant.com -- requires live site (S12 prerequisite satisfied by sprint ordering)
- AC 4: Fastlane config -- verifiable by inspecting Appfile contents
- AC 5: Keycloak login in web view -- requires live site + Keycloak realm (S12 prerequisite)
Test command (
xcodegen generate && xcodebuild -scheme PredictionAssistant -sdk iphonesimulator build) is real and executable on macOS. Note: AC 3 and 5 can only be fully validated after S12 deployment completes.Blast Radius
Low. Isolated iOS scaffold repo. No downstream consumers beyond the TestFlight build ticket (#1776). Pattern already proven with landscaping-assistant-ios. Rails-side Turbo Native support already in place per docs/platform/turbo-native-pipeline.md.
Decomposition Assessment
15 file targets in 1 repo. 5 acceptance criteria (at limit, not over). Estimated agent work: copy-and-adapt from landscaping-assistant-ios reference repo. This is scaffolding work -- no complex logic, no multi-system coordination. Under 5 minutes. No decomposition needed.
Previous Review Findings -- Resolution
[SCOPE]arch-ios note scoped only to landscaping-assistant -- RESOLVED. Thearch-iosnote now has a "Projects Using This Pattern" section listing both landscaping-assistant-ios and prediction-assistant-ios, and carries theprediction-assistanttag.
Recommendation
No action needed.
-
Review v2: Verify prediction-assistant.com is live
review-1774-2026-07-05-v2Verdict: READY
Re-review after refinements applied. All issues from review-1774-2026-07-05 have been resolved: type corrected to Task, File Targets replaced with Scope section, arch-k8s-deploy note created.
Template Completeness
- [x] Type — Task
- [x] Lineage — dependencies listed
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — present
- [x] Context — clear motivation (end-to-end deploy verification)
- [x] Scope — verification-only, no code changes
- [x] Feature Flag — none (appropriate)
- [x] Acceptance Criteria — 5 criteria
- [x] Test Expectations — manual browser + curl command
- [x] Constraints — upstream infra dependency noted
- [x] Checklist — present
- [x] Related — project reference
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:k8s-deploy label — Kubernetes Deployment
- [x] arch note verified — arch-k8s-deploy note exists in pal-e-docs (active, with full Mermaid diagram and component table)
- [x] Forgejo issue — ldraney/prediction-assistant#93, open
File Targets
N/A — Task type with no code changes. Scope section correctly describes verification-only work.
Repo Placement
OK — Issue filed on ldraney/prediction-assistant, matches Repo field. Verification task touches no code.
Dependencies
Lineage section documents: "Depends on: all infra provisioned, CI green, Caddy applied, ArgoCD synced." Board items confirm:
- #1772 — tofu apply (sprint:12, backlog) — direct prerequisite
- #1773 — Woodpecker activation (sprint:12, backlog) — direct prerequisite
- #1771 — Caddy salt state (sprint:11, validation) — direct prerequisite
- #1767 — services terraform (sprint:11, validation) — upstream
- #1768 — Keycloak realm (sprint:11, validation) — upstream
- #1770 — .woodpecker.yaml CI pattern (sprint:11, validation) — upstream
All upstream work is in validation or backlog. Ticket correctly sits in backlog until prerequisites complete.
Acceptance Criteria
5 criteria, all verifiable by an agent:
- curl returns 200 — direct CLI check
- Landing page renders — browser or curl verification
- Login redirects to Keycloak — HTTP redirect inspection
- Keycloak login succeeds — requires test credentials (documented in Keycloak realm)
- ArgoCD shows Synced + Healthy — CLI or API check
Test command provided:
curl -sI https://prediction-assistant.com— real and executable.Blast Radius
None. Verification-only task with no code changes. No downstream consumers affected.
Decomposition Assessment
No decomposition needed. Task type with 0 file targets, 5 acceptance criteria (all simple verification steps), estimated agent work under 2 minutes.
Recommendation
No action needed.
-
Review: Scaffold Turbo Native iOS app
review-1775-2026-07-05Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, modeled after landscaping-assistant-ios
- [x] Repo — ldraney/prediction-assistant-ios
- [x] User Story — present
- [x] Context — present
- [x] File Targets — 15 files to create, 1 exclusion
- [x] Feature Flag — "none" (correct for iOS scaffold)
- [x] Acceptance Criteria — 5 criteria
- [x] Test Expectations — present with run command
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:ios label — iOS / Turbo Native
- [ ] arch note PARTIAL —
arch-iosnote exists in pal-e-docs but is scoped tolandscaping-assistantproject, notprediction-assistant. [SCOPE] Create or update arch-ios note for prediction-assistant iOS component - [x] Forgejo issue — ldraney/prediction-assistant-ios#2, open
File Targets
- [x]
project.yml— verified: matches landscaping-assistant-ios - [x]
PredictionAssistant/AppDelegate.swift— verified: matches LandscapingAssistant/AppDelegate.swift - [x]
PredictionAssistant/SceneDelegate.swift— verified: matches LandscapingAssistant/SceneDelegate.swift - [x]
PredictionAssistant/Info.plist— verified: matches LandscapingAssistant/Info.plist - [x]
PredictionAssistant/Assets.xcassets/— verified: matches LandscapingAssistant/Assets.xcassets/ - [x]
fastlane/Appfile— verified: exists in reference repo - [x]
fastlane/Fastfile— verified: exists in reference repo - [x]
fastlane/Deliverfile— verified: exists in reference repo - [x]
fastlane/metadata/— verified: exists in reference repo with review_information/, en-US/, copyright.txt - [x]
fastlane/rating_config.json— verified: exists in reference repo - [x]
build-testflight.sh— verified: exists in reference repo - [x]
scripts/export-certs.sh— verified: exists in reference repo - [x]
scripts/fix-keychain.sh— verified: exists in reference repo - [x]
scripts/import-ci-keychain.sh— verified: exists in reference repo - [x]
.gitignore— verified: exists in reference repo
Target repo (prediction-assistant-ios) confirmed to contain only README.md currently. All 15 file targets verified against the landscaping-assistant-ios reference repo tree.
Repo Placement
OK. Forgejo issue filed on ldraney/prediction-assistant-ios. Board item links to the same. All work is in one repo. No cross-repo concerns.
Dependencies
- #1774 "Verify prediction-assistant.com is live" (sprint:12, backlog) — direct prerequisite. Issue Lineage states "prediction-assistant.com must be live first." Sprint ordering is correct (S12 before S13).
- #1772 "tofu apply — provision prediction-assistant infra" (sprint:12, backlog) — upstream of #1774.
- #1776 "TestFlight beta build on MacBook" (sprint:13, backlog) — downstream, depends on this ticket completing first.
Sprint ordering (S12 infra, then S13 iOS) is correct. Dependencies are implied by sprint labels and the Lineage section but not explicitly listed in the issue body. Acceptable given the Lineage statement.
Acceptance Criteria
5 criteria, all testable:
- AC 1-2: xcodegen + Xcode build — verifiable locally with the provided run command
- AC 3: App loads prediction-assistant.com — requires live site (S12 prerequisite satisfied by sprint ordering)
- AC 4: Fastlane config — verifiable by inspecting Appfile contents
- AC 5: Keycloak login in web view — requires live site + Keycloak realm (S12 prerequisite)
Test command (
xcodegen generate && xcodebuild -scheme PredictionAssistant -sdk iphonesimulator build) is real and executable on macOS. Note: AC 3 and 5 can only be fully validated after S12 deployment completes.Blast Radius
Low. Isolated iOS scaffold repo. No downstream consumers beyond the TestFlight build ticket (#1776). Pattern already proven with landscaping-assistant-ios. Rails-side Turbo Native support already in place per docs/platform/turbo-native-pipeline.md.
Decomposition Assessment
15 file targets in 1 repo. 5 acceptance criteria (at limit, not over). Estimated agent work: copy-and-adapt from landscaping-assistant-ios reference repo. This is scaffolding work — no complex logic, no multi-system coordination. Under 5 minutes. No decomposition needed.
Recommendation
[SCOPE]Create architecture note for prediction-assistant iOS component. The existingarch-iosnote is scoped tolandscaping-assistant. Either create a prediction-assistant-specific arch note or updatearch-iosto be cross-project with project-specific sections.
-
Review: TestFlight beta build on MacBook
review-1776-2026-07-05Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- "Depends on: iOS scaffold complete, prediction-assistant.com live."
- [x] Repo -- ldraney/prediction-assistant-ios
- [x] User Story -- present
- [x] Context -- present
- [x] File Targets -- "none -- execution task using existing Fastlane config"
- [x] Feature Flag -- "none"
- [x] Acceptance Criteria -- 4 items
- [x] Test Expectations -- present
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:app-experience label -- App Experience (Consumer)
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:ios label -- iOS (turbo-ios) component
- [x] arch note verified -- arch-ios note exists in pal-e-docs (under landscaping-assistant project, same Turbo Native stack). Prediction-assistant also has comprehensive docs/platform/turbo-native-pipeline.md covering iOS architecture.
- [x] Forgejo issue -- ldraney/prediction-assistant-ios#3, open
File Targets
- [x] No file modifications -- this is an execution task (run fastlane beta on MacBook)
- [x] build-testflight.sh -- referenced in Test Expectations; confirmed this file is listed in scaffold ticket (issue #2) File Targets
- [x] fastlane/ -- correctly marked as "do not touch" (created by scaffold ticket)
Repo Placement
OK. Forgejo issue filed on ldraney/prediction-assistant-ios, matching the Repo section. Work is an execution task on the iOS repo. No other repos affected.
Dependencies
- Board item #1775: "Scaffold Turbo Native iOS app" (backlog, sprint:13) -- must complete first. Creates fastlane config, build-testflight.sh, and XcodeGen project.
- Board item #1774: "Verify prediction-assistant.com is live" (backlog, sprint:12) -- must complete first. App loads prediction-assistant.com in the native web view.
- Board item #1772: "tofu apply -- provision prediction-assistant infra" (backlog, sprint:12) -- transitive dependency via #1774.
- All dependencies documented in Lineage section.
Acceptance Criteria
4 criteria, all reasonable for an iOS deployment ticket. Criterion 1 (fastlane beta completes) is agent-verifiable via exit code. Criteria 2-4 (App Store Connect, TestFlight install, login works) require manual verification, which is appropriate for a physical-device deployment task. Test command references SSH to MacBook which matches Constraints section.
Blast Radius
Low. This is a build-and-upload execution task with no code changes. No downstream code consumers affected. The only external system touched is App Store Connect / TestFlight.
Decomposition Assessment
No decomposition needed. Zero file targets (execution task), 4 acceptance criteria, 1 repo, estimated agent work well under 5 minutes for the build trigger. Manual verification steps are inherent to iOS deployment and cannot be decomposed further.
Recommendation
No action needed.
-
Review: Verify prediction-assistant.com is live
review-1774-2026-07-05Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets (states "none — verification only")
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All sections present. However, see [BODY] recommendation below regarding Type classification.
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified —
story-prediction-assistant-app-experienceexists (active) and is listed inproject-prediction-assistantuser-stories section - [x] arch:k8s-deploy label — k8s deployment component
- [ ] arch note MISSING — [SCOPE] Create architecture note
arch-k8s-deployfor the Kubernetes deployment component - [x] Forgejo issue — ldraney/prediction-assistant#93, open
File Targets
- [x] No file modifications — verification-only ticket. k8s manifests exist at
k8s/base/deployment.yaml,k8s/overlays/prod/ingress.yaml, andconfig/environments/production.rbreferencesprediction-assistant.com. No changes needed.
Repo Placement
Filed on
ldraney/prediction-assistant, matches Repo field. Verification touches multiple systems (DNS/Terraform in pal-e-services, Caddy in pal-e-platform, k8s in prediction-assistant) but since no code changes are made, single-repo placement is appropriate.Dependencies
Lineage states "Depends on: all infra provisioned, CI green, Caddy applied, ArgoCD synced." Specific board dependencies:
- S12 peers (backlog): #1772 tofu apply (pal-e-services#173), #1773 Woodpecker activation (prediction-assistant#92) — both still in backlog, must complete first
- S11 upstream (validation): #1767 services terraform, #1768 Keycloak realm, #1769 CNPG database, #1770 Woodpecker YAML, #1771 Caddy salt state — all in validation column
Dependencies are captured at intent level in Lineage but not as specific board item references.
Acceptance Criteria
5 criteria, all verifiable by an agent:
curl -sI https://prediction-assistant.com— real command, verifies HTTP 200- Landing page render — verifiable via browser automation / screenshot
- Keycloak login redirect — verifiable via browser automation
- Keycloak login success + redirect back — verifiable (requires test credentials)
- ArgoCD Synced + Healthy — verifiable via ArgoCD CLI or UI
Criteria are clear and testable. No missing criteria identified.
Blast Radius
Minimal. Verification-only ticket with no code changes. Validates the full deploy pipeline end-to-end (DNS → Caddy → Tailscale → k8s → Rails). No downstream consumers affected.
Decomposition Assessment
0 file targets, 5 acceptance criteria, single repo, estimated agent work under 5 minutes. No decomposition needed.
Recommendation
[BODY]Change### Typefrom "Feature" to "Task" — this is purely verification with no code changes. Per template-issue convention, Task type uses### Scopeinstead of### File Targets. Replace the File Targets section with a Scope section describing the verification steps.[SCOPE]Create architecture notearch-k8s-deployfor the Kubernetes deployment component in pal-e-docs. This note should cover the k8s manifest structure, overlay strategy, ArgoCD sync, and ingress configuration.
-
Review: Activate repo in Woodpecker + first green build
review-1773-2026-07-05Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- documents dependency on .woodpecker.yaml + tofu apply
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- present
- [x] Context -- present, sufficient background
- [x] File Targets -- "none" (correctly identified as Woodpecker UI/API task)
- [x] Feature Flag -- "none" (appropriate for infra task)
- [x] Acceptance Criteria -- 4 criteria, all verifiable
- [x] Test Expectations -- 2 manual verifications
- [x] Constraints -- 2 constraints documented
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:ci-pipeline label -- CI Pipeline
- [x] arch note verified -- arch-ci-pipeline note exists in pal-e-docs (project: pal-e-platform)
- [x] Forgejo issue -- ldraney/prediction-assistant#92, state: open
File Targets
- [x] No file targets claimed -- correct, this is a Woodpecker API/UI activation task
- [x] .woodpecker.yaml verified to exist -- references harbor_username/harbor_password from_secret, consistent with AC
- [x] Dockerfile verified to exist -- referenced by .woodpecker.yaml build-and-push step
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, which is the repo to be activated in Woodpecker. The work itself is Woodpecker API/UI operations, not code changes to the repo. Single repo, no cross-repo concerns.
Dependencies
- #1770 "Update .woodpecker.yaml to match platform CI pattern" -- validation column (prerequisite complete)
- #1772 "tofu apply -- provision prediction-assistant infra" -- backlog, sprint:12 (sequentially blocks this ticket; Harbor project + CI robot credentials come from tofu output)
- #1767 "Add prediction-assistant to services terraform" -- validation (prerequisite for #1772, complete)
Dependency chain is correctly ordered: #1767 (validation) -> #1772 (backlog) -> #1773 (backlog). Lineage section documents the dependency accurately.
Acceptance Criteria
4 criteria, all agent-verifiable:
- "Repo appears in Woodpecker active repos list" -- verifiable via Woodpecker API (list_repos)
- "harbor_username and harbor_password secrets configured" -- verifiable via Woodpecker API (list_repo_secrets)
- "First pipeline on main completes green" -- verifiable via Woodpecker API (list_pipelines + get_pipeline_status)
- "Image prediction-assistant/app:<sha> exists in Harbor" -- verifiable via Harbor API
Note: the pipeline also uses forgejo_user/forgejo_password global secrets for clone. These are global Woodpecker secrets shared across all repos and should already exist. Not a gap in scope.
Blast Radius
Minimal. This is a Woodpecker activation + secret creation task. No code changes to the repo. Only affects prediction-assistant CI pipeline. No downstream consumers affected.
Decomposition Assessment
0 file targets, 4 acceptance criteria, estimated < 5 minutes of agent work. No decomposition needed.
Recommendation
No action needed.
-
Review: tofu apply -- provision prediction-assistant infra
review-1772-2026-07-05Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- dependencies on services terraform, Keycloak, CNPG database
- [x] Repo --
ldraney/pal-e-services - [x] User Story -- present
- [x] Context -- present, explains post-merge apply workflow
- [x] File Targets -- present (correctly states "none" for execution task)
- [x] Feature Flag -- none (correct for infra work)
- [x] Acceptance Criteria -- 5 items, all verifiable
- [x] Test Expectations -- present with run command
- [x] Constraints -- present (merge order, kubeconfig access)
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified --
story-prediction-assistant-platform-setupexists in pal-e-docs (user-story, active, project: prediction-assistant). Listed in project-prediction-assistant user-stories section. - [x] arch:iac label -- Infrastructure as Code
- [x] arch note verified --
arch-iacnote exists (type: architecture, status: active, project: prediction-assistant). Contains Mermaid diagram, components table, and key decisions. - [x] Forgejo issue -- ldraney/pal-e-services#173, open
File Targets
Issue correctly states "none" -- this is a
tofu applyexecution task with no file modifications. All terraform files are already merged via upstream dependencies.Repo Placement
OK. Issue filed on
ldraney/pal-e-services, which is wheretofu applyruns. The terraform directory and tfvars live in pal-e-services. Correct placement.Dependencies
- Upstream (documented in Lineage):
- Board #1767: "Add prediction-assistant to services terraform" (pal-e-services#170) -- validation column (merged)
- Board #1768: "Add Keycloak realm + OIDC client" (pal-e-services#171) -- validation column (merged)
- Board #1769: "Add prediction-assistant database to CNPG" (pal-e-services#172) -- validation column (merged)
- Downstream (not documented but inferred):
- Board #1774: "Verify prediction-assistant.com is live" (sprint:12) -- depends on infra being provisioned
- Board #1773: "Activate repo in Woodpecker + first green build" (sprint:12) -- may depend on namespace/Harbor existing
All upstream dependencies are in validation column (merged, awaiting validation). Lineage section correctly identifies them.
Acceptance Criteria
5 criteria, all machine-verifiable:
- [x]
tofu applyexit code -- directly testable - [x]
kubectl get ns prediction-assistant-- CLI command, verifiable - [x] ArgoCD application check -- verifiable via
argocd app getor kubectl - [x] Harbor project + robot accounts -- verifiable via Harbor API
- [x] Keycloak realm and client -- verifiable via Keycloak admin API
All criteria are testable by an agent with cluster access.
Blast Radius
Low. This provisions NEW resources (namespace, Harbor project, ArgoCD app, Keycloak realm, CNPG database) for the prediction-assistant service. No modifications to existing services. Tofu modules are idempotent. Other services in the same cluster are unaffected.
Decomposition Assessment
No decomposition needed. Zero file targets, 5 acceptance criteria (at threshold), single command execution (
tofu apply) plus verification. Well under 5-minute rule.Recommendation
No action needed. Scope is solid, traceability complete, dependencies documented and merged.
Minor observations (non-blocking):
- The
arch-iacnote heading still references "kalshi-assistant" (old repo name) rather than "prediction-assistant". Not blocking for this ticket but worth a doc cleanup pass. - Issue type is "Feature" but the work is an execution task (no code changes). Functionally correct -- the Checklist item "PR opened" does not apply since there is no PR for a tofu apply. Non-blocking.
-
Review: Add schema.rb drift check to dev agent workflow
review-1779-2026-07-05Verdict: APPROVED
Re-review of board item #1779. Previous review (
review-1779-2026-07-04) flagged 4 issues: wrong story label, missing arch note, vague file targets, repo placement mismatch. All 4 have been resolved.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- present, references S7 QA of PR #96 (issue #88)
- [x] Repo -- present, with explicit cross-repo note
- [x] User Story -- present
- [x] Context -- present, clear explanation of schema.rb drift problem
- [x] File Targets -- present, now specific (see below)
- [x] Feature Flag -- None (correct, documentation-only change)
- [x] Acceptance Criteria -- present, 3 items
- [x] Test Expectations -- present (no code tests needed)
- [x] Constraints -- present, sensible guardrails
- [x] Checklist -- present
- [x] Related -- present, references PR #96 and PR #75
- [x] Points -- 1
Traceability
- [x] story:platform-setup label -- "Platform Setup" (Developer, CI/CD push-to-deploy in under 10 minutes). Previously was story:bot-marketplace (FIXED).
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:rails label -- Rails architecture component
- [x] arch note verified -- arch-rails note exists in pal-e-docs (active, architecture type, project prediction-assistant). Previously missing (FIXED).
- [x] Forgejo issue -- ldraney/prediction-assistant#99, open
File Targets
- [x]
~/claude-custom/agents/dev.md-- verified: file exists (4.3k), already has "Infrastructure Enforcement" and "Python Enforcement" sections where a "Rails Enforcement" section fits naturally. Previously vague ("Dev agent type definition (if applicable)") -- now specific (FIXED). - [x]
pal-e-docs agent-workflow note-- secondary deliverable, note to be created. Acceptable for a 1-point documentation task.
Repo Placement
Issue filed on ldraney/prediction-assistant, primary deliverable in ldraney/claude-custom (agents/dev.md). Cross-repo note in issue body explicitly documents this: "This issue is filed on prediction-assistant because the drift was discovered here (PR #96), but the primary deliverable lives in claude-custom." Previously undocumented (FIXED).
Dependencies
No blockers found. No items in in_progress column. This is a standalone process improvement with no upstream or downstream dependencies.
Acceptance Criteria
3 acceptance criteria, all verifiable by an agent post-implementation:
- AC1: "Dev agents diff schema.rb against base branch before committing" -- verifiable by reading dev.md for the new section
- AC2: "If unrelated changes detected, regenerate from clean db:schema:load && db:migrate cycle" -- clear recovery procedure documented in the section
- AC3: "Document the check in dev agent workflow" -- verifiable by reading dev.md and optionally the pal-e-docs note
Blast Radius
Global fix in dev.md benefits all 7 Rails repos (prediction-assistant, westside-basketball, flightscanner, pal-enterprises, palinks, landscaping-assistant, believers-elite). No downstream consumers affected -- documentation only.
Decomposition Assessment
1 point, 2 file targets (documentation only), 3 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
No action needed. All previously flagged issues have been resolved.
Previous Review Issues -- Resolution Status
- [x] [LABEL] story:bot-marketplace changed to story:platform-setup -- RESOLVED
- [x] [SCOPE] arch-rails note created in pal-e-docs -- RESOLVED
- [x] [BODY] File targets now specify exact path ~/claude-custom/agents/dev.md -- RESOLVED
- [x] [BODY] Cross-repo note added explaining repo placement -- RESOLVED
-
Review: Add schema.rb drift check to dev agent workflow
review-1779-2026-07-04Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — present, references S7 QA of PR #96
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — present
- [x] Context — present, clear explanation of the drift problem
- [x] File Targets — present but vague (see below)
- [x] Feature Flag — None (correct, documentation-only change)
- [x] Acceptance Criteria — present, 3 items
- [x] Test Expectations — present (no code tests needed)
- [x] Constraints — present, sensible guardrails
- [x] Checklist — present
- [x] Related — present, references PR #96 and PR #75
Traceability
- [ ] story:bot-marketplace label — WRONG STORY. This is a dev agent process improvement discovered during QA. It has no relationship to the bot-marketplace user story ("User activates first bot within 2 minutes of login"). The discovery context (issue #88) was story:portfolio-builder work, and the fix is foundational process improvement. [LABEL] Change to story:platform-setup or remove (foundational work, acceptable without story).
- [ ] story note verification — bot-marketplace exists on project-prediction-assistant user-stories section, but the label itself is wrong per above.
- [ ] arch:rails label — present, but no backing architecture note found. search_notes("arch-rails") returned empty. [SCOPE] Create architecture note arch-rails for the Rails component.
- [x] Forgejo issue — ldraney/prediction-assistant#99, open
File Targets
- [ ] "CLAUDE.md or agent-workflow pal-e-docs note" — ISSUE: Vague. CLAUDE.md in prediction-assistant is a symlink to README.md (a docs index, not an instructions file). There is no project-level .claude/CLAUDE.md. No agent-workflow note exists in pal-e-docs (search returned empty). The ticket must specify which file and where. [BODY] Specify exact target: either create a .claude/CLAUDE.md in prediction-assistant with the schema check, or add a Rails enforcement section to ~/.claude/agents/dev.md (lives in claude-custom repo).
- [ ] "Dev agent type definition (if applicable)" — ISSUE: Vague. The dev agent definition exists at ~/.claude/agents/dev.md in the claude-custom repo (not prediction-assistant). It already has domain-specific enforcement sections (Infrastructure, Python) where a "Rails Enforcement" section with the schema.rb check would fit naturally. [BODY] Clarify: ~/.claude/agents/dev.md in ldraney/claude-custom repo.
Repo Placement
Issue is filed on ldraney/prediction-assistant, but the most impactful fix location is ~/.claude/agents/dev.md which lives in the ldraney/claude-custom repo. If the fix only goes in prediction-assistant's CLAUDE.md, it is too narrow — there are 7 Rails projects with schema.rb files (prediction-assistant, westside-basketball, flightscanner, pal-enterprises, palinks, landscaping-assistant, believers-elite) that would all benefit from the check. Adding a "Rails Enforcement" section to dev.md (global) would cover all repos. [BODY] Clarify repo placement: if dev.md in claude-custom is the target, file the issue there or document that the fix is cross-repo.
Dependencies
No blockers found. This is a standalone process improvement. No board items are blocking or blocked by this ticket.
Acceptance Criteria
3 acceptance criteria, all reasonable:
- AC1: "Dev agents diff schema.rb against the base branch before committing" — testable but lacks specificity on implementation mechanism (guideline in CLAUDE.md? section in dev.md? a hook?). The Constraints section says "guideline, not a blocking hook" which helps.
- AC2: "If unrelated changes detected, regenerate from clean db:schema:load && db:migrate cycle" — clear recovery procedure, testable.
- AC3: "Document the check in the dev agent workflow" — testable but vague on location (matches the file targets vagueness).
Blast Radius
7 Rails repos with schema.rb: prediction-assistant, westside-basketball, flightscanner, pal-enterprises, palinks, landscaping-assistant, believers-elite. A global fix in dev.md benefits all. A project-scoped fix in prediction-assistant only benefits one repo. No downstream consumers affected — this is documentation only.
Decomposition Assessment
1 point, 2-3 file targets (documentation only), 3 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
- [LABEL] Change story:bot-marketplace to story:platform-setup (or remove story label — foundational process work is acceptable without a user story).
- [SCOPE] Create architecture note arch-rails for the Rails component in pal-e-docs.
- [BODY] Resolve file target ambiguity: specify whether the fix goes in (a) ~/.claude/agents/dev.md as a "Rails Enforcement" section (global, covers all 7 Rails repos, lives in claude-custom repo), or (b) prediction-assistant/.claude/CLAUDE.md (project-scoped, narrow). Option (a) is recommended given 7 affected repos.
- [BODY] If option (a), update the Repo field to ldraney/claude-custom or note that the fix is cross-repo. If option (b), create the .claude/CLAUDE.md file path since it does not currently exist.
-
Review: Add prediction-assistant to services terraform
review-1767-2026-07-04Verdict: READY
Pass 3 — 2026-07-04. Prior passes had conflicting findings about whether the entry already exists. Verified directly: it does NOT exist in k3s.tfvars. Issue body corrected to say "add new entry".
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag (none)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:platform-setup label — verified in project-prediction-assistant user-stories table
- [x] story note verified — "Platform Setup" entry exists on project-prediction-assistant user-stories section (key: platform-setup, role: Developer (Lucas))
- [x] arch:iac label — present on board item
- [ ] arch note MISSING — arch-iac note does not exist in pal-e-docs. Known platform-wide documentation gap; not blocking per review policy
- [x] Forgejo issue — ldraney/pal-e-services#170, open
File Targets
- [x]
terraform/k3s.tfvars— verified: file exists (symlinked from ~/secrets/pal-e-services/k3s.tfvars). Confirmed prediction-assistant entry does NOT exist (grep returns empty). Services map starts at line 218. Existing pattern clear (landscaping-assistant at line 228 is the closest Rails analog: port 3000, funnel true). - [x]
terraform/services.tf— verified: for_each loop at line 156.coalesce(each.value.source_repo, each.value.forgejo_repo)at line 181 correctly handles null source_repo by falling back to forgejo_repo. Agent correctly told NOT to touch. - [x]
terraform/variables.tf— verified: service type definition at lines 234-247. All required fields present (forgejo_repo, image_repo, port, funnel, source_repo optional, source_path optional). Agent correctly told NOT to touch. - [x]
k8s/overlays/prod/— verified: directory exists in prediction-assistant repo with kustomization.yaml, ingress.yaml, cluster-issuer.yaml, redirect-middleware.yaml. source_path value "k8s/overlays/prod" is accurate.
Repo Placement
Correct. Issue filed on pal-e-services (#170), which is where the services terraform and k3s.tfvars live. Single-repo change — no cross-repo coordination needed.
Dependencies
- #1769 "Add prediction-assistant database to CNPG" (backlog, sprint:9) — sibling, not a blocker. Services entry is independent of database provisioning.
- #1768 "Add Keycloak realm + OIDC client" (backlog, sprint:9) — sibling, not a blocker. Keycloak and services are separate terraform resources.
- #1772 "tofu apply — provision prediction-assistant infra" (backlog, sprint:10) — downstream dependency. Correctly sequenced one sprint later. Depends on this ticket completing first.
- #1770 "Update .woodpecker.yaml to match platform CI pattern" (backlog, sprint:9) — sibling, independent.
No undocumented blockers. Sprint sequencing (sprint:9 before sprint:10) implicitly handles the dependency chain.
Acceptance Criteria
All 4 criteria are concrete and agent-verifiable:
- [x] AC1: "prediction-assistant entry exists in services map without source_repo" — verifiable via grep. Omitting source_repo is a supported pattern: coalesce() falls back to forgejo_repo (line 181 of services.tf). Precedent: platform-validation entry in k3s.tfvars.example also omits source_repo.
- [x] AC2: "source_path is k8s/overlays/prod" — verifiable via grep. Path confirmed to exist in the prediction-assistant repo with kustomization.yaml.
- [x] AC3: "tofu plan shows new namespace, Harbor project, robot accounts, ArgoCD application, Tailscale funnel" — verifiable via tofu plan output.
- [x] AC4: "No errors on plan" — verifiable via exit code.
Test command
cd terraform && tofu planis real and appropriate.Blast Radius
Low. Adding a new entry to the services map is additive — it cannot break existing services. The for_each loop processes each service independently. The image-updater annotation conditional (lines 171-173 of services.tf) correctly omits the kustomization write-back-target when source_repo is null, which is appropriate for a service whose k8s manifests live in the app repo. No similar bug pattern to propagate — this is a new entry, not a fix.
Decomposition Assessment
- 1 file target across 1 repo — below threshold
- 4 acceptance criteria — below threshold
- Estimated agent work: under 2 minutes (add ~8 lines to a tfvars map, run tofu plan)
No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-iacfor the IaC component — platform-wide gap, not blocking this ticket. Track as a separate documentation item.
No other action needed. Scope is solid.
-
Review: Update .woodpecker.yaml to match platform CI pattern
review-1770-2026-07-04Verdict: READY
Template Completeness
Checked against
template-issue-feature(Type: Feature).- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:platform-setup label -- "Platform Setup"
- [x] story note verified --
story-prediction-assistant-platform-setupexists in project-prediction-assistant user-stories section - [x] arch:ci-pipeline label -- CI pipeline component
- [ ] arch note MISSING -- no
arch-ci-pipelinenote found in pal-e-docs. Non-blocking: platform-wide documentation gap, not specific to this ticket. [SCOPE] Create architecture note arch-ci-pipeline for component ci-pipeline. - [x] Forgejo issue -- #91, open
File Targets
- [x]
.woodpecker.yaml-- verified: exists at repo root, contains bare-bones config (ruby:3.4, plugin-docker-buildx, pushes to harbor.tail5b443a.ts.net/ldraney/prediction-assistant). Matches issue description of "minimal version" needing upgrade. - [x]
Dockerfile-- verified: exists, correctly marked "don't touch" (multi-stage Ruby 3.4.9 build) - [x]
Gemfile-- verified: exists, correctly marked "don't touch"
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, file target is
.woodpecker.yamlin the same repo. Single-repo change.Dependencies
- #1696 "CI/CD pipeline -- Woodpecker config" (sprint:2, validation) -- predecessor, original CI setup already done
- #1773 "Activate repo in Woodpecker + first green build" (sprint:10, backlog) -- downstream dependency, validates end-to-end pipeline after this ticket completes
- #1767 "Add prediction-assistant to services terraform" (sprint:9, backlog) -- parallel infra work, may update image references in ArgoCD/Kustomize
- No items in
in_progressthat block this ticket
Acceptance Criteria
6 criteria, all agent-verifiable by reading the resulting YAML:
- In-cluster clone step (alpine/git, Forgejo HTTP) -- check YAML step
- ruby-rails-build:latest base image -- check image field
- Test step: bin/rails test with Postgres service -- check commands and services
- kaniko build-and-push -- check kaniko step config
- In-cluster Harbor registry -- check registry URL
- Build-and-push only on main -- check when condition
Test expectations: "pipeline runs green on first push after merge" is only verifiable post-deploy, which is appropriate for CI pipeline work and covered by downstream ticket #1773.
Blast Radius
Note: K8s deployment files reference the old image path that this ticket changes:
k8s/base/deployment.yaml-- 2 references toharbor.tail5b443a.ts.net/ldraney/prediction-assistant:latestk8s/base/worker-deployment.yaml-- 1 reference to same
After this ticket, CI pushes to
prediction-assistant/app:${CI_COMMIT_SHA}via in-cluster Harbor. The k8s deployments still reference the old path. This is handled by downstream tickets (#1767 services terraform, #1773 activation) and is not a blocker for this ticket's scope.No other files in the repo reference CI-specific patterns (woodpecker, kaniko, ruby-rails-build). Blast radius is contained to the single file.
Decomposition Assessment
1 file target in 1 repo. 6 AC but all describe aspects of a single YAML file rewrite -- tightly coupled. Estimated agent time well under 5 minutes. No decomposition needed.
Recommendation
- [SCOPE] Create architecture note
arch-ci-pipelinefor the CI pipeline component. Non-blocking platform documentation gap.
No other action needed. Ticket is READY for development.
-
Review: LIVE badge + pause button
review-1778-2026-07-04Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #90, split 2 of 2
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- As a user with active trading bots...
- [x] Context -- explains LIVE badge vs active distinction, dependency chain
- [x] File Targets -- 5 modify targets, 3 exclusions
- [x] Feature Flag -- none (correct, this repo has no feature flag infra)
- [x] Acceptance Criteria -- 4 criteria
- [x] Test Expectations -- 5 test cases + run command
- [x] Constraints -- Hotwire patterns, CSS consistency, field naming
- [x] Checklist -- present
- [x] Related -- lists parent #85, parent sub #90, deps #88/#89
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: portfolio-builder, role: Trader (Lucas))
- [x] arch:rails label -- Rails component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-rails for component rails (note: arch:rails is used across 20+ board items; this is a cross-cutting gap, not specific to this ticket)
- [x] Forgejo issue -- #95, open
File Targets
- [x]
app/views/bots/_bot_card.html.erb-- verified: exists, 41 lines, already hasbot.active?conditional and status indicator patterns. Agent will add LIVE badge alongside existing status group. - [x]
app/views/bots/show.html.erb-- verified: exists, ~800+ lines, already hasstatus-badge--liveCSS class and@bot.active?conditionals. Contains existing badge styling infrastructure the agent can extend. - [x]
app/controllers/bots_controller.rb-- verified: exists, already hastoggleaction. Agent addspauseaction alongside it. - [x]
config/routes.rb-- verified: exists, no existing pause route. Agent adds route for pause action. - [x]
test/controllers/bots_controller_test.rb-- verified: exists. Agent adds pause tests. - [x]
app/services/order_service.rb(do-not-touch) -- verified: exists with dry_run enforcement, correctly excluded. - [x]
app/models/strategy.rb(do-not-touch) -- verified: exists, correctly excluded. Note:trading_enabledfield does NOT yet exist in schema -- depends on #88 migration. - [x]
app/views/bots/_activation_panel.html.erb(do-not-touch) -- confirmed does not exist yet (handled in split 1, #94).
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets are in prediction-assistant. Single-repo scope.
Dependencies
- #88 (Trading fields migration + Strategy model validations) -- board item #1764, backlog. Adds
trading_enabledfield to Strategy. CRITICAL: this ticket cannot be started until #88 is merged. Thetrading_enabled?method referenced throughout the AC does not yet exist in the codebase. - #89 (OrderService dry_run enforcement + budget guardrails) -- board item #1765, backlog. Adds enforcement layer. Required for the pause semantics to have meaning.
- #94 (Activation panel + controller toggle action, split 1) -- board item #1777, backlog. Sibling split; provides the activate action this ticket's pause button complements.
- All dependencies are documented in the issue body. All are in backlog -- ordering is correct (this ticket should be scheduled after its dependencies).
Acceptance Criteria
4 criteria, all testable by an agent:
- LIVE badge on bot card -- verifiable via rendered HTML assertion
- LIVE badge on detail page -- verifiable via rendered HTML assertion
- Pause button visibility -- verifiable via conditional rendering test
- Pause action behavior -- verifiable via controller test (trading_enabled: false, active: true)
Test commands are real:
bin/rails test test/controllers/bots_controller_test.rb. Coverage is adequate.Blast Radius
Naming collision awareness needed: The existing
show.html.erbalready usesstatus-badge--liveCSS class tied to@bot.active?, andBotPresenter#status_labelalready returns "Live" whenactive?is true. The new "LIVE" badge will be a separate concept tied totrading_enabled?. The ticket context explains this distinction (active = monitoring, trading_enabled = actual trading), but the implementing agent must take care not to conflate the two. No action needed -- the constraint is implicit in the design and the ticket context is clear enough.No sibling services affected. All changes are UI/controller-level in a single app.
Decomposition Assessment
5 file targets across 1 repo. 4 acceptance criteria. Estimated agent work: under 5 minutes (badge partial, controller action, route, tests). No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails component. This is a cross-cutting gap affecting 20+ board items, not specific to this ticket. Does not block this ticket.
No other action needed. Scope is solid.
-
Review: Add Keycloak realm + OIDC client
review-1768-2026-07-04Verdict: APPROVED
Board item #1768 -- Add Keycloak realm + OIDC client. Forgejo issue: ldraney/pal-e-services#171. Previous review incorrectly flagged arch-keycloak as missing; it exists and is confirmed.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, references PR #63
- [x] Repo -- ldraney/pal-e-services
- [x] User Story -- present
- [x] Context -- explains OmniAuth is merged but realm/client not provisioned
- [x] File Targets -- terraform/k3s.tfvars (modify), terraform/keycloak.tf (do not touch)
- [x] Feature Flag -- none (extra section, acceptable)
- [x] Acceptance Criteria -- 4 criteria, all machine-verifiable
- [x] Test Expectations -- tofu plan
- [x] Constraints -- model after landscaping-assistant, localhost redirect, roles, refresh tokens
- [x] Checklist -- present
- [x] Related -- prediction-assistant project
Traceability
- [x] story:app-experience label -- App Experience story
- [x] story note verified -- found in project-prediction-assistant user-stories section (links to story-prediction-assistant-app-experience)
- [x] arch:keycloak label -- Keycloak architecture component
- [x] arch note verified -- arch-keycloak note exists in pal-e-docs (id: 1728, title: "Architecture: Keycloak")
- [x] Forgejo issue -- ldraney/pal-e-services#171, state: open
File Targets
- [x] terraform/k3s.tfvars -- verified: gitignored by convention (*.tfvars in .gitignore), k3s.tfvars.example is tracked and contains keycloak_realms (line 21) and keycloak_clients (line 123) maps with existing entries (landscaping-assistant at lines 232-256 as model)
- [x] terraform/keycloak.tf -- verified exists (9520 bytes), correctly marked as do-not-touch (for_each loops handle everything)
Repo Placement
Correct. Keycloak realm/client config lives in pal-e-services terraform. Issue filed on pal-e-services. Single repo affected.
Dependencies
- Item #1767 "Add prediction-assistant to services terraform" (sprint:9, backlog) -- sibling infra ticket, independent. Keycloak config can be added before or after broader terraform onboarding.
- Item #1693 "Keycloak realm, client, users, and login theme" (sprint:1, validation) -- historical predecessor for kalshi-assistant. Pattern already established.
- No items in in_progress block this ticket.
Acceptance Criteria
All 4 criteria are machine-verifiable: realm entry check, client entry check, redirect URI check, tofu plan clean. Test command is real (cd terraform && tofu plan). No missing criteria.
Blast Radius
Small. Adding entries to existing HCL map variables (keycloak_realms, keycloak_clients). The for_each pattern in keycloak.tf handles provisioning. No downstream consumers affected -- this creates new resources, does not modify existing ones.
Decomposition Assessment
1 file target, 1 repo, 4 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
No action needed. Scope is solid, traceability complete, file targets verified. Previous review verdict of NEEDS_REFINEMENT was incorrect -- the arch-keycloak note exists.
-
Review: Apply Caddy salt state to edge proxy
review-1771-2026-07-04Verdict: APPROVED
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone
- [x] Repo — ldraney/pal-e-platform
- [x] User Story — present
- [x] Context — present
- [x] File Targets — present (none to modify, correct for apply-only task)
- [x] Feature Flag — none
- [x] Acceptance Criteria — 4 criteria
- [x] Test Expectations — present
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:app-experience — App Experience
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:edge-proxy — Edge Proxy
- [x] arch note verified — arch-edge-proxy note exists in pal-e-docs (architecture note, active status, project my-vibes-world)
- [x] Forgejo issue — ldraney/pal-e-platform#516, open
File Targets
- [x] No files to modify — correct, pillar config already exists
- [x] salt/pillar/caddy.sls — verified: prediction-assistant entry at lines 21-23 (domain: prediction-assistant.com, proxy_target: prediction-assistant.tail5b443a.ts.net, www_redirect: true)
- [x] salt/states/caddy/Caddyfile.j2 — verified: template exists, iterates pillar sites with reverse_proxy and optional www redirect
Repo Placement
OK — issue filed on ldraney/pal-e-platform, Salt states and pillar live in pal-e-platform. Single repo affected.
Dependencies
No blockers. No items currently in_progress on the board. Downstream: board item #1774 "Verify prediction-assistant.com is live" (backlog, sprint:10) depends on this ticket completing first. Item #1692 "DNS + reverse proxy — prediction-assistant.com" (validation) is the original DNS/proxy setup that created the pillar entry this ticket applies.
Acceptance Criteria
4 criteria, all concrete and agent-verifiable:
- [x] Salt state applied — verifiable by running salt-ssh command (provided in Test Expectations)
- [x] Caddy config includes site block — verifiable by inspecting generated Caddyfile on edge-proxy
- [x] ACME cert obtained — verifiable; issue correctly notes may 502 until upstream is live
- [x] curl TLS check — verifiable by running curl -I https://prediction-assistant.com
Test command provided:
salt-ssh edge-proxy state.apply caddy. Real and correct.Blast Radius
Low. Running
state.apply caddyregenerates the entire Caddyfile from all pillar entries (palinks, landscaping, prediction-assistant, westside, paldocs). This is idempotent for existing sites since their pillar entries are unchanged. The only new site block added will be prediction-assistant.com. No downstream consumers affected beyond this service.Decomposition Assessment
0 file targets to modify, 4 acceptance criteria, estimated agent work well under 5 minutes (single salt-ssh command + verification curl). No decomposition needed.
Recommendation
No action needed.
-
Review: Add prediction-assistant database to CNPG
review-1769-2026-07-04Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone
- [x] Repo — ldraney/pal-e-services
- [x] User Story — present, proper As/I want/So that format
- [x] Context — explains SQLite-to-Postgres migration history (Sprint 2, PR #33)
- [x] File Targets — includes both modify and do-not-touch lists
- [x] Feature Flag — none (appropriate for infra)
- [x] Acceptance Criteria — 3 items, all verifiable
- [x] Test Expectations — tofu plan command specified
- [x] Constraints — follow existing pattern
- [x] Checklist — standard 3-item checklist
- [x] Related — prediction-assistant project referenced
Traceability
- [x] story:platform-setup label — Platform Setup
- [x] story note verified —
story-prediction-assistant-platform-setupfound in project-prediction-assistant user-stories section - [x] arch:postgres label — PostgreSQL Architecture
- [x] arch note verified —
arch-postgresnote exists in pal-e-docs (project: prediction-assistant, status: active) - [x] Forgejo issue — ldraney/pal-e-services#172, state: open
File Targets
- [x]
terraform/k3s.tfvars— verified: exists (symlink to../../secrets/pal-e-services/k3s.tfvars). Containsservice_databasesmap at line 15 with existing entries forpalinksandwestside_basketball. Pattern is clear: map key = role name, value = {password, databases list}. - [x]
terraform/databases.tf— verified: exists, containsfor_each = var.service_databasesloop that auto-provisions roles and databases. Correctly listed as do-not-touch.
Database Name Verification
Cross-checked against
config/database.ymlin prediction-assistant repo. Production config expects DATABASE_URL (primary), CACHE_DATABASE_URL, QUEUE_DATABASE_URL, CABLE_DATABASE_URL. The ticket's proposed databases (prediction_assistant, prediction_assistant_cache, prediction_assistant_queue, prediction_assistant_cable) match exactly.Repo Placement
OK — issue filed on ldraney/pal-e-services, file target is in pal-e-services. Single-repo change.
Dependencies
- #1767 (id=1767) "Add prediction-assistant to services terraform" — sprint:9 sibling, independent (provisions namespace/Harbor/ArgoCD, not database)
- #1768 (id=1768) "Add Keycloak realm + OIDC client" — sprint:9 sibling, independent
- #1772 (id=1772) "tofu apply — provision prediction-assistant infra" — sprint:10, depends on this ticket being done first. Sprint ordering handles sequencing correctly.
Dependencies are not explicitly documented in the issue body but the sprint ordering (9 before 10) handles sequencing. Acceptable for infra tickets in the same plan.
Acceptance Criteria
3 criteria, all agent-verifiable:
service_databaseshasprediction_assistantentry — verifiable by grep/read- 4 databases listed — verifiable by reading the databases list in tfvars
- Password in gitignored tfvars — verifiable by checking file location (already a symlink to secrets/)
Test command
cd terraform && tofu planis real and appropriate.Blast Radius
Minimal. Adding a new entry to the
service_databasesmap is purely additive. Thefor_eachloop indatabases.tfis stable and handles new entries without affecting existing databases (palinks, westside_basketball). No downstream consumers are affected by adding a new database role.Decomposition Assessment
1 file target, 1 repo, 3 acceptance criteria. Estimated agent work: under 2 minutes (add a map entry with generated password). No decomposition needed.
Recommendation
No action needed.
-
Review: SimulationResult model + P&L aggregation service
review-1758-2026-07-04Verdict: APPROVED
Re-review of issue #82 after fix for dry_run status pattern. The issue body now correctly references
status: "cancelled"withmetadata: {"dry_run": true}, matching the actualOrderService#handle_dry_runimplementation atapp/services/order_service.rb:270-289.Template Completeness
- [x] Type — Feature
- [x] Lineage — Parent and dependency chain documented
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — AI Portfolio Builder reference
- [x] Context — Dry_run mode background, corrected status pattern
- [x] File Targets — 7 files (4 new, 3 existing)
- [x] Feature Flag — "none" (internal data model, acceptable)
- [x] Acceptance Criteria — 6 criteria
- [x] Test Expectations — Model, job, idempotency, scopes
- [x] Constraints — Listed
- [x] Checklist — Present
- [x] Related — project-prediction-assistant
Traceability
- [x] story:portfolio-builder label — AI Portfolio Builder
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:rails label — Rails architecture
- [ ] arch note MISSING — [SCOPE] No arch-rails note exists in pal-e-docs. Low priority: arch:rails is used pervasively across all prediction-assistant tickets; creating a dedicated note is a project-wide task, not a blocker for this ticket.
- [x] Forgejo issue — #82, open
File Targets
- [x]
app/models/simulation_result.rb— NEW file, does not exist yet (correct) - [x]
db/migrate/XXXXXX_create_simulation_results.rb— NEW migration (correct) - [x]
app/jobs/simulation_aggregator_job.rb— NEW job (correct, existing jobs directory at app/jobs/ confirmed) - [x]
app/models/strategy.rb— EXISTS, verified. Hashas_many :tradesand config validation framework. Addingsimulated_pnl(period:)method is clean. - [x]
test/models/simulation_result_test.rb— NEW test (correct) - [x]
test/models/strategy_test.rb— EXISTS, verified. 12k file with existing test coverage. - [x]
test/jobs/simulation_aggregator_job_test.rb— NEW test (correct)
Critical Fix Verified
The previous review found the issue assumed
status: "dry_run"but OrderService usesstatus: "cancelled"withmetadata: {"dry_run": true}. Verified against actual code:OrderService#handle_dry_run(order_service.rb:270-289):trade.update!(status: "cancelled", metadata: trade.metadata.merge("dry_run" => true))Trade::STATUSES = %w[pending filled cancelled settled]— "dry_run" is NOT a valid trade status, confirming "cancelled" is correct- Issue body AC, Context, and Constraints sections all consistently reference
status: "cancelled"+metadata['dry_run'] == true
Repo Placement
OK — Issue filed on ldraney/prediction-assistant, all file targets are in the same repo.
Dependencies
- Depends on S6 bots (all 4 with dry_run support) — S6 is merged per project memory
- Blocks #83 (Bot card performance indicators, board item #1759, in todo) and #84 (Bot detail P&L dashboard, board item #1760, in backlog)
- Dependencies are documented in the Lineage section
Acceptance Criteria
6 ACs, all testable by an agent:
- AC1: Model existence + schema — verifiable via migration and model file
- AC2: Job aggregation from cancelled/dry_run trades — verifiable via test fixtures
- AC3: Idempotency — verifiable by running job twice
- AC4: Period scopes — verifiable via scope queries
- AC5: Strategy convenience method — verifiable via unit test
- AC6: Test coverage — meta-criterion, verified by presence of tests
Note: The trades table has a
pnlcolumn (decimal) that the existing bots_controller already sums. The aggregation job can rely on this column for P&L computation. For dry_run trades where pnl may be nil, the agent will need to determine the simulation P&L mechanism — this is a reasonable implementation decision within scope.Blast Radius
Minimal. SimulationResult is a new, standalone table. No existing code references it. The existing
bots_controller.rb:13sums Trade.pnl for display, but SimulationResult is a separate aggregation layer that does not modify Trade records. The recurring.yml will need an entry for SimulationAggregatorJob, following the existing MarketScannerJob pattern.Decomposition Assessment
7 file targets / 1 repo / 6 ACs / ~5 min estimated. The AC count (6) is marginally over the >5 threshold, but the work is highly cohesive: model + migration + job + convenience method + tests for a single concept (simulation P&L aggregation). Splitting would create artificial dependency chains between tightly coupled artifacts. No decomposition needed.
Recommendation
No action needed — issue body is correct and complete after the dry_run status fix.
[SCOPE](non-blocking): Create architecture notearch-railsfor the Rails architecture component. This applies to all prediction-assistant tickets with the arch:rails label, not just this one. -
Review: Trading fields migration + Strategy model validations
review-1764-2026-07-04Verdict: APPROVED
Board item #1764 — Forgejo issue
ldraney/prediction-assistant#88. Sub-ticket of #85 (Go-live activation flow), split 1 of 3. First review.Template Completeness
- [x] Type — Feature
- [x] Lineage — Sub-ticket of #85
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — present, well-formed
- [x] Context — includes naming conflict rationale
- [x] File Targets — 4 files (1 new, 3 existing) + explicit do-not-touch list
- [x] Feature Flag — "none" with rationale (internal model change)
- [x] Acceptance Criteria — 9 criteria
- [x] Test Expectations — 7 unit tests + run command
- [x] Constraints — 4 constraints including column naming rationale
- [x] Checklist — standard 3-item
- [x] Related — project, parent issue, user story doc
Traceability
- [x] story:portfolio-builder label — AI Portfolio Builder
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for the Rails application component. This is a project-wide gap affecting all arch:rails tickets, not specific to this issue.
- [x] Forgejo issue — #88, open
File Targets
- [x]
db/migrate/YYYYMMDD_add_trading_fields_to_strategies.rb— new file; naming convention matches existing migrations (e.g.20260704000001_create_price_patterns.rb) - [x]
app/models/strategy.rb— verified: exists (82 lines), has base validations, config_value helper, and validation helpers for subclasses. Correct target for new trading validations. - [x]
test/models/strategy_test.rb— verified: exists (335 lines), comprehensive test suite for STI, config validations. Correct target for new trading validation tests. - [x]
db/schema.rb— verified: exists, strategies table at lines 76-85 currently has active, config, name, type columns. Auto-updated by migration. - [x]
app/models/late_game_lock_config.rb— verified:max_concurrent_positionsconfirmed on line 10 as JSONB config key. Do-not-touch designation correct.
Repo Placement
OK — issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.
Dependencies
- Sub-ticket of #85 (board item #1761, backlog). Split 1 of 3 — this is the data layer (migration + model), independent of the other splits (OrderService guardrails, Activation UI).
- No blocking dependencies in in_progress or todo columns.
- Sibling sub-tickets: #89 (OrderService dry_run enforcement, item #1765) and #90 (Activation UI panel, item #1766) — both in backlog, both depend on this ticket's columns existing.
- Dependencies correctly documented in Lineage section.
Acceptance Criteria
9 AC, all agent-verifiable. Test command provided:
bin/rails test test/models/strategy_test.rb. Each criterion is specific and testable.Minor observation: Only
budget_centshas an explicit presence validation AC. The Constraints section says "Budget fields are nullable (only required when trading_enabled is true)" which could imply all three monetary/position fields need presence validations. However, the AC is intentionally asymmetric —max_bet_centsandtrading_max_positionshave numericality checks but no presence requirement, meaning they are optional even when trading is enabled. This is a reasonable design choice (budget is the hard constraint; bet size and position limits are optional tuning).Blast Radius
max_concurrent_positionsis referenced in 6+ files as a JSONB config key (late_game_lock_bot.rb, position_tracker.rb, bot_catalog.rb, and multiple test files). The ticket correctly avoids this name by usingtrading_max_positions.- No existing code references
trading_enabled,budget_cents,max_bet_cents, ortrading_max_positions— clean namespace. - New columns are nullable (except
trading_enableddefault false). No existing Strategy records, tests, or fixtures will break. - BotPresenter, BotsController, and job classes reference Strategy but only query
active,config,type, andname. No downstream breakage risk.
Decomposition Assessment
4 file targets in 1 repo — under the 3-files/2-repos threshold. 9 AC exceeds the >5 threshold, but the work is atomically cohesive: one migration adding 4 columns, one model adding conditional validations, one test file. Splitting would create artificial dependencies (migration in one PR, validations in another). Estimated agent time: ~3 minutes. 1 story point. No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-railsin pal-e-docs for the Rails application component. This is a project-wide gap, not a blocker for this ticket.
Scope is solid. All file targets verified. Naming conflict analysis confirmed against live code. Blast radius minimal. Ticket is ready for implementation.
-
Review: Bot detail P&L chart + summary stats
review-1762-2026-07-04Verdict: APPROVED
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-issue of #84, decomposition documented
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- complete As/I want/So that format
- [x] Context -- clear background, references existing page structure
- [x] File Targets -- 3 files (1 new, 2 modify) + explicit exclusions
- [x] Feature Flag -- None (acceptable: internal UI enhancement, no feature flag doc in repo)
- [x] Acceptance Criteria -- 5 verifiable criteria
- [x] Test Expectations -- 3 tests + run command
- [x] Constraints -- 4 constraints (inline SVG/CSS only, Turbo Frame patterns, no external JS, match styling)
- [x] Checklist -- present
- [x] Related -- 4 references (#84 parent, #82 dependency, #83 sibling, docs)
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- story-prediction-assistant-portfolio-builder exists in pal-e-docs (active user-story note)
- [x] arch:rails label -- present on board item
- [ ] arch note MISSING -- [SCOPE] No arch-rails note found in pal-e-docs. Systemic gap: arch:rails is used across 20+ board items but no backing note exists. Not specific to this ticket.
- [x] Forgejo issue -- #86, open, valid URL https://forgejo.tail5b443a.ts.net/ldraney/prediction-assistant/issues/86
File Targets
- [x] app/views/bots/_performance_dashboard.html.erb -- NEW file. Correct directory verified: sibling partials exist (_activity_feed.html.erb, _bot_card.html.erb, _config_fields.html.erb, etc.)
- [x] app/controllers/bots_controller.rb -- verified: exists (180 lines). show action at line 26 already loads strategy and trade data. Extension point is clear.
- [x] test/controllers/bots_controller_test.rb -- verified: exists (20k). Test patterns established for show action.
Repo Placement
OK. Issue #86 filed on ldraney/prediction-assistant. All file targets are in this repo. Single-repo change.
Dependencies
- #82 (SimulationResult model + P&L aggregation service) -- DOCUMENTED dependency. Board item #1758, currently in backlog. SimulationResult does not exist in the codebase yet. This ticket must not move to in_progress until #82 is merged.
- #84 (parent issue) -- in backlog. This ticket was decomposed from #84.
- #83 (Bot card performance indicators) -- sibling feature, not a blocker.
- #87 (Bot detail trade history table) -- sibling sub-issue, not a blocker.
All dependencies are properly documented in the issue body and Related section.
Acceptance Criteria
All 5 criteria are verifiable by an agent:
- AC1: Check rendered HTML for performance dashboard partial above activity feed -- testable via controller test
- AC2: Check for inline SVG markup, absence of external script tags -- testable via response body inspection
- AC3: Verify Turbo Frame markup and period param handling -- testable (existing Turbo Frame patterns in activity.html.erb provide reference)
- AC4: Check response body for stat labels (total P&L, win rate, total trades, best day, worst day) -- testable
- AC5: Test with no simulation data returns 200 with empty-state content -- explicitly covered in Test Expectations
Test run command is valid:
bin/rails test test/controllers/bots_controller_test.rbBlast Radius
Low. The change adds a new partial rendered in show.html.erb (line 944 area, above the activity feed render). Does not modify existing partials or sibling concerns. The controller extension adds SimulationResult queries to show action. No downstream consumers affected. Activity feed and marketplace index are explicitly excluded from scope.
Turbo Frame patterns are well-established in the codebase (activity.html.erb, _activity_feed.html.erb) providing clear reference for the period toggle implementation.
Decomposition Assessment
3 file targets in 1 repo, 5 acceptance criteria, estimated ~5 minutes agent work. The inline SVG chart is the most complex component but is bounded by the constraint of no external libraries. No decomposition needed.
Recommendation
- [SCOPE] Create architecture note arch-rails for the Rails application component. This is a systemic gap affecting 20+ board items, not specific to this ticket. Does not block approval.
-
Review: Bot detail trade history table + pagination
review-1763-2026-07-04Verdict: APPROVED
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-issue of #84, decomposition documented
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- As a/I want/So that format, clear
- [x] Context -- Sufficient background, references existing show page layout and dependency
- [x] File Targets -- 3 files (1 create, 2 modify), plus "NOT to touch" list
- [x] Feature Flag -- "None" (appropriate for internal display feature)
- [x] Acceptance Criteria -- 5 items, all testable
- [x] Test Expectations -- 4 test cases + run command
- [x] Constraints -- 4 constraints including Turbo Frame requirement and responsive design
- [x] Checklist -- Present
- [x] Related -- 4 related issues documented
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: portfolio-builder, role: Trader (Lucas))
- [x] arch:rails label -- present on board item
- [ ] arch note MISSING -- [SCOPE] No arch-rails note found in pal-e-docs. This is systemic across many board items sharing this label. Not a blocker for this ticket.
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/prediction-assistant/issues/87, open
File Targets
- [x]
app/views/bots/_trade_history.html.erb-- new partial to create. Does not exist yet (correct). - [x]
app/controllers/bots_controller.rb-- verified: exists,showaction at line 26, already loads strategy and activity logs. Extension point is clear. - [x]
test/controllers/bots_controller_test.rb-- verified: exists with 589 lines of existing tests covering index, show, update, toggle, activity. New trade history tests fit naturally.
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, work targets the same repo. Single-repo scope.
Dependencies
- #82 (SimulationResult model + P&L aggregation service) -- Hard dependency, correctly documented in Context section. Board item #1758 is currently in backlog. SimulationResult model does not exist in the codebase yet. This ticket must not start until #82 is merged.
- #84 (parent issue) -- Decomposed, this ticket is one of two sub-issues.
- #86 (P&L chart + summary stats) -- Sibling sub-issue, independent scope. Correctly listed in "Files NOT to touch."
- #83 (Bot card performance indicators) -- Related but independent.
Acceptance Criteria
5 acceptance criteria, all verifiable by automated tests:
- Table rendering -- assert_select for partial presence
- Column list -- assert_select for column headers
- Pagination at 10 per page -- controller test with count assertion
- Empty state message -- controller test with message text assertion
- Turbo Frame pagination -- test response includes turbo-frame element
Test expectations (4) align well with AC. Run command provided:
bin/rails test test/controllers/bots_controller_test.rb.Blast Radius
Low. The existing codebase already has a Turbo Frame pagination pattern in
_activity_feed.html.erb(cursor-based with "Load older entries"). The new trade history adds a second pagination mechanism (offset/limit) on the same page. The ticket explicitly calls out using offset/limit rather than cursor, which is appropriate for a trade history table where users navigate forward and backward. No downstream consumers are affected. The change is additive -- new partial, minor controller extension.Decomposition Assessment
3 file targets in 1 repo, 5 acceptance criteria, 4 test expectations. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails application component. This is systemic across many board items and not specific to this ticket.
No other action needed. Scope is solid, file targets verified, dependencies documented, acceptance criteria testable.
-
Review: OrderService dry_run enforcement + budget guardrails
review-1765-2026-07-04Verdict: APPROVED
Ticket is well-scoped, file targets verified, traceability solid. One minor arch note gap flagged as systemic (not blocking).
Template Completeness
- [x] Type — Feature
- [x] Lineage — Sub-ticket of #85, split 2 of 3
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — present, well-formed
- [x] Context — explains relationship to #85, dependency on sub-ticket 1
- [x] File Targets — 2 files to modify, 2 files explicitly excluded
- [x] Feature Flag — "none" with justification (internal service change, no FF infra)
- [x] Acceptance Criteria — 7 items
- [x] Test Expectations — 5 unit tests + run command
- [x] Constraints — backward compat, per-strategy budget, integer cents, log-not-raise
- [x] Checklist — present
- [x] Related — parent issue, dependency, user story doc
Traceability
- [x] story:portfolio-builder label — AI Portfolio Builder
- [x] story note verified — found in project-prediction-assistant user-stories section (key: portfolio-builder, role: Trader)
- [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] No
arch-railsnote found in pal-e-docs. This is a project-wide gap: many prediction-assistant board items carryarch:railsbut no backing note exists. Recommend creatingarch-railsas a project-level architecture note covering the Rails 8.1 + Hotwire + Solid Queue stack. - [x] Forgejo issue — #89, open
File Targets
- [x]
app/services/order_service.rb— verified: exists (14k), containsOrderServiceclass withplace_order,cancel_order,check_fill_statusmethods. Already has@dry_runpattern withhandle_dry_runmethod. Thebot:param is typed asStrategy, sobot.trading_enabled?andbot.budget_centsaccess path is valid once sub-ticket 1 adds those fields. - [x]
test/services/order_service_test.rb— verified: exists (18k), established test file for OrderService - [x] NOT-TOUCH:
app/models/strategy.rb— verified: currently has notrading_enabledorbudget_centsfields (correct, those come from sub-ticket 1) - [x] NOT-TOUCH: Bot job files — verified: jobs (
sweep_eligible_job.rb,pregame_threshold_job.rb) do not call OrderService directly; they delegate through bot service classes
Repo Placement
OK. Issue #89 filed on ldraney/prediction-assistant, all file targets are in that repo. Single-repo change.
Dependencies
- Depends on sub-ticket 1: issue #88 "Trading fields migration + Strategy model validations" (board item #1764, currently in backlog). This dependency is documented in the Lineage and Context sections.
trading_enabled?andbudget_centsmust exist on Strategy before this ticket can be implemented. - No downstream blockers identified — this ticket is a prerequisite for sub-ticket 3 (Activation UI panel, #90).
Acceptance Criteria
7 ACs are well-defined and testable by an agent:
- AC 1-2:
trading_enabled?check + dry_run forcing — verifiable via unit test assertions on return value - AC 3-5: Budget enforcement — verifiable via unit tests with known trade amounts
- AC 6: ActivityLog recording — verifiable by asserting
ActivityLog.countchange - AC 7: Backward compatibility — verifiable by running existing test suite unchanged
Run command is valid:
bin/rails test test/services/order_service_test.rbBlast Radius
- Callers safe:
PregameStackerBotandLateGameLockBotboth createOrderService.new(client:, dry_run:)and passbot: strategytoplace_order. The new enforcement is internal to OrderService — callers need no changes. - cancel_order not affected: ACs scope enforcement to "placing any order" — cancellations are correctly excluded since the concern is preventing real money outflow.
- No sibling service concern: OrderService is the single shared trade execution service; no similar pattern exists elsewhere that would need the same fix.
Decomposition Assessment
- File targets: 2 files in 1 repo — under the 3-file threshold
- Acceptance criteria: 7 — over the 5-AC threshold on paper, but all are tightly coupled variations of one behavioral change (guard clause + budget check in a single method)
- Estimated agent work: well under 5 minutes — add guard clause to
place_order, add budget helper method, add ~5 test cases to existing test file - No decomposition needed
Recommendation
[SCOPE]Create architecture notearch-railscovering the Rails 8.1 + Hotwire + Solid Queue stack. This is a project-wide gap affecting many board items, not specific to this ticket. Non-blocking for this review.
-
Review: Bot card performance indicators on marketplace grid
review-1759-2026-07-04Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- present, documents parent (Paper trading dashboard S7) and dependency (SimulationResult model)
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- references AI Portfolio Builder
- [x] Context -- clear motivation for adding performance badges
- [x] File Targets -- 5 files listed
- [x] Feature Flag -- none (enhancement to existing bot card)
- [x] Acceptance Criteria -- 6 criteria
- [x] Test Expectations -- unit, integration, N+1 described
- [x] Constraints -- read-only display, dark-theme CSS compatibility
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: portfolio-builder, role: Trader (Lucas))
- [x] arch:rails label -- Rails architecture component
- [x] arch note verified -- arch-rails note exists in pal-e-docs (id: 2347, status: active). Note: search_notes does not surface this note but get_note with exact slug confirms it exists.
- [x] Forgejo issue -- ldraney/prediction-assistant#83, state: open
File Targets
- [x]
app/views/bots/_bot_card.html.erb-- verified: exists, contains bot card template with stats section (expected_return, trades, P&L). Adding a performance badge here is consistent. - [x]
app/presenters/bot_presenter.rb-- verified: exists, BotPresenter class with pnl_display/pnl_css_class methods. Adding daily_pnl/weekly_pnl/pnl_trend follows established pattern. - [x]
app/views/bots/index.html.erb-- verified: exists, renders_bot_cardpartial at line 270. Presenter wiring change may be needed here or in controller. - [x]
test/presenters/bot_presenter_test.rb-- verified: exists, has comprehensive presenter tests for pnl formatting and status display. - [x]
test/controllers/bots_controller_test.rb-- verified: exists, has integration tests for bot pages.
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.
Dependencies
- SimulationResult model (issue #82, board item #1758) -- documented in Lineage section. Currently in backlog. The SimulationResult model does not yet exist in the codebase. This ticket cannot be implemented until #82 lands, but the dependency is properly documented. This is an ordering concern for sprint planning, not a scope defect.
- No other blocking dependencies identified on the board.
- This ticket blocks nothing (per Lineage).
Acceptance Criteria
6 criteria, all agent-verifiable:
- AC 1-3: badge rendering (positive/negative/no-data/trend) -- verifiable via view tests
- AC 4: presenter methods (daily_pnl, weekly_pnl, pnl_trend) -- verifiable via unit tests
- AC 5: N+1 query prevention -- verifiable via query count assertion
- AC 6: test coverage for all badge states -- meta-criterion, verifiable by running test suite
Test expectations describe what to test (unit + integration + N+1). Standard Rails test runner (bin/rails test).
Blast Radius
- BotPresenter is used in: bots_controller.rb (3 instantiation sites), 4 config partials (comments only), _bot_card partial, index view.
- _bot_card partial is only rendered from bots/index.html.erb -- no other consumers.
- Changes are additive -- new methods on presenter, new HTML in partial. Existing functionality is not affected.
- The presenter currently takes pnl_sum as a constructor argument. New daily/weekly P&L data will likely follow the same passive-data pattern (computed in controller, passed to presenter). No architectural change required.
- No sibling services or downstream consumers affected.
Decomposition Assessment
5 file targets across 1 repo (under threshold). 6 acceptance criteria (technically >5 threshold, but all are tightly coupled to a single small feature -- adding a badge to a card). Estimated agent work: well under 5 minutes. No decomposition needed.
Recommendation
No action needed.
-
Review: Go-live activation flow -- simulation to real trading transition
review-1761-2026-07-04Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Parent: Paper trading dashboard (S7). Depends on: Bot detail P&L dashboard, Registration form (#58)
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- Links to docs/user-stories/ai-portfolio-builder.md (uses link style, not As/I want/So that format -- acceptable)
- [x] Context -- Clear explanation of simulation vs real trading separation
- [x] File Targets -- 6 files listed (4 existing, 2 new)
- [x] Feature Flag -- none (core safety mechanism)
- [x] Acceptance Criteria -- 8 items
- [x] Test Expectations -- 5 expectations listed
- [x] Constraints -- 3 constraints listed
- [x] Checklist -- Standard 3-item checklist
- [x] Related -- project-prediction-assistant
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section (Key: portfolio-builder, Role: Trader (Lucas))
- [x] arch:rails label -- Rails Architecture
- [x] arch note verified -- arch-rails note exists in pal-e-docs (title: "Rails Architecture: Prediction Assistant", status: active)
- [x] Forgejo issue -- ldraney/prediction-assistant#85, open
File Targets
- [x]
app/models/strategy.rb-- verified: EXISTS. Currently hasactiveboolean, no trading_enabled or budget fields. Correct modification target. - [x]
db/migrate/XXXXXX_add_trading_fields_to_strategies.rb-- new migration, expected to not exist yet - [x]
app/views/bots/_activation_panel.html.erb-- new partial, expected to not exist yet - [x]
app/services/order_service.rb-- verified: EXISTS. Currently uses@dry_runconstructor parameter. Ticket wants it to checkstrategy.trading_enabled?-- this is achievable sinceplace_orderalready receivesbot:(the strategy). - [x]
test/models/strategy_test.rb-- verified: EXISTS, 320 lines of existing tests - [x]
test/controllers/bots_controller_test.rb-- verified: EXISTS, 457 lines of existing tests
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets are in the same repo. No cross-repo concerns.
Dependencies
- Registration form (#58, S6) -- board item 1729 is currently in
todocolumn, not yet complete. Documented in Lineage. - Bot detail P&L dashboard -- dependency is documented but no specific issue number referenced. This should be clarified.
- No in_progress items block this ticket directly.
Acceptance Criteria
8 ACs total. All are testable by an agent. However:
- AC #4 (OrderService checks trading_enabled) is achievable --
place_order(bot: strategy, ...)already receives the strategy record. - AC #7 (Budget guardrail) requires summing existing trades against budget_cents -- straightforward but adds scope.
- Naming conflict: AC #1 lists
max_concurrent_positionsas a new integer column on the strategies table. However,max_concurrent_positionsalready exists as a JSONB config key inLateGameLockConfig(app/models/late_game_lock_config.rb:10) andBotCatalog(app/models/bot_catalog.rb:214). Adding a same-named column creates ambiguity -- ActiveRecord will shadow the JSONB key with the column accessor.
Blast Radius
- OrderService consumers: PregameStackerBot (app/services/pregame_stacker_bot.rb) and BulkSweepJob (app/jobs/bulk_sweep_job.rb) both construct OrderService with
dry_run:parameter. The ticket's change to checkstrategy.trading_enabled?inside OrderService would affect all callers -- they would get forced dry_run regardless of their constructor param. This is the intended behavior but must be tested across all consumers. - Toggle flow: The existing
activetoggle in BotsController (app/controllers/bots_controller.rb:74-85) and BotPresenter (app/presenters/bot_presenter.rb:19) usestrategy.active?. The ticket introducestrading_enabledas a separate concept -- existingactiveremains for monitoring. No unintended collision.
Decomposition Assessment
- File targets: 6 files, 1 repo -- does NOT trigger the >3 files across >2 repos rule
- Acceptance criteria: 8 items -- TRIGGERS the >5 AC rule
- Estimated agent work: Model + migration + view partial + OrderService change + tests across 2 test files -- estimated 10-15 minutes, TRIGGERS the >5 minutes rule
NEEDS DECOMPOSITION -- suggested split:
- Model + migration (3 AC): Add
trading_enabled,budget_cents,max_bet_centsfields; migration; model validations and tests - OrderService guard + budget enforcement (2 AC):
trading_enabled?check forces dry_run; budget guardrail rejects over-budget orders - Activation UI + controller flow (3 AC): Activation panel partial, LIVE badge, pause button, controller integration tests
Recommendation
[BODY]Renamemax_concurrent_positionscolumn to avoid collision with existing JSONB config key in LateGameLockConfig. Suggested:trading_max_positionsor move to JSONB config instead of a column.[DECOMPOSE]8 AC across 6 files, estimated >5 minutes. Route to skill-decompose-ticket with the three-way split above.
-
Review: Sport-specific game clock integration for time-conditioned bots
review-1723-2026-07-04Verdict: READY
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets (create / modify / do-not-touch sections)
- [x] Feature Flag (none)
- [x] Acceptance Criteria (7 items)
- [x] Test Expectations (5 items + run command)
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:rails label -- Rails Architecture
- [x] arch note verified -- arch-rails note exists in pal-e-docs (id: 2347)
- [x] Forgejo issue -- ldraney/prediction-assistant#40, open
File Targets
- [x]
app/services/game_clock_estimator.rb-- to create, does not exist yet (correct) - [x]
config/game_durations.yml-- to create, does not exist yet (correct) - [x]
test/services/game_clock_estimator_test.rb-- to create, does not exist yet; test/services/ directory exists (correct) - [x]
app/jobs/market_scanner_job.rb-- to modify, EXISTS; emit_time_update method at line 112 confirmed as integration point - [x]
app/jobs/time_update_job.rb-- to modify, EXISTS; stub job with perform(ticker:, series_ticker:, event_start_time:, captured_at:) ready for extension - [x]
test/jobs/market_scanner_job_test.rb-- to modify, EXISTS; comprehensive test suite with FakeKalshiClient pattern
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, repo field matches, all file targets in this repo. Single-repo scope.
Dependencies
- Issue #4 (Late-Game Lock) -- primary consumer of enriched time data, currently in
todocolumn (board item #1689). This ticket is a prerequisite for Late-Game Lock's time condition. - Issue #2 (MarketScanner) -- parent feature, in
validationcolumn (board item #1687). Scanner is the emission point being extended. - Issue #29 (Edge Learner) -- may use time data for pattern learning, in
backlogcolumn (board item #1716). - No blocking dependencies for this ticket -- it enriches scanner output using only existing data (series_ticker + event_start_time) without requiring other tickets first.
Acceptance Criteria
7 criteria, all testable by an agent. Test commands are valid:
bin/rails test test/services/game_clock_estimator_test.rb test/jobs/market_scanner_job_test.rb. AC #7 (backward compatibility for existing TimeUpdateJob consumers) is important -- the agent must use optional kwargs with defaults when extending TimeUpdateJob#perform to avoid breaking existing scanner calls during implementation.Blast Radius
Contained. TimeUpdateJob is currently a stub (
# Stub -- bot consumers implement in Sprint 4) with no real downstream consumers. Only emitted by MarketScannerJob, which is one of the files being modified. No bot implementations need to change -- the ticket explicitly scopes bot-side interpretation to ticket #4 (Late-Game Lock). Adding new keyword arguments to TimeUpdateJob#perform requires backward-compatible defaults to satisfy AC #7.Decomposition Assessment
6 file targets across 1 repo (does not trigger >3 files across >2 repos). 7 acceptance criteria (above the >5 threshold). However, all 7 ACs test behavioral facets of a single service (GameClockEstimator) and its integration point -- they are not independent deliverables. The work naturally splits into: (1) create GameClockEstimator + config + tests, (2) wire into scanner + extend TimeUpdateJob. These are tightly coupled -- you cannot test the estimator integration without both pieces. 3 story points is a modest estimate consistent with a single agent pass under 5 minutes. No decomposition needed.
Recommendation
No action needed.
-
Review: Bot detail P&L dashboard with time-series chart
review-1760-2026-07-04Verdict: NEEDS_REFINEMENT
Board item #1760 — Forgejo issue
ldraney/prediction-assistant#84. Type: Feature.Template Completeness
- [x] Type — Feature
- [x] Lineage — Parent and dependencies identified
- [x] Repo —
ldraney/prediction-assistant - [x] User Story — AI Portfolio Builder
- [x] Context — clear motivation
- [x] File Targets — 5 files (3 new, 2 existing)
- [x] Feature Flag — none (appropriate for core bot detail feature)
- [x] Acceptance Criteria — 8 criteria
- [x] Test Expectations — present
- [x] Constraints — no external JS, Turbo Native compatible, dark theme
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:portfolio-builder label — AI Portfolio Builder
- [x] story note verified — found in project-prediction-assistant user-stories section
- [x] arch:rails label — Rails Architecture
- [x] arch note verified — arch-rails note exists in pal-e-docs (id: 2347, status: active)
- [x] Forgejo issue — ldraney/prediction-assistant#84, state: open
File Targets
- [x]
app/views/bots/show.html.erb— verified: exists (19k), renders bot detail page with P&L display via BotPresenter - [x]
app/views/bots/_performance_dashboard.html.erb— new partial to create (no conflict, directory exists) - [x]
app/views/bots/_trade_history.html.erb— new partial to create (no conflict, directory exists) - [x]
app/controllers/bots_controller.rb— verified: exists, show action already loads strategy + pnl_sum via Trade queries - [x]
test/controllers/bots_controller_test.rb— verified: exists (15k)
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.
Dependencies
- SimulationResult model (issue #82, board item #1758) — in backlog. The ticket's Lineage says "Depends on: SimulationResult model (this sprint)" but #82 has no sprint label and is still in backlog. This is a real dependency: the P&L chart and trade history depend on simulated trade data. The current Trade model has no
dry_runfield; simulation tracking today is only via ActivityLog actions. #82 must be implemented before this ticket can be worked. - Activity feed (#30, board item #1717) — in todo. The issue says the dashboard goes "above the activity feed." If #30 isn't done yet, the show page layout reference point doesn't exist. However, the dashboard partial can still be added to show.html.erb at a logical position regardless.
- Go-live activation flow (#85) — in backlog. This ticket blocks #85 per the Lineage. No action needed on this ticket's scope.
Acceptance Criteria
8 acceptance criteria. All are testable and verifiable by an agent:
- Chart rendering — verifiable via HTML assertions on SVG/CSS elements
- Period toggles — verifiable via Turbo Frame request/response tests
- Summary stats — verifiable via presence of stat elements with computed values
- Trade history table — verifiable via table row assertions
- Pagination — verifiable via Turbo Frame page navigation
- Empty state — verifiable with no trades in test fixture
- Tests — meta-criterion, verifiable by test pass
Test expectations describe what to test but do not specify exact test commands. This is acceptable since the repo uses standard Rails
rails test.Blast Radius
- BotPresenter already has
pnl_displayandpnl_css_classmethods. This ticket extends the presenter, not replaces it. Low risk. - The bot index page also displays P&L (simple total). No changes needed there.
- The "no external JS charting libraries" constraint aligns with the existing Propshaft + importmap architecture (no Node.js build step). Inline SVG/CSS is the right approach.
- No similar P&L dashboard pattern exists elsewhere in the app to keep consistent with.
Decomposition Assessment
NEEDS DECOMPOSITION — route to skill-decompose-ticket.
- File targets: 5 files in 1 repo — within single-repo threshold
- Acceptance criteria: 8 ACs — exceeds the >5 threshold
- Estimated agent work: SVG charting from scratch + Turbo Frame period toggles + trade history table + Turbo Frame pagination + 5 summary stats + empty state + tests across all — likely >5 minutes
- Natural decomposition: (A) Performance chart + stats + period toggles (ACs 1-4), (B) Trade history table + pagination + empty state (ACs 5-7), with tests (AC 8) split across both
Recommendation
[DECOMPOSE]8 ACs across 2 functional areas. Split into: (A) P&L chart with summary stats and period toggles, (B) Trade history table with pagination and empty state. Route to skill-decompose-ticket.
-
Review: Fix EdgeLearnerConfig max_group_size validation
review-1753-2026-07-04Verdict: READY
Template Completeness
- [x] Type -- Bug
- [x] Lineage -- Sprint 6 sub-ticket of #29, regression from #3
- [x] Repo -- ldraney/prediction-assistant
- [x] What Broke -- EdgeLearnerConfig validates max_group_size as positive integer, but spec defines it as enum
- [x] Repro Steps -- 4 clear steps to reproduce
- [x] Expected Behavior -- enum values should pass validation
- [x] Environment -- file, line, commit, spec reference all provided
- [x] Acceptance Criteria -- 5 criteria, all verifiable
- [x] Related -- parent and introducing issue identified
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:rails label -- Rails Architecture
- [x] arch note verified -- arch-rails note exists in pal-e-docs (architecture, active)
- [x] Forgejo issue -- ldraney/prediction-assistant#72, open
File Targets
- [x]
app/models/edge_learner_config.rb:24-- verified:validate_positive_integer("max_group_size")is the bug - [x]
docs/bots/edge-learner.md:72-- verified: spec defines max_group_size as enum with values "pairs", "triples", "uncapped" - [x]
app/models/bot_catalog.rb:248-249-- verified: CONFIG_SCHEMAS hastype: :number, default: 3(needs updating totype: :select, default: "triples") - [x]
test/models/strategy_test.rb:47-- verified:"max_group_size" => 4(integer, needs enum value) - [x]
test/controllers/bots_controller_test.rb:53-- verified:"max_group_size" => 3(integer, needs enum value) - [x]
test/controllers/bots_controller_test.rb:343-- verified:max_group_size: "3"(string integer, needs enum value) - [x]
test/services/position_tracker_test.rb:43-- verified:"max_group_size" => 4(integer, needs enum value)
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo fix.
Dependencies
- Parent: #29 (Edge Learner bot, board item 1716, backlog) -- not blocking; this is an independent bug fix
- Introduced by: #3 (EdgeLearnerConfig STI, board item 1688, validation) -- original source of the bug
- No items on the board are blocked by this ticket
- No undocumented dependencies found
Acceptance Criteria
5 criteria, all agent-verifiable:
- AC1: Change
validate_positive_integertovalidate_inclusion-- verifiable by code inspection - AC2: Test enum acceptance/rejection -- verifiable by running test suite
- AC3: BotCatalog CONFIG_SCHEMAS update -- verifiable by code inspection
- AC4: Test helper updates across 3 test files -- verifiable by running test suite
- AC5: Migration if schema change needed -- JSONB config column stores values as JSON; changing from integer to string values does not require a schema migration. This criterion is correctly conditional.
Blast Radius
validate_positive_integeris used correctly in 4 other locations (BulkSweepConfig, LateGameLockConfig, StackerConfig, EdgeLearnerConfig's own min_simultaneous_markets) for fields that are genuinely integers. No same-bug pattern elsewhere.- All
max_group_sizereferences in test fixtures use integer values (3 or 4) that will need updating to enum strings -- the issue correctly identifies all 3 affected test files. - No downstream consumers of max_group_size outside the identified files. GroupBuilder service (mentioned in Related) is not yet implemented (part of #29).
Decomposition Assessment
No decomposition needed. 3 source files + 3 test files, all in one repo. 5 acceptance criteria (at boundary but straightforward). Estimated agent work well under 5 minutes -- this is a validation type swap with test fixture updates.
Recommendation
No action needed.
-
Review: EdgeLearnerJob consumer + fan-out wiring
review-1752-2026-07-04Verdict: READY
Board item #1752 -- Forgejo issue
ldraney/prediction-assistant#71. Re-review after issue update (issue updated 12:05 UTC, prior review at 10:32 UTC). Prior [BODY] findings largely resolved. All findings resolved. Prior arch-rails gap was a false positive (note exists at slugarch-rails, confirmed by multiple agents).Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sprint 6, sub-ticket of #29
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- "AI Portfolio Builder" (link reference format; matches story:portfolio-builder label). Prior review flagged "Bot Marketplace" mismatch -- now FIXED in current issue body.
- [x] Context -- thorough; explains 3 event types, delegation targets, fan-out wiring needs with specific code references
- [x] File Targets -- 5 targets (3 modify, 2 new)
- [x] Feature Flag -- None (activation via EdgeLearnerConfig active toggle)
- [x] Dependencies -- documented with issue refs and explicit ordering
- [x] Merge Coordination -- clear merge order: PricePattern -> GroupBuilder -> EdgeLearnerJob, plus Late-Game Lock coordination
- [x] Acceptance Criteria -- 5 items
- [x] Test Expectations -- 5 specific test scenarios
- [x] Constraints -- 4 constraints including concurrency and learning feedback
- [x] Checklist -- standard 3-item
- [x] Related -- parent and dependency references
Traceability
- [x] story:portfolio-builder label -- present on board item
- [x] story note verified -- "portfolio-builder" found in project-prediction-assistant user-stories section (row: Trader (Lucas), links to story-prediction-assistant-portfolio-builder)
- [x] arch:rails label -- present on board item
- [x] arch note verified --
arch-railsnote exists in pal-e-docs (confirmed by multiple agents; prior "missing" finding was a false positive) - [x] Forgejo issue -- #71, open, valid URL
File Targets
- [x]
app/jobs/edge_learner_job.rb-- verified: does not exist yet (new file). Reference pattern exists atapp/jobs/pregame_threshold_job.rb(23 lines, delegates to bot service in perform method) - [x]
app/jobs/price_update_job.rb-- verified: exists (21 lines), is a stub with empty perform body and comment "Stub -- bot consumers implement in Sprint 4". Header confirms consumers: "Late-Game Lock, Edge Learner" - [x]
app/jobs/time_update_job.rb-- verified: exists (19 lines), is a stub with empty perform body and comment "Stub -- bot consumers implement in Sprint 4". Header confirms consumers: "Late-Game Lock, Edge Learner" - [x]
app/jobs/sweep_eligible_job.rb-- verified: exists (27 lines), fans out to BulkSweepJob only, has comment "Edge Learner will be added in Sprint 4 (#29)". Fan-out pattern is established:BulkSweepJob.perform_later(...) - [x]
test/jobs/edge_learner_job_test.rb-- verified: does not exist yet (new file)
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, all file targets are in this repo. Single repo scope.
Dependencies
- GroupBuilder service (#69) -- board item #1750, backlog column.
app/services/group_builder.rbdoes not exist. Hard dependency for AC4. Issue documents this: "Depends on GroupBuilder service (sub-ticket)". - PricePattern model (#67) -- board item #1748, backlog column.
app/models/price_pattern.rbdoes not exist. Hard dependency for Constraints ("Closed trade results must be fed back into PricePattern"). Issue documents this. - PositionTracker (#24) -- board item #1711, validation column.
app/services/position_tracker.rbEXISTS. Required for AC3 exit logic. - OrderService (#23) -- board item #1710, validation column.
app/services/order_service.rbEXISTS. Required for AC5. - EdgeLearnerConfig model -- EXISTS at
app/models/edge_learner_config.rb. All referenced config keys verified: risk_level, bet_size_per_group, max_portfolio_exposure, stop_loss, take_profit, learning_sensitivity. - ActivityLog model -- EXISTS at
app/models/activity_log.rb. Current ACTIONS: place_order, cancel_order, fill, partial_fill, error, dry_run, bulk_sweep. Agent will need to add Edge Learner-specific actions (group_generation, pattern_detection) during implementation. - Late-Game Lock -- board items #1747 and #1689, both in todo column. Also targets PriceUpdateJob and TimeUpdateJob. Issue correctly states: "Must merge AFTER Late-Game Lock PR to avoid Solid Queue job conflicts."
Prior review concern resolved: Previous review recommended adding explicit ordering and merge coordination notes. These sections already exist in the issue body: Dependencies section states "Must merge AFTER Late-Game Lock" and Merge Coordination section gives explicit merge order "PricePattern -> GroupBuilder -> EdgeLearnerJob".
Acceptance Criteria
5 AC items, all testable with caveats:
- AC1: Testable -- consumer pattern well-established from PregameThresholdJob
- AC2: Testable -- mechanical fan-out additions (add
EdgeLearnerJob.perform_later(...)to 3 jobs) - AC3: Testable -- complex but well-specified. 3 risk-level exit strategies (low=immediate, medium=trailing stop, high=take-profit). Requires PositionTracker (EXISTS) and OrderService (EXISTS)
- AC4: Testable only after GroupBuilder (#69) merges -- delegates to GroupBuilder for group generation. Hard dependency documented in issue.
- AC5: Testable -- standard ActivityLog pattern
Minor gap: No AC covers specific
time_updateevent handling behavior beyond AC1's "processes time_update payloads". Constraints mention "Learning model reversal signal overrides risk-level hold rules" but no AC explicitly tests this override.Blast Radius
Low risk. All fan-out changes are additive:
- PriceUpdateJob and TimeUpdateJob are stubs -- adding fan-out is their first real consumer wiring
- SweepEligibleJob already fans out to BulkSweepJob -- adding EdgeLearnerJob follows the identical pattern
- MarketScannerJob (the event source) is not modified -- it already emits all 3 event types
- Late-Game Lock also targets PriceUpdateJob/TimeUpdateJob but merge order is documented
Decomposition Assessment
5 file targets in 1 repo, 5 acceptance criteria, follows established PregameThresholdJob consumer pattern. Fan-out changes are mechanical (3 one-line additions). The new job is the most complex piece but has clear AC and a reference implementation. No decomposition needed.
Recommendation
All checks pass. The sole prior blocker (
[SCOPE]arch-rails note missing) was a false positive -- the note exists at slugarch-railsin pal-e-docs, confirmed by multiple agents. Prior [BODY] recommendations from first review were resolved in the current issue body. Ticket is ready for development. -
Review: PricePattern model + migration + data collection
review-1748-2026-07-04Verdict: READY
Board item #1748 -- Forgejo issue
ldraney/prediction-assistant#67. Sub-ticket of #29 (Edge Learner bot). Re-review: all 3 prior issues resolved. Arch-rails false positive confirmed.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sprint 6, sub-ticket of #29
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- AI Portfolio Builder (FIXED from prior review: was Bot Marketplace, now correctly references AI Portfolio Builder)
- [x] Context -- clear motivation for PricePattern as the Edge Learner learning layer
- [x] File Targets -- 4 new files listed
- [x] Feature Flag -- None, controlled by EdgeLearnerConfig active toggle
- [x] Acceptance Criteria -- 5 criteria listed
- [x] Test Expectations -- 4 items
- [x] Constraints -- indexes and recalculation requirement noted
- [x] Checklist -- standard 3-item checklist
- [x] Related -- parent, dependency, consumer documented
All required template sections present.
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- "portfolio-builder" row found in project-prediction-assistant user-stories section, links to story-prediction-assistant-portfolio-builder
- [x] arch:rails label -- Rails component
- [x] arch note verified --
arch-railsnote exists in pal-e-docs (confirmed by multiple agents; prior "missing" finding was a false positive due to search returning zero results despite the note existing at slugarch-rails) - [x] Forgejo issue -- ldraney/prediction-assistant#67, open
File Targets
- [x]
db/migrate/YYYYMMDDHHMMSS_create_price_patterns.rb-- verified: no price_patterns table exists indb/schema.rb(schema version 2026_07_03_200002). Parent dirdb/migrate/exists with 6 existing migrations. New file. - [x]
app/models/price_pattern.rb-- verified: no PricePattern model exists. Parent dirapp/models/exists with 14 models. New file. - [x]
test/models/price_pattern_test.rb-- verified: does not exist. Parent dirtest/models/exists with 8 test files. New file. - [x]
test/fixtures/price_patterns.yml-- verified: does not exist. Parent dirtest/fixtures/exists. New file.
All four file targets are net-new. No references to
PricePatternorprice_patternexist anywhere in the codebase (confirmed via grep across app/, test/, db/). Only existing mention of "price patterns" is inapp/models/bot_catalog.rbmarketing copy strings.Repo Placement
OK. Issue filed on
ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.Dependencies
- Parent: #29 (Edge Learner bot) -- board item 1716, in backlog (Sprint 6). This ticket is a decomposed sub-ticket.
- Depends on: #2 (MarketScanner data layer + Solid Queue event bus) -- prediction-assistant#2, closed/merged. Dependency satisfied.
- Consumed by: EdgeLearnerJob consumer (future sub-ticket of #29) -- not yet a standalone board item. PricePattern is foundational; the consumer will use it once both are built.
No blocking dependencies. PricePattern is a standalone data layer that can be built independently.
Acceptance Criteria
- AC 1 (migration columns) -- concrete and verifiable. Specifies all column names, types, and precision.
- AC 2 (model validations) -- concrete and verifiable.
- AC 3 (
for_situationscope) -- concrete and verifiable. Clear query pattern with ordering. - AC 4 (confidence scoring) -- FIXED from prior review. Now specifies explicit formula:
(win_count / sample_count) * log2(sample_count + 1) / log2(max_sample_count + 1), withwin_countdefined as patterns withexit_price > entry_pricefor the same(sport, game_situation)pair, capped at 1.0, minimum 5 samples before confidence exceeds 0.5. Minor ambiguity:max_sample_countis not explicitly defined (likely the max across all pairs, but could be a constant). Acceptable -- an agent can infer from context. - AC 5 (tests) -- concrete and verifiable.
All 5 criteria are agent-verifiable. Prior vagueness in AC 4 has been resolved.
Blast Radius
Low. PricePattern is entirely new and self-contained. No existing code references it. No foreign keys to existing tables. The
tickerandseries_tickercolumns matchmarket_snapshotsnaming conventions (suggesting future integration), but this ticket introduces no coupling. Existing model patterns (MarketSnapshot validations, Strategy STI) provide clear Rails conventions to follow.Decomposition Assessment
- 4 file targets in 1 repo -- under threshold
- 5 acceptance criteria -- at limit but acceptable
- All new files following standard Rails model + migration + test pattern
- Estimated agent work: under 5 minutes
No decomposition needed.
Prior Review Issues -- Resolution Status
- [x]
[BODY]User Story reference fixed: now correctly says "AI Portfolio Builder" with link todocs/user-stories/ai-portfolio-builder.md - [x]
[BODY]AC #4 confidence scoring clarified: explicit formula now provided with method name, calculation, and threshold - [x]
[SCOPE]arch-rails note: FALSE POSITIVE -- the note exists at slugarch-railsin pal-e-docs. Prior review's search returned zero results, but multiple agents have confirmed the note exists. No action needed.
Recommendation
All checks pass. No
[BODY],[LABEL],[SCOPE], or[DECOMPOSE]recommendations remain. The ticket is well-scoped and ready for implementation. -
Review: GroupBuilder service -- combinatorial market group generation
review-1750-2026-07-04Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sprint 6, sub-ticket of #29
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- AI Portfolio Builder, Edge Learner group evaluation engine
- [x] Context -- detailed background on Group Builder sub-system
- [x] File Targets -- 2 new files listed
- [x] Feature Flag -- None (internal service, appropriate)
- [x] Acceptance Criteria -- 5 criteria
- [x] Test Expectations -- 4 test areas
- [x] Constraints -- 3 constraints listed
- [x] Checklist -- standard 3-item checklist
- [x] Related -- parent, consumer, config references
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section, links to story-prediction-assistant-portfolio-builder
- [x] arch:rails label -- Rails component
- [x] arch note verified -- arch-rails note exists in pal-e-docs (false positive in prior review; confirmed by multiple agents)
- [x] Forgejo issue -- #69, open
File Targets
- [x]
app/services/group_builder.rb-- verified: new file, parent directoryapp/services/exists with 5 existing services (kalshi_client.rb, order_service.rb, position_tracker.rb, pregame_stacker_bot.rb, sizing_engine.rb) - [x]
test/services/group_builder_test.rb-- verified: new file, parent directorytest/services/exists with 5 existing test files
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all work scoped to the same repo. Single-repo change, no cross-repo concerns.
Dependencies
- Parent: #29 (Edge Learner bot) -- board item 1716, backlog, sprint:6
- Consumed by: EdgeLearnerJob (separate sub-ticket of #29, not yet created or in backlog)
- Config: EdgeLearnerConfig
max_group_sizefield exists (line 7 of edge_learner_config.rb) -- but currently validated as positive integer. Issue spec says it should be enum ("pairs"/"triples"/"uncapped"). The issue acknowledges this in Related section: "fix tracked in separate bug sub-ticket". This is a known dependency, not a scoping failure. - No blocking items in in_progress column.
- Pure logic service with zero database access -- no migration or schema dependency.
Acceptance Criteria
5 criteria, all verifiable by an agent:
- AC1: Interface contract (
GroupBuilder.new(markets, max_group_size:).call) -- testable with unit test - AC2: Exact group counts (3=7, 4=15, 5=31) -- testable with assertions
- AC3: max_group_size filtering -- testable with enum boundary tests
- AC4: Combined probability calculation -- testable with known inputs
- AC5: Efficiency for 10 markets (1023 groups) -- testable with timing benchmark
No missing criteria. Test expectations align with ACs. No test commands specified but the test file path is clear and follows existing conventions.
Blast Radius
Minimal. GroupBuilder is a new standalone service consumed only by EdgeLearnerJob (not yet built). No existing services reference GroupBuilder or use combinatorial logic. The only related pattern is
sizing_engine.rbwhich uses "combination" in a different context (position sizing). No downstream consumers affected.Decomposition Assessment
2 file targets, 1 repo, 5 acceptance criteria. Pure logic service with no external dependencies. Estimated agent work: under 5 minutes. No decomposition needed.
Recommendation
All checks pass. The prior NEEDS_REFINEMENT verdict was based on a false positive: the arch-rails architecture note does exist at slug
arch-railsin pal-e-docs (confirmed by multiple agents). No remaining scope issues. -
Review: Late-Game Lock: entry logic + OrderService integration
review-1749-2026-07-04-r2Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #4, second of 3 from decomposition
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- present, well-formed
- [x] Context -- thorough explanation of bot behavior and pattern references
- [x] File Targets -- 3 files to modify/create, 3 files NOT to touch
- [x] Feature Flag -- "none" with explanation (no flag infra, config controls activation)
- [x] Acceptance Criteria -- 5 criteria, all testable
- [x] Test Expectations -- unit tests, edge cases, dry-run, run command
- [x] Constraints -- 4 constraints documented
- [x] Checklist -- present
- [x] Related -- project, parent issue, dependencies listed
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading
- [x] story note verified -- story-prediction-assistant-watchdog-trading exists (active, user-story type); entry found in project-prediction-assistant user-stories section
- [x] arch:rails label -- Rails Architecture
- [x] arch note verified -- arch-rails note exists in pal-e-docs (active, architecture type)
- [x] Forgejo issue -- ldraney/prediction-assistant#68, open
File Targets
- [x]
app/services/late_game_lock_bot.rb-- new file (correct, to be created) - [x]
app/services/late_game_lock_evaluator.rb-- file to modify; does not exist yet but depends on #66 (event dispatch sub-ticket, board item #1747 in todo column). Dependency correctly documented in Lineage. When #66 completes, this target will be valid. - [x]
test/services/late_game_lock_bot_test.rb-- new file (correct, to be created) - [x]
app/services/order_service.rb-- exists (14k, verified API:place_order(bot:, ticker:, side:, quantity:, price:)) - [x]
app/services/position_tracker.rb-- exists (11k, verified API:open_positions(user:, bot:),conflict?(user:, ticker:, side:, exclude_strategy:)) - [x]
app/models/late_game_lock_config.rb-- exists (1.1k, hasbet_sizeandmax_concurrent_positionsin REQUIRED_CONFIG_KEYS)
Repo Placement
OK. Issue #68 is filed on ldraney/prediction-assistant and all file targets are in that same repo. Single repo, no cross-repo concerns.
Dependencies
- Blocking: Board item #1747 (issue #66, "Late-Game Lock: event dispatch wiring + dual-trigger evaluator") -- in
todocolumn. Creates theLateGameLockEvaluatorthat this ticket modifies. Correctly documented in Lineage section. - Merged: Board item #1710 (#23, OrderService) -- in
validationcolumn. File exists and API verified. - Merged: Board item #1711 (#24, PositionTracker) -- in
validationcolumn. File exists and API verified.
Acceptance Criteria
5 ACs, all verified against actual codebase APIs:
- [x] AC1:
OrderService.place_ordersignature matches -- takesbot:, ticker:, side:, quantity:, price: - [x] AC2:
PositionTracker.open_positions(bot: config)works --user:defaults to nil - [x] AC3:
config.trades.where(ticker:, status: %w[pending filled]).exists?matches PregameStackerBot#already_trading? pattern (line 132-134) - [x] AC4:
PositionTracker.conflict?(ticker:, side:, exclude_strategy:)API matches --user:defaults to nil - [x] AC5: Logging pattern
Rails.logger.info("[LateGameLock] ...")consistent with PregameStackerBot convention
All criteria are agent-verifiable via unit tests.
Blast Radius
Limited. New bot service following the established PregameStackerBot pattern. No changes to shared services (OrderService, PositionTracker). Error handling pattern (
rescue DuplicateOrderError,OrderError) is consistent with existing consumers (PregameStackerBot inapp/services/pregame_stacker_bot.rblines 201-205, BulkSweepJob inapp/jobs/bulk_sweep_job.rblines 169-176). No downstream consumers affected.Decomposition Assessment
3 file targets in 1 repo, 5 ACs, straightforward pattern-following implementation. Well under all thresholds (<3 files across >2 repos, <=5 ACs, estimated <5 min agent work). No decomposition needed.
Recommendation
No action needed.
-
Review: Late-Game Lock: exit management + PositionTracker integration
review-1751-2026-07-04Verdict: READY
Re-review: Previous review was NEEDS_REFINEMENT due to missing
arch-railsnote. That note now exists (id 2347, status active). All checks pass.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #4, third of 3 sub-tickets
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- As a trader, exit management for profit/loss
- [x] Context -- Explains PositionTracker integration and auto_sell_vs_hold
- [x] Architecture -- References arch-rails note (extra section, not required)
- [x] File Targets -- 2 modify + 2 do-not-touch
- [x] Feature Flag -- none (acceptable, no flag infra exists)
- [x] Acceptance Criteria -- 5 criteria
- [x] Test Expectations -- unit + edge cases + integration, run command provided
- [x] Constraints -- 4 constraints
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project, parent, dependencies
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: watchdog-trading, role: Trader)
- [x] arch:rails label -- Rails architecture component
- [x] arch note verified -- arch-rails note exists in pal-e-docs (id 2347, note_type: architecture, status: active, title: "Rails Architecture: Prediction Assistant")
- [x] Forgejo issue -- #70, open
File Targets
- [x]
app/services/late_game_lock_bot.rb-- does not exist yet; correctly depends on #68 (entry logic) which will create this file. Issue says "extend" which is accurate given the sequencing dependency. - [x]
test/services/late_game_lock_bot_test.rb-- does not exist yet; same dependency on #68. Correct sequencing. - [x]
app/services/position_tracker.rb(NOT touch) -- verified:exit_candidates(bot:)at line 138,exit_signalat line 273,STOP_LOSS_THRESHOLDat line 32,TAKE_PROFIT_THRESHOLDat line 33 all present. - [x]
app/services/order_service.rb(NOT touch) -- verified:place_order(bot:, ticker:, side:, ...)at line 72, acceptsside: "sell".
Repo Placement
OK. Issue filed on ldraney/prediction-assistant, all file targets are in this repo. Single-repo scope.
Dependencies
- #4 (parent, board item 1689) -- in
todocolumn - #66 (sibling, board item 1747) -- in
todo: event dispatch wiring + dual-trigger evaluator. Transitive dependency. - #68 (sibling, board item 1749) -- in
backlog: entry logic + OrderService integration. Direct dependency documented in Lineage. This ticket createslate_game_lock_bot.rbthat #70 extends. - #24 PositionTracker (board item 1711) -- in
validation(merged). Provides exit_candidates/exit_signal. - #23 OrderService (board item 1710) -- in
validation(merged). Provides place_order.
Dependency chain: #66 -> #68 -> #70. Predecessors correctly sequenced. Merged dependencies (#24, #23) confirmed in codebase.
Acceptance Criteria
5 criteria, all testable by an agent:
- process_exit calls PositionTracker.exit_candidates -- verifiable via unit test mock
- Stop-loss sell via OrderService -- verifiable
- Take-profit sell (auto_sell_vs_hold = "sell") -- verifiable
- Take-profit hold (auto_sell_vs_hold = "hold") -- verifiable, logs signal but no sell
- Idempotency: no duplicate sell orders -- verifiable via pending trade check
Test expectations align with criteria. Run command:
rails test test/services/late_game_lock_bot_test.rb.Blast Radius
- No existing bot implements exit management via PositionTracker -- this is the first consumer of
exit_candidates/exit_signal. - PregameStackerBot has zero exit logic. BulkSweepBot has no exit logic either.
- Pattern established here will likely be reused by other bots, but scope is correctly limited to Late-Game Lock.
auto_sell_vs_holdconfig key validated inLateGameLockConfig(line 26), accepts "hold" or "sell" -- aligns with AC.
Decomposition Assessment
2 file targets in 1 repo, 5 acceptance criteria (at threshold), estimated agent time ~3-5 minutes. No decomposition needed.
Recommendation
No action needed.
-
Review: Fix EdgeLearnerConfig max_group_size validation
review-1753-2026-07-04-v2Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Bug
- [x] Lineage -- Sprint 6, sub-ticket of #29, pre-existing from #3
- [x] Repo -- ldraney/prediction-assistant
- [x] What Broke -- max_group_size validated as positive integer, should be enum
- [x] Repro Steps -- 4-step reproduction path
- [x] Expected Behavior -- string enum values should pass validation
- [x] Environment -- file, line, commit, spec reference all present
- [x] Acceptance Criteria -- 5 criteria listed
- [x] Related -- parent, introduced-by, and downstream consumer identified
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:rails label -- Rails component
- [ ] arch note MISSING -- [SCOPE] search for "arch-rails" returned no results. Rails is the project's foundational framework; acceptable as foundational infrastructure if arch notes are only created for custom components.
- [x] Forgejo issue -- ldraney/prediction-assistant#72, open
File Targets
- [x]
app/models/edge_learner_config.rb, line 24 -- verified:validate_positive_integer("max_group_size")is exactly as described - [x]
docs/bots/edge-learner.md, line 72 -- verified:max_group_size | enum | "triples"with values "pairs", "triples", "uncapped" - [x]
app/models/strategy.rb, line 73 -- verified:validate_inclusion(key, allowed)method exists in base class, ready to use - [x]
app/models/bot_catalog.rb, line 248 -- verified:max_group_sizedefined astype: :number, default: 3in CONFIG_SCHEMAS (needs change totype: :select)
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo fix.
Dependencies
- Parent ticket #29 (Edge Learner bot, board item #1716) is in backlog. This bug fix is independent and can proceed without the parent.
- GroupBuilder service referenced in "Related" does not exist yet -- it is part of the parent feature. No downstream consumer to break.
- No blocking dependencies. No items in in_progress that block this.
Acceptance Criteria
- [x] AC 1 -- Testable: swap
validate_positive_integerforvalidate_inclusionwith%w[pairs triples uncapped] - [x] AC 2 -- Testable: unit tests for valid/invalid values
- [ ] AC 3 -- INACCURATE: says "BotCatalog::ENTRIES config_fields" but the config field definitions live in
BotCatalog::CONFIG_SCHEMAS, notENTRIES. TheENTRIESarray holds display metadata (Entry structs). The actual change needed is at line 248 in CONFIG_SCHEMAS: changetype: :number, default: 3totype: :select, default: "triples"with options for pairs/triples/uncapped. - [ ] AC 4 -- INACCURATE: says "Test fixtures in test/fixtures/" but there are no EdgeLearner YAML fixture files. The test data with integer max_group_size values lives in test helper methods:
test/models/strategy_test.rb:47("max_group_size" => 4),test/controllers/bots_controller_test.rb:53("max_group_size" => 3), andtest/services/position_tracker_test.rb:43("max_group_size" => 4). These test files WILL need modification (changing integer values to enum strings), which contradicts "without modification". - [x] AC 5 -- Likely not needed: config is stored as JSON/JSONB, so string values work without schema migration. Correct to include as conditional.
Blast Radius
validate_positive_integeris used in 5 other places across LateGameLockConfig, StackerConfig, and BulkSweepConfig -- all correct for their integer fields, no similar enum mismatch found.max_group_sizewith integer values appears in 3 test files (strategy_test, bots_controller_test, position_tracker_test) -- all need updating to enum strings.- GroupBuilder service does not exist yet, so no runtime downstream breakage.
- BotCatalog CONFIG_SCHEMAS renders the form field -- changing type from :number to :select will affect the bot detail page form rendering. The form rendering code should already handle :select type (used by risk_level, time_remaining_threshold, etc.).
Decomposition Assessment
3 source files + 3 test files in 1 repo. 5 AC (at threshold). Estimated agent time: under 5 minutes -- this is a mechanical validation swap, catalog field type change, and test data update. No decomposition needed.
Recommendations
[BODY]AC 3: Change "BotCatalog::ENTRIES config_fields for the affected bot(s) are updated" to "BotCatalog::CONFIG_SCHEMAS entry for EdgeLearnerConfig is updated -- max_group_size field changes from type: :number, default: 3 to type: :select, default: 'triples' with options pairs/triples/uncapped"[BODY]AC 4: Change "Test fixtures in test/fixtures/ are updated to reflect the config model changes -- all existing tests pass without modification" to "Test helper methods in strategy_test.rb, bots_controller_test.rb, and position_tracker_test.rb are updated to use enum string values ('triples' or 'pairs') instead of integers for max_group_size -- all tests pass"[SCOPE]arch:rails note missing -- create architecture note arch-rails if the convention requires arch notes for framework-level technology choices, or document that foundational framework labels do not require backing notes.
-
Review: Late-Game Lock: entry logic + OrderService integration
review-1749-2026-07-04Verdict: NEEDS_REFINEMENT
Scope is solid and implementation-ready. Single issue: missing
arch-railsbacking note in pal-e-docs (systemic gap across allarch:railsboard items).Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading story found in project-prediction-assistant user-stories section
- [x] story note verified -- entry exists on project page with key, role, and success metric
- [x] arch:rails label present
- [ ] arch note MISSING -- [SCOPE] Create architecture note
arch-railsfor the Rails component. This is a systemic gap affecting allarch:railsitems on the board. - [x] Forgejo issue --
ldraney/prediction-assistant#68, open
File Targets
- [x]
app/services/late_game_lock_bot.rb-- verified: does not exist yet, to be created (new bot service) - [x]
app/services/late_game_lock_evaluator.rb-- verified: does not exist yet. Created by dependency #66 (event dispatch sub-ticket). Ticket correctly notes dependency in Lineage section: "Depends on the event dispatch sub-ticket (evaluator must exist to call the bot)." - [x]
test/services/late_game_lock_bot_test.rb-- verified: does not exist yet, to be created - [x]
app/services/order_service.rb(NOT to touch) -- verified exists.place_order,DuplicateOrderError,PermanentApiError,dry_runall confirmed present. - [x]
app/services/position_tracker.rb(NOT to touch) -- verified exists.open_positions(bot:)andconflict?(ticker:, side:, exclude_strategy:)signatures confirmed. - [x]
app/models/late_game_lock_config.rb(NOT to touch) -- verified exists. Inherits fromStrategy(which hashas_many :trades). All referenced config keys present:bet_size,max_concurrent_positions,price_threshold,stop_loss,take_profit,auto_sell_vs_hold.
Repo Placement
OK. Issue filed on
ldraney/prediction-assistant, all file targets are in the same repo.Dependencies
- #66 (event dispatch wiring + dual-trigger evaluator) -- BLOCKING dependency. Creates
late_game_lock_evaluator.rbthat this ticket modifies. Currently in backlog (item #1747). Must complete before this ticket can start. Documented in Lineage section. - #23 (OrderService) -- merged (in validation column). Provides
place_order, error classes, dry-run support. Verified on disk. - #24 (PositionTracker) -- merged (in validation column). Provides
open_positions,conflict?. Verified on disk. - #70 (exit management, 3rd sub-ticket) -- depends on THIS ticket. Will extend
late_game_lock_bot.rbwithprocess_exitmethod. - #4 (parent issue) -- in todo column. Decomposed into #66 -> #68 -> #70.
Dependency chain is well-documented and correctly ordered.
Acceptance Criteria
5 ACs, all agent-verifiable:
- AC1 (YES buy order): testable with mocked OrderService
- AC2 (max_concurrent_positions): testable with PositionTracker mock returning varying counts
- AC3 (dedup guard): testable -- exact pattern from
PregameStackerBot#already_trading?confirmed:config.trades.where(ticker: ticker, status: %w[pending filled]).exists? - AC4 (conflict detection): testable with PositionTracker.conflict? mock
- AC5 (logging): testable by asserting log output
Test command provided:
rails test test/services/late_game_lock_bot_test.rbMinor note: AC1 references
config.bet_sizebut actual accessor pattern in codebase isconfig.config["bet_size"](JSON column). Agent should follow PregameStackerBot pattern. Not blocking -- intent is clear.Blast Radius
Low risk. This ticket creates new files (
late_game_lock_bot.rb, tests) and modifies one file created by a dependency (late_game_lock_evaluator.rb). No changes to shared services. Follows identical patterns toPregameStackerBot-- sameOrderServiceAPI, samePositionTrackerAPI, same dedup logic. No downstream consumers affected beyond #70 which extends the same file.Decomposition Assessment
- 3 file targets (2 new, 1 modify) across 1 repo -- within limit
- 5 acceptance criteria -- at boundary, acceptable
- Estimated agent work: ~3-4 minutes (follows well-established PregameStackerBot pattern)
No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails component in pal-e-docs. This is a systemic gap -- noarch-railsnote exists, and the label is used across many board items. This is not a blocker for implementation but blocks full traceability compliance.
-
Review: Late-Game Lock: event dispatch wiring + dual-trigger evaluator
review-1747-2026-07-04Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #4, first of 3
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- As a trader, dual-trigger evaluation
- [x] Context -- PriceUpdateJob/TimeUpdateJob stubs, pattern reference to PregameThresholdJob
- [x] File Targets -- 6 files (2 modify, 4 create) + 2 files NOT to touch
- [x] Feature Flag -- none (correct, no flag infra in codebase)
- [x] Acceptance Criteria -- 5 criteria, all testable
- [x] Test Expectations -- Unit and job tests, run command provided
- [x] Constraints -- Queue, pattern, error handling, additivity
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project, parent #4, #40, #29
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading story
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: watchdog-trading, role: Trader)
- [x] arch:rails label -- Rails architecture component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-rails for component Rails. Note: arch:rails is used across 15+ tickets on this board as foundational infrastructure. This is a project-level hygiene item, not specific to this ticket.
- [x] Forgejo issue -- #66, open
File Targets
- [x] app/jobs/price_update_job.rb -- verified: exists, contains stub with correct parameters (ticker, series_ticker, yes_bid, yes_ask, last_price, previous_price), comment says "Consumers (Sprint 4): Late-Game Lock, Edge Learner"
- [x] app/jobs/time_update_job.rb -- verified: exists, contains stub with correct parameters (ticker, series_ticker, event_start_time, captured_at), matching comment
- [x] app/services/late_game_lock_evaluator.rb -- does not exist yet (to be created), correct
- [x] test/jobs/price_update_job_test.rb -- does not exist yet (to be created), correct
- [x] test/jobs/time_update_job_test.rb -- does not exist yet (to be created), correct
- [x] test/services/late_game_lock_evaluator_test.rb -- does not exist yet (to be created), correct
- [x] app/jobs/market_scanner_job.rb -- verified: NOT to touch, event emission already correct (emit_price_update, emit_time_update)
- [x] app/models/late_game_lock_config.rb -- verified: NOT to touch, has time_remaining_threshold validation with presets [last_5_pct, last_10_pct, last_15_pct, last_quarter], sport_filters, price_threshold range 0.5-1.0
Repo Placement
OK -- Forgejo issue filed on ldraney/prediction-assistant, all file targets are in the same repo. Single-repo change.
Dependencies
- Parent #4 (board item 1689) -- "Late-Game Lock bot -- dual-trigger consumer" in todo column. This ticket is the first of 3 sub-tickets from decomposing #4.
- #68 (board item 1749) -- "Late-Game Lock: entry logic + OrderService integration" in backlog. Downstream sibling: needs the evaluator from this ticket before entry logic can be wired.
- #70 (board item 1751) -- "Late-Game Lock: exit management + PositionTracker integration" in backlog. Downstream sibling: depends on #68.
- #29 (board item 1716) -- "Edge Learner bot" in backlog. Also consumes PriceUpdateJob/TimeUpdateJob in Sprint 6. Ticket correctly preserves Edge Learner stub comments.
- #40 (board item 1723) -- "Sport-specific game clock integration" in backlog. Correctly identified as separate concern for real-time clock; this ticket uses elapsed-time ratio from event_start_time as a simpler proxy.
No blockers: nothing in in_progress blocks this ticket. Dependency ordering is clear: #66 -> #68 -> #70.
Acceptance Criteria
5 criteria, all verifiable by an agent:
- AC 1-2: Job dispatch to evaluator -- standard job test pattern, matches existing pregame_threshold_job_test.rb structure
- AC 3: Dual-trigger logic -- unit-testable with mock config and event data. Note: the evaluator will need to query MarketSnapshot for the "other half" of the dual trigger (price data on time events, time data on price events). This is an implicit implementation detail but follows naturally from the existing MarketSnapshot model.
- AC 4: Sport filter matching -- references PregameStackerBot#qualifies? pattern (verified: lines 85-103 of pregame_stacker_bot.rb). Pattern is clear and copyable.
- AC 5: Fault tolerance -- rescue per-config, log and continue. Matches PregameStackerBot pattern (lines 48-54).
Test command is valid: rails test test/services/late_game_lock_evaluator_test.rb test/jobs/price_update_job_test.rb test/jobs/time_update_job_test.rb
Blast Radius
- PriceUpdateJob and TimeUpdateJob are shared event jobs consumed by multiple bots. The ticket correctly preserves Edge Learner stub comments for Sprint 6 (#29).
- MarketScannerJob emission is NOT changed -- the scanner already emits both PriceUpdateJob and TimeUpdateJob on every scan cycle.
- SweepEligibleJob follows the same fan-out pattern (delegates to BulkSweepJob), confirming architectural consistency.
- No other consumers of PriceUpdateJob/TimeUpdateJob exist currently beyond the stubs.
Decomposition Assessment
6 file targets in 1 repo, 5 acceptance criteria, estimated agent work under 5 minutes. The pattern is well-defined (follow PregameThresholdJob -> PregameStackerBot). No decomposition needed.
Recommendation
- [SCOPE] Create architecture note arch-rails for the Rails component. This is a project-wide hygiene item affecting 15+ board items, not specific to this ticket. Does not block implementation.
-
Review: Registration form -- Kalshi API credential capture and validation
review-1729-2026-07-04Verdict: APPROVED
Re-review of board item #1729 after refinement. Previous review
review-1729-2026-07-03found NEEDS_REFINEMENT with 7[BODY]recommendations and 1[SCOPE]recommendation. All 7[BODY]items have been addressed in the updated issue.Template Completeness
- [x] Type -- Feature
- [x] User Story -- present
- [x] Lineage -- present (Story: Landing Page, Sprint: 6)
- [x] Repo -- ldraney/prediction-assistant
- [x] Context -- present, now explicitly clarifies KalshiClient per-user integration is out of scope
- [x] File Targets -- 8 targets, all verified (see below)
- [x] Feature Flag -- "None" (acceptable)
- [x] Acceptance Criteria -- 5 items (reduced from 6; credential revocation removed)
- [x] Test Expectations -- 4 items including mailer test
- [x] Constraints -- 5 items including Rails 8 encrypts requirement
- [x] Checklist -- 7 items
- [x] Related -- present
Extra sections:
### Scope,### Follow-ups(both helpful, not in template, harmless).Traceability
- [x] story:landing-page label -- Landing Page & Registration
- [x] story note verified --
landing-pageentry found in project-prediction-assistant user-stories section - [x] arch:rails label -- present on board item
- [ ] arch note MISSING -- [SCOPE]
arch-railsnote does not exist in pal-e-docs (carried over from previous review; project-level organizational task, not a scope blocker for this ticket) - [x] Forgejo issue -- #58, open
File Targets
- [x]
app/models/user.rb-- verified: marked as (new), does not exist, correctly describes creating User model with Rails 8encrypts. Previous review flagged this as incorrectly described; now fixed. - [x]
db/migrate/YYYYMMDD_create_users.rb-- verified: marked as (new), correctly says "create users table". Previous review flagged "add columns" language; now fixed. - [x]
app/controllers/registrations_controller.rb-- verified: marked as (new), does not exist - [x]
app/views/registrations/new.html.erb-- verified: marked as (new), does not exist - [x]
config/routes.rb-- verified: exists, currently has Keycloak auth routes and bot resources at lines 12-21 - [x]
app/mailers/user_mailer.rb-- verified: marked as (new),app/mailers/directory does not exist. Previous review flagged this as missing; now added. - [x]
app/views/user_mailer/welcome.html.erb-- verified: marked as (new), does not exist. Previous review flagged this as missing; now added. - [x]
app/services/keycloak_admin_service.rb-- verified: marked as (new), does not exist. Previous review flagged this as missing; now added.
Repo Placement
OK -- all 8 file targets are in ldraney/prediction-assistant, matching the Forgejo issue. No cross-repo concern.
Dependencies
- Depends on #57 (Keycloak login flow) -- board item #1728, currently in validation column. Soft blocker but not blocking scope review.
watchdog_configs.user_idFK -- properly deferred to Follow-ups section (schema.rb line 98 hasuser_idcolumn with no FK constraint).- No other blocking dependencies found on the board.
Acceptance Criteria
- 5 ACs, all testable and verifiable by an agent.
- AC #6 (credential revocation) was removed per previous review recommendation and properly deferred to Follow-ups.
- Scope items 5 (Keycloak user creation) and 6 (welcome email) are covered by Checklist items but not by ACs. Acceptable -- the ACs cover the user-facing behavior, and test expectations cover the mailer.
Blast Radius
Properly contained. The updated issue explicitly states that KalshiClient per-user integration is out of scope. The Follow-ups section documents the blast radius (kalshi_client.rb, order_service.rb, market_scanner_job.rb, and bot consumers) as a separate ticket. No undisclosed downstream effects.
Decomposition Assessment
8 file targets in 1 repo. 5 acceptance criteria. Scope covers: User model creation, migration, controller, view, routes, mailer, Keycloak admin service, credential validation. All targets are in a single repo and follow standard Rails conventions. With credential revocation and KalshiClient per-user integration removed, estimated agent work fits within 5 minutes. No decomposition needed.
Previous Review Resolution
All 7
[BODY]recommendations fromreview-1729-2026-07-03verified as fixed:user.rbfile target now correctly marked as (new) -- FIXED- Migration description now says "create users table" -- FIXED
- Mailer file target added (
user_mailer.rb+ template) -- FIXED - Keycloak admin service file target added -- FIXED
- Encryption approach pinned to Rails 8
encryptsmacro -- FIXED - AC #6 (credential revocation) removed, deferred to Follow-ups -- FIXED
- KalshiClient per-user integration explicitly out of scope in Context + Follow-ups -- FIXED
1
[SCOPE]recommendation carried forward:arch-railsarchitecture note still missing from pal-e-docs (project-level task, non-blocking)
Recommendation
[SCOPE]Create architecture notearch-railsfor component rails (carried over from previous review -- project-level organizational task, does not block implementation)
No other action needed. Ticket is ready for implementation.
-
Review: Per-bot live activity feed -- Turbo Streams
review-1717-2026-07-04Verdict: APPROVED
Re-review of
review-1717-2026-07-03(NEEDS_REFINEMENT). All four[BODY]fixes have been correctly applied. The issue spec now matches the actual codebase schema.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sprint 4, depends on #26 and bots running
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- Bot Marketplace
- [x] Context -- detailed background with references
- [x] File Targets -- 7 files listed (3 pre-existing, 4 to create)
- [x] Feature Flag -- None (integral to UI, acceptable)
- [x] Acceptance Criteria -- 10 criteria
- [x] Test Expectations -- model, channel, system tests listed
- [x] Constraints -- Action Cable, strategy scoping, append-only, throttling
- [x] Checklist -- 11 items
- [x] Related -- dependencies listed with issue refs
All required sections present per
template-issue-feature.Traceability
- [x] story:bot-marketplace label -- Bot Marketplace user story
- [x] story note verified -- found in project-prediction-assistant user-stories section (key: bot-marketplace, links to story-prediction-assistant-bot-marketplace)
- [x] arch:frontend label -- frontend component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-frontend for component frontend (carried forward from review-1717-2026-07-03; non-blocking for issue spec)
- [x] Forgejo issue -- ldraney/prediction-assistant#30, open
File Targets
- [x]
app/models/activity_log.rb-- EXISTS, schema now matches AC #1 exactly (strategy_id, bot_name, ticker, action, side, price, quantity, status, message, metadata) - [x]
db/migrate/20260703200001_create_activity_logs.rb-- EXISTS - [x]
app/channels/bot_activity_channel.rb-- does not exist yet, to be created (correct) - [x]
app/views/bots/_activity_feed.html.erb-- does not exist yet, to be created (correct) - [x]
app/views/activity_logs/_activity_log.html.erb-- does not exist yet, to be created (correct) - [x]
test/models/activity_log_test.rb-- EXISTS with 14 tests covering validations, scopes (for_bot, recent, successes, failures), associations, metadata defaults - [x]
test/channels/bot_activity_channel_test.rb-- does not exist yet, to be created (correct)
Previous Review Fix Verification
All four
[BODY]recommendations fromreview-1717-2026-07-03verified as correctly applied:- [x] AC #1 fields updated -- now lists
strategy_id,bot_name(not bot_type), correct action enum values,message(not rationale),metadata(jsonb). Nouser_idortimestamp. Matchesdb/schema.rbandactivity_log.rbmodel constants exactly. - [x] AC #6 scoping updated -- now says "scoped to
strategy_id(user-level scoping deferred until User model lands)". No user_id reference. - [x] AC #8 field name updated -- display list now says "message" not "rationale".
- [x] AC #9 reframed -- prefixed with "Pre-existing:" and reworded as "verify integration and ensure all bots write correctly".
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets in that repo. Single-repo scope.
Dependencies
- #26 (Bot Detail pages) -- validation column, merged.
app/views/bots/show.html.erbexists on disk. SATISFIED. - #23 (OrderService) -- validation column.
OrderServiceconfirmed to callActivityLog.create!inapp/services/order_service.rb. SATISFIED. - #27 (Pregame Stacker) -- validation column, merged. SATISFIED.
- #28 (Bulk Sweep) -- validation column, merged. SATISFIED.
- #29 (Edge Learner) -- in backlog (sprint:6). NOT blocking -- feed works with whatever bots exist.
- #48 (Hotwire conversion) -- validation column. Action Cable configured:
config/cable.ymluses solid_cable adapter,application.rbrequiresaction_cable/engine,application_cable/directory exists with channel.rb and connection.rb. SATISFIED.
Acceptance Criteria
- AC #1 (model fields) -- now matches actual schema. Verified against db/schema.rb and model ACTIONS/STATUSES constants.
- AC #2 (Kalshi market link) -- testable, straightforward
- AC #3 (feed partial on detail page) -- testable, show.html.erb exists to embed it
- AC #4 (per-bot filtering) -- testable,
for_botscope exists and tested - AC #5 (Turbo Streams real-time) -- testable, Action Cable + solid_cable fully configured
- AC #6 (channel scoped to strategy_id) -- correctly scoped, user_id deferred
- AC #7 (pagination) -- testable
- AC #8 (entry display fields) -- now uses correct field names (message, not rationale)
- AC #9 (pre-existing integration) -- correctly reframed as verification of existing OrderService integration
- AC #10 (reverse chronological) -- testable,
recentscope exists and tested
All criteria are accurate and agent-verifiable.
Blast Radius
OrderServicealready creates ActivityLog entries -- addingafter_createbroadcast will fire on every trade execution across all bots- BulkSweepJob processes many markets rapidly -- broadcasting per-entry could flood the cable. Constraints section mentions throttling but no specific mechanism prescribed (acceptable at 2pt scope -- agent can choose debounce/batch strategy)
- Action Cable uses solid_cable (database-backed pub/sub) -- performance under high-frequency broadcasting should be monitored
- No cross-user leakage concern currently since there is no multi-user model yet
Decomposition Assessment
7 file targets (3 already exist), 10 acceptance criteria (2 pre-existing, effective count ~8). 1 repo. Remaining work is 4 new files + wiring. Standard Rails patterns (channel, partials, Turbo Streams). 2 story points. No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-frontendfor component frontend (carried forward from previous review; non-blocking -- "frontend" is a broad architectural label, and the issue spec is self-contained and implementable without it).
No further
[BODY]or[LABEL]fixes needed. Issue is ready for implementation. -
Review: Watchdog — auto-buy when market crosses 85% threshold
review-1689-2026-07-03Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- "Feature (bot consumer -- Solid Queue job)"
- [x] Lineage -- Present, references Sprint 4 dependencies
- [x] Repo --
ldraney/prediction-assistant - [x] User Story -- Present (references AI-Powered Portfolio Builder)
- [x] Context -- Detailed, explains dual-trigger architecture
- [x] File Targets -- 4 files + tests listed
- [ ] Feature Flag -- Name only (
late_game_lock_enabled). Missing required fields: Type, Default, Visibility, Removal. Also, no feature flag infrastructure exists in the codebase. - [x] Acceptance Criteria -- 17 items (excessive, see Decomposition)
- [x] Test Expectations -- Present with unit, integration, and edge cases
- [x] Constraints -- Present
- [x] Checklist -- Present
- [x] Related -- Present
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading story
- [x] story note verified --
watchdog-tradingfound in project-prediction-assistant user-stories section - [ ] User story body mismatch -- Issue body references "AI-Powered Portfolio Builder" (
portfolio-builder) but label isstory:watchdog-trading. The label is correct (Late-Game Lock targets 85%+ win rate), but the issue body should reference the matching story. [BODY] - [x] arch:rails label -- Rails component
- [ ] arch note MISSING -- No
arch-railsnote found in pal-e-docs. [SCOPE] Create architecture note arch-rails for Rails component. - [x] Forgejo issue --
https://forgejo.tail5b443a.ts.net/ldraney/prediction-assistant/issues/4, open. Redirects from oldkalshi-assistantURL.
File Targets
- [ ]
app/jobs/late_game_lock_job.rb-- ISSUE: Issue says this should be on thelate_game_lockqueue, but existing architecture hasPriceUpdateJobandTimeUpdateJobas stubs on theeventsqueue waiting for Sprint 4 consumers (their comments say "Consumers (Sprint 4): Late-Game Lock, Edge Learner"). The Late-Game Lock should be called FROM these event jobs, not subscribe to its own queue. Queue architecture needs reconciliation. [BODY] - [ ]
app/services/late_game_lock_evaluator.rb-- New file, reasonable scope for dual-trigger logic. - [ ]
app/services/late_game_lock_exit_checker.rb-- ISSUE:PositionTracker(app/services/position_tracker.rb) already hasexit_candidatesandexit_signalmethods that evaluate stop_loss and take_profit thresholds. Creating a separateLateGameLockExitCheckerwould duplicate this logic. Issue should clarify whether to extend PositionTracker or replace its exit logic. [BODY] - [ ]
config/late_game_lock_sport_mappings.yml-- ISSUE:LateGameLockConfigmodel already validatestime_remaining_thresholdagainst a hardcoded list:%w[last_5_pct last_10_pct last_15_pct last_quarter]. But the issue specifies sport-specific mappings (NFL 4th quarter <5min, MLB 9th inning, etc.) which are a different concept than generic time percentages. The YAML config and the model validation need reconciliation. [BODY]
Repo Placement
OK. Issue specifies
ldraney/prediction-assistant, which matches the current repo name. The board item Forgejo URL still uses the oldkalshi-assistantname but redirects correctly.Dependencies
- #2 MarketScanner + event bus -- board item 1687, in validation column
- #3 Strategy STI schema -- board item 1688, in validation column
- OrderService -- board item 1710, in validation column
- PositionTracker -- board item 1711, in validation column
All 4 dependencies are in the validation column (not yet done). If validation surfaces issues in any dependency, this ticket's implementation may need to change. The dependencies themselves exist in the codebase and are functional:
MarketScannerJobemitstime_updateandprice_updateevents,OrderServicehandles trade execution,PositionTrackerhandles position monitoring including exit signals, andLateGameLockConfigSTI model is already implemented.Acceptance Criteria
17 acceptance criteria. All are individually testable. However:
- Missing AC for
late_game_lock_enabledfeature flag behavior (what happens when disabled?) - Missing AC for activity logging (OrderService logs trades, but bot-level event processing logs are not specified)
- Missing AC for error handling when dependencies (OrderService, PositionTracker) are unavailable
- AC #1 says "on the
late_game_lockqueue" which conflicts with the stub-based event dispatch pattern in PriceUpdateJob/TimeUpdateJob - AC #11-14 (exit checker) overlap with PositionTracker's existing exit_candidates/exit_signal methods
Blast Radius
- PriceUpdateJob (app/jobs/price_update_job.rb) -- Currently a stub. Implementing Late-Game Lock requires adding consumer dispatch logic here. Edge Learner (Sprint 6) will also consume from this job. Changes must be additive.
- TimeUpdateJob (app/jobs/time_update_job.rb) -- Currently a stub. Same concern as PriceUpdateJob.
- PositionTracker (app/services/position_tracker.rb) -- Already has exit_candidates and exit_signal logic. Creating a separate LateGameLockExitChecker risks duplication or inconsistency.
- LateGameLockConfig (app/models/late_game_lock_config.rb) -- Already validates time_remaining_threshold against hardcoded values. YAML sport mappings would need to align with or replace this validation.
- Other bots (PregameStacker, BulkSweep) are not affected -- they use different event paths.
Decomposition Assessment
NEEDS DECOMPOSITION -- 17 ACs across 4+ new files + test files + modifications to 2 existing stub jobs. Estimated agent work exceeds 5 minutes significantly.
Recommended decomposition into 3 sub-tickets:
- Event dispatch wiring + dual-trigger evaluator (ACs 1-6, 9): Wire PriceUpdateJob and TimeUpdateJob stubs to dispatch to Late-Game Lock. Create LateGameLockEvaluator with sport-specific time mapping and dual-trigger logic. ~5 pts.
- Entry logic + OrderService integration (ACs 7-8, 10, 16-17): Flat bet sizing, config reading, OrderService calls, idempotency. ~3 pts.
- Exit management + PositionTracker integration (ACs 11-15): Reconcile with existing PositionTracker exit logic. Stop-loss, take-profit, auto_sell_vs_hold. ~3 pts.
Recommendation
[LABEL]Update board item title from "Watchdog -- auto-buy when market crosses 85% threshold" to "Late-Game Lock bot -- dual-trigger consumer (price + time)" -- the issue explicitly says "This is NOT the watchdog/scanner."[BODY]Fix queue architecture: Replace "late_game_lock queue" with dispatch from PriceUpdateJob/TimeUpdateJob stubs. Both stubs already have comments saying "Consumers (Sprint 4): Late-Game Lock, Edge Learner".[BODY]Reconcile exit checker with PositionTracker: Either extend PositionTracker.exit_candidates (which already handles stop_loss/take_profit) or document why a separate LateGameLockExitChecker is needed.[BODY]Reconcile sport mappings YAML with LateGameLockConfig validation: The model validates time_remaining_threshold against generic presets (last_5_pct, last_10_pct, etc.) but the issue specifies sport-specific mappings (NFL 4th quarter <5min, MLB 9th inning, etc.). These are different concepts.[BODY]Complete Feature Flag section with Type, Default, Visibility, and Removal fields per template-issue-feature. Note: no feature flag infrastructure exists in the codebase yet.[BODY]Fix user story reference to match label: body says "AI-Powered Portfolio Builder" but label is story:watchdog-trading ("Watchdog Trading").[SCOPE]Create architecture note arch-rails for the Rails component.[DECOMPOSE]17 ACs across 4+ new files + 2 stub modifications exceeds the 5-minute rule. Route to skill-decompose-ticket with the 3-way split recommended above.
-
Review: Registration form — Kalshi API credential capture and validation
review-1729-2026-07-03Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — present
- [x] Repo — ldraney/prediction-assistant
- [x] User Story — present
- [x] Context — present
- [x] File Targets — present (but inaccurate, see below)
- [x] Feature Flag — "None" (acceptable for this ticket)
- [x] Acceptance Criteria — 6 items present
- [x] Test Expectations — present
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
Extra section:
### Scope(not in template, harmless).Traceability
- [x] story:landing-page label — Landing Page & Registration
- [x] story note verified —
story-prediction-assistant-landing-pageexists in pal-e-docs and in project-prediction-assistant user-stories section - [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] Create architecture note
arch-rails - [x] Forgejo issue — #58, open
File Targets
- [ ]
app/models/user.rb— ISSUE: file does not exist. Issue says "add encrypted credential fields" implying modification, butuser.rband theuserstable need to be created from scratch. No User model or users table exists in the current schema. - [ ]
db/migrate/— ISSUE: description says "add credential columns" but there is no users table in the schema. Should say "create users table with credential columns." - [x]
app/controllers/registrations_controller.rb— verified: marked as new, correctly does not exist yet - [x]
app/views/registrations/new.html.erb— verified: marked as new, correctly does not exist yet - [x]
config/routes.rb— verified: exists, currently has Keycloak auth routes and bot resources
Missing file targets:
- No mailer listed — but Scope item 5 says "Send welcome email with generated password." Needs
app/mailers/target. - No Keycloak admin API integration — but Scope item 4 says "Create Keycloak user account on successful validation." Needs a service or initializer for Keycloak Admin REST API calls (and likely
keycloak-admingem in Gemfile). - No encryption gem specified — Gemfile currently has no encryption library (lockbox, attr_encrypted, etc.). Issue should specify whether to use Rails 8 encrypted attributes, lockbox, or another approach, and add the gem to Gemfile.
- No credential management UI — but AC #6 says "Revoking API access (deleting credentials) is possible." Needs controller action and possibly a view for credential deletion.
Repo Placement
OK — all file targets are in ldraney/prediction-assistant. Keycloak admin API calls are made from the Rails app, so no cross-repo concern, though Keycloak realm configuration (client permissions for admin API) may need a separate infra ticket if not already set up.
Dependencies
- Explicitly depends on #57 (Keycloak login flow) — board item #1728, currently in validation column. Implemented but not yet validated. Soft blocker.
- No other blocking dependencies found on the board.
watchdog_configstable already has auser_idcolumn (schema.rb line 98) but with no foreign key to a users table — this ticket will need to address that relationship.
Acceptance Criteria
- AC #1–#5 are testable and clear.
- AC #6 "Revoking API access (deleting credentials) is possible" — introduces credential management functionality that is not mentioned in the Scope or File Targets sections. Should either be removed (separate ticket) or explicitly scoped with file targets.
- Missing AC for Keycloak user creation (Scope item 4) and welcome email delivery (Scope item 5).
Blast Radius
Per-user credential transition:
KalshiClient(app/services/kalshi_client.rb) currently reads credentials fromRails.application.config.kalshi(global singleton). Moving to per-user credentials will require changes in how KalshiClient is instantiated across at least 4 files:app/services/order_service.rbapp/jobs/market_scanner_job.rbapp/services/pregame_stacker_bot.rbapp/jobs/bulk_sweep_job.rb
None of these are in the file targets. The issue should clarify whether this ticket wires per-user credentials into the service layer or if that integration is a separate ticket.
Decomposition Assessment
5 listed file targets (really 8+ when missing targets are added). 6 acceptance criteria. 6 scope items spanning: User model creation, migration, controller, view, Keycloak admin API integration, email sending, encryption setup, and credential validation. Estimated agent work exceeds 5 minutes. However, if scope is tightened to just credential capture and storage (removing Keycloak user creation, email, and revocation), it could fit. Borderline — tighten scope or decompose.
Recommendations
[BODY]Fix file target:app/models/user.rbshould say "(new — create User model with encrypted credential fields)" since the file and users table do not exist[BODY]Fix migration description: "create users table with encrypted credential columns" not "add credential columns"[BODY]Add missing file target: mailer for welcome email (Scope item 5)[BODY]Add missing file target: Keycloak admin API service for programmatic user creation (Scope item 4)[BODY]Specify encryption approach and add gem to Gemfile if needed (lockbox, attr_encrypted, or Rails encrypted attributes)[BODY]Either remove AC #6 (credential revocation) to a separate ticket, or add file targets for credential management controller/view[BODY]Clarify whether this ticket wires per-user credentials into KalshiClient/OrderService or if that is a separate integration ticket (blast radius: 4+ service/job files not listed)[SCOPE]Create architecture notearch-railsfor component rails
-
Review: Per-bot live activity feed -- Turbo Streams
review-1717-2026-07-03Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sprint 4, depends on #26 and bots running
- [x] Repo -- ldraney/prediction-assistant
- [x] User Story -- Bot Marketplace
- [x] Context -- detailed background
- [x] File Targets -- 7 files listed
- [x] Feature Flag -- None (integral to UI)
- [x] Acceptance Criteria -- 10 criteria
- [x] Test Expectations -- listed
- [x] Constraints -- listed
- [x] Checklist -- 11 items
- [x] Related -- dependencies listed
All required sections present per
template-issue-feature.Traceability
- [x] story:bot-marketplace label -- Bot Marketplace user story
- [x] story note verified -- found in project-prediction-assistant user-stories section
- [x] arch:frontend label -- frontend component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-frontend for component frontend
- [x] Forgejo issue -- #30, open
File Targets
- [x]
app/models/activity_log.rb-- EXISTS but schema diverges from AC (see Recommendations) - [x]
db/migrate/20260703200001_create_activity_logs.rb-- EXISTS, matches actual model - [ ]
app/channels/bot_activity_channel.rb-- does not exist yet, to be created - [ ]
app/views/bots/_activity_feed.html.erb-- does not exist yet, to be created - [ ]
app/views/activity_logs/_activity_log.html.erb-- does not exist yet, to be created - [x]
test/models/activity_log_test.rb-- EXISTS with full validation/scope coverage - [ ]
test/channels/bot_activity_channel_test.rb-- does not exist yet, to be created
Critical mismatch: AC #1 specifies fields that do not match the existing
ActivityLogmodel:- AC says
user_id-- no User model exists in the app, no user_id on ActivityLog or Strategy - AC says
bot_type-- actual field isbot_name - AC says action values
(order_placed, fill_received, position_opened, exit_triggered, error)-- actual values areplace_order, cancel_order, fill, partial_fill, error, dry_run, bulk_sweep - AC says
rationale(text) -- actual fields aremessage(text) +metadata(jsonb) - AC says
timestamp-- actual field iscreated_at(standard Rails timestamps)
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, all file targets in that repo. Single-repo scope.
Dependencies
- #26 (Bot Detail pages) -- in validation column, merged. Show page exists at
app/views/bots/show.html.erb. SATISFIED. - #23 (OrderService) -- in validation column. Already creates ActivityLog entries via
ActivityLog.create!. SATISFIED. - #27 (Pregame Stacker) -- in validation column, merged. SATISFIED.
- #28 (Bulk Sweep) -- in validation column, merged. SATISFIED.
- #29 (Edge Learner) -- in backlog (sprint:6). NOT blocking -- feed works with whatever bots exist.
- #48 (Hotwire conversion) -- in validation column. Turbo/Stimulus/Action Cable are available. SATISFIED.
- Undocumented: User authentication model -- AC #6 says scope by user_id but no User model exists. Keycloak OIDC is integrated (#57, closed) but no Rails User model has been created. Action Cable Connection has no auth.
Acceptance Criteria
- AC #1 (model fields) -- STALE, model already exists with different schema. Needs update.
- AC #2 (Kalshi market link) -- testable, straightforward
- AC #3 (feed partial on detail page) -- testable, show.html.erb exists to embed it
- AC #4 (per-bot filtering) -- testable,
for_botscope exists - AC #5 (Turbo Streams real-time) -- testable, Action Cable + solid_cable configured
- AC #6 (channel scoped to user_id + strategy_id) -- PROBLEMATIC: no User model, no user_id. Must scope by strategy_id only for now.
- AC #7 (pagination) -- testable
- AC #8 (entry display: rationale) -- STALE: field is
message, notrationale - AC #9 (entries created by bots/OrderService) -- ALREADY MET: OrderService already creates ActivityLog entries
- AC #10 (reverse chronological) -- testable,
recentscope exists
Blast Radius
OrderServicealready creates ActivityLog entries -- addingafter_createbroadcast will fire on every trade execution across all bots- BulkSweepJob processes many markets rapidly -- broadcasting per-entry could flood the cable. Constraints section mentions throttling but no specific mechanism is prescribed
- Action Cable uses
solid_cable(database-backed pub/sub, not Redis) -- performance under high-frequency broadcasting should be monitored - No cross-user leakage concern currently since there is no multi-user model yet
Decomposition Assessment
7 file targets (3 already exist), 10 acceptance criteria (exceeds 5 threshold), 1 repo. Remaining work is 4 new files + 3 modifications. The work is standard Rails patterns (channel, partials, Turbo Streams wiring) that are boilerplate-heavy but not complex. At 2 story points the scope is reasonable for a single agent pass once the AC is corrected, provided AC #9 is marked as pre-existing. No decomposition needed after AC cleanup -- effective AC count drops to 7-8, and the remaining file creation is templated.
Recommendation
[BODY]Update AC #1 field list to match existing ActivityLog schema:strategy_id,bot_name(not bot_type),action(place_order, cancel_order, fill, partial_fill, error, dry_run, bulk_sweep),ticker,side,quantity,price,status(success, failure, dry_run, rejected),message(not rationale),metadata(jsonb). Removeuser_idandtimestamp.[BODY]Update AC #6: removeuser_idscoping -- scope BotActivityChannel tostrategy_idonly. User scoping is a future concern when User model lands.[BODY]Update AC #8: replace "rationale" with "message" to match actual schema.[BODY]Mark AC #9 as pre-existing (OrderService already writes to ActivityLog) or reframe as "verify existing integration".[SCOPE]Create architecture notearch-frontendfor component frontend.
-
Review: Edge Learner bot -- multi-event consumer with learning
review-1716-2026-07-03Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All 12 required sections present per template-issue-feature.
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- story-prediction-assistant-portfolio-builder exists in pal-e-docs (active, user-story type)
- [x] arch:rails label -- Rails component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-rails for component rails. Search for "arch-rails" returned no results.
- [x] Forgejo issue -- ldraney/prediction-assistant#29, state: open
File Targets
- [x]
app/jobs/edge_learner_job.rb-- new file, pattern consistent with existing jobs (bulk_sweep_job.rb, pregame_threshold_job.rb) - [x]
app/models/price_pattern.rb-- new file, pattern consistent with existing models - [x]
app/services/group_builder.rb-- new file, pattern consistent with existing services - [x]
test/jobs/edge_learner_job_test.rb-- new file - [x]
test/models/price_pattern_test.rb-- new file - [x]
test/services/group_builder_test.rb-- new file - [ ] MISSING:
db/migrate/YYYYMMDDHHMMSS_create_price_patterns.rb-- PricePattern model requires a database table but no migration is listed. Schema needs columns for sport, game_situation, entry_price, exit_price, hold_duration, confidence, etc. - [ ] MISSING:
app/jobs/price_update_job.rb-- currently a stub ("bot consumers implement in Sprint 4"). Needs modification to fan out to EdgeLearnerJob. - [ ] MISSING:
app/jobs/time_update_job.rb-- currently a stub ("bot consumers implement in Sprint 4"). Needs modification to fan out to EdgeLearnerJob. - [ ] MISSING:
app/jobs/sweep_eligible_job.rb-- has comment "Edge Learner will be added in Sprint 4 (#29)". Needs modification to fan out to EdgeLearnerJob alongside BulkSweepJob.
Repo Placement
OK -- issue filed on ldraney/prediction-assistant, ### Repo field says ldraney/prediction-assistant. Single repo, no cross-repo concerns.
Dependencies
- #2 (MarketScanner emitting events) -- board item 1687, validation column. Code exists, not yet validated.
- #23 (OrderService) -- board item 1710, validation column. Code exists at app/services/order_service.rb.
- #24 (PositionTracker) -- board item 1711, validation column. Code exists at app/services/position_tracker.rb.
- #3 (EdgeLearnerConfig STI) -- board item 1688, validation column. Code exists at app/models/edge_learner_config.rb.
All 4 dependencies are correctly documented. All are in validation column (code exists, awaiting final validation). Not blocking implementation.
Acceptance Criteria
15 acceptance criteria. All are individually testable by an agent (group counts are deterministic, risk levels have clear behavior, OrderService usage is greppable). However, 15 AC is 3x the decomposition threshold (5). The criteria span 4 independent sub-systems (Group Builder, Portfolio Monitor, Predictive Entry, Risk-Adjusted Closer) plus infrastructure (fan-out wiring, PricePattern model/migration).
Blast Radius
- EdgeLearnerConfig.max_group_size validation bug: The existing model (from #3) validates max_group_size as a positive_integer, but both the issue spec and docs/bots/edge-learner.md define it as an enum ("pairs", "triples", "uncapped"). This mismatch will cause validation failures when the job tries to use string values. Needs fix in edge_learner_config.rb line 25.
- Fan-out jobs: 3 existing fan-out jobs (price_update_job.rb, time_update_job.rb, sweep_eligible_job.rb) need modification to dispatch to EdgeLearnerJob. These are not listed as file targets.
- No downstream consumers affected: Edge Learner is a leaf consumer -- it reads events and places orders, no other bots depend on it.
- Lineage inconsistency: Issue body says "Sprint 5" but board item label says sprint:6.
Decomposition Assessment
NEEDS DECOMPOSITION -- route to skill-decompose-ticket.
- 6 new file targets + 3 missing modification targets + 1 missing migration = 10 files total
- 15 acceptance criteria (3x the 5-AC threshold)
- 4 independent sub-systems (Group Builder, Portfolio Monitor, Predictive Entry, Risk-Adjusted Closer)
- Estimated agent work: 20-30 minutes for a single pass (well over 5-minute rule)
Suggested decomposition: split into sub-tickets per sub-system (Group Builder, Portfolio Monitor, Predictive Entry + PricePattern model, Risk-Adjusted Closer) plus a wiring ticket for fan-out job updates and EdgeLearnerJob shell.
Recommendation
[BODY]Add migration file target:db/migrate/YYYYMMDDHHMMSS_create_price_patterns.rb-- PricePattern model needs a database table[BODY]Add fan-out job modification targets:app/jobs/price_update_job.rb,app/jobs/time_update_job.rb,app/jobs/sweep_eligible_job.rb[BODY]Fix Lineage: says "Sprint 5" but board item is labeled sprint:6[BODY]Note pre-existing bug: EdgeLearnerConfig validates max_group_size as positive_integer but spec requires enum ("pairs", "triples", "uncapped") -- fix needed in edge_learner_config.rb[SCOPE]Create architecture note arch-rails for component rails[DECOMPOSE]15 AC across 4 sub-systems + infrastructure, estimated 20-30 min agent work. Route to skill-decompose-ticket.
-
Review: Mobile app — API key connection and strategy dashboard
review-1691-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — present ("Depends on all backend tickets (#1-#5)")
- [x] Repo — present (
ldraney/kalshi-assistant) - [x] User Story — full As a / I want / So that format
- [x] Context — good description with user flow reference
- [ ] File Targets — present but "TBD" — not actionable for an agent
- [x] Feature Flag — "none"
- [x] Acceptance Criteria — 6 criteria present
- [ ] Test Expectations — present but "TBD based on framework choice" — not actionable
- [x] Constraints — 3 constraints present
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:app-experience — App Experience — verified in project-kalshi-assistant user-stories section
- [x] story:credential-onboarding — Credential Onboarding — verified in project-kalshi-assistant user-stories section
- [ ] arch:frontend — arch note MISSING — [SCOPE] Create architecture note arch-frontend for component frontend
- [ ] arch:auth — arch note MISSING — [SCOPE] Create architecture note arch-auth for component auth
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/kalshi-assistant/issues/6, open
File Targets
- [ ] File Targets are "TBD — depends on frontend framework decision (React Native / Flutter / Rails Turbo Native)" — no concrete paths to verify. The codebase currently contains only docs (no application code). An agent cannot act on this ticket until file targets are specified.
Repo Placement
Issue is filed on
ldraney/kalshi-assistantand the Repo section matches. However, a mobile app (React Native or Flutter) may warrant a separate repo. This decision is blocked on the framework choice. If the frontend lives in a separate repo, the Forgejo issue should be refiled there.Dependencies
- Documented: #1-#5 (all backend tickets). All are in backlog. Sprint:4 sequencing is correct — this ticket runs after sprint:1-3 backend work.
- Undocumented: #10 (Keycloak realm, client, users, and login theme — board item #1693, sprint:1, arch:keycloak,arch:auth) is a clear dependency for the auth flow. The mobile app needs Keycloak for user login and session management, but #10 is not listed in the Lineage section.
- All dependencies are in backlog — none are blocking this ticket from scoping, but all must be completed before implementation.
Acceptance Criteria
6 criteria spanning multiple feature areas:
- Auth: API key + private key input screen with validation; User can revoke API access
- Strategy: Strategy selection (Watchdog, Option D); Budget configuration per strategy
- Dashboard: Live dashboard: active positions, unrealized P&L
- History: Trade history log
Each criterion is testable in principle, but "Live dashboard: active positions, unrealized P&L" is vague — it should specify what data source, refresh interval, and failure states. The criteria span at least 4 distinct screens/features, making this too broad for a single agent pass.
Blast Radius
Limited. No existing frontend code to break. The codebase contains only documentation. This ticket introduces a new surface area. Downstream effects: the auth flow touches Keycloak (ticket #10) and all API endpoints from backend tickets #1-#5.
Decomposition Assessment
NEEDS DECOMPOSITION — route to skill-decompose-ticket
- 8 points (largest ticket on the board)
- 6 acceptance criteria spanning 4+ feature areas (auth, strategy config, live dashboard, trade history)
- File targets TBD — likely many files for a full mobile app
- Framework decision is an unresolved prerequisite — should be a separate Spike ticket
- Estimated agent work: well over 5 minutes (full mobile app with auth, multiple screens, real-time data)
Recommendation
[SCOPE]Create architecture notearch-frontendfor component frontend[SCOPE]Create architecture notearch-authfor component auth[SCOPE]Framework decision (React Native / Flutter / Rails Turbo Native) should be resolved first — consider creating a Spike ticket to evaluate options and make this decision before decomposing[BODY]File Targets are "TBD" — need concrete paths after framework decision is made[BODY]Test Expectations are "TBD" — need concrete test commands after framework decision[BODY]Add Keycloak ticket (#10) to Lineage as a dependency: "Depends on #10 (Keycloak) and all backend tickets (#1-#5)"[DECOMPOSE]8 points, 6 AC across 4 feature areas (auth, strategy, dashboard, history) — route to skill-decompose-ticket. Suggested split: (1) Spike: framework decision, (2) API credential input + validation, (3) Strategy selection + budget config, (4) Live dashboard, (5) Trade history, (6) Access revocation
-
Review: Kustomize deployment overlays -- prod and dev
review-1695-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag -- "none"
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All required sections present per template-issue-feature.
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- found in project-kalshi-assistant user-stories section, links to story-kalshi-assistant-platform-setup
- [x] arch:kustomize label -- Kustomize overlays
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-kustomize
- [x] arch:k8s-deploy label -- Kubernetes deployment
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-k8s-deploy
- [x] Forgejo issue -- ldraney/kalshi-assistant#9, open
File Targets
- [x] overlays/kalshi-assistant/prod/kustomization.yaml -- to create; matches landscaping-assistant pattern
- [x] overlays/kalshi-assistant/prod/deployment-patch.yaml -- to create; matches landscaping-assistant pattern
- [x] overlays/kalshi-assistant/prod/secrets.enc.yaml -- to create; matches landscaping-assistant pattern
- [x] overlays/kalshi-assistant/dev/kustomization.yaml -- to create
- [ ] overlays/kalshi-assistant/dev/deployment.yaml -- to create; ISSUE: dev overlay is incomplete
Dev overlay gap: The issue says "Following the landscaping-assistant model" but the dev file targets list only 2 files (kustomization.yaml, deployment.yaml). The landscaping-assistant dev overlay has 6 files: configmap.yaml, deployment.yaml, ingress.yaml, kustomization.yaml, namespace.yaml, service.yaml. The missing files (configmap, ingress, namespace, service) are required for a functional dev overlay. Without them,
kustomize buildfor dev will fail.Prod kustomization.yaml gap: The landscaping-assistant prod kustomization.yaml contains extensive inline patches for renaming Deployment, Service, and ServiceMonitor resources from the generic "app" name to the project name. These rename patches are not mentioned in the issue body or file targets. The implementing agent would need to infer them from the reference pattern.
Repo Placement
Mismatch: The issue
### Repofield correctly identifiesldraney/pal-e-deploymentsas the target repo, but the Forgejo issue is filed onldraney/kalshi-assistant. The implementing agent's PR must target pal-e-deployments, not kalshi-assistant. This cross-repo tracking is acceptable if intentional (tracking deployment work under the project), but the agent must be explicitly directed to open the PR on the correct repo.Dependencies
Undocumented dependencies found on the board:
- #1694 "Service onboarding -- namespace, Harbor, ArgoCD, Tailscale funnel" (sprint:1, backlog) -- prerequisite. Kustomize overlays need the namespace and ArgoCD application to exist. This is sprint:1 work that must complete before sprint:2 overlays.
- #1686 "Rails app scaffold with Kalshi API client" (sprint:1, backlog) -- prerequisite. The container image must exist in Harbor before the deployment can reference it.
- #1696 "CI/CD pipeline -- Woodpecker config" (sprint:2, backlog) -- sibling. CI pipeline pushes images that the overlay references, but overlays can be created first with placeholder tags.
None of these dependencies are documented in the issue scope.
Acceptance Criteria
6 acceptance criteria, all verifiable via
kustomize buildoutput inspection:- [x] AC1: kustomize build renders valid manifests -- directly testable
- [x] AC2: SOPS encryption -- testable (encryption verifiable; cluster decryption requires live cluster)
- [x] AC3: Init container runs db:prepare -- verifiable in rendered YAML
- [x] AC4: Probes on /up:3000 -- verifiable in rendered YAML
- [x] AC5: Resource limits -- verifiable in rendered YAML
- [x] AC6: Security context -- verifiable in rendered YAML
Missing AC: No acceptance criterion for the dev overlay. Test Expectations only mention
kustomize buildfor both overlays but AC only describes prod characteristics. Dev overlay should have its own AC (nginx proxy to dev machine IP, correct namespace kalshi-dev).Blast Radius
Low risk. 15+ services already use this overlay pattern in pal-e-deployments. The work is additive (new directory) and does not modify any existing overlays or bases. No downstream consumers are affected.
Decomposition Assessment
5 file targets in 1 repo (below the >3 files across >2 repos threshold). 6 AC (marginally above >5 threshold). However, all AC describe configuration aspects of a single deployment-patch.yaml file. The work is highly formulaic -- copying the landscaping-assistant pattern and adjusting names, secrets, and ports. Estimated agent time: 3-4 minutes. No decomposition needed.
Recommendation
- [BODY] Add missing dev overlay file targets: configmap.yaml, ingress.yaml, namespace.yaml, service.yaml (per landscaping-assistant reference pattern)
- [BODY] Document prod kustomization.yaml inline rename patches (Deployment, Service, ServiceMonitor) in File Targets or Context
- [BODY] Add dependency documentation: blocked by #1694 (service onboarding) and #1686 (Rails app scaffold)
- [BODY] Add dev-specific acceptance criteria (nginx proxy, kalshi-dev namespace)
- [SCOPE] Create architecture note arch-kustomize for component kustomize
- [SCOPE] Create architecture note arch-k8s-deploy for component k8s-deploy
-
Review: Service onboarding -- namespace, Harbor, ArgoCD, Tailscale funnel
review-1694-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone
- [x] Repo -- ldraney/pal-e-services
- [x] User Story -- present, well-formed
- [x] Context -- present, describes foundational nature
- [x] File Targets -- present, with both modify and do-not-touch sections
- [x] Feature Flag -- none (appropriate for infra ticket)
- [x] Acceptance Criteria -- 5 items
- [x] Test Expectations -- present with run command
- [x] Constraints -- present, references landscaping-assistant pattern
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- story-kalshi-assistant-platform-setup exists in pal-e-docs, listed in project-kalshi-assistant user-stories section
- [x] arch:iac label -- Infrastructure as Code
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-iac for component iac
- [x] arch:k8s-deploy label -- Kubernetes Deployment
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-k8s-deploy for component k8s-deploy
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/kalshi-assistant/issues/7, open
File Targets
- [x]
terraform/k3s.tfvars-- verified: file exists (symlink to ~/secrets/pal-e-services/k3s.tfvars),servicesmap starts at line 193, landscaping-assistant pattern confirmed at lines 203-210 with matching structure (forgejo_repo, image_repo, port 3000, funnel true, source_repo, source_path). No existing kalshi-assistant entry -- clean for addition.
Repo Placement
Issue filed on
ldraney/kalshi-assistantbut### Reposection explicitly declares work is inldraney/pal-e-services. This is an acceptable pattern: project-specific infrastructure tickets are filed on the project repo, with the shared infrastructure repo declared as the target. Work touches only one repo (pal-e-services). No multi-repo issue needed.Dependencies
This ticket is correctly identified as foundational in Context: "nothing else deploys until this is done." Board analysis confirms downstream dependencies:
- #1686 Rails app scaffold (sprint:1) -- blocked by this ticket (needs namespace)
- #1692 DNS + reverse proxy (sprint:1) -- depends on namespace/funnel existing
- #1693 Keycloak realm (sprint:1) -- depends on namespace existing
- #1695 Kustomize overlays (sprint:2) -- depends on ArgoCD app existing
- #1696 CI/CD pipeline (sprint:2) -- depends on Harbor project existing
Dependencies are documented implicitly in Context but not explicitly enumerated. Acceptable for a clearly foundational ticket.
Acceptance Criteria
All 5 criteria are verifiable by an agent:
tofu plan-- exits 0 with expected resources (testable)tofu apply-- succeeds (testable, creates real resources)- Namespace check --
kubectl get ns kalshi-assistant(testable) - Harbor project check -- Harbor API or UI (testable)
- ArgoCD app check --
argocd app get kalshi-assistant(testable)
Test Expectations section includes a run command:
cd ~/pal-e-services && tofu plan -var-file=terraform/k3s.tfvars. Good.Blast Radius
Low. Adds a new entry to a shared tfvars file without modifying existing entries. The pattern is well-established with multiple existing service entries (landscaping-assistant, believers-elite, mdview, gcal-scheduler, etc.). No downstream consumers affected by addition.
Decomposition Assessment
No decomposition needed:
- 1 file target in 1 repo
- 5 acceptance criteria (at threshold, not over)
- Estimated agent work: under 2 minutes (single block addition following a clear pattern)
Recommendation
- [SCOPE] Create architecture note
arch-iacdocumenting the IaC patterns (Terraform/OpenTofu modules, tfvars structure, service map convention) - [SCOPE] Create architecture note
arch-k8s-deploydocumenting the k8s deployment pipeline (ArgoCD, Image Updater, namespace provisioning, Tailscale funnel)
These are platform-level architecture notes that would serve all projects using the pal-e-platform infrastructure, not just kalshi-assistant. The ticket scope itself is solid -- clear target, verified pattern, testable criteria. The missing arch notes are a documentation gap, not a scope problem.
-
Review: Option D sizing engine -- optimized stack with hedging
review-1690-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- present (depends on #3)
- [x] Repo -- present
- [x] User Story -- present
- [x] Context -- present, references docs/strategy/sizing-models.md
- [x] File Targets -- present (2 files to create)
- [x] Feature Flag -- "none"
- [x] Acceptance Criteria -- present (6 items)
- [x] Test Expectations -- present (3 tests + run command)
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- story-kalshi-assistant-portfolio-builder exists in pal-e-docs, listed in project-kalshi-assistant user-stories section
- [x] arch:app label -- application component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-app for the Rails application component
- [x] Forgejo issue -- ldraney/kalshi-assistant#5, open
File Targets
- [ ] app/services/sizing_engine.rb -- ISSUE: file to be created, but the app/ directory does not exist. The repo is currently docs-only. Rails scaffold (issue #1) must be completed first to establish the app/services/ directory structure.
- [ ] app/services/scenario_analyzer.rb -- ISSUE: same as above -- depends on Rails scaffold existing.
- [x] docs/strategy/sizing-models.md -- verified: contains Option D math (83/17 split, -$5.77 worst case, all scenario tables). Context reference is accurate.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, work targets ldraney/kalshi-assistant. Single repo, no cross-repo concerns.
Dependencies
- Declared: #3 (Strategy engine -- database schema, board item #1688, sprint:2, backlog). Correct -- the sizing engine needs the strategy/trade schema.
- Undocumented: #1 (Rails app scaffold, board item #1686, sprint:1, backlog). The app/services/ path assumes a Rails app structure that does not yet exist. This is a hard blocker -- without the Rails framework, there is no directory to create services in and no test runner to execute rails test.
- Both dependencies are in the backlog column. This ticket (sprint:3) cannot start until sprint:1 (#1) and sprint:2 (#3) complete.
Acceptance Criteria
6 acceptance criteria, all concrete and agent-verifiable:
- Input/output contracts are well-defined (picks array, budget, contract allocations)
- Optimization target is clear (brute-force over 50-99% YES/NO ratio)
- Scenario table output is specified (2^N outcomes with probability and P&L)
- Scale constraint is bounded (1-10 picks, max 1024 scenarios)
- Test expectations reference concrete values from docs (83/17 ratio, -$5.77 worst case) which are verified in docs/strategy/sizing-models.md
- Run command (rails test) is standard for Rails
Criteria are testable. However, count of 6 AC exceeds the >5 decomposition threshold.
Blast Radius
Low. This creates new service classes in a greenfield codebase. No existing code patterns to search for similar issues. No downstream consumers at this stage. The sizing engine is self-contained computation with no external integrations.
Decomposition Assessment
- File targets: 2 files in 1 repo -- OK (below >3 across >2 repos threshold)
- Acceptance criteria: 6 -- exceeds >5 threshold
- Estimated agent time: under 5 minutes -- the math is fully documented in sizing-models.md, and the two services are tightly coupled (scenario_analyzer feeds sizing_engine)
One of three decomposition triggers fires (6 AC > 5). However, the work is tightly coupled -- SizingEngine and ScenarioAnalyzer form a single computation pipeline. Splitting them into separate tickets would create artificial boundaries and add coordination overhead. The 6 AC describes aspects of a single algorithm, not independent features. Recommend the author either consolidate to 5 AC (e.g., merge "returns optimal ratio" into the output AC) or accept the borderline count given the tight coupling.
Recommendation
- [BODY] Add dependency on #1 (Rails app scaffold) to the Lineage section. Current text mentions only #3 (schema), but the app/services/ path requires the Rails framework to exist. Suggested: "Depends on ldraney/kalshi-assistant #1 (scaffold) and #3 (schema)."
- [SCOPE] Create architecture note arch-app for the Rails application component. The arch:app label on this and other board items has no backing architecture note in pal-e-docs.
- [BODY] Consider consolidating AC from 6 to 5 by merging "Returns optimal ratio and expected value" into "Output: contracts to buy for each YES and NO position" (both describe output shape). This avoids the >5 decomposition trigger. Alternatively, accept the 6 AC given the tight coupling of the work.
-
Review: Watchdog -- auto-buy when market crosses 85% threshold
review-1689-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
Issue type: Feature (template-issue-feature)
- [x] Type -- "Feature"
- [x] Lineage -- documents deps on #2 (scanner) and #3 (schema)
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- present, well-formed
- [x] Context -- references watchdog-strategy.md, API endpoint verified
- [x] File Targets -- 3 CREATE targets listed
- [x] Feature Flag -- watchdog_live_trading, global, disabled by default
- [x] Acceptance Criteria -- 6 criteria listed
- [x] Test Expectations -- unit tests + run command
- [x] Constraints -- dry-run default, logging, error handling
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:watchdog-trading label -- verified in project-kalshi-assistant user-stories section
- [x] story note verified -- "Watchdog Trading" entry exists with success metric "85%+ win rate, $0.10-$0.15 avg profit per contract"
- [ ] arch:app note MISSING -- [SCOPE] No arch-app note exists in pal-e-docs. Project page references arch-domain-kalshi-assistant, arch-dataflow-kalshi-assistant, arch-deployment-kalshi-assistant instead. Label may need realignment.
- [ ] arch:api note MISSING -- [SCOPE] No arch-api note exists in pal-e-docs. Same mismatch with project page architecture naming.
- [x] Forgejo issue -- ldraney/kalshi-assistant#4, state: open
File Targets
- [ ] app/services/watchdog_service.rb -- ISSUE: app/ directory does not exist yet. Requires Rails scaffold (issue #1) to be completed first. Correctly marked as CREATE target.
- [ ] app/jobs/watchdog_job.rb -- ISSUE: Same dependency on #1 for app/ directory to exist.
- [ ] app/services/order_service.rb -- ISSUE: Same dependency. Also note: this is a shared service that Option D sizing (#5) will likely also need.
The referenced docs/strategy/watchdog-strategy.md DOES exist and confirms the strategy description. API endpoint POST /portfolio/events/orders with side: bid confirmed in openapi.yaml (line 1143). The strategy doc uses the full path /trade-api/v2/portfolio/events/orders.
Repo Placement
OK -- issue filed on ldraney/kalshi-assistant, all file targets are in the same repo. Single-repo ticket.
Dependencies
- Documented: #2 Market scanner (sprint:2, backlog), #3 Strategy engine schema (sprint:2, backlog)
- Undocumented: #1 Rails app scaffold (sprint:1, backlog) -- the app/ directory structure comes from the scaffold. This ticket cannot be implemented without #1.
- Sprint ordering: Correct -- this is sprint:3, dependencies are sprint:1 and sprint:2
- Board state: All 12 items are in backlog. No items are in_progress or blocking.
- Downstream: #5 Option D sizing (sprint:3) may share order_service.rb
Acceptance Criteria
6 criteria, all verifiable by an agent:
- [x] Threshold detection (yes_bid >= confidence_threshold) -- unit testable
- [x] API order placement (POST /portfolio/events/orders, side: bid) -- integration testable with HTTP mocks
- [x] Trade record creation with order_id -- DB assertion testable
- [x] Sell triggers at 95%+ (take profit) and below 80% (cut loss) -- unit testable
- [x] Dry-run mode logs without executing -- unit testable with feature flag mock
- [x] Pick and Trade record creation -- DB assertion testable
All criteria are concrete and testable. Count of 6 exceeds the >5 decomposition threshold.
Blast Radius
Greenfield project -- no existing application code to conflict with. order_service.rb is a candidate shared service (also needed by #5 Option D sizing). No sibling services or downstream consumers exist yet.
Decomposition Assessment
- 3 file targets in 1 repo -- OK (under the >3 files across >2 repos threshold)
- 6 acceptance criteria -- exceeds the >5 threshold by 1
- Estimated agent work -- ~5 minutes, borderline
Borderline decomposition case. The natural split would extract order_service.rb (shared API client for order placement) into a separate foundational ticket, reducing this ticket to 4 AC focused on watchdog-specific logic. This also benefits #5 (Option D sizing) which will need the same order service.
Recommendations
- [BODY] Add issue #1 (Rails app scaffold) to Lineage dependencies. The app/ directory does not exist without it.
- [LABEL] Align arch labels with project page architecture notes. The project page defines arch-domain-kalshi-assistant, arch-dataflow-kalshi-assistant, arch-deployment-kalshi-assistant -- but the board item uses arch:app and arch:api which have no backing notes.
- [SCOPE] Create architecture notes for this project. Either create arch-app and arch-api notes to match the current labels, or realign labels to the project page's architecture naming (arch-domain, arch-dataflow, arch-deployment) and create those notes.
- [DECOMPOSE] 6 AC exceeds >5 threshold. Recommend extracting order_service.rb into a separate foundational ticket (shared Kalshi API order client), reducing this ticket to 4 AC. The order service is also needed by #5 (Option D sizing).
-
Review: Market scanner — continuous polling of same-day games
review-1687-2026-07-02Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Depends on ldraney/kalshi-assistant #1
- [x] Repo — ldraney/kalshi-assistant
- [x] User Story — As the watchdog system / scan same-day markets / detect 85% threshold
- [x] Context — Watchdog strategy background, series tickers, rate limits
- [x] File Targets — 4 files to create
- [x] Feature Flag — none
- [x] Acceptance Criteria — 6 items
- [x] Test Expectations — unit + integration tests, run command
- [x] Constraints — Solid Queue, rate limits, 24h history
- [x] Checklist — PR, tests, no unrelated changes
- [x] Related — project reference
All sections present per template-issue-feature.
Traceability
- [x] story:watchdog-trading label — Watchdog Trading
- [x] story note verified — story-kalshi-assistant-watchdog-trading exists (active, user-story type)
- [x] story entry verified — found in project-kalshi-assistant user-stories table
- [x] arch:api label present
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-api for component api
- [x] arch:app label present
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-app for component app
- [ ] arch label mismatch — [LABEL] Story note references arch-domain-kalshi-assistant and arch-dataflow-kalshi-assistant, but board item has arch:api and arch:app. These should be reconciled.
- [x] Forgejo issue — ldraney/kalshi-assistant#2, open
File Targets
- [x] app/jobs/market_scanner_job.rb — to create (Solid Queue job). No app/ directory exists yet; expected since this depends on issue #1 (Rails scaffold).
- [x] app/models/market_snapshot.rb — to create (snapshot model). Same dependency on #1.
- [x] db/migrate/xxx_create_market_snapshots.rb — to create (migration). Same dependency on #1.
- [x] config/market_series.yml — to create (series config). Same dependency on #1.
All file targets are files to CREATE, not modify. File paths follow Rails conventions. The repo has no Rails structure yet because the prerequisite (issue #1 — Rails scaffold) hasn't been completed. File targets are valid assuming #1 is done first.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, Repo section says ldraney/kalshi-assistant. Single repo, no multi-repo concern.
Dependencies
- Upstream: Depends on issue #1 (Rails scaffold + API client) — documented in Lineage. Board item #1686 is in backlog (sprint:1). This ticket is sprint:2. Correct ordering.
- Downstream: Board item #1689 "Watchdog — auto-buy when market crosses 85% threshold" (sprint:3, issue #4) logically depends on this scanner. Not documented in this ticket's scope but is in the correct sprint order.
- Parallel: Board item #1688 "Strategy engine — database schema" (sprint:2, issue #3) is in the same sprint. No apparent conflict — these can run in parallel once #1 is complete.
Acceptance Criteria
6 criteria, all testable by an agent:
- [x] Background job polls — verifiable via test that job enqueues and runs
- [x] Scans configured series — verifiable via config iteration test
- [x] Stores snapshots with specified fields — verifiable via DB assertions
- [x] Filters same-day/next-day — verifiable via date filtering test
- [x] Respects rate limits — verifiable via configurable delay check
- [x] Logs 85% threshold crossing — verifiable via log output assertion
Test expectations are reasonable: unit tests for model validations and filtering logic, integration test for full job execution. Run command
rails testis standard Rails.Blast Radius
- New repo with no existing production code (only docs and README). Minimal blast radius.
- Referenced docs exist: docs/api/market-data-guide.md and docs/strategy/watchdog-strategy.md both present in repo.
- Ticker discrepancy: Issue Context lists 11 series tickers including crypto tickers (KXBTC15M, KXETH15M, KXSOL15M, KXDOGE15M, KXXRP15M, KXBNB15M, KXNEAR15M, KXHYPE15M) and KXWNBA. The market-data-guide.md only documents KXMLBGAME, KXWCGAME, KXMLB, KXNBA, KXNHL. The additional tickers in the issue are not sourced. This should be reconciled — either update the market data guide or cite the source for these tickers in the issue body.
Decomposition Assessment
- 4 file targets across 1 repo — under the >3 files across >2 repos threshold.
- 6 acceptance criteria — borderline exceeds the >5 threshold by 1.
- Estimated agent work: ~5 minutes. Creating 4 tightly coupled files (model, job, migration, config) plus tests for a single feature.
The 6 AC are all aspects of a single scanner component. Decomposition would create artificial sub-tickets with heavy coupling. No decomposition needed — the borderline AC count does not warrant splitting this coherent feature.
Recommendation
[SCOPE]Create architecture note arch-api for the Kalshi API client component.[SCOPE]Create architecture note arch-app for the application layer component.[LABEL]Reconcile arch labels: story note references arch-domain-kalshi-assistant and arch-dataflow-kalshi-assistant, but board item uses arch:api and arch:app. Decide which taxonomy to use and align both.[BODY]Cite source for crypto and WNBA tickers in Context section (KXBTC15M, KXETH15M, KXSOL15M, KXDOGE15M, KXXRP15M, KXBNB15M, KXNEAR15M, KXHYPE15M, KXWNBA) or update docs/api/market-data-guide.md to include them.
-
Review: Service onboarding -- namespace, Harbor, ArgoCD, Tailscale funnel (r2)
review-1694-2026-07-02-r2Verdict: APPROVED
Re-review after refinement. Previous review (
review-1694-2026-07-02) found two missing architecture notes. Both have been created and verified.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone
- [x] Repo -- ldraney/pal-e-services
- [x] User Story -- present, well-formed
- [x] Context -- present, describes foundational nature
- [x] File Targets -- present, with both modify and do-not-touch sections
- [x] Feature Flag -- none (appropriate for infra ticket)
- [x] Acceptance Criteria -- 5 items
- [x] Test Expectations -- present with run command
- [x] Constraints -- present, references landscaping-assistant pattern
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- story-kalshi-assistant-platform-setup listed in project-kalshi-assistant user-stories section
- [x] arch:iac label -- Infrastructure as Code
- [x] arch note verified --
arch-iacnote exists (type: architecture, status: active, project: kalshi-assistant). Sections: Diagram, Components, Key Decisions, Related. - [x] arch:k8s-deploy label -- Kubernetes Deployment
- [x] arch note verified --
arch-k8s-deploynote exists (type: architecture, status: active, project: kalshi-assistant). Sections: Diagram, Components, Key Decisions, Related. - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/kalshi-assistant/issues/7, open
File Targets
- [x]
terraform/k3s.tfvars-- verified: file exists (symlink to ~/secrets/pal-e-services/k3s.tfvars),servicesmap at line 193, landscaping-assistant pattern confirmed at lines 203-210 with matching structure (forgejo_repo, image_repo, port 3000, funnel true, source_repo, source_path). No existing kalshi-assistant entry -- clean for addition.
Repo Placement
OK. Issue filed on
ldraney/kalshi-assistantbut### Reposection explicitly declares work is inldraney/pal-e-services. Acceptable pattern for project-specific infrastructure tickets. Single-repo change.Dependencies
Foundational ticket -- "nothing else deploys until this is done." Downstream items on board-kalshi-assistant:
- #1686 Rails app scaffold (sprint:1) -- blocked, needs namespace
- #1692 DNS + reverse proxy (sprint:1) -- depends on namespace/funnel
- #1693 Keycloak realm (sprint:1) -- depends on namespace
- #1695 Kustomize overlays (sprint:2) -- depends on ArgoCD app
- #1696 CI/CD pipeline (sprint:2) -- depends on Harbor project
Acceptance Criteria
All 5 criteria are agent-verifiable:
tofu planexit 0,tofu applysuccess,kubectl get ns, Harbor API check,argocd app get. Test command provided:cd ~/pal-e-services && tofu plan -var-file=terraform/k3s.tfvars.Blast Radius
Low. Adds a new entry to the services map without modifying existing entries. Pattern well-established with multiple existing services (believers-elite, landscaping-assistant, mdview, etc.).
Decomposition Assessment
No decomposition needed: 1 file target, 1 repo, 5 acceptance criteria (at threshold), estimated agent work under 2 minutes.
Recommendation
No action needed. Previous [SCOPE] items resolved:
- [FIXED]
arch-iacnote created -- architecture note with Diagram, Components, Key Decisions sections - [FIXED]
arch-k8s-deploynote created -- architecture note with Diagram, Components, Key Decisions sections
-
Review: Rails app scaffold with Kalshi API client (re-review)
review-1686-2026-07-02-r2Verdict: APPROVED
Re-review of board item #1686 after refinement. Previous review (
review-1686-2026-07-02) found 4 issues. All have been resolved.Previous Issues — Resolution
- [x]
arch-railsnote — FIXED: notearch-rails("Rails Architecture: Kalshi Assistant") now exists, status active, project kalshi-assistant - [x]
arch-apinote — FIXED: notearch-api("API Integration: kalshi-assistant") now exists, status active, project kalshi-assistant - [x] Faraday contradiction in Constraints — FIXED: now reads "Use Net::HTTP (stdlib) or Faraday — no other HTTP client gems"
- [x] Env-dependent AC — FIXED: last AC now includes "(requires API credentials in ~/secrets/kalshi-api-key-id and ~/secrets/kalshi-private-key.key; alternatively verify with a stub/mock if credentials unavailable)"
Template Completeness
- [x] Type — Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag — "none" (acceptable, no feature-flags.md in repo)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:portfolio-builder label — AI Portfolio Builder
- [x] story note verified — found in project-kalshi-assistant user-stories section (key: portfolio-builder, links to story-kalshi-assistant-portfolio-builder)
- [x] arch:rails label — Rails framework component
- [x] arch note verified —
arch-railsnote exists in pal-e-docs (active, project kalshi-assistant) - [x] arch:api label — Kalshi API integration component
- [x] arch note verified —
arch-apinote exists in pal-e-docs (active, project kalshi-assistant) - [x] Forgejo issue — ldraney/kalshi-assistant#1, open
File Targets
- [x]
app/services/kalshi_client.rb— to be created (greenfield scaffold, directory does not yet exist, correct) - [x]
config/initializers/kalshi.rb— to be created (greenfield scaffold, correct) - [x]
Gemfile— to be created (greenfield scaffold, correct) - [x]
docs/api/overview.md— referenced in Context, verified exists in repo - [x]
docs/api/openapi.yaml— referenced in Context, verified exists in repo
Note: All target files are "to create" since this is a greenfield Rails scaffold. No existing files will be modified. The docs/ directory is explicitly excluded from modification.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, Repo section says
ldraney/kalshi-assistant. Single repo, consistent.Dependencies
No explicit dependencies documented. This is the first ticket for the project (Lineage: "Standalone"). Other sprint:1 items on the board:
- #1693 Keycloak realm (sprint:1, type:infra) — parallel, no dependency
- #1694 Service onboarding — namespace, Harbor, ArgoCD (sprint:1, type:infra) — parallel, not required for scaffold
- #1692 DNS + reverse proxy (sprint:1, type:infra) — parallel, no dependency
Sprint:2 item #1688 (Strategy engine — database schema) depends on the Rails scaffold being in place. This is implicit and correctly sequenced via sprint labels.
Acceptance Criteria
7 acceptance criteria. All are testable by an agent:
- "Rails 8 app initialized" — verifiable via file existence and
rails --version - "Kalshi API client class with RSA-PSS signing" — verifiable via unit test
- "Support for: GET markets, GET orderbook, GET portfolio/balance, POST orders" — verifiable via method existence
- "Rate limit awareness" — verifiable via code inspection or unit test
- "Demo environment config" — verifiable via config file check
- "API key/secret loaded from environment variables" — verifiable via code inspection
- "Can run rails console and call KalshiClient.new.balance successfully" — now includes stub/mock fallback if credentials unavailable, testable in all environments
Blast Radius
Minimal. Greenfield scaffold, no existing code patterns to check. The docs/ directory is explicitly excluded from modification. No downstream consumers yet.
Decomposition Assessment
- File targets: 3 files to create, 1 repo — under threshold
- Acceptance criteria: 7 — technically exceeds the >5 threshold
- Estimated agent work: ~5 minutes (Rails scaffold + API client is a single coherent unit)
No decomposition needed. The 7 AC items are tightly coupled: items 2-7 are all aspects of a single API client built on top of the Rails scaffold (item 1). Decomposing would create artificial dependencies between sub-tickets.
Recommendation
No action needed.
- [x]
-
Review: Option D sizing engine -- optimized stack with hedging
review-1690-2026-07-02-r2Verdict: APPROVED
Re-review after refinement. Previous review (review-1690-2026-07-02) found 3 issues: missing arch-app note, missing dependency on #1, 6 ACs needing consolidation. All three are now resolved.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on #1 (Rails scaffold) and #3 (schema). Both must complete before this sprint:3 ticket.
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- present, well-formed
- [x] Context -- present, references docs/strategy/sizing-models.md (verified)
- [x] File Targets -- 2 files to create (app/services/sizing_engine.rb, app/services/scenario_analyzer.rb)
- [x] Feature Flag -- "none"
- [x] Acceptance Criteria -- 5 items (consolidated from 6)
- [x] Test Expectations -- 3 tests + run command (rails test)
- [x] Constraints -- present (pure Ruby, <1s for 10 picks)
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- story-kalshi-assistant-portfolio-builder exists, listed in project-kalshi-assistant user-stories section
- [x] arch:app label -- application component
- [x] arch note verified -- arch-app note exists in pal-e-docs (slug: arch-app, type: architecture, status: active). Contains Mermaid service diagram, component table with SizingEngine entry, and key decisions documenting the 83/17 split.
- [x] Forgejo issue -- ldraney/kalshi-assistant#5, open
File Targets
- [x] app/services/sizing_engine.rb -- to be created. Path depends on Rails scaffold (#1). Dependency is declared in Lineage.
- [x] app/services/scenario_analyzer.rb -- to be created. Same dependency chain as above.
- [x] docs/strategy/sizing-models.md -- verified: contains Option D math (83% YES / 17% NO split, -$5.77 worst case, all scenario tables with probabilities and P&L). Context reference is accurate.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, work targets ldraney/kalshi-assistant. Single repo, no cross-repo concerns.
Dependencies
- Declared: #1 (Rails app scaffold, board item #1686, sprint:1, backlog) -- provides the app/services/ directory structure and test runner. Hard blocker.
- Declared: #3 (Strategy engine -- database schema, board item #1688, sprint:2, backlog) -- provides the strategy/trade schema the sizing engine operates on.
- Both dependencies are in backlog. Sprint ordering (1 → 2 → 3) enforces the correct sequence.
- Note: The arch-app diagram shows Watchdog (#1689, issue #4, sprint:3) consumes SizingEngine. That dependency belongs on the Watchdog ticket, not this one.
Acceptance Criteria
5 acceptance criteria, all concrete and agent-verifiable:
- Input contract: picks array with ticker/yes_ask/no_ask + budget -- well-defined interface
- Optimization method: brute-force over 50-99% YES/NO ratio -- deterministic, reproducible
- Output contract: optimal ratio, expected value, contracts per position -- complete output spec
- Scenario table: 2^N outcomes with probability and P&L -- verifiable against docs
- Scale constraint: 1-10 picks (1024 scenarios max) -- bounded and testable
Test expectations reference concrete values from docs (83/17, -$5.77) which are verified in sizing-models.md. Run command (rails test) is standard.
Blast Radius
Low. Creates new service classes in a greenfield codebase. No existing code to search for similar patterns. No downstream consumers at this stage. SizingEngine is self-contained computation with no external integrations.
Decomposition Assessment
- File targets: 2 files in 1 repo -- OK (below >3 across >2 repos threshold)
- Acceptance criteria: 5 -- at threshold, not over
- Estimated agent time: under 5 minutes -- math fully documented, two tightly coupled services
No decomposition needed.
Previous Review Issues -- Resolution
Issue Type Status arch-app note missing [SCOPE] FIXED -- arch-app note created with service diagram, component table, key decisions Missing dependency on #1 in Lineage [BODY] FIXED -- Lineage now reads "Depends on #1 (Rails app scaffold) and #3 (schema)" 6 ACs exceeding threshold [BODY] FIXED -- Consolidated to 5 by merging "Returns optimal ratio and expected value" into the output AC Recommendation
No action needed. All previous issues resolved. Ticket is ready to move to todo.
-
Review: Mobile app -- API key connection and strategy dashboard
review-1691-2026-07-02-r2Verdict: NEEDS_REFINEMENT
Re-review of board item #1691. Previous review (
review-1691-2026-07-02) returned NEEDS_REFINEMENT. Five of six findings were addressed in refinement. One blocker remains: decomposition has not been performed.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- dependencies listed (#1-#5 backend, #10 Keycloak, #4 Watchdog)
- [x] Repo --
ldraney/kalshi-assistant - [x] User Story -- present
- [x] Context -- present, includes decomposition recommendation
- [x] File Targets -- filled (preliminary Rails + Turbo Native paths, marked pending framework spike)
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 6 items
- [x] Test Expectations -- filled (system tests, Xcode simulator)
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:app-experience label -- App Experience story
- [x] story note verified -- found in project-kalshi-assistant user-stories section
- [x] story:credential-onboarding label -- Credential Onboarding story
- [x] story note verified -- found in project-kalshi-assistant user-stories section
- [x] arch:frontend label -- Frontend component
- [x] arch note verified --
arch-frontendnote exists (was MISSING in first review, now FIXED) - [x] arch:auth label -- Authentication component
- [x] arch note verified --
arch-authnote exists (was MISSING in first review, now FIXED) - [x] Forgejo issue -- ldraney/kalshi-assistant#6, open
File Targets
- [~]
app/views/dashboard/-- does not exist yet; acceptable for Sprint 4 ticket pending Sprint 1 scaffold - [~]
app/controllers/dashboard_controller.rb-- does not exist yet; same rationale - [~]
app/views/credentials/-- does not exist yet; same rationale - [~]
app/controllers/credentials_controller.rb-- does not exist yet; same rationale - [~]
ios/-- does not exist yet; Turbo Native shell, pending framework spike
All file targets are preliminary and correctly noted as "Pending framework spike." The repo currently contains only docs (no Rails scaffold yet -- that is ticket #1). File targets cannot be verified until Sprint 1 completes. This is acceptable for Sprint 4 scoping but means an agent cannot execute this ticket as-is.
Repo Placement
OK. Issue filed on
ldraney/kalshi-assistant, which matches### Repo. Theios/Turbo Native shell is kept in the same repo -- reasonable for a thin native wrapper.Dependencies
- #1 Rails scaffold (item #1686, backlog) -- prerequisite for all file targets
- #2 Market scanner (item #1687, backlog) -- provides market data for dashboard
- #3 Strategy engine (item #1688, backlog) -- provides strategy/trade models
- #4 Watchdog (item #1689, backlog) -- dashboard needs watchdog data (added in refinement)
- #5 Option D sizing (item #1690, backlog) -- strategy option
- #10 Keycloak realm/client (item #1693, backlog) -- auth prerequisite (added in refinement)
All dependencies documented in Lineage. All are in backlog (Sprint 1-3), correctly blocking this Sprint 4 ticket. FIXED from previous review.
Acceptance Criteria
6 criteria spanning 4 distinct feature areas: (1) credential input/validation, (2) strategy + budget configuration, (3) live dashboard, (4) trade history + access revocation. Each criterion is individually testable, but the breadth across 4 domains makes this too large for a single agent pass. Test commands are described at a reasonable level (system tests with mock data, manual Xcode simulator for iOS).
Blast Radius
No existing code in the repo to check -- currently docs only. The credential storage and API key handling patterns described here will set security precedent for the project. Encrypted-at-rest requirement in Constraints is critical -- ensure it aligns with
arch-authnote's credential storage design.Decomposition Assessment
NEEDS DECOMPOSITION -- route to skill-decompose-ticket.
- 8 story points
- 6 acceptance criteria across 4 feature areas
- 5+ file targets spanning controllers, views, and a native iOS shell
- Estimated agent work well exceeds 5 minutes
- The issue Context section itself recommends splitting into 6 sub-tickets
Suggested decomposition (from issue Context, validated by this review):
- Spike: framework decision (React Native / Flutter / Rails Turbo Native)
- Credential input UI -- API key + private key with validation
- Strategy + budget configuration
- Live dashboard -- active positions, unrealized P&L
- Trade history log
- Access revocation
Previous Review Findings -- Resolution Status
- [x] FIXED: arch-frontend note created
- [x] FIXED: arch-auth note created
- [x] FIXED: File Targets filled (was TBD)
- [x] FIXED: Test Expectations filled (was TBD)
- [x] FIXED: Keycloak dependency #10 added to Lineage
- [ ] OPEN: Decomposition not performed -- note added to Context acknowledging need, but ticket remains a monolith
Recommendation
[DECOMPOSE]8 points, 6 AC across 4 feature areas -- route to skill-decompose-ticket. Suggested split: (1) Spike: framework decision, (2) Credential input UI, (3) Strategy + budget config, (4) Live dashboard, (5) Trade history, (6) Access revocation.
-
Review: Market scanner -- continuous polling of same-day games
review-1687-2026-07-02-r2Verdict: APPROVED
Re-review after refinement. Previous review
review-1687-2026-07-02found 4 issues (NEEDS_REFINEMENT). All resolved.Previous Findings Resolution
- [x]
[SCOPE]arch-api note missing -- RESOLVED:arch-apicreated (API Integration: kalshi-assistant, architecture type, active, project: kalshi-assistant). Covers RSA-PSS auth, rate limits, endpoint groups. - [x]
[SCOPE]arch-app note missing -- RESOLVED:arch-appcreated (Application Domain: Kalshi Assistant, architecture type, active, project: kalshi-assistant). Covers MarketScanner, KalshiClient, Watchdog, SizingEngine components. - [x]
[LABEL]Arch label mismatch -- RESOLVED: No actual conflict. Board item labelsarch:apiandarch:appreference component-level notes (what the ticket touches). Story note referencesarch-domain-kalshi-assistantandarch-dataflow-kalshi-assistant(cross-cutting views). These are complementary layers.arch-applinks to both domain and dataflow notes in its Related section. - [x]
[BODY]Undocumented series tickers -- RESOLVED: Context section now cites source ("Kalshi API exploration, see docs/api/market-data-guide.md for methodology") and clarifies design intent ("scanner should discover active series dynamically rather than hardcoding these"). Ticker list is informational;config/market_series.ymlfile target provides configurable defaults.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on ldraney/kalshi-assistant #1
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- As the watchdog system / scan same-day markets / detect 85% threshold
- [x] Context -- Watchdog strategy background, series tickers with source citation, rate limits, dynamic discovery design
- [x] File Targets -- 4 files to create
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 6 items
- [x] Test Expectations -- unit + integration tests, run command
- [x] Constraints -- Solid Queue, rate limits, 24h history
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project reference
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading
- [x] story note verified -- story-kalshi-assistant-watchdog-trading exists (active, user-story type)
- [x] story entry verified -- found in project-kalshi-assistant user-stories table (row: watchdog-trading, role: Trader)
- [x] arch:api label -- Kalshi API integration component
- [x] arch note verified -- arch-api exists (active, architecture type, project: kalshi-assistant)
- [x] arch:app label -- Application domain component
- [x] arch note verified -- arch-app exists (active, architecture type, project: kalshi-assistant)
- [x] Forgejo issue -- ldraney/kalshi-assistant#2, open
File Targets
- [x] app/jobs/market_scanner_job.rb -- to create (Solid Queue job). Depends on #1 (Rails scaffold).
- [x] app/models/market_snapshot.rb -- to create (snapshot model). Depends on #1.
- [x] db/migrate/xxx_create_market_snapshots.rb -- to create (migration). Depends on #1.
- [x] config/market_series.yml -- to create (configurable series list). Depends on #1.
All file targets are files to CREATE. Paths follow Rails conventions. Repo currently has no Rails structure (only docs). Valid assuming #1 completes first.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, Repo section says ldraney/kalshi-assistant. Single repo, no multi-repo concern.
Dependencies
- Upstream: Depends on issue #1 (Rails scaffold + API client) -- documented in Lineage. Board item #1686 in backlog (sprint:1). This ticket is sprint:2. Correct ordering.
- Downstream: Board item #1689 "Watchdog -- auto-buy when market crosses 85% threshold" (sprint:3, issue #4) logically depends on this scanner. Correct sprint order.
- Parallel: Board item #1688 "Strategy engine -- database schema" (sprint:2, issue #3) is in the same sprint. No conflict -- can run in parallel once #1 completes.
Acceptance Criteria
6 criteria, all agent-testable:
- [x] Background job polls -- verifiable via test that job enqueues and runs
- [x] Scans configured series -- verifiable via config iteration test
- [x] Stores snapshots with specified fields -- verifiable via DB assertions
- [x] Filters same-day/next-day -- verifiable via date filtering test
- [x] Respects rate limits -- verifiable via configurable delay check
- [x] Logs 85% threshold crossing -- verifiable via log output assertion
Blast Radius
Minimal. New repo with only docs and README -- no existing production code. Referenced docs confirmed present: docs/api/market-data-guide.md and docs/strategy/watchdog-strategy.md both exist in repo. Architecture notes arch-api and arch-app document the components this ticket creates.
Decomposition Assessment
- 4 file targets across 1 repo -- under the >3 files across >2 repos threshold.
- 6 acceptance criteria -- borderline exceeds the >5 threshold by 1.
- Estimated agent work: ~5 minutes. Creating 4 tightly coupled files for a single scanner feature.
No decomposition needed. The 6 AC are all aspects of a single coherent scanner component. Splitting would create artificially coupled sub-tickets.
Recommendation
No action needed. All previous findings resolved. Scope is solid, traceability complete, file targets verified, fits in a single agent pass.
- [x]
-
Review: Strategy engine -- database schema for strategies and trades (re-review)
review-1688-2026-07-02-r2Verdict: APPROVED
Re-review of board item #1688 after refinement. Previous review (
review-1688-2026-07-02) found two missing architecture backing notes. Both have been created and verified.Previous Findings -- Resolution
- [x]
[SCOPE]Create architecture note arch-rails -- FIXED.arch-railsexists (note_type=architecture, status=active, project=kalshi-assistant). Contains Rails 8 component diagram, service objects, Solid Queue/Cable decisions. - [x]
[SCOPE]Create architecture note arch-postgres -- FIXED.arch-postgresexists (note_type=architecture, status=active, project=kalshi-assistant). Contains ER diagram with strategies, trades, markets, portfolios. Includes CNPG and jsonb strategy polymorphism decisions.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on ldraney/kalshi-assistant #1 (Rails scaffold)
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- As a developer / I want a database schema / So that strategies are data-driven
- [x] Context -- Strategy explanation with doc references
- [x] File Targets -- 6 files to create
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 6 criteria
- [x] Test Expectations -- Unit tests, rails test command
- [x] Constraints -- 3 constraints listed
- [x] Checklist -- PR/tests/no unrelated changes
- [x] Related -- kalshi-assistant project
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- found in project-kalshi-assistant user-stories section (key: portfolio-builder, links to story-kalshi-assistant-portfolio-builder)
- [x] arch:rails label -- Rails framework
- [x] arch note verified --
arch-railsnote exists in pal-e-docs (note_type=architecture, status=active, project=kalshi-assistant) - [x] arch:postgres label -- PostgreSQL database
- [x] arch note verified --
arch-postgresnote exists in pal-e-docs (note_type=architecture, status=active, project=kalshi-assistant) - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/kalshi-assistant/issues/3, open
File Targets
All file targets are files to CREATE. The repo is currently docs-only because this ticket depends on #1 (Rails scaffold, sprint:1, backlog). File targets cannot be verified against existing code but are standard Rails conventions.
- [x] app/models/strategy.rb -- to create: name, thresholds, allocation percentages
- [x] app/models/pick.rb -- to create: belongs_to strategy, market ticker, implied_prob
- [x] app/models/trade.rb -- to create: belongs_to pick, side, contracts, price, status
- [x] app/models/outcome.rb -- to create: settlement result, P&L
- [x] db/migrate/ -- to create: all migrations
- [x] db/seeds.rb -- to create: seed Option D and Watchdog strategies
Repo Placement
OK. Issue #3 is filed on ldraney/kalshi-assistant and all work targets that same repo. Single repo, no cross-repo concerns.
Dependencies
- Documented: Depends on #1 (Rails scaffold, item #1686, sprint:1, backlog). Correctly sequenced -- this ticket is sprint:2.
- Downstream consumers: #1689 Watchdog (sprint:3) and #1690 Option D sizing engine (sprint:3) both build on models created here. #1687 Market scanner (sprint:2) may interact with Pick model for storing scan results.
- Dependencies are properly documented in the Lineage section.
Acceptance Criteria
6 criteria, all agent-verifiable:
- Strategy/Pick/Trade/Outcome model fields -- verifiable via schema inspection and model attribute checks
- Seeds -- verifiable via rails runner or db:seed + query
Strategy.find_by(name: 'watchdog').confidence_thresholdreturns 0.85 -- very specific, directly testable
Values verified against docs:
- 83/17 split: confirmed in docs/strategy/sizing-models.md ("83% YES / 17% NO hedge on all picks")
- 0.85 confidence threshold: confirmed in docs/strategy/core-strategy.md ("85%+ implied probability")
- Watchdog strategy: docs/strategy/watchdog-strategy.md exists in the repo
Blast Radius
Minimal. Greenfield project -- no existing code to break. Models created here become the foundation for sprint 3 tickets (watchdog, sizing engine). No external services consumed by this ticket directly.
Decomposition Assessment
6 file targets in 1 repo. 6 acceptance criteria (marginally over 5 threshold). However, this is standard Rails model/migration/seed work -- well under 5 minutes for an agent. All targets are in one repo and belong to a single domain (data models). No decomposition needed.
Recommendation
No action needed. All previous findings resolved.
- [x]
-
Review: Monitoring -- AlertManager, blackbox, Grafana, PrometheusRules (re-review)
review-1697-2026-07-02-r2Verdict: APPROVED
Re-review of board item #1697. Previous review (
review-1697-2026-07-02) returned NEEDS_REFINEMENT with 3 issues. All 3 have been resolved.Previous Issues -- Resolution Status
# Tag Issue Status 1 [SCOPE]Create architecture note arch-observabilityFIXED -- note exists (id 2344), comprehensive content with Mermaid diagram, component table, key decisions, and related links. Project: kalshi-assistant. 2 [BODY]Add dependencies to issue body FIXED -- Lineage section updated: "Depends on #7 (service onboarding), #9 (kustomize), #1 (Rails app /up endpoint)." 3 [BODY]Add cross-repo note FIXED -- Callout block added: "Cross-repo: All code changes target ldraney/pal-e-platform. PR targets pal-e-platform, not this repo." Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on #7, #9, #1 (updated from "Standalone")
- [x] Repo -- ldraney/pal-e-platform
- [x] User Story
- [x] Context -- includes cross-repo callout
- [x] File Targets -- 2 targets (1 modify, 1 create)
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 4 items
- [x] Test Expectations -- tofu plan
- [x] Constraints -- pattern matching, Telegram receiver naming, dashboard JSON format
- [x] Checklist
- [x] Related
Traceability
- [x] story:platform-setup label -- Platform Setup
- [x] story note verified -- found in project-kalshi-assistant user-stories section (key: platform-setup, role: Developer, metric: CI/CD push-to-deploy in under 10 minutes)
- [x] arch:observability label -- observability component
- [x] arch note verified --
arch-observabilitynote exists in pal-e-docs (id 2344, project kalshi-assistant). Includes Mermaid diagram, component table (ServiceMonitor, PrometheusRules, AlertManager, blackbox-exporter, Grafana dashboards), key decisions, and related links. - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/kalshi-assistant/issues/12, open
- [x] arch-deployment-kalshi-assistant (mentioned in Related) -- verified, note exists (id 2327)
File Targets
- [x]
terraform/modules/monitoring/main.tf-- verified: exists (28k), landscaping-assistant pattern confirmed (AlertManager route/receiver, blackbox probe, dashboard ConfigMap, PrometheusRule). No kalshi-assistant content yet (work not started). - [x]
terraform/dashboards/kalshi-assistant-golden-signals.json-- to create: dashboards directory exists with 8 existing dashboards includinglandscaping-assistant-golden-signals.jsonas the template to follow.
Repo Placement
Cross-repo filing is now explicitly documented. Issue filed on
ldraney/kalshi-assistant, code changes targetldraney/pal-e-platform. The### Repofield and the new cross-repo callout make this unambiguous for implementing agents. Single repo affected (pal-e-platform), so no multi-issue coordination needed.Dependencies
All dependencies now documented in Lineage section:
- #7 / board #1694 (Service onboarding -- namespace, Harbor, ArgoCD, Tailscale funnel) -- sprint:1. Namespace must exist.
- #9 / board #1695 (Kustomize deployment overlays -- prod and dev) -- sprint:2. ServiceMonitor provisioned here.
- #1 / board #1686 (Rails app scaffold with Kalshi API client) -- sprint:1. Provides /up health endpoint for blackbox probe.
Sprint:3 placement is correct given all 3 dependencies are sprint:1 or sprint:2. All dependencies are on the same board (board-kalshi-assistant), currently in backlog.
Acceptance Criteria
4 criteria, all agent-verifiable:
- AlertManager routing -- verifiable via
tofu planoutput - Blackbox probe endpoint -- verifiable via
tofu plan; runtime verification requires deployed app - Grafana dashboard golden signals -- verifiable by checking ConfigMap creation in plan
- PrometheusRule thresholds -- verifiable via
tofu planchecking rule expressions
All criteria are well-scoped and measurable. Runtime verification depends on upstream deployments but infrastructure-level verification is self-contained.
Blast Radius
Low. Changes follow the established landscaping-assistant pattern exactly. All modifications are additive:
- New AlertManager route and receiver (append to existing arrays)
- New blackbox probe target (append to existing targets)
- New dashboard JSON file (no modifications to existing dashboards)
- New PrometheusRule kubernetes_manifest (no modifications to existing rules)
No downstream consumers affected.
Decomposition Assessment
No decomposition needed:
- 2 file targets in 1 repo -- under threshold
- 4 acceptance criteria -- under threshold
- Estimated agent work: 3-5 minutes (pattern copy from landscaping-assistant, adapt names/namespaces) -- within 5-minute rule
Recommendation
No action needed. All previous issues resolved. Ticket is ready for implementation.
-
Review: Watchdog -- auto-buy when market crosses 85% threshold (re-review)
review-1689-2026-07-02-r2Verdict: APPROVED
Re-review of board item #1689. Previous review (
review-1689-2026-07-02) returned NEEDS_REFINEMENT with four findings. All have been addressed.Previous Findings Resolution
- [x] [BODY] Lineage missing #1 -- RESOLVED. Lineage now reads: "Depends on
ldraney/kalshi-assistant #1(Rails app scaffold),#2(scanner), and#3(schema). Theapp/directory doesn't exist yet -- it's created by #1." - [x] [LABEL] Arch label mismatch -- RESOLVED. Rather than realigning labels, backing architecture notes were created to match the existing
arch:appandarch:apilabels. - [x] [SCOPE] Create architecture notes -- RESOLVED.
arch-app(Application Domain: Kalshi Assistant) created with Mermaid diagram, component table, and key decisions.arch-api(API Integration: kalshi-assistant) created with sequence diagram, endpoints, rate limits, and auth flow. - [x] [DECOMPOSE] 6 AC, extract OrderService -- ACCEPTED AS BORDERLINE. Context section now acknowledges OrderService extraction option: "Consider extracting a shared OrderService... either as part of this ticket or split into a foundational ticket." AC count remains 6 (1 over threshold), but this is acceptable: single repo, 3 tightly-coupled files, ~5 min estimated work.
Template Completeness
Issue type: Feature (template-issue-feature)
- [x] Type -- "Feature"
- [x] Lineage -- documents deps on #1 (scaffold), #2 (scanner), #3 (schema)
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- present, well-formed
- [x] Context -- references watchdog-strategy.md (verified exists), API endpoint, OrderService note
- [x] File Targets -- 3 CREATE targets listed
- [x] Feature Flag -- watchdog_live_trading, global, disabled by default
- [x] Acceptance Criteria -- 6 criteria listed, all testable
- [x] Test Expectations -- unit tests + run command
- [x] Constraints -- dry-run default, logging, error handling
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:watchdog-trading label -- Watchdog Trading
- [x] story note verified --
story-kalshi-assistant-watchdog-tradingexists (active, user-story); entry found in project-kalshi-assistant user-stories table with success metric "85%+ win rate, $0.10-$0.15 avg profit per contract" - [x] arch:app label -- Application Domain
- [x] arch note verified --
arch-appnote exists (active, architecture); includes Mermaid diagram showing Watchdog component, service object table, key decisions - [x] arch:api label -- API Integration
- [x] arch note verified --
arch-apinote exists (active, architecture); includes sequence diagram, endpoint groups, rate limit table, RSA-PSS auth flow - [x] Forgejo issue -- ldraney/kalshi-assistant#4, state: open
File Targets
- [x]
app/services/watchdog_service.rb-- CREATE. Requires #1 (Rails scaffold) for app/ directory. Dependency documented in Lineage. - [x]
app/jobs/watchdog_job.rb-- CREATE. Same #1 dependency. Solid Queue job pattern documented in arch-app and arch-rails notes. - [x]
app/services/order_service.rb-- CREATE. Shared Kalshi API order client. Reuse by #5 (Option D sizing) acknowledged in Context.
Repo Placement
OK. Single repo (ldraney/kalshi-assistant), all targets in same repo. Issue filed on correct repo.
Dependencies
- #1 Rails app scaffold (sprint:1, backlog) -- app/ directory structure. NOW DOCUMENTED in Lineage.
- #2 Market scanner (sprint:2, backlog) -- scanner triggers watchdog. Documented.
- #3 Strategy engine schema (sprint:2, backlog) -- Trade/Pick/Strategy models. Documented.
- Sprint ordering: Correct -- this is sprint:3, all deps are sprint:1-2.
- Downstream: #5 (Option D sizing, sprint:3) may share order_service.rb -- acknowledged in Context.
- Board state: All 12 items remain in backlog. No blockers in_progress.
Acceptance Criteria
6 AC, all verifiable by an agent:
- [x] Threshold detection (yes_bid >= confidence_threshold) -- unit testable, aligns with watchdog-strategy.md 85%+ entry
- [x] API order placement (POST /portfolio/events/orders, side: bid) -- confirmed in openapi.yaml line 1143; integration testable with HTTP mocks
- [x] Trade record with order_id -- DB assertion testable
- [x] Sell triggers 95%+ / below 80% -- unit testable, matches watchdog-strategy.md sell triggers table
- [x] Dry-run mode -- unit testable with feature flag mock
- [x] Pick and Trade records -- DB assertion testable
Blast Radius
Greenfield project -- no existing application code. All file targets are CREATE. order_service.rb is a shared candidate for #5 but that creates no conflict since #5 is also greenfield.
Decomposition Assessment
- 3 file targets in 1 repo -- OK (under threshold)
- 6 acceptance criteria -- borderline (1 over >5 threshold)
- Estimated agent work -- ~5 minutes, borderline
- OrderService extraction acknowledged as option in Context but kept in this ticket for cohesion
No decomposition needed. Borderline case accepted: tightly coupled domain logic, single repo, and Context explicitly flags the extraction option for future consideration.
Observations (non-blocking)
arch-apikey endpoints table uses legacy endpoint path (/portfolio/orders) while issue body and openapi.yaml use the newer/portfolio/events/orders. Should be corrected in the arch note separately.- Feature flag section filled despite no
docs/feature-flags.mdin repo. Acceptable for greenfield; the doc will be established as part of the Rails scaffold (#1).
Recommendation
No action needed. All previous findings resolved. Ticket is ready for implementation once sprint:1 and sprint:2 dependencies are complete.
- [x] [BODY] Lineage missing #1 -- RESOLVED. Lineage now reads: "Depends on
-
Re-Review: Kustomize deployment overlays -- prod and dev
review-1695-2026-07-02-v2Verdict: APPROVED
Re-review of board item #1695 after refinement. All 6 issues from the initial review (review-1695-2026-07-02) have been addressed. Scope is solid, traceability complete, file targets verified against the actual landscaping-assistant reference pattern.
Previous Findings -- Resolution
- [x] Dev overlay file targets incomplete -- FIXED: 6 dev files added (configmap.yaml, ingress.yaml, namespace.yaml, service.yaml plus the 2 originals), matching landscaping-assistant pattern exactly
- [x] Prod rename patches undocumented -- FIXED: kustomization.yaml description now includes "inline rename patches (Deployment, Service, ServiceMonitor from 'app' to 'kalshi-assistant')"
- [x] Dependencies undocumented -- FIXED: Lineage changed from "Standalone" to "Depends on #7 (service onboarding -- creates namespace and ArgoCD app), #1 (Rails scaffold -- produces container image)"
- [x] No dev-specific acceptance criteria -- FIXED: 3 dev ACs added (kalshi-dev namespace, nginx proxy routes, kustomize build dev succeeds)
- [x] Architecture notes missing -- FIXED: arch-kustomize and arch-k8s-deploy notes created in pal-e-docs, both active, project kalshi-assistant
- [x] Cross-repo note missing -- FIXED: callout added "PR targets ldraney/pal-e-deployments, not this repo"
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on #7, #1
- [x] Repo -- ldraney/pal-e-deployments
- [x] User Story -- present
- [x] Context -- present, references landscaping-assistant model
- [x] File Targets -- 9 files (3 prod, 6 dev)
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 9 criteria
- [x] Test Expectations -- kustomize build command provided
- [x] Constraints -- pattern, namespace, port, secrets documented
- [x] Checklist -- PR, build, SOPS, no unrelated changes
- [x] Related -- project and arch note referenced
Traceability
- [x] story:platform-setup label -- verified in project-kalshi-assistant user-stories table
- [x] story note verified -- "Platform Setup" entry exists with link to story-kalshi-assistant-platform-setup
- [x] arch:kustomize label -- arch-kustomize note exists (active, project kalshi-assistant)
- [x] arch:k8s-deploy label -- arch-k8s-deploy note exists (active, project kalshi-assistant)
- [x] Forgejo issue -- ldraney/kalshi-assistant#9, state: open
File Targets
- [x] overlays/kalshi-assistant/prod/kustomization.yaml -- to create; matches landscaping-assistant/prod/kustomization.yaml
- [x] overlays/kalshi-assistant/prod/deployment-patch.yaml -- to create; matches landscaping-assistant/prod/deployment-patch.yaml
- [x] overlays/kalshi-assistant/prod/secrets.enc.yaml -- to create; matches landscaping-assistant/prod/secrets.enc.yaml
- [x] overlays/kalshi-assistant/dev/kustomization.yaml -- to create; matches landscaping-assistant/dev/kustomization.yaml
- [x] overlays/kalshi-assistant/dev/deployment.yaml -- to create; matches landscaping-assistant/dev/deployment.yaml
- [x] overlays/kalshi-assistant/dev/configmap.yaml -- to create; matches landscaping-assistant/dev/configmap.yaml
- [x] overlays/kalshi-assistant/dev/ingress.yaml -- to create; matches landscaping-assistant/dev/ingress.yaml
- [x] overlays/kalshi-assistant/dev/namespace.yaml -- to create; matches landscaping-assistant/dev/namespace.yaml
- [x] overlays/kalshi-assistant/dev/service.yaml -- to create; matches landscaping-assistant/dev/service.yaml
All 9 file targets verified against the actual landscaping-assistant overlay in pal-e-deployments. Pattern match is exact (3 prod files, 6 dev files, identical names). No kalshi-assistant overlay exists yet (expected).
Repo Placement
Issue filed on ldraney/kalshi-assistant, work targets ldraney/pal-e-deployments. Cross-repo callout clearly documented in issue body. Implementing agent must PR against pal-e-deployments. Acceptable -- issue is scoped to the project, code lives in the deployment repo.
Dependencies
- #7 Service onboarding (board item #1694, sprint:1) -- creates namespace, Harbor project, ArgoCD app. Must complete before this ticket. Currently in backlog. Documented in Lineage.
- #1 Rails app scaffold (board item #1686, sprint:1) -- produces the container image that prod overlay deploys. Must complete before this ticket. Currently in backlog. Documented in Lineage.
Sprint ordering is consistent: dependencies are sprint:1, this ticket is sprint:2.
Acceptance Criteria
9 criteria, all agent-verifiable:
- [x] kustomize build prod -- testable via provided command
- [x] SOPS encryption -- verifiable with sops decrypt
- [x] Init container db:prepare -- verifiable in YAML
- [x] Liveness/readiness probes -- verifiable in YAML
- [x] Resource limits -- verifiable in YAML
- [x] Security context -- verifiable in YAML
- [x] Dev namespace -- verifiable via kustomize build
- [x] Dev nginx proxy -- verifiable in YAML
- [x] kustomize build dev -- testable via command
Test command provided:
cd ~/pal-e-deployments && kustomize build overlays/kalshi-assistant/prod. All criteria are concrete and machine-verifiable.Blast Radius
Low. Creates new files only in a new overlay directory. No existing services or overlays are modified. No shared base files are touched.
Decomposition Assessment
9 acceptance criteria exceeds the >5 threshold. However, all files are in one repo, follow an established pattern (landscaping-assistant), and the work is mechanical pattern-copy with service-specific values. Estimated agent time: 3-5 minutes. No decomposition needed.
Note
The arch-kustomize note's diagram shows a slightly different file structure (base/ directory, rename-patches.yaml, servicemonitor.yaml) than what the actual landscaping-assistant pattern and this issue's file targets use. The issue spec correctly follows the real pattern. The arch note may warrant a minor update to align with the actual implementation, but this does not affect the ticket scope.
Recommendation
No action needed. All previous findings resolved. Ticket is ready for implementation.
-
Review: DNS + reverse proxy — kalshi-assistant.com
review-1692-2026-07-02Verdict: APPROVED
Scope is solid. All file targets verified against pal-e-platform codebase. Template complete. 2 file targets in 1 repo, 4 acceptance criteria — well within the 5-minute rule.
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone
- [x] Repo — ldraney/pal-e-platform
- [x] User Story — present
- [x] Context — present, references landscaping-assistant.app model
- [x] File Targets — 2 files to modify, 2 exclusions documented
- [x] Feature Flag — none (infrastructure, appropriate)
- [x] Acceptance Criteria — 4 criteria
- [x] Test Expectations — 3 items with run command
- [x] Constraints — 3 pattern constraints documented
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified — found in project-kalshi-assistant user-stories section (role: Consumer)
- [x] arch:edge-proxy label — edge proxy component
- [ ] arch note arch-edge-proxy — not found in pal-e-docs. Shared platform component; acceptable for infra work, not blocking.
- [x] arch:iac label — infrastructure-as-code component
- [ ] arch note arch-iac — not found in pal-e-docs. Shared platform component; acceptable for infra work, not blocking.
- [x] Forgejo issue — ldraney/kalshi-assistant#8, open
File Targets
- [x]
terraform/dns.tf— verified: exists in pal-e-platform, containslandscaping_assistant_aresource pattern at line 12 - [x]
salt/pillar/caddy.sls— verified: exists in pal-e-platform, containslandscapingsite entry at line 17 with domain, proxy_target, www_redirect fields
Repo Placement
Issue filed on ldraney/kalshi-assistant, work happens in ldraney/pal-e-platform. This is the standard pattern for platform-level infrastructure work tracked in the project repo. OK.
Dependencies
No blocking dependencies. Service onboarding (#1694, sprint:1) is a related item but can proceed independently — DNS and reverse proxy do not depend on namespace or ArgoCD setup. The issue correctly notes that Keycloak theme and monitoring are separate tickets.
Acceptance Criteria
4 criteria, all verifiable by an agent.
tofu planis a real command.digandcurl -Iare standard verification commands. The expected 502 response (no app deployed yet) is a thoughtful criterion that prevents false positives. Test expectations align with acceptance criteria.Blast Radius
Minimal. Adding a new GoDaddy A record and Caddy site entry. Pattern follows existing landscaping-assistant.app model. No existing DNS records or Caddy configs are modified. No downstream consumers affected — the domain currently has no services behind it.
Decomposition Assessment
2 file targets in 1 repo, 4 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
No action needed. Scope is complete and well-structured.
Minor advisory (non-blocking): arch notes
arch-edge-proxyandarch-iacdo not exist in pal-e-docs. These are shared platform components used across multiple projects. Consider creating them as shared architecture notes when convenient. -
Review: CI/CD pipeline — Woodpecker config
review-1696-2026-07-02Verdict: APPROVED
CI/CD pipeline ticket is well-scoped, all template sections complete, traceability solid. Minor recommendation to create the backing architecture note for arch:ci-pipeline.
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone
- [x] Repo — ldraney/kalshi-assistant
- [x] User Story — present
- [x] Context — present, references landscaping-assistant pattern
- [x] File Targets — 2 files to create
- [x] Feature Flag — none (explicitly stated)
- [x] Acceptance Criteria — 6 criteria
- [x] Test Expectations — present
- [x] Constraints — present with Harbor base image and target
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:platform-setup label — Platform Setup
- [x] story note verified — found in project-kalshi-assistant user-stories section
- [x] arch:ci-pipeline label — CI Pipeline
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-ci-pipeline for component ci-pipeline
- [x] Forgejo issue — ldraney/kalshi-assistant#11, open
File Targets
- [x]
.woodpecker.yaml— to create; confirmed does not exist yet - [x]
Dockerfile— to create (if not created by rails scaffold ticket); confirmed does not exist yet
Repo Placement
OK — issue filed on ldraney/kalshi-assistant, all work targets the same repo.
Dependencies
- Board item #1694 "Service onboarding — namespace, Harbor, ArgoCD, Tailscale funnel" (sprint:1, todo) — upstream dependency. Harbor registry and ArgoCD must exist before CI can push images and trigger deploys.
- Board item #1686 "Rails app scaffold with Kalshi API client" (sprint:1, todo) — upstream dependency. Dockerfile and CI steps require a Rails app to build.
- Board item #1695 "Kustomize deployment overlays" (sprint:2, backlog) — related but not a hard blocker for CI pipeline creation.
Dependencies are implicit in sprint ordering (sprint:1 items before sprint:2) but not explicitly documented in the issue scope. Acceptable for infra work where sprint ordering conveys dependency.
Acceptance Criteria
6 criteria, all agent-verifiable: pipeline trigger behavior (push to any branch vs main), RuboCop lint pass, RSpec with Postgres service, Kaniko image build+push, ArgoCD Image Updater pickup. Test expectations include manual push trigger and Harbor image verification. Solid and testable.
Blast Radius
Minimal. Repo is currently bare (only README.md and docs/). No existing CI config, no Dockerfile, no conflicting patterns. The .woodpecker.yaml and Dockerfile are new additions with no downstream consumers yet.
Decomposition Assessment
2 file targets across 1 repo. 6 acceptance criteria (at threshold but within bounds). Estimated agent work well under 5 minutes — straightforward CI config following an established pattern (landscaping-assistant). No decomposition needed.
Recommendation
- [SCOPE] Create architecture note
arch-ci-pipelinefor the ci-pipeline component. Non-blocking — the work is well-defined without it, but traceability would be complete with the note.
No other action needed. Ticket is ready for implementation.
-
Review: Keycloak realm, client, users, and login theme
review-1693-2026-07-02Verdict: APPROVED
Re-review of board item #1693. All 7 issues from the previous NEEDS_REFINEMENT review have been verified fixed. One new documentation issue found in arch notes (non-blocking). Ticket is ready for implementation.
Previous Review Fixes (all verified)
- [x] Theme file paths corrected from
keycloak-theme/tokeycloak/themes/kalshi-assistant/ - [x] ConfigMap reference removed (themes are directly mounted, no ConfigMap pattern exists)
- [x] AC #6 replaced: "OmniAuth callback works" (unachievable) changed to "Keycloak client configured with correct redirect URI for future Rails OmniAuth integration (verified in Keycloak admin console)"
- [x] Dependencies added to Lineage: depends on #7 (service onboarding), soft dep on #1 (Rails scaffold)
- [x] Cross-Repo Note section added explaining PRs target pal-e-services and pal-e-platform, not kalshi-assistant
- [x] Repo description cleaned: "theme ConfigMap" changed to "theme files"
- [x] Architecture note
arch-keycloak-kalshi-assistantcreated - [x] Architecture note
arch-authcreated
Template Completeness
Validated against
template-issue-feature.- [x] Type — Feature
- [x] Lineage — depends on #7, notes #1
- [x] Repo — ldraney/pal-e-services + ldraney/pal-e-platform
- [x] Cross-Repo Note — bonus section, clarifies PR targeting
- [x] User Story — login with Keycloak SSO
- [x] Context — follows landscaping-assistant model, Auth Code + PKCE
- [x] File Targets — 3 files across 2 repos
- [x] Feature Flag — none
- [x] Acceptance Criteria — 6 items
- [x] Test Expectations — tofu plan + manual test
- [x] Constraints — landscaping pattern, registration, PKCE, no direct grants
- [x] Checklist — PR, tofu plan, theme, no unrelated changes
- [x] Related — project, story, SOP references
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified — "app-experience" found in project-kalshi-assistant user-stories section
- [x] arch:keycloak label — Keycloak configuration
- [x] arch note verified —
arch-keycloak-kalshi-assistantexists in pal-e-docs (note: slug uses-kalshi-assistantsuffix becausearch-keycloakwas taken) - [x] arch:auth label — Authentication architecture
- [x] arch note verified —
arch-authexists in pal-e-docs - [x] Forgejo issue — ldraney/kalshi-assistant#10, open
File Targets
- [x]
terraform/k3s.tfvars(pal-e-services) — verified: file exists (symlink to secrets),keycloak_realmsat line 40,keycloak_clientsat line 92,keycloak_usersat line 292. Landscaping-assistant pattern at lines 139-166 confirmed as reference. - [x]
keycloak/themes/kalshi-assistant/login/theme.properties(pal-e-platform) — to create. Matches convention:keycloak/themes/landscaping/login/theme.propertiesexists. - [x]
keycloak/themes/kalshi-assistant/login/resources/css/login.css(pal-e-platform) — to create. Matches convention:keycloak/themes/landscaping/login/resources/css/login.cssexists.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant (the project repo), but work targets ldraney/pal-e-services (Terraform config) and ldraney/pal-e-platform (theme files). Cross-Repo Note explicitly documents this. PRs should target those repos. This is acceptable for project-level infrastructure work.
Dependencies
- #7 (Service onboarding — namespace, Harbor, ArgoCD, Tailscale funnel) — board item 1694, sprint:1, backlog. Hard dependency: namespace and ArgoCD app must exist first. Documented in Lineage.
- #1 (Rails app scaffold with Kalshi API client) — board item 1686, sprint:1, backlog. Soft dependency: needed for full OAuth flow testing only. Documented in Lineage.
Acceptance Criteria
6 criteria, all testable:
- AC 1-4: verifiable via
tofu plan(realm, client, redirect URIs, seeded user) - AC 5: manual verification (login page branding)
- AC 6: verifiable in Keycloak admin console (redirect URI configuration)
All criteria are achievable within this ticket's scope (AC #6 was correctly scoped down from the previous "OmniAuth callback works" version).
Blast Radius
Low. All changes are additive:
- k3s.tfvars: adding new realm/client/user entries alongside existing ones. No modifications to landscaping, westside-basketball, or platform realms.
- Theme files: new directory under
keycloak/themes/. No changes to existing themes.
Decomposition Assessment
3 file targets across 2 repos (does not exceed >3 across >2 threshold). 6 AC (borderline at >5 threshold, but work is cohesive: one Terraform block + two theme files). Estimated agent time ~3-4 minutes. No decomposition needed.
New Finding: Arch Notes Contradict Issue Spec
Both
arch-keycloak-kalshi-assistantandarch-authdescribe ROPC/direct grant with a public client, but the issue spec and the verified landscaping-assistant pattern (k3s.tfvars lines 139-166) both specify Auth Code + PKCE with a confidential client anddirect_access_grants_enabled = false.Specific contradictions:
arch-keycloak-kalshi-assistant: diagram showsIOS -->|"direct grant"| CLIENT, components table says "Direct grant enabled. Public client", key decisions say "Direct grant for mobile — Public client with ROPC"arch-auth: diagram showsApp->>KC: Direct grant (username + password), components table says "Direct grant flow (no browser redirect)", key decisions say "Direct grant over redirect flow"
The issue spec is correct (Auth Code + PKCE, confidential, no ROPC). The arch notes should be updated to match. This is non-blocking because the Forgejo issue is the implementation authority, and it is correct.
Recommendation
[SCOPE]Updatearch-keycloak-kalshi-assistant: change "direct grant / public client / ROPC" references to "Auth Code + PKCE / confidential client / standard flow". Fix diagram, components table, and key decisions section.[SCOPE]Updatearch-auth: change "direct grant (username + password)" to "Auth Code + PKCE via ASWebAuthenticationSession". Fix diagram, components table, and key decisions section.
- [x] Theme file paths corrected from
-
Review: Spike: Mobile framework decision
review-1698-2026-07-02Verdict: READY
Template Completeness
Validated against
template-issue-spike.- [x] Type — Spike
- [x] Lineage — Related to
ldraney/kalshi-assistant #6(parent issue). Decision gate for all mobile app work in sprint 4. - [x] Repo —
ldraney/kalshi-assistant - [x] Question — Main question with 5 sub-questions covering Rails+Turbo Native+Capacitor, PWA, React Native/Flutter, secure storage, and developer velocity
- [x] Deliverables — 3 deliverables: ADR doc, follow-up ticket updates, decision record
- [x] Time-box — 1 session, with escalation path
- [x] Related — Project and parent issue linked
Traceability
- [x] story:app-experience label — App Experience
- [x] story note verified —
story-kalshi-assistant-app-experiencefound in project-kalshi-assistant user-stories section - [x] arch:frontend label — Frontend
- [x] arch note verified —
arch-frontendnote exists in pal-e-docs (title: "Frontend: kalshi-assistant", status: active) - [x] Forgejo issue —
ldraney/kalshi-assistant #13, open
File Targets
- [x]
docs/architecture/mobile-framework-adr.md— target deliverable. Directorydocs/architecture/does not exist yet; will be created as part of the spike. Parentdocs/exists. Appropriate for a spike that produces docs.
Repo Placement
OK. Issue filed on
ldraney/kalshi-assistant, matches### Repofield. Single-repo investigation.Dependencies
- Parent: #1691 (issue #6) "Mobile app — API key connection and strategy dashboard" (backlog, sprint 4, 8pts) — documented in Lineage
- Downstream sprint 4 frontend items blocked by this decision:
- #1699 (issue #14) "Credential input and management UI" (backlog, 2pts)
- #1700 (issue #15) "Strategy and budget configuration UI" (backlog, 1pt)
- #1701 (issue #16) "Live strategy dashboard" (backlog, 2pts)
- #1702 (issue #17) "Trade history and performance" (backlog, 1pt)
- No items in
in_progressblock this spike - Dependencies documented in issue Lineage section: "Decision gate for all mobile app work in sprint 4"
Acceptance Criteria
Spike uses Deliverables instead of Acceptance Criteria (per template). Assessment:
docs/architecture/mobile-framework-adr.mdcreated — verifiable by file existence and ADR content check- Follow-up ticket file targets updated — verifiable by checking issue #6 children for revised file paths
- Team decision recorded with rationale — verifiable by ADR content inspection (somewhat redundant with deliverable 1, but acceptable)
All deliverables are agent-verifiable.
Blast Radius
- Decision affects all 5 sprint 4 frontend items (all currently in backlog)
- No existing code in the repo (docs only) — no breaking changes possible
- Note:
arch-frontendalready documents "Turbo Native iOS shell wrapping Rails views with Capacitor native bridge". This spike may confirm or revise that assumption. No conflict — spikes are intended for exactly this kind of validation. - No sibling services or downstream consumers affected
Decomposition Assessment
No decomposition needed.
- File targets: 1 docs file
- Deliverables: 3 (all part of single investigation)
- Repos: 1
- Estimated work: 1 session (within time-box)
Recommendation
No action needed.
-
Review: Trade history and performance
review-1702-2026-07-02Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references parent #6 and dependency #3
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- well-formed As/I want/So that
- [x] Context -- explains trade records origin, read-only nature, navigation flow
- [x] File Targets -- 2 targets (controller + views), clear boundary with DO NOT TOUCH list
- [x] Feature Flag -- mobile_trade_history specified (note: no docs/feature-flags.md exists yet in repo; template says skip with "none" when absent, but forward planning is acceptable)
- [x] Acceptance Criteria -- 4 criteria, all testable
- [x] Test Expectations -- unit + integration tests with run command
- [x] Constraints -- model ownership boundary, pagination, Turbo Frames
- [x] Checklist -- standard 3-item checklist
- [x] Related -- project slug and parent/dependency issues
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder story
- [x] story note verified -- story-kalshi-assistant-portfolio-builder exists in pal-e-docs
- [x] story entry verified -- portfolio-builder row found in project-kalshi-assistant user-stories section
- [x] arch:frontend label -- Frontend architecture component
- [x] arch note verified -- arch-frontend note exists in pal-e-docs (Turbo Native iOS shell, Hotwire/Turbo views)
- [x] Forgejo issue -- ldraney/kalshi-assistant#17, state: open
File Targets
- [x] app/controllers/trades_controller.rb -- to be created. Standard Rails controller path. Consistent with scaffold pattern from #1.
- [x] app/views/trades/ -- to be created. Standard Rails view directory. Consistent with Rails conventions.
- [x] DO NOT TOUCH boundary -- app/models/trade.rb (owned by #3), app/controllers/dashboard_controller.rb (separate ticket). Clean ownership separation.
Note: The Rails app does not exist yet (greenfield project). File targets cannot be verified against existing code because dependencies #1 (Rails scaffold) and #3 (strategy engine) have not been implemented. Paths follow standard Rails conventions and are reasonable.
Repo Placement
OK -- issue filed on ldraney/kalshi-assistant, file targets are Rails files in the same repo. Single-repo ticket, no cross-repo concerns.
Dependencies
- #1 (Rails app scaffold) -- implicit dependency, currently in todo column (sprint 1)
- #3 (Strategy engine -- trade records) -- explicit dependency, currently in todo column (sprint 2). Provides the Trade model this ticket consumes.
- #16 (Live strategy dashboard) -- explicit dependency ("navigation context comes from the dashboard"), currently in backlog column (sprint 4). Same sprint but dashboard links to trade history.
- #6 (Mobile app) -- parent issue, currently in backlog (sprint 4).
Dependencies are documented in the Lineage section. Sprint ordering is correct: sprint 1 and 2 dependencies must complete before this sprint 4 work begins.
Acceptance Criteria
4 criteria, all verifiable by an agent:
- Trade history table sorted by date (newest first) -- verifiable via integration test
- Filter by date range -- verifiable via controller test
- Filter by market or outcome -- verifiable via controller test
- Summary stats (P&L, win rate, total trades) -- verifiable via unit test
Test run command is valid: bin/rails test test/controllers/trades_controller_test.rb
Blast Radius
Minimal. This is a read-only view ticket -- it adds a controller and views that consume data from the Trade model (owned by #3). No data mutations. No downstream consumers. No cross-service impact. The Turbo Frames constraint keeps updates scoped to the trades page.
Decomposition Assessment
No decomposition needed.
- 2 file targets in 1 repo -- under threshold
- 4 acceptance criteria -- under threshold
- Estimated agent work: well under 5 minutes (standard CRUD controller + views)
- 1 point ticket -- correctly sized
Recommendation
No action needed. Scope is solid, traceability complete, and ticket is correctly sized for a single agent pass.
Minor observation: The Feature Flag section specifies mobile_trade_history but the repo has no docs/feature-flags.md. Per template guidance, this should be "none" when no flag infrastructure exists. However, this is forward planning and not blocking -- the flag can be implemented when the flag infrastructure is created as part of the Rails scaffold or a separate ticket.
-
Review: Credential input and management UI
review-1699-2026-07-02Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references parent #6, dependencies on spike, #10, #1
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- As a Kalshi trader / securely enter and manage API credentials
- [x] Context -- explains Kalshi API key ID + RSA private key requirement, encryption at rest, credential verification flow
- [x] File Targets -- 3 create targets, 2 do-not-touch targets
- [x] Feature Flag -- mobile_credential_management, global, disabled by default
- [x] Acceptance Criteria -- 5 criteria in when/then format
- [x] Test Expectations -- 4 tests with run command
- [x] Constraints -- encryption, pattern adherence, error handling, one-set-per-user
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project, parent, dependencies
Traceability
- [x] story:credential-onboarding label -- Credential Onboarding
- [x] story note verified -- found in project-kalshi-assistant user-stories section (key: credential-onboarding, role: Consumer, metric: 90% of users complete setup without support)
- [x] arch:frontend label -- Frontend component
- [x] arch note verified -- arch-frontend note exists ("Frontend: kalshi-assistant", architecture, active)
- [x] arch:auth label -- Authentication component
- [x] arch note verified -- arch-auth note exists ("Authentication: kalshi-assistant", architecture, active)
- [x] Forgejo issue -- ldraney/kalshi-assistant#14, open
File Targets
- [x] app/controllers/credentials_controller.rb -- TO CREATE: standard Rails CRUD controller. Does not exist yet (expected: depends on Rails scaffold #1).
- [x] app/views/credentials/ -- TO CREATE: form views for key input, status display, verification. Does not exist yet (expected).
- [x] app/models/credential.rb -- TO CREATE: model with encrypted attributes. Does not exist yet (expected).
- [x] Do-not-touch: app/controllers/dashboard_controller.rb -- correctly scoped out (separate ticket)
- [x] Do-not-touch: app/controllers/strategies_controller.rb -- correctly scoped out (separate ticket)
Note: No application code exists yet. The repo is docs-only. All file targets are to-be-created, which is correct since this ticket depends on Rails scaffold (#1) being completed first. The Kalshi API docs confirm RSA-PSS key-pair signing, consistent with the ticket's description of API key ID + RSA private key storage.
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, matches ### Repo field. Single-repo scope.
Dependencies
- #1 (Rails app scaffold with Kalshi API client) -- board item #1686, todo column -- DOCUMENTED in Lineage, BLOCKING
- #10 (Keycloak realm, client, users, and login theme) -- board item #1693, todo column -- DOCUMENTED in Lineage, BLOCKING
- #13 (Spike: Mobile framework decision) -- board item #1698, backlog column -- DOCUMENTED as "spike (child of #6)" in Lineage, BLOCKING
All three dependencies are correctly identified in the Lineage section and none are complete yet. This ticket is appropriately in backlog until its dependencies move through the pipeline.
Acceptance Criteria
5 criteria, all in clear when/then format and verifiable by an agent:
- Form with API key ID and RSA private key fields (PEM paste or file upload) -- verifiable via view rendering
- Submit valid credentials -> stored encrypted + success message -- verifiable via model test + integration test
- Verify Credentials button -> test API call + status display -- verifiable via controller test with mocked API
- Update existing credentials -- verifiable via CRUD integration test
- Revoke credentials with confirmation dialog -- verifiable via destroy action test
Test expectations include 4 tests with a concrete run command. Testable and complete.
Blast Radius
Minimal. Greenfield application with no existing code. The Kalshi API docs (docs/api/overview.md, docs/api/openapi.yaml) confirm the RSA-PSS signing approach matches what the ticket specifies. No downstream consumers to affect. No sibling services to check for similar patterns.
Decomposition Assessment
- 3 file targets in 1 repo -- OK (under threshold of >3 across >2 repos)
- 5 acceptance criteria -- OK (not exceeding 5)
- Estimated agent work: under 5 minutes (standard Rails CRUD + encrypted attributes) -- OK
No decomposition needed.
Recommendation
No action needed. Scope is solid, traceability is complete, template is filled, and the ticket fits comfortably in a single agent pass.
-
Review: Live strategy dashboard
review-1701-2026-07-02Verdict: READY
Re-review: Previous review incorrectly flagged arch-frontend and arch-app as missing. Both confirmed to exist. Verdict upgraded from NEEDS_REFINEMENT to READY.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references parent #6, dependencies #4 and #1
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- As a Kalshi trader, I want a real-time dashboard...
- [x] Context -- explains dashboard purpose, Turbo Streams approach, traffic expectations
- [x] File Targets -- 3 create targets, 2 do-not-touch entries
- [x] Feature Flag -- mobile_live_dashboard, global, disabled by default
- [x] Acceptance Criteria -- 4 When/Then criteria
- [x] Test Expectations -- unit + integration tests with run command
- [x] Constraints -- Turbo Streams, mobile perf, Rails patterns, edge cases
- [x] Checklist -- standard 3-item checklist
- [x] Related -- project, parent, and dependency references
Traceability
- [x] story:app-experience label -- "App Experience" story
- [x] story note verified -- found in project-kalshi-assistant user-stories section (key: app-experience, role: Consumer)
- [x] arch:frontend label -- "Frontend: kalshi-assistant"
- [x] arch note verified -- arch-frontend (id 2343) exists in pal-e-docs, status active, project kalshi-assistant
- [x] arch:app label -- "Application Domain: Kalshi Assistant"
- [x] arch note verified -- arch-app (id 2349) exists in pal-e-docs, status active, project kalshi-assistant
- [x] Forgejo issue -- ldraney/kalshi-assistant#16, state: open
File Targets
- [x] app/controllers/dashboard_controller.rb -- to be created; follows Rails convention; parent directory will exist after #1 (Rails scaffold)
- [x] app/views/dashboard/ -- to be created; standard Rails view directory
- [x] app/channels/dashboard_channel.rb -- to be created; Action Cable channel for Turbo Streams
- [x] Do-not-touch: app/services/watchdog_service.rb (from #4) -- correctly scoped out
- [x] Do-not-touch: app/controllers/trades_controller.rb (separate ticket) -- correctly scoped out
Note: No app/ directory exists yet. This is expected -- the Rails scaffold (#1) must complete first. All file targets are new files to create, following standard Rails conventions.
Repo Placement
OK. Issue filed in ldraney/kalshi-assistant; all work targets the same repo. Single-repo scope.
Dependencies
- #1 (Rails app scaffold) -- in todo column. Hard dependency: provides app/ directory structure and base controller patterns. Must complete before this ticket starts.
- #4 (Watchdog) -- in todo column. Data dependency: watchdog generates the strategy status data displayed on the dashboard. Must complete before dashboard can show real watchdog data.
- #6 (Mobile app parent) -- in backlog. This is the parent decomposition issue; not a blocking dependency.
- Credential UI (child of #6) -- referenced in Lineage; not a direct blocker for dashboard functionality.
Dependencies are correctly documented in the Lineage section. Sprint ordering (sprint:4) aligns with dependency chain (#1 sprint:1, #4 sprint:3).
Acceptance Criteria
4 criteria, all in When/Then format. Each is agent-verifiable:
- AC1: Active positions with market prices -- verifiable via controller test and integration test
- AC2: Watchdog trigger status display -- verifiable via integration test with mock data
- AC3: Real-time updates via Turbo Streams -- verifiable via Action Cable integration test
- AC4: P&L display (unrealized + realized) -- verifiable via unit test on calculation logic
Test expectations include specific test file paths and a run command. Complete and testable.
Blast Radius
Minimal. Greenfield feature in a repo with no existing application code. No downstream consumers affected. Dashboard reads from services defined in other tickets (#4 watchdog, #2 market scanner) but does not modify them.
Decomposition Assessment
No decomposition needed.
- 3 file targets in 1 repo -- under threshold (max 3 across 2+ repos)
- 4 acceptance criteria -- under threshold (max 5)
- 2 story points -- fits single agent pass well under 5-minute estimate
Recommendation
No action needed. Scope is solid, traceability is complete (including backing notes for both arch labels and user story), template is fully populated, and the ticket fits in a single agent pass.
-
Review: Strategy and budget configuration UI
review-1700-2026-07-02Verdict: APPROVED
Re-review of board item #1700. Previous review incorrectly flagged arch-frontend and arch-app as missing. Both architecture notes exist and are verified.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references parent #6 and dependencies #3, #1
- [x] Repo -- ldraney/kalshi-assistant
- [x] User Story -- present
- [x] Context -- present, explains relationship to strategy engine and watchdog
- [x] File Targets -- present (create targets + do-not-touch boundaries)
- [x] Feature Flag -- mobile_strategy_config, global, disabled by default
- [x] Acceptance Criteria -- 4 items
- [x] Test Expectations -- unit + integration with run command
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:portfolio-builder label -- AI Portfolio Builder
- [x] story note verified -- story-kalshi-assistant-portfolio-builder exists (id 2321, active)
- [x] story entry verified -- found in project-kalshi-assistant user-stories section
- [x] arch:frontend label -- Frontend: kalshi-assistant
- [x] arch note verified -- arch-frontend exists (id 2343, active)
- [x] arch:app label -- Application Domain: Kalshi Assistant
- [x] arch note verified -- arch-app exists (id 2349, active)
- [x] Forgejo issue -- ldraney/kalshi-assistant#15, open
File Targets
- [x] app/controllers/strategies_controller.rb -- to create: CRUD for strategy configuration. Repo is greenfield (no Rails structure yet), appropriate since this depends on #1 Rails scaffold (sprint:1)
- [x] app/views/strategies/ -- to create: strategy selection form, parameter config, budget allocation. Same greenfield note applies
- [x] app/models/strategy.rb -- correctly marked as do-not-touch (owned by #3)
- [x] app/services/watchdog_service.rb -- correctly marked as do-not-touch (owned by #4)
Repo Placement
OK. Issue filed on ldraney/kalshi-assistant, Repo section specifies ldraney/kalshi-assistant. Single repo, no cross-repo concerns.
Dependencies
- #1 (Rails scaffold, sprint:1) -- hard dependency, provides base app structure. Board item 1686, currently in todo.
- #3 (Strategy engine DB schema, sprint:2) -- hard dependency, defines the Strategy model this UI reads/writes. Board item 1688, currently in todo.
- #4 (Watchdog, sprint:3) -- soft dependency, this UI must match the watchdog service interface for configuration parameters. Board item 1689, currently in todo.
- #6 (Mobile app, sprint:4) -- parent issue. Board item 1691, currently in backlog.
- All dependencies are documented in the issue's Lineage, Context, and Constraints sections. Sprint ordering is correct: 1 -> 2 -> 3 -> 4.
Acceptance Criteria
4 criteria, all agent-verifiable. Test expectations include unit and integration tests with specific run command (bin/rails test). Criteria cover CRUD operations and budget validation logic. No missing criteria for the stated scope.
Blast Radius
Low. Creates new controller and views only. Explicitly boundaries off the strategy model (#3) and watchdog service (#4). No existing code to conflict with (greenfield repo). Feature flag gates the new UI surface.
Decomposition Assessment
No decomposition needed. 2 file targets in 1 repo, 4 acceptance criteria, estimated agent work under 5 minutes. Well within single-pass scope.
Recommendation
No action needed.
Architecture 13
-
Architecture: Kubernetes Deployment
arch-k8s-deployKubernetes Deployment: prediction-assistant
How prediction-assistant is deployed to the k3s cluster. Kustomize overlays define environment-specific configuration, Woodpecker CI builds and pushes images to Harbor, and ArgoCD syncs manifests to the cluster. Tailscale funnel + Traefik ingress handle HTTPS routing.
Diagram
graph TB subgraph CI["Woodpecker CI"] TEST["bin/rails test"] BUILD["docker buildx
build + push"] end subgraph Registry["Harbor Registry"] IMG["harbor.tail5b443a.ts.net
/ldraney/prediction-assistant
:SHA / :latest"] end subgraph Repo["prediction-assistant repo"] K8S_BASE["k8s/base/
deployment, worker, service, configmap"] K8S_PROD["k8s/overlays/prod/
ingress, cluster-issuer, patches"] K8S_DEV["k8s/overlays/dev/
resource patches"] K8S_MON["k8s/monitoring/
service-monitor, rules, grafana"] end subgraph ArgoCD["ArgoCD"] APP["Application CR
prediction-assistant"] end subgraph Cluster["k3s Cluster — prediction-assistant namespace"] WEB["Deployment: web
bin/rails server"] WORKER["Deployment: worker
bin/rails solid_queue:start"] SVC["Service: ClusterIP :80 → :3000"] ING["Traefik Ingress
prediction-assistant.com"] TLS["cert-manager
Let's Encrypt TLS"] FUNNEL["Tailscale Funnel
HTTPS entrypoint"] end TEST -->|pass| BUILD BUILD --> IMG IMG --> APP K8S_PROD --> APP APP -->|sync| WEB APP -->|sync| WORKER APP -->|sync| SVC APP -->|sync| ING ING --> TLS FUNNEL --> ING SVC --> WEBDirectory Structure
k8s/ ├── base/ │ ├── kustomization.yaml # namespace: prediction-assistant, shared labels │ ├── deployment.yaml # web pod (Rails server, port 3000) │ ├── worker-deployment.yaml # Solid Queue worker pod │ ├── service.yaml # ClusterIP :80 → :3000 │ └── configmap.yaml # RAILS_ENV, log, threads, port ├── overlays/ │ ├── prod/ │ │ ├── kustomization.yaml # 2 web replicas, prod resources, log=info │ │ ├── ingress.yaml # Traefik ingress for prediction-assistant.com │ │ ├── cluster-issuer.yaml # Let's Encrypt ACME via cert-manager │ │ └── redirect-middleware.yaml # HTTP → HTTPS redirect │ └── dev/ │ └── kustomization.yaml # 1 replica each, smaller limits, log=debug └── monitoring/ ├── service-monitor.yaml # Prometheus scrape config (/metrics, 30s) ├── prometheus-rules.yaml # Golden signal alerts └── grafana-dashboard-configmap.yamlComponents
Component Purpose Notes Base Kustomization Shared resources for all environments Sets namespace prediction-assistant, common labels (app.kubernetes.io/name,managed-by)Web Deployment Rails application server Image from Harbor, init container runs db:preparebefore server start, liveness/readiness on/upWorker Deployment Solid Queue background job processor Same image, runs bin/rails solid_queue:start, liveness viapgrep -f solid_queueService ClusterIP routing to web pods Port 80 → targetPort 3000 ConfigMap Non-secret environment variables RAILS_ENV=production, RAILS_LOG_TO_STDOUT=true, RAILS_MAX_THREADS=3, PORT=3000 Secrets (external) Sensitive credentials prediction-assistant-secrets: DATABASE_URL, SECRET_KEY_BASE, KALSHI_API_KEY_ID, KALSHI_PRIVATE_KEY (API keys optional)Image Build & Push
Woodpecker CI (
.woodpecker.yaml) handles the build pipeline:- Test step: Runs
bin/rails testagainst a Postgres 16 sidecar service. - Build-push step (main branch only): Uses
woodpeckerci/plugin-docker-buildxto build a multi-stage Docker image and push to Harbor.
Tags pushed:
${CI_COMMIT_SHA}andlatest. Registry:harbor.tail5b443a.ts.net/ldraney/prediction-assistant.The Dockerfile uses a two-stage build: build stage (ruby:3.4.9-slim) installs gems, precompiles bootsnap + assets; runtime stage copies artifacts into a minimal image running as non-root user
rails(UID 1000).Kustomize Overlays
Setting Dev Prod Web replicas 1 2 Worker replicas 1 1 Web CPU request/limit 50m / 250m 200m / 1 core Web memory request/limit 128Mi / 256Mi 512Mi / 1Gi Worker CPU request/limit 50m / 250m 200m / 1 core Worker memory request/limit 128Mi / 256Mi 512Mi / 1Gi RAILS_LOG_LEVEL debug info Ingress / TLS none Traefik + Let's Encrypt ArgoCD Sync Pattern
ArgoCD watches the repo's
k8s/overlays/prodpath (registered via theargocd-appTerraform module in pal-e-services). On each merge to main:- Woodpecker CI builds and pushes a new image tagged with the commit SHA +
latest. - ArgoCD detects manifest changes and syncs the Kustomize overlay.
- Kubernetes pulls the updated image from Harbor using the robot-account pull secret provisioned by the
harbor-robotTerraform module.
Ingress & TLS
Production ingress chain:
- Tailscale Funnel — Public HTTPS entrypoint provisioned by the
tailscale-funnelTerraform module. Maps external traffic into the Tailscale network. - Traefik Ingress Controller — Routes
prediction-assistant.comto theprediction-assistant-webClusterIP service. - cert-manager ClusterIssuer —
letsencrypt-prodissues TLS certificates via HTTP-01 challenge through Traefik. - Redirect Middleware — Traefik middleware forces HTTP → HTTPS with a permanent redirect.
DNS (managed in pal-e-platform via the
godaddy-dnsTerraform module) pointsprediction-assistant.comto the Tailscale funnel address.Monitoring
The
k8s/monitoring/directory defines observability resources:- ServiceMonitor: Prometheus scrapes
/metricsevery 30s from pods in theprediction-assistantnamespace. - PrometheusRule: Golden-signal alerts — HTTP error rate > 5%, p95 latency > 2s, pod not ready for 5m, Solid Queue failures or backlog > 100 jobs.
- Grafana dashboard: ConfigMap-provisioned dashboard for at-a-glance service health.
Key Decisions
- Kustomize over Helm: The app's configuration is simple enough that Kustomize overlays (base + patches) keep things readable without Helm templating complexity.
- In-repo manifests: k8s manifests live alongside application code in the
k8s/directory. Changes to infrastructure and code ship together in the same PR. - Init container for migrations: The web deployment runs
db:preparein an init container, ensuring schema is ready before the server starts. Only the web pod runs migrations; the worker relies on web readiness. - Separate web and worker deployments: Allows independent scaling and resource allocation. The worker runs Solid Queue for background jobs (market scanning, order execution).
- Harbor robot accounts: Pull secrets are provisioned by Terraform (pal-e-services), not manually created. Scoped to the prediction-assistant Harbor project.
- Tailscale funnel over NodePort/LoadBalancer: No cloud load balancer needed on bare-metal k3s. Tailscale funnel provides a stable public entrypoint with automatic TLS.
- Non-root container: Runtime image runs as UID 1000 (rails user) for security best practice.
- Docker buildx over kaniko: Woodpecker CI uses
plugin-docker-buildxfor multi-stage builds. Tags both:SHAand:latest.
Related
- IaC: prediction-assistant — Terraform modules that provision namespace, Harbor, ArgoCD app, funnel
- Kustomize Overlays: prediction-assistant
- Observability: prediction-assistant
- Test step: Runs
-
Kustomize Overlays: prediction-assistant
arch-kustomizeKustomize Overlays: kalshi-assistant
Directory structure and overlay strategy for kalshi-assistant manifests in pal-e-deployments. Follows the pattern established by landscaping-assistant. Two overlays: prod (full cluster deployment) and dev (nginx proxy to developer workstation).
Diagram
graph TB subgraph PalEDeployments["pal-e-deployments repo"] subgraph KalshiDir["kalshi-assistant/"] subgraph Base["base/"] B_KUST["kustomization.yaml"] B_DEPLOY["deployment.yaml"] B_SVC["service.yaml"] B_CM["configmap.yaml"] end subgraph Prod["overlays/prod/"] P_KUST["kustomization.yaml"] P_NS["namespace.yaml"] P_ING["ingress.yaml"] P_SM["servicemonitor.yaml"] P_RENAME["rename-patches.yaml"] end subgraph Dev["overlays/dev/"] D_KUST["kustomization.yaml"] D_NGINX["nginx-proxy-conf"] D_DEPLOY["deployment-override.yaml
(nginx image)"] D_CM["configmap.yaml
(dev machine IP)"] end end end subgraph Targets["Deployment Targets"] PROD_K8S["Prod: k3s cluster
real app pods"] DEV_K8S["Dev: k3s cluster
nginx proxy to dev machine"] end Base --> Prod Base --> Dev Prod --> PROD_K8S Dev --> DEV_K8SComponents
Component Purpose Notes base/deployment.yaml Core deployment spec shared by all overlays Container image, ports, resource limits, health probes base/service.yaml ClusterIP service exposing the app port Referenced by ingress (prod) and nginx proxy (dev) base/configmap.yaml Shared configuration values Environment-specific values patched by overlays overlays/prod/namespace.yaml Namespace resource for prod Created by IaC but declared here for completeness overlays/prod/ingress.yaml Ingress resource for Tailscale funnel routing Routes external traffic to the service overlays/prod/servicemonitor.yaml Prometheus ServiceMonitor for metrics scraping Targets the /metrics endpoint; see arch-observability overlays/prod/rename-patches.yaml Strategic merge patches for prod naming Adds namespace prefix, labels, annotations for prod context overlays/dev/nginx-proxy-conf Nginx config that proxies to dev machine IP Enables cluster-hosted dev URL pointing to localhost dev server overlays/dev/deployment-override.yaml Replaces app container with nginx Nginx image serves as reverse proxy to dev workstation overlays/dev/configmap.yaml Dev machine IP and port Updated when developer's Tailscale IP changes Key Decisions
- Landscaping-assistant as reference pattern: kalshi-assistant follows the exact directory structure and overlay strategy proven by landscaping-assistant. Consistency across services reduces cognitive load.
- Dev overlay uses nginx proxy, not port-forward: Instead of running the app in-cluster during development, the dev overlay deploys an nginx reverse proxy that forwards traffic to the developer's local machine. This gives a real cluster URL while the developer iterates locally.
- Prod overlay includes ServiceMonitor: Observability is wired in at the deployment level, not bolted on later. Every prod deployment includes its ServiceMonitor for Prometheus scraping.
- Rename patches for namespace scoping: Strategic merge patches handle namespace-specific naming so the base manifests remain environment-agnostic.
- No Helm: Plain Kustomize overlays with YAML patches. The complexity budget is spent on getting the overlay structure right, not on a templating engine.
Related
-
Observability: prediction-assistant
arch-observabilityObservability: kalshi-assistant
Monitoring, alerting, and dashboards for kalshi-assistant. All observability resources are configured in pal-e-platform under
terraform/modules/monitoring/main.tf, following the patterns established by existing services.Diagram
graph TB subgraph KalshiNS["kalshi-assistant namespace"] APP["kalshi-assistant pod
/metrics endpoint"] SM["ServiceMonitor
(from Kustomize prod overlay)"] end subgraph Monitoring["monitoring namespace"] PROM["Prometheus"] AM["AlertManager"] RULES["PrometheusRules
(golden signals)"] BB["blackbox-exporter"] GRAF["Grafana"] end subgraph PalEPlatform["pal-e-platform repo"] TF_MON["terraform/modules/
monitoring/main.tf"] TF_RULES["alert rules
(per-service block)"] TF_BB["blackbox targets
(probe list)"] TF_DASH["dashboard JSON
(golden signals)"] end subgraph Alerts["Alert Destinations"] EMAIL["Email notifications"] WEBHOOK["Webhook receivers"] end SM -->|scrape config| PROM PROM -->|evaluates| RULES RULES -->|fires| AM AM --> EMAIL AM --> WEBHOOK BB -->|HTTP probes| APP PROM -->|data source| GRAF TF_MON --> RULES TF_MON --> TF_BB TF_MON --> TF_DASH TF_RULES -.->|defines| RULES TF_BB -.->|defines| BB TF_DASH -.->|provisions| GRAFComponents
Component Purpose Notes ServiceMonitor Tells Prometheus to scrape kalshi-assistant's /metrics endpoint Deployed via Kustomize prod overlay; matches service labels PrometheusRules Alert rules for golden signals (latency, traffic, errors, saturation) Defined in pal-e-platform monitoring module; follows existing service patterns AlertManager Routes and deduplicates alerts Shared cluster-wide; per-service routing via labels blackbox-exporter External HTTP probes for uptime monitoring Probes the public Tailscale funnel URL; alerts on non-2xx responses Grafana dashboards Golden signals dashboard for kalshi-assistant Request rate, error rate, latency percentiles, resource utilization monitoring/main.tf Terraform that provisions all monitoring resources Adding kalshi-assistant means adding a service block following the existing pattern Key Decisions
- Golden signals framework: Every service dashboard tracks the four golden signals (latency, traffic, errors, saturation). This standardization means any team member can read any service dashboard without learning a new layout.
- Monitoring as code in pal-e-platform: Alert rules, blackbox targets, and dashboards are Terraform resources, not manual Grafana/Prometheus config. Changes are reviewed in PRs and applied deterministically.
- Blackbox probes for external perspective: In addition to internal metrics scraping, blackbox-exporter probes the public URL. This catches issues that internal metrics miss (DNS, Tailscale funnel, TLS).
- Follow existing service patterns: kalshi-assistant's monitoring block mirrors the structure used by other services in main.tf. Copy-paste-adapt, not reinvent.
- ServiceMonitor in Kustomize, rules in Terraform: The scrape target (ServiceMonitor) lives with the deployment manifests. The alert rules and dashboards live in the platform repo. This split matches ownership: app team owns what to expose, platform owns how to alert on it.
Related
-
IaC: prediction-assistant
arch-iacInfrastructure as Code: kalshi-assistant
How infrastructure is provisioned for the kalshi-assistant service. OpenTofu (Terraform) modules in pal-e-services onboard each new service, while pal-e-platform manages shared platform resources like DNS.
Diagram
graph TB subgraph Developer["Developer Workstation"] TF["tofu apply
(pal-e-services)"] TF_PLAT["tofu apply
(pal-e-platform)"] end subgraph PalEServices["pal-e-services repo"] TFVARS["k3s.tfvars
service definitions"] MOD_NS["module: namespace"] MOD_HARBOR["module: harbor-robot"] MOD_ARGO["module: argocd-app"] MOD_TS["module: tailscale-funnel"] end subgraph PalEPlatform["pal-e-platform repo"] DNS_MOD["module: godaddy-dns"] GODADDY["GoDaddy API"] end subgraph K3s["k3s Cluster"] NS["kalshi-assistant
namespace"] ROBOT["Harbor robot account
+ pull secret"] ARGOAPP["ArgoCD Application
kalshi-assistant"] FUNNEL["Tailscale Funnel
HTTPS ingress"] end TF --> TFVARS TFVARS --> MOD_NS --> NS TFVARS --> MOD_HARBOR --> ROBOT TFVARS --> MOD_ARGO --> ARGOAPP TFVARS --> MOD_TS --> FUNNEL TF_PLAT --> DNS_MOD --> GODADDYComponents
Component Purpose Notes k3s.tfvars Declares kalshi-assistant as a service entry Single source of truth for namespace name, Harbor project, ArgoCD app name, funnel hostname namespace module Creates k8s namespace Idempotent; includes resource quotas and labels harbor-robot module Creates Harbor robot account and k8s pull secret Scoped to the service's Harbor project; secret placed in namespace argocd-app module Registers ArgoCD Application CR Points at pal-e-deployments repo path for this service tailscale-funnel module Provisions Tailscale funnel for HTTPS ingress Maps public hostname to internal k8s service godaddy-dns module Manages DNS records via GoDaddy API Lives in pal-e-platform; CNAME or A records pointing to Tailscale funnel Key Decisions
- OpenTofu over raw kubectl: Declarative state management prevents drift and enables reproducible onboarding. Every new service follows the same module pattern.
- Split repos (services vs platform): pal-e-services handles per-service resources; pal-e-platform handles shared infra (DNS, monitoring). Separation of concerns keeps blast radius small.
- tfvars-driven onboarding: Adding a new service means adding an entry to k3s.tfvars rather than writing new Terraform. This keeps onboarding fast and consistent.
- GoDaddy DNS via Terraform: DNS is managed as code alongside infrastructure, not manually in a web console. Changes are auditable in git.
Related
-
API Integration
Kalshi REST API integration layer. Answers: how does the app communicate with the Kalshi exchange?
Diagram
sequenceDiagram participant App as kalshi-assistant participant Auth as RSA-PSS Signer participant API as Kalshi API /trade-api/v2 participant WS as Kalshi WebSocket Note over App,WS: Authenticated Request Flow App->>Auth: Sign {timestamp}{METHOD}{path} Auth->>App: RSA-PSS SHA-256 signature App->>API: Request + KALSHI-ACCESS-KEY + KALSHI-ACCESS-TIMESTAMP + KALSHI-ACCESS-SIGNATURE API->>App: JSON response Note over App,WS: Market Scanning (Read Path) App->>API: GET /markets?series_ticker={series} API->>App: Market list with yes_bid, no_bid App->>API: GET /markets/{ticker}/orderbook API->>App: Orderbook depth Note over App,WS: Order Execution (Write Path) App->>API: POST /portfolio/orders API->>App: Order confirmation App->>API: GET /portfolio/positions API->>App: Current positions Note over App,WS: Real-time Monitoring App->>WS: Connect + authenticate WS->>App: Market updates (streaming)Components
Component Purpose Notes RSA-PSS Signer Signs each API request with user's private key RSA-PSS SHA-256. Signs {timestamp_ms}{HTTP_METHOD}{path} Kalshi REST API Exchange API for markets, orders, portfolio Base: https://external-api.kalshi.com/trade-api/v2 Kalshi WebSocket Real-time market data streaming wss://api.kalshi.com/trade-api/ws/v2 Demo API Sandbox environment for development https://external-api.demo.kalshi.co/trade-api/v2 Key Decisions
- RSA-PSS over session tokens — Kalshi requires per-request RSA-PSS SHA-256 signing. No OAuth, no session cookies. Each request carries three headers: KALSHI-ACCESS-KEY, KALSHI-ACCESS-TIMESTAMP, KALSHI-ACCESS-SIGNATURE.
- Basic tier rate limits constrain scanning — 20 reads/sec and 10 writes/sec at Basic tier. Watchdog strategy (scanning all live markets) must stay within these bounds. Poll only same-day markets, batch where possible.
- Demo-first development — All development and testing against demo.kalshi.co. Production keys used only in deployed app with real user accounts.
- No fund handling — The app never touches deposits or withdrawals. All money flows through Kalshi directly. We only read balances and execute trades via API.
- WebSocket for live monitoring — REST polling is sufficient for market scanning at Basic tier, but WebSocket provides real-time updates for active position monitoring without burning read quota.
Rate Limits
Tier Read/sec Write/sec Basic 20 10 Advanced 30 30 Premier 100 100 Prime 400 400 Key Endpoint Groups
Group Key Endpoints Usage Markets GET /markets, GET /markets/{ticker}/orderbook Market scanning, orderbook analysis Orders POST /portfolio/orders, DELETE /portfolio/orders/{id} Trade execution and cancellation Portfolio GET /portfolio/positions, GET /portfolio/balance Position tracking, balance checks Events GET /events, GET /events/{ticker} Event metadata, fee schedules Related
-
Frontend: prediction-assistant
arch-frontendFrontend Architecture
Turbo Native iOS shell wrapping Rails views with Capacitor native bridge. Answers: how does the user interact with the app?
Diagram
graph TB subgraph iOS["iOS App (Turbo Native)"] TN[Turbo Native Shell] CAP[Capacitor Bridge] PUSH[Push Notifications] end subgraph Rails["Rails Server"] VIEWS["Rails Views (Hotwire/Turbo)"] API_C[API Controllers] TF[Turbo Frames] TS[Turbo Streams] end subgraph Dashboard["Strategy Dashboard"] POS[Live Positions] HIST[Trade History] WATCH[Watchdog Triggers] PERF[Performance Metrics] end TN -->|"loads HTML"| VIEWS CAP -->|"native APIs"| TN PUSH -->|"alerts"| TN VIEWS --> TF VIEWS --> TS TF --> Dashboard TS -->|"real-time updates"| POS API_C -->|"JSON"| CAPComponents
Component Purpose Notes Turbo Native Shell iOS wrapper that renders Rails HTML views natively No React Native or Flutter. Server-rendered HTML with native navigation chrome. Capacitor Bridge Native API access from web views Biometric auth, push notifications, secure keychain storage for API keys Rails Views (Hotwire) Server-rendered UI with Turbo Frames and Streams Strategy dashboard, position views, trade history Turbo Frames Partial page updates without full reload Dashboard sections update independently Turbo Streams Real-time DOM updates via WebSocket Live position values, watchdog trigger alerts Strategy Dashboard Main user interface showing portfolio state Live positions, trade history, active watchdog triggers, performance metrics Key Decisions
- Turbo Native over React Native — Server-rendered HTML wrapped in a native shell. One codebase (Rails views) serves both web and mobile. Faster iteration, no JavaScript framework churn.
- Capacitor for native bridge — Provides access to iOS APIs (keychain, biometrics, push) without leaving the Turbo Native pattern. Lighter than Cordova.
- Hotwire for interactivity — Turbo Frames for partial updates, Turbo Streams for real-time pushes. No SPA complexity. Dashboard sections refresh independently.
- Strategy dashboard as primary view — Users see live positions, trade history, and active watchdog triggers in one view. Performance metrics show cumulative P&L and win rate.
- Kalshi app handles fund management — Our app never shows deposit/withdrawal UI. Users manage funds directly in the Kalshi app. We show read-only balance for context.
Related
-
PostgreSQL Architecture: Prediction Assistant
arch-postgresPostgreSQL Architecture: Kalshi Assistant
Database schema and storage architecture. Answers: what are the tables and how does the strategy engine use them?
Diagram
erDiagram users ||--o{ credentials : "has" users ||--o{ portfolios : "owns" users ||--o{ strategies : "defines" strategies ||--o{ portfolios : "drives" strategies ||--o| watchdog_configs : "configures" strategies ||--o| sizing_configs : "configures" portfolios ||--o{ trades : "contains" markets ||--o{ trades : "referenced by" market_scans ||--o{ markets : "discovers" users { bigint id PK string keycloak_sub string email timestamps created_updated } credentials { bigint id PK bigint user_id FK string kalshi_api_key_id text encrypted_private_key boolean validated datetime last_verified_at } strategies { bigint id PK bigint user_id FK string name string strategy_type jsonb parameters boolean active } watchdog_configs { bigint id PK bigint strategy_id FK decimal buy_threshold decimal take_profit_threshold decimal cut_loss_threshold text series_tickers } sizing_configs { bigint id PK bigint strategy_id FK decimal yes_pct decimal no_pct integer max_picks } portfolios { bigint id PK bigint user_id FK bigint strategy_id FK string name decimal budget string status date trading_date } trades { bigint id PK bigint portfolio_id FK bigint market_id FK string kalshi_order_id string ticker string side decimal price integer quantity string status decimal pnl } markets { bigint id PK string ticker string series_ticker string title decimal yes_bid decimal yes_ask string status datetime close_time } market_scans { bigint id PK datetime scanned_at integer markets_found integer above_threshold }Components
Component Purpose Notes users Keycloak-authenticated user reference Maps keycloak_sub to local user; no password stored locally credentials Encrypted Kalshi API credentials per user RSA private key encrypted at rest via Rails credentials strategies Strategy definitions (watchdog, stacking) Polymorphic via strategy_type + jsonb parameters; avoids STI watchdog_configs Threshold parameters for watchdog auto-buy buy_threshold=0.85, take_profit=0.95, cut_loss=0.80 sizing_configs YES/NO allocation for Option D sizing Default: yes_pct=83, no_pct=17; per-strategy override portfolios Daily trading session container Scoped to trading_date; one active per day per strategy trades Individual order records with Kalshi reconciliation Tracks kalshi_order_id; pnl computed on settlement markets Cached Kalshi market data TTL-based refresh; indexed on ticker and series_ticker market_scans Audit log of polling cycles Tracks markets_found and above_threshold per scan Key Decisions
- CNPG shared cluster with 4 databases — primary (app data), cache (Solid Cache), queue (Solid Queue), cable (Solid Cable); follows Rails 8 Solid stack convention on shared CloudNativePG cluster
- Strategy polymorphism via strategy_type + jsonb — avoids STI complexity; keeps schema simple while supporting future strategy types beyond watchdog and stacking
- Market data cached in PostgreSQL not Redis — simpler ops; strategy engine needs SQL joins between markets and thresholds for filtering
- Credentials encrypted at rest — RSA private keys are highly sensitive; validated on save via test API call to Kalshi demo environment
- Portfolio scoped to trading_date — enforces same-day-only rule at database level; prevents stale multi-day positions from accumulating
- Decimal types for all monetary and price columns — avoids floating-point rounding errors in trade PnL calculations and Option D sizing math
Related
- arch-rails — Active Record models that map to these tables
- arch-app — Service objects that query and mutate this data
- arch-domain-kalshi-assistant — Entity relationship overview
- arch-deployment-kalshi-assistant — CNPG cluster hosting
- project-kalshi-assistant — Parent project page
-
Application Domain: Kalshi Assistant
Core service architecture and domain logic. Answers: what are the services and how do they interact?
Diagram
graph TB subgraph Services["Core Services"] KC[KalshiClient] MS[MarketScanner] WD[Watchdog] SE[SizingEngine] end subgraph Jobs["Solid Queue Jobs"] MSJ[MarketScanJob] PMJ[PositionMonitorJob] end subgraph External["External"] API[Kalshi API v2] end subgraph Data["Data Layer"] DB[(PostgreSQL)] end MSJ -->|"every N seconds"| MS MS -->|"uses"| KC KC -->|"GET /markets"| API MS -->|"caches markets"| DB MS -->|"above 85%"| WD WD -->|"calculates allocation"| SE SE -->|"83/17 YES/NO split"| WD WD -->|"places order"| KC KC -->|"POST /orders + RSA-PSS"| API KC -->|"records trade"| DB PMJ -->|"checks positions"| KC KC -->|"GET /positions"| API PMJ -->|"sell trigger hit"| WDComponents
Component Purpose Notes KalshiClient HTTP wrapper for Kalshi API v2 with RSA-PSS authentication Signs each request with timestamp + method + path; handles rate limiting (20 reads/sec, 10 writes/sec basic tier) MarketScanner Polls same-day markets and filters by confidence threshold GET /markets?series_ticker=SERIES&status=open; caches results in markets table; identifies candidates above buy_threshold Watchdog Auto-buy when market crosses threshold; auto-sell on triggers Entry at 85%+, take profit at 95%+, cut loss below 80%; creates Trade records in active Portfolio SizingEngine Calculates optimal YES/NO allocation per Option D model Default: 83% YES / 17% NO; brute-force optimized to minimize worst-case loss (-$5.77 on $100 budget) MarketScanJob Recurring Solid Queue job for market polling Runs every N seconds; calls MarketScanner.scan; creates MarketScan audit record PositionMonitorJob Monitors open positions for sell triggers Checks price movement on open trades; triggers Watchdog sell logic on threshold breach Key Decisions
- Service object pattern — each service has a single responsibility: KalshiClient (auth/HTTP), MarketScanner (polling/filtering), Watchdog (buy/sell logic), SizingEngine (allocation math)
- Watchdog auto-buy at 85%+ — threshold configurable per strategy via watchdog_configs; avoids pregame prediction entirely; rides mid-game momentum when the outcome becomes clear
- Option D 83/17 split as default sizing — brute-force optimized worst-case loss; stored in sizing_configs for per-strategy override; adjusts based on pick count and confidence levels
- Rate limit awareness in KalshiClient — tracks request count per second; backs off before hitting basic tier limits (20 reads/sec, 10 writes/sec)
- MarketScan audit trail — every polling cycle logged with markets_found and above_threshold counts; enables analysis of scan frequency vs. opportunity detection rate
- Sell triggers as configurable thresholds — take_profit (95%+) and cut_loss (below 80%) stored in watchdog_configs; not hardcoded, tunable per strategy
Related
- arch-rails — Rails framework hosting these services
- arch-postgres — Database tables these services read and write
- arch-dataflow-kalshi-assistant — Runtime sequence flows between services
- arch-domain-kalshi-assistant — Entity definitions
- arch-deployment-kalshi-assistant — Where services run in the cluster
- project-kalshi-assistant — Parent project page
-
Authentication: prediction-assistant
arch-authAuthentication Architecture
Two-layer authentication: Keycloak SSO for app access, Kalshi API keys for trading. Answers: how are users authenticated and authorized?
Diagram
sequenceDiagram participant User participant App as iOS App participant KC as Keycloak participant Rails as Rails API participant KS as Kalshi API Note over User,KS: Layer 1 - App Login (Keycloak SSO) User->>App: Open app App->>KC: Direct grant (username + password) KC->>App: JWT access token + refresh token App->>Rails: API requests + Bearer JWT Rails->>KC: Validate JWT (JWKS) KC->>Rails: Token valid Rails->>App: Authorized response Note over User,KS: Layer 2 - Kalshi API Credentials (One-time Setup) User->>App: Enter Kalshi API key ID User->>App: Paste RSA private key PEM App->>Rails: POST /api/credentials (encrypted) Rails->>Rails: Encrypt + store per-user Note over User,KS: Trading Flow (Both Layers) App->>Rails: Execute trade + Bearer JWT Rails->>KC: Validate JWT Rails->>Rails: Decrypt user Kalshi credentials Rails->>KS: Signed API request (RSA-PSS) KS->>Rails: Trade result Rails->>App: Trade confirmationComponents
Component Purpose Notes Keycloak SSO App-level authentication and user management Direct grant flow (no browser redirect). Realm: kalshi-assistant JWT Tokens Stateless auth between iOS app and Rails API Access token + refresh token. Validated via JWKS endpoint. Kalshi API Key ID Identifies the user's Kalshi account for API access Public identifier, stored per-user in DB RSA Private Key Signs Kalshi API requests on behalf of the user PEM format. Encrypted at rest. Never transmitted after initial setup. Credential Store Per-user encrypted storage of Kalshi API credentials Rails encrypted credentials or DB-level encryption Key Decisions
- Two auth layers, not one — Keycloak handles "who is this user of our app?" Kalshi API keys handle "can this user trade?" Separating these means users can log in and browse without having Kalshi credentials set up yet.
- Direct grant over redirect flow — Mobile apps use Keycloak's direct grant (Resource Owner Password Credentials). No browser redirect needed. Cleaner native UX.
- Per-user Kalshi credential storage — Each user brings their own Kalshi API key and RSA private key. Keys are encrypted at rest. The app signs requests on behalf of users but never holds their funds.
- User can revoke access anytime — Users can delete their API key from Kalshi's settings at any time, immediately revoking our trading access. No lock-in.
- RSA private key never leaves the server — After initial submission, the private key is encrypted and stored server-side. It is used only for signing Kalshi API requests. Never returned to the client.
Related
-
Domain Model: Prediction Assistant
arch-domain-prediction-assistantDomain Model: Kalshi Assistant
Diagram
erDiagram User ||--o{ Credential : "has" User ||--o{ Portfolio : "owns" Credential { string kalshi_api_key_id text encrypted_private_key boolean validated datetime last_verified_at } Portfolio ||--o{ Trade : "contains" Portfolio { string name decimal budget string status date trading_date } Strategy ||--o{ Portfolio : "drives" Strategy { string name string strategy_type jsonb parameters boolean active } WatchdogConfig ||--|| Strategy : "configures" WatchdogConfig { decimal buy_threshold decimal take_profit_threshold decimal cut_loss_threshold string series_tickers } SizingConfig ||--|| Strategy : "configures" SizingConfig { decimal yes_pct decimal no_pct integer max_picks } Trade { string kalshi_order_id string ticker string side decimal price integer quantity string status decimal pnl } Market { string ticker string series_ticker string title decimal yes_bid decimal yes_ask string status datetime close_time } MarketScan ||--o{ Market : "discovers" MarketScan { datetime scanned_at integer markets_found integer above_threshold }Components
Component Purpose Notes User App user authenticated via Keycloak Keycloak JWT — maps to CrewMember-style model Credential Stores Kalshi API key ID and encrypted RSA private key Encrypted at rest, validated on save via test API call Strategy Polymorphic strategy definition (watchdog, stacking) strategy_type + jsonb parameters for flexibility WatchdogConfig Threshold configuration for watchdog strategy Buy at 85%, take profit at 95%, cut loss at 80% SizingConfig YES/NO allocation ratios for Option D sizing Default: 83% YES / 17% NO Portfolio A set of trades for a single trading day Same-day-only constraint enforced at model level Trade Individual buy/sell order placed on Kalshi Tracks kalshi_order_id for reconciliation Market Cached Kalshi market data Refreshed by MarketScan jobs, TTL-based cache MarketScan Audit log of each market polling cycle Tracks markets found and above-threshold count Key Decisions
- Credentials encrypted at rest — RSA private keys are highly sensitive
- Strategy is polymorphic via strategy_type + jsonb — avoids STI complexity while keeping extensibility
- Market data cached locally to reduce API calls within rate limits
- Trade tracks Kalshi order ID for reconciliation
- Portfolio scoped to trading_date — enforces same-day-only rule at data model level
Related
arch-dataflow-kalshi-assistant— how data moves between these entities at runtimearch-deployment-kalshi-assistant— where these entities are hostedproject-kalshi-assistant— parent project pageconvention-architecture-ids— arch: label naming
-
Data Flow: Prediction Assistant
arch-dataflow-prediction-assistantData Flow: Kalshi Assistant
Diagram
Flow 1: Watchdog Scan
sequenceDiagram participant SQ as Solid Queue participant Rails as Rails App participant DB as PostgreSQL participant Kalshi as Kalshi API SQ->>Rails: MarketScanJob.perform Rails->>Kalshi: GET /markets?series_ticker=SERIES Kalshi-->>Rails: Market list with prices Rails->>DB: Cache market data Rails->>Rails: Check thresholds (yes_bid >= 85%) alt Market crosses buy threshold Rails->>Kalshi: POST /portfolio/events/orders Kalshi-->>Rails: Order confirmation Rails->>DB: Create Trade record endFlow 2: Position Monitor
sequenceDiagram participant SQ as Solid Queue participant Rails as Rails App participant DB as PostgreSQL participant Kalshi as Kalshi API SQ->>Rails: PositionMonitorJob.perform Rails->>DB: Load open Trade records Rails->>Kalshi: GET /markets/ticker for each position Kalshi-->>Rails: Current prices Rails->>Rails: Check sell triggers alt Sell trigger hit Rails->>Kalshi: POST /portfolio/events/orders (sell) Kalshi-->>Rails: Sell confirmation Rails->>DB: Update Trade with pnl endFlow 3: User Auth
sequenceDiagram participant App as iOS App participant KC as Keycloak participant Rails as Rails App App->>KC: Auth Code + PKCE login KC-->>App: ID token + access token App->>Rails: API requests with Bearer token Rails->>KC: Verify token (JWKS) Rails-->>App: Strategy dashboard dataComponents
Component Purpose Notes Solid Queue Background job runner for scan and monitor loops Rails 8 built-in, no Redis dependency Rails App Core application logic, API layer, strategy engine Port 3000, Rails 8 PostgreSQL Primary data store for all entities Shared CNPG cluster, 4 databases Kalshi API External market data and trade execution RSA-PSS SHA-256 auth, rate-limited Keycloak Identity provider, SSO Auth Code + PKCE, same pattern as landscaping-assistant iOS App Turbo Native shell for mobile access ASWebAuthenticationSession for login Key Decisions
- Solid Queue over Sidekiq — eliminates Redis dependency, sufficient for polling frequency
- RSA-PSS signature computed per request — Kalshi requires timestamp + method + path signed with private key
- Market data cached in PostgreSQL not Redis — simpler ops, query-friendly for strategy evaluation
- Auth Code + PKCE flow — matches landscaping-assistant pattern, works with iOS
Related
arch-domain-kalshi-assistant— entity definitions referenced in flowsarch-deployment-kalshi-assistant— where these services runproject-kalshi-assistant— parent project page
-
Keycloak: prediction-assistant
arch-keycloak-prediction-assistantKeycloak Configuration
Keycloak realm and client setup for kalshi-assistant. Follows pal-e-platform and pal-e-services patterns. Answers: how is the identity provider configured?
Diagram
graph TB subgraph Keycloak["Keycloak Server"] REALM["Realm: kalshi-assistant"] CLIENT["Client: kalshi-assistant-app"] THEME[Custom Login Theme] USERS[User Federation] end subgraph Platform["pal-e-platform"] THEMES_DIR["keycloak/themes/kalshi-assistant/"] LOGIN_THEME["login/theme.properties + templates"] end subgraph Services["pal-e-services"] TFVARS["k3s.tfvars realm + client config"] TF[Terraform Keycloak Provider] end subgraph App["kalshi-assistant"] IOS[iOS App] RAILS[Rails API] end TFVARS -->|"provisions"| TF TF -->|"creates"| REALM TF -->|"creates"| CLIENT THEMES_DIR -->|"deployed to"| THEME LOGIN_THEME --> THEMES_DIR IOS -->|"direct grant"| CLIENT RAILS -->|"validate JWT"| REALM USERS -->|"manages"| REALMComponents
Component Purpose Notes Realm: kalshi-assistant Identity boundary for the app's users Separate realm per app. Follows pal-e-platform convention. Client: kalshi-assistant-app OAuth2 client for the iOS app Direct grant enabled. Public client (no client secret for mobile). Custom Login Theme Branded login page for kalshi-assistant Located at keycloak/themes/kalshi-assistant/ in pal-e-platform Terraform Keycloak Provider IaC provisioning of realm and client Configured in pal-e-services k3s.tfvars pal-e-platform themes dir Theme source files deployed to Keycloak keycloak/themes/{app-name}/login/ pal-e-services tfvars Realm and client configuration as code k3s.tfvars defines realm name, client ID, grant types Key Decisions
- Follows landscaping-assistant pattern — Realm and client setup mirrors the existing landscaping-assistant Keycloak configuration in pal-e-platform and pal-e-services. Proven pattern, no new infrastructure decisions.
- Theme at keycloak/themes/{app-name}/ — Custom login page branded for kalshi-assistant. Theme files live in pal-e-platform repo, deployed as part of the Keycloak container image.
- Terraform-managed configuration — Realm and client provisioned via Terraform Keycloak provider in pal-e-services. Configuration lives in k3s.tfvars alongside other app realms. No manual Keycloak admin console changes.
- Direct grant for mobile — Public client with Resource Owner Password Credentials grant type. No browser redirect. The iOS app collects username/password and exchanges directly for tokens.
- Separate realm per app — kalshi-assistant gets its own realm, not a shared one. Users are app-specific. Follows the one-realm-per-app convention across pal-e projects.
Related
-
Deployment: Prediction Assistant
arch-deployment-prediction-assistantDeployment: Kalshi Assistant
Diagram
graph TB subgraph Internet Browser[Browser / iOS App] Domain[prediction-assistant.com] end subgraph Hetzner["Hetzner Edge VPS"] Caddy[Caddy Reverse Proxy] end subgraph GoDaddy DNS["A Record to Hetzner IP"] end subgraph k3s["k3s Cluster"] subgraph ns_prod["kalshi-assistant namespace"] Rails[Rails 8 + Solid Queue] end subgraph ns_dev["kalshi-dev namespace"] DevProxy["nginx dev proxy"] end subgraph ns_pg["postgres namespace"] CNPG[PostgreSQL 17 CNPG] end subgraph ns_kc["keycloak namespace"] KC[Keycloak SSO] end Funnel[Tailscale Funnel] end subgraph CICD["CI/CD"] Forgejo[Forgejo Git] Woodpecker[Woodpecker CI] Harbor[Harbor Registry] ArgoCD[ArgoCD + Image Updater] end subgraph External KalshiAPI[Kalshi API v2] end Domain --> DNS --> Caddy Caddy --> Funnel --> Rails Browser --> Domain Rails --> CNPG Rails --> KC Rails --> KalshiAPI Forgejo --> Woodpecker Woodpecker --> Harbor Harbor --> ArgoCD ArgoCD --> RailsComponents
Component Purpose Notes Rails 8 + Solid Queue Application server and background jobs Namespace: kalshi-assistant, port 3000 PostgreSQL 17 CNPG Shared database cluster 4 databases: primary, cache, queue, cable Keycloak SSO identity provider Separate realm for kalshi-assistant Caddy TLS termination for custom domain Auto Let's Encrypt, reverse proxies via Tailscale Tailscale Funnel Public HTTPS ingress to k3s kalshi-assistant.tail5b443a.ts.net GoDaddy DNS A record for prediction-assistant.com Managed via godaddy-tofu Terraform provider Woodpecker CI Build and test pipeline RuboCop lint, RSpec tests, Kaniko image build Harbor Container registry Project: kalshi-assistant, SHA-tagged images ArgoCD GitOps deployment Image Updater detects new SHA tags nginx dev proxy Dev tunnel to local machine Namespace: kalshi-dev Kalshi API v2 External trading API RSA-PSS SHA-256 auth, rate-limited Key Decisions
- Three-repo model (pal-e-platform, pal-e-services, pal-e-deployments) — same proven pattern as landscaping-assistant
- Port 3000 — Rails default, consistent with landscaping-assistant
- Tailscale Funnel for prod ingress, Hetzner edge + Caddy for custom domain
- Solid Queue replaces Sidekiq — no Redis pod needed
- 4 PostgreSQL databases — Rails 8 Solid stack pattern on shared CNPG cluster
- SOPS-encrypted secrets in pal-e-deployments for Kalshi credentials and Keycloak client secret
URLs
Environment URL Production (custom domain) https://prediction-assistant.com Production (Tailscale) https://kalshi-assistant.tail5b443a.ts.net Dev (Tailscale) https://kalshi-dev.tail5b443a.ts.net Local http://localhost:3000 Related
arch-domain-kalshi-assistant— entities hosted in this deploymentarch-dataflow-kalshi-assistant— runtime flows between these componentsproject-kalshi-assistant— parent project pageservice-onboarding-sop— SOP for provisioning new services
Project Page 1
-
Prediction Assistant
project-prediction-assistantVision
AI-powered trading assistant for Kalshi prediction markets. Uses automated strategies (watchdog scanning, portfolio stacking with Option D hedging) to generate consistent returns while bounding worst-case loss. The system deploys a 4-bot architecture — Pregame Stacker, Late-Game Lock, Bulk Sweep, and Edge Learner — driven by a watchdog fan-out pattern that scans markets and dispatches opportunities to specialized bots. Users connect their Kalshi API credentials through an iOS app at prediction-assistant.com and the system trades on their behalf — they watch results live in the official Kalshi app.
User Stories
Key Story Note Role Success Metric portfolio-builder AI Portfolio Builder Trader (Lucas) Positive EV across 100+ trades, worst-case loss under 6% watchdog-trading Watchdog Trading Trader (Lucas) 85%+ win rate, $0.10–$0.15 avg profit per contract app-experience App Experience Consumer First automated trade within 5 min of connecting credentials credential-onboarding Credential Onboarding Consumer 90% of users complete setup without support platform-setup Platform Setup Developer (Lucas) CI/CD push-to-deploy in under 10 minutes landing-page Landing Page & Registration Consumer 80% of visitors who start registration complete it bot-marketplace Bot Marketplace Consumer User activates first bot within 2 minutes of login Architecture
- Domain Model — User, Credential, Strategy, Portfolio, Trade, Market entities
- Data Flow — watchdog scan loop, position monitoring, user auth flows
- Deployment — k3s + Tailscale Funnel + Hetzner edge + Caddy for prediction-assistant.com
- Rails — Rails 8 application architecture
- API — API layer design
- App — Application structure
- Postgres — Database schema and design
- Frontend — Frontend architecture
- Auth — Authentication and authorization
- Keycloak — Keycloak integration for prediction-assistant
Key decisions:
- Rails 8 with Solid Queue (no Sidekiq/Redis)
- Kalshi API auth: RSA-PSS SHA-256 per-request signatures
- Strategy polymorphism via strategy_type + jsonb parameters
- Three-repo model: pal-e-platform, pal-e-services, pal-e-deployments
Board
Status
Project setup complete. All 16 tickets reviewed and in todo across 4 sprints. Bot architecture established (4 bots on watchdog fan-out). Strategy docs, API integration, and bot specs documented. PR #19 merged with bot specs and user stories. PR #20 merged with Late-Game Lock math fix and Edge Learner synthetic parlay clarification. Rails scaffold and infrastructure provisioning are next (Sprint 1).
Milestones
- 2026-07-02 — Strategy research and API exploration complete
- 2026-07-03 — Bot architecture established, all tickets reviewed and moved to todo, PR #19 and #20 merged
Repos
Repo Platform Role Status ldraney/kalshi-assistant Forgejo Rails app + docs Active (docs only, Rails scaffold pending) ldraney/kalshi-assistant-ios Forgejo Turbo Native iOS shell Not yet created
Untyped 2
-
Bot Marketplace
story-prediction-assistant-bot-marketplaceAs a registered user, I want to browse, configure, and activate trading bots with my own settings, so that I can automate my prediction market trading. See docs/user-stories/bot-marketplace.md for full spec.
-
Landing Page & Registration
story-prediction-assistant-landing-pageAs a visitor to prediction-assistant.com, I want to understand what the platform does and register quickly, so that I can start using automated trading bots on Kalshi. See docs/user-stories/landing-page.md for full spec.
User Story 5
-
Platform Setup
story-prediction-assistant-platform-setupstory: Platform Setup
Role
Developer (Lucas)
Key
platform-setup
Want
As a developer, I want the full pal-e-platform infrastructure provisioned — namespace, Harbor, ArgoCD, CI/CD, DNS, monitoring, Keycloak, kustomize overlays
So That
So that the Rails app can be deployed, monitored, and accessed at kalshi-assistant.com through the standard three-repo pipeline
Acceptance Criteria
- Service onboarded in pal-e-services (namespace, Harbor, ArgoCD, funnel)
- DNS A record and Caddy reverse proxy for kalshi-assistant.com
- Kustomize overlays for prod and dev in pal-e-deployments
- Keycloak realm, client, users, and login theme
- Woodpecker CI pipeline with lint, test, build stages
- Monitoring: AlertManager, blackbox probe, Grafana dashboard, PrometheusRules
- End-to-end: push to main → CI green → image in Harbor → ArgoCD deploys → app live at kalshi-assistant.com
Success Metric
Full CI/CD pipeline operational: code push to production deploy in under 10 minutes
Related Architecture
arch-deployment-kalshi-assistant— deployment diagram showing all infrastructure componentsarch-dataflow-kalshi-assistant— auth flow through Keycloak
Related
project-kalshi-assistant— parent project pageboard-kalshi-assistant— project boardservice-onboarding-sop— standard procedure for new services
-
Credential Onboarding
story-prediction-assistant-credential-onboardingstory: Credential Onboarding
Role
Consumer (new user)
Key
credential-onboarding
Want
As a new user, I want step-by-step guidance within the app to create my Kalshi account, generate API credentials, and paste them into the app
So That
So that I can connect my Kalshi account without needing external documentation or technical knowledge about API keys and RSA private keys
Acceptance Criteria
- In-app walkthrough guides user to create Kalshi account and deposit funds
- Step-by-step instructions for generating API key ID and private key in Kalshi settings
- Secure input fields for pasting API key ID and RSA private key
- Validation that credentials work (test API call on save)
- Credentials stored encrypted at rest
- Clear error messages if credentials are invalid or expired
Success Metric
90% of users complete credential setup without contacting support
Related Architecture
arch-domain-kalshi-assistant— User, Credential entitiesarch-dataflow-kalshi-assistant— credential validation flowarch-deployment-kalshi-assistant— secrets management for stored credentials
Related
project-kalshi-assistant— parent project pageboard-kalshi-assistant— project boardstory-kalshi-assistant-app-experience— parent user experience story
-
Watchdog Trading
story-prediction-assistant-watchdog-tradingstory: Watchdog Trading
Role
Trader (Lucas)
Key
watchdog-trading
Want
As a trader, I want a watchdog that continuously scans all same-day markets and automatically buys YES when odds cross 85%, then sells at 95% (take profit) or 80% (cut loss)
So That
So that I can capture reliable mid-game profits without needing pregame prediction, riding game state instead of forecasting outcomes
Acceptance Criteria
- Continuous polling of all active same-day markets via API
- Auto-buy YES when any market's yes_bid crosses 85% threshold
- Auto-sell at 95%+ (take profit) or below 80% (cut loss)
- Configurable thresholds per strategy instance
- Solid Queue background job for continuous scanning
- Rate-limit-aware polling (stays within 20 reads/sec)
- Tracks all positions and P&L in real time
Success Metric
85%+ win rate on watchdog trades with average profit of $0.10–$0.15 per contract
Related Architecture
arch-domain-kalshi-assistant— Strategy, WatchdogConfig, Trade entitiesarch-dataflow-kalshi-assistant— scan loop → threshold detection → order placement
Related
project-kalshi-assistant— parent project pageboard-kalshi-assistant— project board
-
App Experience
story-prediction-assistant-app-experiencestory: App Experience
Role
Consumer (end user)
Key
app-experience
Want
As a user, I want to download the app from the App Store, connect my Kalshi API credentials, and have the AI run portfolio strategies that I can watch live in the Kalshi app
So That
So that I can benefit from automated trading strategies without needing to understand the math, while retaining full visibility through my Kalshi account
Acceptance Criteria
- App available on iOS App Store
- User can log in via Keycloak (no redirect-based flow — native feel)
- User can enter and save their Kalshi API key ID and private key
- AI strategies run automatically after credentials are connected
- User can see strategy projections and rationale before trades execute
- All trades visible in the official Kalshi app (we don't duplicate portfolio UI)
Success Metric
User connects credentials and sees first automated trade within 5 minutes during active market hours
Related Architecture
arch-domain-kalshi-assistant— User, Credential entitiesarch-dataflow-kalshi-assistant— credential storage → API auth → trade executionarch-deployment-kalshi-assistant— iOS pipeline, App Store distribution
Related
project-kalshi-assistant— parent project pageboard-kalshi-assistant— project board
-
AI Portfolio Builder
story-prediction-assistant-portfolio-builderstory: AI Portfolio Builder
Role
Trader (Lucas)
Key
portfolio-builder
Want
As a trader, I want an AI system that analyzes Kalshi markets, constructs optimized portfolios using stacking and NO-contract hedging, and executes trades via the API
So That
So that I can achieve consistent returns by combining high-confidence picks with bounded downside risk, overcoming the house edge through informational edge and volume
Acceptance Criteria
- System scans all same-day markets and identifies 85%+ confidence picks
- Portfolio constructed using Option D sizing (83% YES / 17% NO hedge)
- Worst-case loss bounded to ~6% of portfolio value
- Trades executed via Kalshi API with RSA-PSS SHA-256 auth
- Strategy codified as database schema with configurable parameters
- System respects API rate limits (20 reads/sec, 10 writes/sec)
Success Metric
Positive EV across 100+ trades with worst-case single-portfolio loss under 6%
Related Architecture
arch-domain-kalshi-assistant— Strategy, Trade, Market, Portfolio entitiesarch-dataflow-kalshi-assistant— market scan → strategy evaluation → trade execution flow
Related
project-kalshi-assistant— parent project pageboard-kalshi-assistant— project board
Board 1
-
Prediction Assistant
board-prediction-assistantNo content