Created
Jul 08, 07:39
Started
Jul 08, 12:44
Completed
Jul 08, 16:55
DevOps handoff
Type
Feature
Shape
ui+db
Worktree Slug
turf-model-page-adoption
Repositories
turf-monster
Release Slug
—
Branch
feat/turf-model-page-adoption
Pull Request
https://github.com/amcritchie/turf-monster/pull/173Acceptance Criteria
Expected Test Plan
Checks Run
How long this task spent in each testing phase — Build → Local Certification → CI → Review → Operator Acceptance.
Build
25 minutes
Completed
Local Certification
—
Missing
CI
—
Missing
Review
38 minutes
Completed
Operator Acceptance
—
Missing
Stage Timeline
Who handled each stage, the time it took (measured), and the model / tokens / cost reported (best-effort) — plus who's on it right now. — means the agent didn't report that metric.
Conversation
QA review feedback, agent handoffs, and follow-up notes for this task.
Fast-follow of mcritchie adoption (PR #456). Engine 0.12 draws the routes/controller/view into turf automatically; turf just registers its models + adds a link. turf already passed consumer CI vs 0.12 (green on engine PR #12), so the bump is safe (~> 0.11 already permits 0.12). OPEN DECISIONS for the builder: (1) which models to register — recommend Entry, Contest, Game, Player, PaypalPurchase (high-value inspectable records); (2) where the Model link lives (turf has no /deployments/all — pick an admin surface). Apply the same to_prepare registration + as_json column filter for any wallet/payment models with sensitive fields.
Scout report: merge-ready - PRIMARY: merge-ready. PII/security audit clean — 4 registered models expose only public/on-chain columns via record.as_json (no include, no serialization override repo-wide); all sensitive models (User/PendingTransaction/CdpRampTransaction/PaypalPurchase/StripePurchase/TransactionLog) NOT registered and 404 on direct URL. dor-check passes, CI 7/7 green, acceptance all met. Reporter: carl Outcome: merge-ready Findings: - Entry cols (user_id/contest_id int FKs, score, status, payout_cents, onchain_entry_id, onchain_tx_signature, slug…) all public/game/on-chain — SAFE - Contest cols (name, entry_fee_cents, onchain_contest_id/tx_signature, slug, creator user_id…) all public metadata — SAFE - Game cols (slug, team slugs, kickoff, venue, scores) + Player cols (slug, name, position, jersey) all public — SAFE - No as_json/serializable_hash/include_root_in_json override anywhere in app/config/lib → no association leakage; engine ModelPage#json calls record.as_json with NO include - Sensitive models confirmed EXCLUDED: only 4 ModelPage.register calls exist repo-wide; User(email+session_token+encrypted_web2_solana_private_key), PendingTransaction(serialized_tx), CdpRampTransaction(raw_payload) present in schema but unregistered; unknown key → 404 (test: /models/user/whatever → not_found) - Admin gate real: Studio::ModelsController before_action :require_admin (engine ErrorHandling#require_admin redirects non-admin → root); routes drawn via Studio.routes(self); integration test asserts non-admin redirect + admin 200 - to_prepare registration idempotent across Zeitwerk reloads (hash keyed by string; re-points registry to freshly-reloaded host classes — correct pattern, matches studio adoption) - NIT: integration test refutes only user+paypal_purchase; could add refutes for pending_transaction/cdp_ramp_transaction/stripe_purchase/transaction_log to lock exclusion of every comment-named sensitive model against future accidental registration Questions: - none Checks: - dor-check turf-model-page-adoption PASS → ready submitted→reviewed (full-suite-bypass legit: no bin/full-suite-check; CI-equiv green rails test 1403/0, rubocop 442/0) - GitHub CI 7/7 green (scan_ruby, scan_js, lint, test, playwright 1/2/3) - studio-engine ~> 0.12 bump consistent: Gemfile ~> 0.12 + Gemfile.lock 0.12.0 - Acceptance all met: 0.12 bump / ModelPage.register in to_prepare / admin-only inspector renders / Model JSON dashboard card
Scout report: merge-ready - Light UI+security second read: admin-dashboard Model JSON card is admin-gated (Admin::DashboardController before_action :require_admin) and reuses the _quick_action theme primitive (dark/light/mobile parity); engine route + models are admin-gated defense-in-depth; the 4 registered models expose only public/on-chain columns; sensitive models genuinely excluded. Merge-ready. Reporter: shannon Outcome: merge-ready Findings: - Admin gate verified TWICE: dashboard #show require_admin (card never renders for non-admins) AND engine Studio::ModelsController before_action :require_admin on show+random. - Card reuses _quick_action partial (card/text-heading/text-secondary/text-muted/hover:bg-surface-alt role tokens); no new Tailwind utility, no mb-* grid trap, no letter-spacing trap; links to studio_model_random_path(contest). - ERB comment is %-free (compliant with <%# %> single-terminator rule); single line, no HTML-comment double-hyphen risk. - Security 2nd read: Entry/Contest/Game/Player carry only public on-chain IDs, slugs, scores, sports data + integer FK user_id (not PII); no as_json overrides so no association leakage. - Excluded models confirmed NOT registered: grep ModelPage.register across app/config/lib finds only the 4 safe registrations; User/PaypalPurchase/StripePurchase/PendingTransaction/CdpRampTransaction/TransactionLog absent. - NIT (non-blocking): Model JSON card targets a RANDOM contest; on an empty-contest DB the engine random action returns head :not_found (bare 404). Harmless in prod (always has contests). Questions: - none Checks: - diff matches all 4 acceptance criteria (bump ~>0.12, register in to_prepare, admin /models inspector, dashboard link) - CI green: scan_ruby scan_js lint test playwright(1/2/3) all SUCCESS (glanced, not re-run)
Avi review approved (2 merge-ready: carl PRIMARY + shannon LIGHT). SECURITY AUDIT CLEAN from two independent reads: engine renders record.as_json (own columns only — zero as_json/serializable_hash/include overrides repo-wide, so no association leak); all 4 registered models (Entry/Contest/Game/Player) walked column-by-column = public/on-chain/sports data only, no PII; only 4 register calls exist; every sensitive model (User encrypted_web2_solana_private_key+session_token+email, PendingTransaction#serialized_tx, CdpRampTransaction#raw_payload, PaypalPurchase/StripePurchase/TransactionLog) is unregistered and the engine 404s unknown keys. Admin-gated verified at Admin::DashboardController + engine Studio::ModelsController (require_admin, defense-in-depth). dor-check PASS; CI 7/7 green; full-suite-bypass legit (turf has no bin/full-suite-check; rails test 1403/0 + rubocop 442/0). Non-blocking follow-ups (not rework): (1) integration test refutes only user+paypal_purchase — add a refute-registered per named excluded model to keep test in lockstep with the initializer comment; (2) dashboard 'Model JSON' card jumps to a random contest and 404s on an empty-contest DB — future empty-state polish. Ready for Steffon's qa-release sweep.
Sealed-bid sizing
Edit →Alex (PM)
—
Avi (PO)
SMALL
Dev
SMALL
Actual
LARGE
We emailed a one-tap sign-in link to . It expires shortly and can only be used once.
No email? Check spam, or close this and try again.