Files
project-work/worker-toolkit-stocks-in-the-future/repo/docs/map/CONTEXT.md

5.3 KiB
Raw Blame History

How to walk this map

One job: tell a cold agent which parts of the app are in force, which are decoration, and which words mean two things — before it opens a card.

Verified against commit 63732df (detached HEAD), 2026-08-16.

The three universes

Universe Meaning
live In force. Implement and cite against these.
leftover Still present and still wired, but no longer the main path. Touch only if that path is in scope.
ghost Named or filed, not wired. Do not implement against these.

Everything in objects/ and processes/ is live unless its frontmatter says otherwise.

Ghosts — present in the tree, unreachable

  • SchoolsController + app/views/schools/* (9 files). No route reaches them. resources :schools appears only inside namespace :admin (config/routes.rb:58), which resolves to Admin::SchoolsController. Rails scaffold remnant. If you want to change school admin, edit app/controllers/admin/schools_controller.rb.
  • admin_v2 / /admin-new. Survives only as a comment (config/routes.rb:42). The in-house admin is the live namespace :admin at /admin.

Leftovers — wired, but not the path to build on

  • users.classroom_id direct membership. See the trap below — this one is load-bearing, not dead.
  • PortfolioTransaction.reason: grade_earnings (enum value 3). Marked # Deprecated, will be removed in future at app/models/portfolio_transaction.rb:13 and referenced nowhere else. New earnings use math_earnings / reading_earnings.
  • docs/old-site/. Training material for the predecessor site.

The traps

Four places where the obvious reading of the code is wrong. Each one has bitten or is likely to.

1. A student's classroom has two rival sources of truth

Both are wired right now:

Path Where Used by
users.classroom_id db/schema.rb:374, app/models/user.rb:20 Classroom#students (app/models/classroom.rb:20), Order.for_teacher (app/models/order.rb:40-42), ApplicationController redirects
classroom_enrollments app/models/classroom_enrollment.rb Student#current_classrooms (app/models/student.rb:24), Classroom#current_students (app/models/classroom.rb:74)

Student#primary_classroom bridges them and falls back to classroom_id (app/models/student.rb:37-43, commented "for backward compatibility"). Student creation writes both: create_initial_enrollment fires only when classroom_id is present (app/models/student.rb:10,82-86).

Consequence: a student enrolled only via ClassroomEnrollment is invisible to Classroom#students and to teacher order scoping. Changing either path without the other splits the roster. Start at objects/org/classroom-enrollment.md.

2. Money is integer cents — except in one method

Every column is cents (amount_cents, price_cents, worth_cents). But Portfolio#cash_balance returns dollars as a float (app/models/portfolio.rb:16-18 → cash_on_hand → / 100.0 at app/models/portfolio.rb:67-69).

Callers must multiply back: app/models/order.rb:137 does (user.portfolio&.cash_balance || 0) * 100. Any new caller that forgets is off by 100×. Detail: objects/money/portfolio.md.

3. Cash is never stored

portfolios has exactly three columns — id, user_id, timestamps (db/schema.rb:181-186). There is no balance column. Every balance is a live SUM over portfolio_transactions, plus a subtraction for pending orders and their fee (app/models/portfolio.rb:71-100). Balance is therefore a function of open orders, not just settled history.

4. One API key, two homes, two different failure modes

Reader Source Missing-key behaviour
AlphaVantageApiClient ENV["ALPHA_VANTAGE_API_KEY"], default nil (app/services/alpha_vantage_api_client.rb:11) logs an error and returns nil (:31-36)
StockAttributeUpdate global API_KEY (app/services/stock_attribute_update.rb:75) from config/initializers/api_keys.rb:1, default "test-api-key" silently queries Alpha Vantage with a junk key

One fact, two homes. If you consolidate, objects/trading/stock.md lists what reads it.

Name collisions, stated once

Product word Code name Note
SIF dollars PortfolioTransaction#amount_cents integer cents; no Money/BigDecimal wrapper
balance / cash on hand Portfolio#cash_balance derived; returns dollars
grade (5th–8th) Grade, grades.level app/models/grade.rb
grade (A+…F) GradeEntry#math_grade, #reading_grade app/models/grade_entry.rb:15
admin users.admin boolean not an STI type (app/models/user.rb:39,43)
student / teacher STI on users.type Student < User, Teacher < User
holding / position PortfolioStock rows vs PortfolioPosition rows are append-only lots; the PORO is the aggregate
gradebook "finalize" GradeBook#verified! then completed! two statuses, one button
Stocks for Good StocksInTheFuture docs/README.md:1 vs config/application.rb:14

Walking order

  1. This file — universes and traps.
  2. objects/_index.md — find the noun.
  3. One card. Follow its See: link into the app tree.
  4. Before editing: effects/CONTEXT.md.

Do not read the whole objects/ folder. The index exists so you do not have to.