| [ef1c1c7] | 1 | = Normalization 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 Sonnet 5.
|
|---|
| 9 |
|
|---|
| 10 | == Final result ==
|
|---|
| 11 |
|
|---|
| 12 | === Results in details / description ===
|
|---|
| 13 |
|
|---|
| 14 | The AI:
|
|---|
| 15 |
|
|---|
| 16 | * Built the single de-normalized relation `R_EDUBERZA` (68 attributes) by taking every
|
|---|
| 17 | attribute from every entity and attributed relationship in
|
|---|
| 18 | [wiki:ERModel], plus the foreign-key-style linking attributes
|
|---|
| 19 | that the eight attributeless relationships need to be representable in one flat table at
|
|---|
| 20 | all, and disambiguating every repeated name (`id`, `created_at`, `quantity`, `type`, …)
|
|---|
| 21 | with a per-origin prefix (`U_`, `C_`, `M_`, `H_`, `O_`, `T_`, `MT_`, `MC_`, `W_`, `WI_`).
|
|---|
| 22 | * Derived the canonical cover (17 functional dependencies) directly from each entity's/
|
|---|
| 23 | relationship's own key and its `UNIQUE` constraints, checked minimality of the composite
|
|---|
| 24 | left-hand sides by example, and separately listed the functional dependencies that hold by
|
|---|
| 25 | foreign-key substitution (e.g. `M_CRYPTO_ID → C_SYMBOL, C_NAME, C_CREATED_AT`) without
|
|---|
| 26 | folding them into the canonical cover, since they are derivable rather than independent.
|
|---|
| 27 | * Computed the candidate keys of `R_EDUBERZA` from first principles: since `Holds`,
|
|---|
| 28 | `Contains`, `Orders`, `Transactions`, `MarketTrades`, `MarketCandles` and `Watchlists` are
|
|---|
| 29 | independent of each other, the only candidate keys are combinations that pick one
|
|---|
| 30 | identifying attribute set per cluster — 96 in total — and selected the all-surrogate-key
|
|---|
| 31 | combination as primary key, with a full closure computation shown step by step.
|
|---|
| 32 | * Decomposed `R_EDUBERZA` using 3NF/BCNF '''synthesis''' on the canonical cover (rather than the
|
|---|
| 33 | binary decomposition algorithm), producing ten relations in one step, then separately
|
|---|
| 34 | verified 3NF (checking every foreign-key-carried transitive dependency by name and showing
|
|---|
| 35 | none of them lands inside any single resulting relation) and BCNF (a determinant/candidate-key
|
|---|
| 36 | table for all ten relations) as distinct, explicit checks per the phase template, even
|
|---|
| 37 | though no additional splitting was needed at either stage.
|
|---|
| 38 | * Verified dependency preservation (every canonical-cover FD's determinant and dependents
|
|---|
| 39 | land inside exactly one resulting relation) and lossless join (every foreign key is
|
|---|
| 40 | equated to the primary key it references, the textbook sufficient condition) explicitly,
|
|---|
| 41 | rather than asserting them.
|
|---|
| 42 | * Compared the result to [wiki:RelationalDesign] and
|
|---|
| 43 | found it identical relation-for-relation and key-for-key, including the less obvious
|
|---|
| 44 | composite candidate keys; documented the one real difference (`holdings.avg_price` is a
|
|---|
| 45 | derived/cached attribute — a property no single-relation normal form check can see) and
|
|---|
| 46 | concluded, with reasoning, that P2's design should continue to be used unchanged.
|
|---|
| 47 | * Added a short cross-reference to this page from
|
|---|
| 48 | [wiki:RelationalDesign], since the phase instructions
|
|---|
| 49 | ask for Phase 2 documentation to be updated with the outcome of this phase.
|
|---|
| 50 | * Wrote Normalization following the section headings given in the phase
|
|---|
| 51 | template exactly (`De-normalized database form` → `Functional dependencies` →
|
|---|
| 52 | `Candidate keys and primary key` → `1NF decomposition` → `2NF decomposition` →
|
|---|
| 53 | `3NF decomposition` → `BCNF if possible` → `Final result and discussion`).
|
|---|
| 54 |
|
|---|
| 55 | == Summary of AI involvement ==
|
|---|
| 56 |
|
|---|
| 57 | ||= =||= This session — 2026-09-16 =||
|
|---|
| 58 | || '''What I brought''' || The phase rubric for P5, pasted in full, and everything already produced in P1–P4 (in particular the `reserved_quantity` addition to `Holds` from the previous session) ||
|
|---|
| 59 | || '''What the AI did''' || Built the de-normalized relation, derived the canonical cover, found the candidate keys, ran the 1NF→2NF→3NF→BCNF synthesis, and wrote the comparison against P2 ||
|
|---|
| 60 | || '''What I decided''' || To let the AI carry out the full formal derivation rather than write my own first pass, since the rubric's own advice ("start from the canonical cover") is a mechanical method rather than a matter of taste; to keep P2's schema unchanged, per the AI's reasoning that the two designs coincide exactly ||
|
|---|
| 61 |
|
|---|
| 62 | This phase's rule is that AI is used '''to improve the student's own initial work''', and that
|
|---|
| 63 | any idea taken from the AI is logged as a change against that starting point. I did not
|
|---|
| 64 | produce an independent first attempt at the canonical cover or the decomposition before
|
|---|
| 65 | asking for this — I gave the AI the rubric directly and asked it to carry out the phase, the
|
|---|
| 66 | same way P1–P4 were produced (see
|
|---|
| 67 | [wiki:ERModelAIUsage] for that history). What I own here
|
|---|
| 68 | is checking the result: that the 68-attribute list in `R_EDUBERZA` really is every attribute
|
|---|
| 69 | of my P1 model with nothing missing or invented, that the functional dependencies match what
|
|---|
| 70 | I already know to be true of the model (each `UNIQUE` constraint in
|
|---|
| 71 | `schema_creation.sql` shows up as an alternate-key FD,
|
|---|
| 72 | and no others were invented), and that the final ten relations really do match
|
|---|
| 73 | [wiki:RelationalDesign] column for column — which I
|
|---|
| 74 | checked by reading both side by side rather than taking the AI's claim of a match on faith.
|
|---|
| 75 |
|
|---|
| 76 | The tables in `schema_creation.sql` that carry `UNIQUE` constraints:
|
|---|
| 77 |
|
|---|
| 78 | {{{
|
|---|
| 79 | -- ============================================================================
|
|---|
| 80 | -- USERS
|
|---|
| 81 | -- Platform users. Each user has virtual (prop) balances used for simulation.
|
|---|
| 82 | -- ============================================================================
|
|---|
| 83 | CREATE TABLE project.users (
|
|---|
| 84 | id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|---|
| 85 | username varchar(50) NOT NULL UNIQUE,
|
|---|
| 86 | email varchar(255) NOT NULL UNIQUE,
|
|---|
| 87 | full_name varchar(200),
|
|---|
| 88 | password_hash varchar(255) NOT NULL,
|
|---|
| 89 | available_balance numeric(18,4) NOT NULL DEFAULT 0 CHECK (available_balance >= 0),
|
|---|
| 90 | invested_balance numeric(18,4) NOT NULL DEFAULT 0 CHECK (invested_balance >= 0),
|
|---|
| 91 | created_at timestamptz NOT NULL DEFAULT now(),
|
|---|
| 92 | updated_at timestamptz
|
|---|
| 93 | );
|
|---|
| 94 |
|
|---|
| 95 | -- ============================================================================
|
|---|
| 96 | -- CRYPTO
|
|---|
| 97 | -- Catalog of crypto assets available on the platform.
|
|---|
| 98 | -- ============================================================================
|
|---|
| 99 | CREATE TABLE project.crypto (
|
|---|
| 100 | id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|---|
| 101 | symbol varchar(20) NOT NULL UNIQUE,
|
|---|
| 102 | name varchar(255) NOT NULL,
|
|---|
| 103 | created_at timestamptz NOT NULL DEFAULT now()
|
|---|
| 104 | );
|
|---|
| 105 |
|
|---|
| 106 | -- ============================================================================
|
|---|
| 107 | -- MARKETS
|
|---|
| 108 | -- A market is a (crypto, quote_currency) pair, e.g. BTC/USD.
|
|---|
| 109 | -- ============================================================================
|
|---|
| 110 | CREATE TABLE project.markets (
|
|---|
| 111 | id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|---|
| 112 | crypto_id uuid NOT NULL REFERENCES project.crypto(id),
|
|---|
| 113 | quote_currency char(3) NOT NULL DEFAULT 'USD',
|
|---|
| 114 | is_active boolean NOT NULL DEFAULT true,
|
|---|
| 115 | created_at timestamptz NOT NULL DEFAULT now(),
|
|---|
| 116 | CONSTRAINT uq_markets UNIQUE (crypto_id, quote_currency)
|
|---|
| 117 | );
|
|---|
| 118 |
|
|---|
| 119 | -- ============================================================================
|
|---|
| 120 | -- HOLDINGS
|
|---|
| 121 | -- Per-user crypto position with running weighted average entry price.
|
|---|
| 122 | -- ============================================================================
|
|---|
| 123 | CREATE TABLE project.holdings (
|
|---|
| 124 | id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|---|
| 125 | user_id uuid NOT NULL REFERENCES project.users(id) ON DELETE CASCADE,
|
|---|
| 126 | crypto_id uuid NOT NULL REFERENCES project.crypto(id),
|
|---|
| 127 | quantity numeric(20,4) NOT NULL CHECK (quantity >= 0),
|
|---|
| 128 | -- Committed to the user's own open sell orders, not yet removed from the
|
|---|
| 129 | -- position. quantity - reserved_quantity is what is actually free to
|
|---|
| 130 | -- sell — the crypto-side equivalent of users.available_balance.
|
|---|
| 131 | reserved_quantity numeric(20,4) NOT NULL DEFAULT 0
|
|---|
| 132 | CHECK (reserved_quantity >= 0 AND reserved_quantity <= quantity),
|
|---|
| 133 | -- Weighted-average entry price. NOT NULL so that the P/L arithmetic in
|
|---|
| 134 | -- v_portfolio can never silently produce NULL for an existing position.
|
|---|
| 135 | avg_price numeric(18,6) NOT NULL DEFAULT 0 CHECK (avg_price >= 0),
|
|---|
| 136 | created_at timestamptz NOT NULL DEFAULT now(),
|
|---|
| 137 | updated_at timestamptz,
|
|---|
| 138 | CONSTRAINT uq_holdings_user_crypto UNIQUE (user_id, crypto_id)
|
|---|
| 139 | );
|
|---|
| 140 | }}}
|
|---|
| 141 |
|
|---|
| 142 | {{{
|
|---|
| 143 | -- ============================================================================
|
|---|
| 144 | -- MARKET CANDLES
|
|---|
| 145 | -- OHLCV aggregates over standard timeframes.
|
|---|
| 146 | -- ============================================================================
|
|---|
| 147 | CREATE TABLE project.market_candles (
|
|---|
| 148 | id bigserial PRIMARY KEY,
|
|---|
| 149 | market_id uuid NOT NULL REFERENCES project.markets(id),
|
|---|
| 150 | timeframe varchar(5) NOT NULL CHECK (timeframe IN ('1m', '5m', '1h', '1d')),
|
|---|
| 151 | open numeric(18,6) NOT NULL,
|
|---|
| 152 | high numeric(18,6) NOT NULL,
|
|---|
| 153 | low numeric(18,6) NOT NULL,
|
|---|
| 154 | close numeric(18,6) NOT NULL,
|
|---|
| 155 | volume numeric(20,6) NOT NULL,
|
|---|
| 156 | candle_time timestamptz NOT NULL,
|
|---|
| 157 | CONSTRAINT uq_candle UNIQUE (market_id, timeframe, candle_time)
|
|---|
| 158 | );
|
|---|
| 159 | }}}
|
|---|
| 160 |
|
|---|
| 161 | {{{
|
|---|
| 162 | CREATE TABLE project.watchlist_items (
|
|---|
| 163 | id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|---|
| 164 | watchlist_id uuid NOT NULL REFERENCES project.watchlists(id) ON DELETE CASCADE,
|
|---|
| 165 | crypto_id uuid NOT NULL REFERENCES project.crypto(id),
|
|---|
| 166 | added_at timestamptz NOT NULL DEFAULT now(),
|
|---|
| 167 | CONSTRAINT uq_watchlist_crypto UNIQUE (watchlist_id, crypto_id)
|
|---|
| 168 | );
|
|---|
| 169 | }}}
|
|---|
| 170 |
|
|---|
| 171 | == Entire AI usage log ==
|
|---|
| 172 |
|
|---|
| 173 | === 2026-09-16 ===
|
|---|
| 174 |
|
|---|
| 175 | '''Intent:''' hand over the full P5 rubric and have the phase carried out end to end —
|
|---|
| 176 | de-normalized relation, functional dependencies, candidate keys, the four-normal-form
|
|---|
| 177 | decomposition, and the comparison against P2 — in one pass.
|
|---|
| 178 |
|
|---|
| 179 | '''Prompt (student, verbatim):'''
|
|---|
| 180 | > We will go phase by phase, here are the instructions for P5:
|
|---|
| 181 | > Instructions on Phase P5: Normalization
|
|---|
| 182 | > [the full task description was pasted: parts (a) initial de-normalized relation and
|
|---|
| 183 | > functional dependencies, (b) candidate keys and primary key selection, (c) step-by-step
|
|---|
| 184 | > decomposition to the highest possible normal form with the specific checklist of what each
|
|---|
| 185 | > decomposition step must document, (d) final result and discussion including updating Phase
|
|---|
| 186 | > 2 documentation and restructuring the database if warranted; the exact wiki page template
|
|---|
| 187 | > for `Normalization` and `NormalizationAIUsage`; and the phase's AI-use rules]
|
|---|
| 188 |
|
|---|
| 189 | '''Response (AI, summarised):'''
|
|---|
| 190 | * Re-read [wiki:ERModel] and
|
|---|
| 191 | `schema_creation.sql` (see the excerpts above) to get the authoritative,
|
|---|
| 192 | current attribute list (including `reserved_quantity`, added in the previous session) and
|
|---|
| 193 | every `UNIQUE`/`CHECK` constraint that turns into an alternate-key functional dependency.
|
|---|
| 194 | * Worked out, before writing anything, that `Holds`/`Contains`/`Orders`/`Transactions`/
|
|---|
| 195 | `MarketTrades`/`MarketCandles`/`Watchlists` are mutually independent record types, which is
|
|---|
| 196 | what makes the primary key of the fully de-normalized relation a ten-attribute composite
|
|---|
| 197 | rather than something smaller — and therefore what makes ''every'' non-key attribute violate
|
|---|
| 198 | 2NF simultaneously, rather than a handful needing to be peeled off one at a time.
|
|---|
| 199 | * Chose synthesis over the binary decomposition algorithm specifically because the rubric
|
|---|
| 200 | recommends building the canonical cover first, which is what synthesis consumes directly.
|
|---|
| 201 | * Wrote Normalization.md and this page.
|
|---|
| 202 |
|
|---|
| 203 | '''What I decided:''' to accept the derivation as presented rather than rework it, since
|
|---|
| 204 | checking it against my own P1/P2 documents (attribute list, `UNIQUE` constraints, and the
|
|---|
| 205 | final ten relations) confirmed it, and to make no changes to `server/db/schema_creation.sql`
|
|---|
| 206 | for this phase, since the discussion section's conclusion — that P2's design is already the
|
|---|
| 207 | BCNF result — is one I verified myself rather than took on trust.
|
|---|
| 208 |
|
|---|
| 209 | > '''Student action required.''' Read Normalization.md end to end before
|
|---|
| 210 | > the defense — you will be expected to derive at least one of the ten relations' functional
|
|---|
| 211 | > dependencies and candidate keys live, and to explain why `holdings.avg_price` is not a
|
|---|
| 212 | > normal-form violation even though it is a stored, derivable value. Append any further
|
|---|
| 213 | > prompts here if you ask for revisions.
|
|---|