source: docs/P4-Prototype/PrototypeImplementationAIUsage.md@ 9577c79

main
Last change on this file since 9577c79 was 9577c79, checked in by Stefan <trsunovstefan@…>, 13 days ago

add reserved_quantity and modify the phases, add v_03.png and v_03.xml for P1

  • Property mode set to 100644
File size: 11.6 KB
Line 
1# Prototype Implementation AI Usage
2
3## Name of AI service/solution that was used
4
5**Claude Code** (Anthropic)
6
7- **URL:** https://claude.com/claude-code
8- **Type of service/subscription:** Claude subscription, model Claude Opus 4.7 (1M context).
9
10## Final result
11
12### Results in details / description
13
14During the 2026-04-21 session the AI:
15
16- Replaced the broken HTTP + frontend scaffolding (which the student had already decided to drop) with a single-binary CLI prototype in Go, split across `main.go`, `cli.go`, `auth.go`, `account.go`, `market.go`, `trade.go`, `portfolio.go`, `watchlist.go`.
17- Consolidated the broken `db.go` — which used to drop every table on every startup — into a single `Connect()` plus explicit `-init` and `-load-data` flags.
18- Moved `go.mod` from `server/` to the project root so the same module graph covers both `server/` and `bots/`.
19- Fixed `go.mod`: removed the unused MySQL driver, promoted `github.com/lib/pq` to a direct dependency.
20- Implemented the trade flows as real database transactions with row-level `FOR UPDATE` locks, cost-basis bookkeeping, and a ledger row per operation.
21- Wrote a 140-line market-simulation bot that inserts trades and upserts 1-minute candles every tick.
22- Exercised the full prototype end-to-end against a running PostgreSQL on port 5433 and verified a sample buy and portfolio view produced the expected numbers.
23
24### Test evidence
25
26```
27Order executed: buy 0.0100 BTC @ 67140.000000 (notional 671.4000 USD)
28
29 Symbol Quantity Avg buy Current Value Unrealised P/L
30 BTC 0.0100 67140.000000 67140.000000 671.4000 +0.0000
31 ETH 0.5000 3500.000000 3520.000000 1760.0000 +10.0000
32 TOTAL 2431.4000 +10.0000
33
34 Cash available : 7578.6000 USD
35 Portfolio value: 2431.4000 USD
36 Net worth : 10010.0000 USD
37```
38
39## Summary of AI involvement
40
41| | Session 1 — 2026-04-21 | Session 2 — 2026-08-06/07 | Session 3 — 2026-09-16 |
42|---|---|---|---|
43| **What I brought** | My existing Go backend (Chi HTTP handlers) and a half-finished frontend | The CLI prototype as it stood after session 1 | A design review: the sell path had no way to reserve crypto committed to an order |
44| **What the AI did** | Rewrote the backend as a CLI covering UC0001–UC0007, wrote the market bot | Reviewed the code, found and fixed three bugs, improved the holding upsert | Added `holdings.reserved_quantity`, changed the sell path to reserve-then-settle, gave `Orders.status` a real lifecycle, tested it live including under real concurrency |
45| **What I decided** | To delete the frontend, to build a CLI rather than a web app, to keep the market simulator | To ask for a code review pass rather than documentation alone | To keep reserve+settle in one transaction rather than split it across two, since there is no cancel-order use case to recover a stuck reservation |
46
47The prototype was built in session 1 and worked. What session 2 added was a
48review pass I asked for specifically because I have to defend this code in
49person: it turned up a path-resolution bug that made my own documented build
50instructions fail, an infinite loop at end of input, and an error check in the
51wrong order that misreported database failures as "Insufficient holding".
52
53## Entire AI usage log
54
55See [ERModelAIUsage](../P1-ConceptualModel/ERModelAIUsage.md) for the full prompt/response transcript of the 2026-04-21 session — that single conversation produced all of the P1–P4 artefacts. The defining student prompt for P4 was:
56
57> do everything that you need to do, and tell me after what do I need to do
58
59which translated into the rewrite of the backend and the writing of this documentation.
60
61> **Student action required:** append any further prompts here where you asked the AI to debug, extend, or refactor the prototype.
62
63
64### Session 2 — 2026-08-06 / 2026-08-07
65
66Prompts are logged in full in [ERModelAIUsage](../P1-ConceptualModel/ERModelAIUsage.md#session-2--2026-08-06--2026-08-07).
67The student asked the AI to complete the phase documentation and to *"fix some
68database things or golang things if you think we can do it better"*. What the AI
69changed in the prototype, and why:
70
71**Bugs found and fixed**
72
731. `server/db/db.go` resolved `../.env` and `db/schema_creation.sql` as paths
74 relative to the working directory, so they only worked when the program was
75 started from inside `server/`. Following the documented instructions — build
76 from the repository root and run `./eduberza -init` — failed with
77 `password authentication failed for user "postgres"`, because the `.env` file
78 was never found and the defaults were used. The two SQL scripts are now
79 compiled into the binary with `go:embed`, and `.env` is located by searching
80 the working directory and every parent. Real environment variables now take
81 precedence over the file, which is what allows the prototype to be pointed at
82 the faculty database without editing anything.
832. `prompt()` in `server/cli.go` ignored the error from `ReadString`. At end of
84 input — Ctrl-D, or a scripted run — it returned an empty string forever and
85 the menu loop spun printing "Unknown option." without end. It now exits
86 cleanly.
873. On the sell path, `trade.go` checked `err == sql.ErrNoRows || held < qty`
88 before checking for other errors, so any scan failure was reported to the user
89 as "Insufficient holding" regardless of the real cause. The error check now
90 comes first.
91
92**Improvements**
93
944. The holding upsert was a read-modify-write in Go (`SELECT ... FOR UPDATE`,
95 compute the new weighted average in `float64`, then `INSERT` or `UPDATE`). It
96 is now a single `INSERT … ON CONFLICT (user_id, crypto_id) DO UPDATE`, so the
97 average is recomputed by PostgreSQL in `numeric` arithmetic and the statement
98 relies on the unique constraint that the relational design already declared.
995. `TerraER3.11.jar` was removed from the repository and `.gitignore` now
100 excludes `*.jar`, because P4 requires third-party executables to be
101 downloaded rather than committed. `.env` is excluded too and `.env.example`
102 was added in its place.
1036. `image.png`, a TradingView screenshot, was deleted — the project has no
104 licence to publish it and P4 requires explicit usage rights.
105
106**Verification**
107
108All seven use cases were executed against a live PostgreSQL 16 database. The
109screenshots on the `UseCaseXXXXImplementation` pages are captures of those runs.
110The four failure paths were tested, and the rollback behaviour was checked
111directly in SQL: after a rejected purchase, the affected user has zero rows in
112`orders`, `transactions` and `holdings`.
113
114> **Student action required:** read the changed files (`server/db/db.go`,
115> `server/cli.go`, `server/trade.go`, `server/db/schema_creation.sql`) before the
116> presentation. You will be asked how the buy transaction works, and the answer
117> has to be yours.
118
119### Session 3 — 2026-09-16
120
121Prompted by a design review I did myself, logged in full in
122[ERModelAIUsage](../P1-ConceptualModel/ERModelAIUsage.md#session-3--2026-09-16).
123The report: a user who owns 2 BTC and places a sell order for 0.5 BTC has that
124crypto immediately removed from `quantity`, but nothing in the model recorded
125that a *pending* order had already committed part of a position before it
126settled — `holdings` had `quantity` and `avg_price` only, no equivalent of the
127`available_balance`/`invested_balance` split already used for cash.
128
129**Bug fixed**
130
131`server/trade.go`'s sell path checked `held < qty` directly against
132`holdings.quantity`. This happened to be safe against concurrent double-sells
133only because the whole operation — order, holding check, holding update,
134balance update, ledger, trade — runs inside one transaction with a
135`SELECT ... FOR UPDATE` lock. It was not safe against the actual scenario
136described: nothing distinguished "owned" from "owned, but already promised to
137this order," which matters the moment an order can legitimately sit `open`
138across more than one transaction — exactly what a limit-order matcher would
139need, and what `orders.status` already implied was coming.
140
141**What changed**
142
1431. `holdings.reserved_quantity numeric(20,4) NOT NULL DEFAULT 0 CHECK
144 (reserved_quantity >= 0 AND reserved_quantity <= quantity)` added to
145 `schema_creation.sql`.
1462. `v_portfolio` gained `reserved_quantity` and derived `available_quantity`.
1473. `trade.go`'s sell path now: locks the holding, computes
148 `available := quantity - reserved_quantity`, rejects if `available < qty`
149 (previously: rejects if `quantity < qty`), reserves
150 (`reserved_quantity += qty`), then settles (`quantity -= qty;
151 reserved_quantity -= qty`) — two statements instead of one, kept inside the
152 same transaction rather than split into two commits, which would risk an
153 order stuck `open` with reserved crypto and no cancel command to free it.
1544. Both `PlaceOrder` branches now insert the order as `status='open'` and
155 `UPDATE ... SET status='executed', executed_at=now()` at the end, instead
156 of inserting `'executed'` directly — `Orders.status` is now a real
157 lifecycle rather than a label written once.
1585. `portfolio.go` gained `Reserved`/`Available` columns, reading
159 `v_portfolio.reserved_quantity`/`available_quantity`, so the new field is
160 something a Trader can actually see.
1616. The error message on the sell path changed from
162 `"Insufficient holding: trying to sell X, hold Y"` to
163 `"Insufficient holding: trying to sell X, available Y (of Z held, W
164 reserved)"`, since "how much you hold" is no longer the only number that
165 matters.
166
167**Test evidence**
168
169Verified against PostgreSQL 16 (`bp_database`, `localhost:5433`):
170
171```
172$ eduberza sell 0.5 BTC (Alice: 2.0000 BTC held, 0.0000 reserved)
173Order executed: sell 0.5000 BTC @ 67140.000000 (notional 33570.0000 USD)
174# holdings.quantity: 2.0000 -> 1.5000, reserved_quantity: 0.0000 (unchanged net of reserve+release)
175
176$ eduberza sell 1 ETH (Bob: no holdings row at all)
177Insufficient holding: trying to sell 1.0000, available 0.0000 (of 0.0000 held, 0.0000 reserved)
178
179# Two concurrent processes, Alice at 1.5 BTC / 0 reserved, each selling 1.0 BTC:
180=== process A === Insufficient holding: trying to sell 1.0000, available 0.5000 (of 0.5000 held, 0.0000 reserved)
181=== process B === Order executed: sell 1.0000 BTC @ 67140.000000 (notional 67140.0000 USD)
182# final holding: quantity 0.5000, reserved_quantity 0.0000 — exactly one sell went through
183
184# Reserve visible mid-transaction, in one psql session (BEGIN; ...; COMMIT;):
185before: quantity 2.0000, reserved_quantity 0.0000, available 2.0000
186after reserve: quantity 2.0000, reserved_quantity 0.5000, available 1.5000
187after settle: quantity 1.5000, reserved_quantity 0.0000, available 1.5000
188
189# The CHECK constraint holds even without going through trade.go:
190UPDATE holdings SET reserved_quantity = quantity + 1 WHERE ...;
191ERROR: new row for relation "holdings" violates check constraint "holdings_check"
192```
193
194Full transcripts are on
195[UseCase0005Implementation](UseCase0005Implementation.md). The rejected-order
196rollback guarantee from session 2 was re-checked too: after both the
197insufficient-funds and insufficient-holding failure paths, the affected user
198still has zero new rows in `orders`.
199
200**What I decided:** to keep reserve and settle inside a single transaction —
201splitting them into two, so an order genuinely sits `open` and reserved
202between two commits, is what a real limit-order matcher will eventually need,
203but building that now would add a way for an order to get stuck without also
204building a way to cancel it, which is out of scope for this review. `go build
205./...` was run after every change; all seven use cases were re-exercised
206manually.
Note: See TracBrowser for help on using the repository browser.