Blame
|
1 | # From SRS to Detailed Designs — Data and Logic |
||||||
| 2 | ||||||||
| 3 | The Hamilton and Alexandra College · Year 12 · 2026 |
|||||||
| 4 | ||||||||
| 5 | The [Mock-ups sibling of this page](From%20SRS%20to%20Detailed%20Designs%20-%20Mock-ups) traces a *screen* back to a requirement. This page traces the **data and logic** the same way, using the same real project — `vsd-sat-grader`, the SAT folio grader your teacher actually built. |
|||||||
| 6 | ||||||||
| 7 | C05-1 asks for four data/logic design tools: a **data dictionary**, **IPO charts**, **pseudocode**, and **object descriptions**. The trap is to treat them as four separate deliverables you grind out one after another. They are not. They are **four views of one design**, and the proof is simple: a single sentence from your SRS shows up in all four of them. |
|||||||
| 8 | ||||||||
| 9 | Here is that sentence. It is from §7 (Data model) of the real SRS, quoted exactly: |
|||||||
| 10 | ||||||||
| 11 | > Derived values (bands, calculated scores, totals, ranks) are **computed, never stored**. |
|||||||
| 12 | ||||||||
| 13 | That one rule — *store the inputs, compute everything you can derive from them* — is the spine of this page. We follow it through all four tools, then through the built UI, and you will see the same idea each time wearing a different costume. |
|||||||
| 14 | ||||||||
| 15 | --- |
|||||||
| 16 | ||||||||
| 17 | ## The four tools are one design |
|||||||
| 18 | ||||||||
| 19 | The SRS data model is the source. Each design tool is a different lens on it, and each lens also surfaces in the app you can run. |
|||||||
| 20 | ||||||||
| 21 | ```mermaid |
|||||||
| 22 | flowchart TD |
|||||||
| 23 | SRS["C03 · SRS §7<br/>Data model<br/>'computed, never stored'"] |
|||||||
| 24 | SRS --> DD["Data dictionary<br/><i>what is stored vs derived</i>"] |
|||||||
| 25 | SRS --> OD["Object descriptions<br/><i>attribute vs method</i>"] |
|||||||
| 26 | SRS --> PC["Pseudocode<br/><i>how a value is derived</i>"] |
|||||||
| 27 | SRS --> IPO["IPO charts<br/><i>input → process → output</i>"] |
|||||||
| 28 | DD --> UI["Built UI"] |
|||||||
| 29 | OD --> UI |
|||||||
| 30 | PC --> UI |
|||||||
| 31 | IPO --> UI |
|||||||
| 32 | UI --> SEE["You can see the rule<br/>on screen:<br/>totals, bands, live summary"] |
|||||||
| 33 | ``` |
|||||||
| 34 | ||||||||
| 35 | The four tools answer four questions about the *same* truth — and because the SRS forbids storing derived values, every tool has to agree on which values those are. Disagreement between tools is a design bug. Agreement is traceability. |
|||||||
| 36 | ||||||||
| 37 | --- |
|||||||
| 38 | ||||||||
| 39 | ## Fully worked: "computed, never stored", through all four tools |
|||||||
| 40 | ||||||||
| 41 | We will now walk the one SRS sentence through every tool, quoting each artefact's own wording so you can see the rule restated in each language. |
|||||||
| 42 | ||||||||
| 43 | ### Tool 1 — Data dictionary: a separate section for what is *not* stored |
|||||||
| 44 | ||||||||
| 45 | The data dictionary has a §4 for the **student record** (everything stored to disk) and a separate §5 for **derived values**. The heading is exact: |
|||||||
| 46 | ||||||||
| 47 | > ## 5. Derived values (computed, never stored) |
|||||||
| 48 | ||||||||
| 49 | A few of its rows: |
|||||||
| 50 | ||||||||
| 51 | | Value | Derivation | Example | |
|||||||
| 52 | | --- | --- | --- | |
|||||||
| 53 | | Total 1 | Sum of criterion results for C01–C05 (Unit 3 Outcome 2) | `15` | |
|||||||
| 54 | | Total 2 | Sum of criterion results for C06–C10 (Unit 4 Outcome 1) | `0` | |
|||||||
| 55 | | Rank | Cohort summary row order: sorted by Total, descending | top row | |
|||||||
| 56 | ||||||||
| 57 | Now look at the built Leaderboard. Those rows are not abstractions — they are columns on screen: |
|||||||
| 58 | ||||||||
| 59 |  |
|||||||
| 60 | ||||||||
| 61 | The column headers **Total 1 (C01–C05)**, **Total 2 (C06–C10)** and **Total** are the three data-dictionary rows above, made visible. And the **row order is the derived "Rank"**: Cohen (Total 15) sits above Connor (Total 9) because the table is "sorted by Total, descending" — the app never stores a rank number, it sorts and the position *is* the rank. |
|||||||
| 62 | ||||||||
| 63 | > [!NOTE] |
|||||||
| 64 | > The scores here are **Sprint 1 mock data**, not real grades. Cohen's C03 indicators are `[8, 7]` — the exact example student record shown in the SRS §7 code block. That is why the same numbers reappear throughout this page: they are the SRS's own worked example travelling from artefact to artefact. |
|||||||
| 65 | ||||||||
| 66 | ### Tool 2 — Object descriptions: stored is an attribute, derived is a method |
|||||||
| 67 | ||||||||
| 68 | The object descriptions say the same thing in object-oriented language. Teaching point 3, quoted exactly: |
|||||||
| 69 | ||||||||
| 70 | > **Stored vs derived, as attribute vs method** — `final` is an attribute (a teacher's decision, stored); `calculated()` is a method (a weighted average, derived). This is the class-diagram form of our data rule "derived values are never stored". |
|||||||
| 71 | ||||||||
| 72 | So the data dictionary's "stored vs derived" split is the object model's "attribute vs method" split. `final` carries `()` nowhere — it is a value you keep. `calculated()` carries `()` — it is a value you *compute on demand* and throw away. |
|||||||
| 73 | ||||||||
| 74 | ### Tool 3 — Pseudocode: how the derived value is actually computed |
|||||||
| 75 | ||||||||
| 76 | The data dictionary says a calculated score *is* derived. The object model says `calculated()` is a method. The pseudocode says **how**. Algorithm 1 derives it, hop by hop, for Cohen's C03 (`[8, 7]`, weights `[60, 40]`): |
|||||||
| 77 | ||||||||
| 78 | - For each scored indicator, add `indicatorScore × weight` to `totalWeighted` and `weight` to `totalWeight`: `8 × 60 = 480`, `7 × 40 = 280`, so `totalWeighted = 760`, `totalWeight = 100`. |
|||||||
| 79 | - `weighted ← totalWeighted / totalWeight` → `760 / 100 = 7.6`. |
|||||||
| 80 | - `RETURN RoundHalfUp(weighted)` → `7.6 → 8`. |
|||||||
| 81 | ||||||||
| 82 | Nothing in that algorithm reads a stored score. It reads the **inputs** (indicator scores, weights) and derives the result fresh every time — exactly what "computed, never stored" demands. |
|||||||
| 83 | ||||||||
| 84 | ### Tool 4 — IPO charts: it can recompute live *because* nothing is stored |
|||||||
| 85 | ||||||||
| 86 | The IPO charts have an event row that only makes sense if derived values are never stored. Quoted exactly from the event-level table: |
|||||||
| 87 | ||||||||
| 88 | > `live_summary` — Recompute the criterion score as indicator scores are typed. |
|||||||
| 89 | ||||||||
| 90 | And a sibling row: |
|||||||
| 91 | ||||||||
| 92 | > `band_of` — Which rubric band a score falls in. |
|||||||
| 93 | ||||||||
| 94 | If the calculated score were stored, you would have to save it before it could update. Because it is derived, the app can **recompute it on every keystroke**. Here is the Grade tab where both rows fire: |
|||||||
| 95 | ||||||||
| 96 |  |
|||||||
| 97 | ||||||||
| 98 | The **7-8 band is highlighted in orange** because `band_of(8)` returns the `7-8` band — that highlight is the `band_of` IPO output rendered on screen. As you type a score, `live_summary` re-derives the criterion score behind the Score tab. Neither value is written to disk until you Save; both are derived live. That is the IPO chart's restatement of the same one rule. |
|||||||
| 99 | ||||||||
| 100 | Four tools, four costumes, one sentence. That is what "four views of one design" means. |
|||||||
| 101 | ||||||||
| 102 | --- |
|||||||
| 103 | ||||||||
| 104 | ## Each tool, anchored to a requirement (your turn to finish each) |
|||||||
| 105 | ||||||||
| 106 | Above, the guidance was full. Below, it fades: each tool gets a short section that names *which requirement it answers*, then ends with **one question** for you to take into your design log. |
|||||||
| 107 | ||||||||
| 108 | ### Data dictionary ← FR2 + SRS §7 |
|||||||
| 109 | ||||||||
| 110 | FR2 quoted exactly: |
|||||||
| 111 | ||||||||
| 112 | > All data is persisted as **markdown files** (one file per student) — the single source of truth, editable by hand or by AI tools. |
|||||||
| 113 | ||||||||
| 114 | "One file per student" is why the data dictionary's §4 documents a single **student record** shape (`student`, `grades`, `comment`, `advice`) rather than a database schema. SRS §7 shows that record as YAML frontmatter; the data dictionary gives each field a type, format, example and validation rule. The frontmatter shape *is* the data dictionary, written out as a file. |
|||||||
| 115 | ||||||||
| 116 | > **Your design log:** find one field in data-dictionary §4 whose **Validation** column would be impossible to enforce if data lived in a database instead of one markdown file per student. (Hint: look at `student` — "Unique within cohort".) |
|||||||
| 117 | ||||||||
| 118 | ### IPO charts ← the context diagram |
|||||||
| 119 | ||||||||
| 120 | You met **context diagrams** back in C02 — one process, the external entities around it, the data flowing in and out. The IPO charts pick up exactly there. The system-level IPO row is built straight from the context diagram: |
|||||||
| 121 | ||||||||
| 122 | | Input | Process | Output | |
|||||||
| 123 | | --- | --- | --- | |
|||||||
| 124 | | Indicator scores + evidence, cross-mark + note, final score + note, report comments (Teacher 1); AI suggested score + evidence (Claude Code, via markdown) | Grade each criterion per indicator; weight indicator scores into calculated criterion scores; support reconciliation; aggregate cohort totals | Rubric descriptors, calculated scores with working, reconcile view, cohort summary (Teacher 1); evidence + rubric + scores as markdown (to Claude Code); final scores + report (to School Report System) | |
|||||||
| 125 | ||||||||
| 126 | The external entities from the context diagram (Teacher 1, Claude Code, the School Report System) reappear here as the *sources* of inputs and the *destinations* of outputs. |
|||||||
| 127 | ||||||||
| 128 | > [!TIP] |
|||||||
| 129 | > The event-level IPO charts are **generated from the app's own event wiring**, so design and build cannot drift apart. The artefact says so: every Gradio handler is `trigger.change(process, [inputs], [outputs])`, so the charts are produced by `tools/generate_ipo.py` and you "regenerate after any wiring change with `uv run python tools/generate_ipo.py`". Change the build, regenerate, the design updates — they are never out of sync. |
|||||||
| 130 | ||||||||
| 131 | Here is one clean event row — `band_of`, the band highlight you saw on the Grade tab: |
|||||||
| 132 | ||||||||
| 133 | | Event (trigger) | Input | Process | Output | |
|||||||
| 134 | | --- | --- | --- | --- | |
|||||||
| 135 | | Indicator score → change ×4 | Indicator score | `band_of` — Which rubric band a score falls in. | Band | |
|||||||
| 136 | ||||||||
| 137 | The big `refresh` row — the one fired by changing student or criterion — has an Output column listing every component on every tab (`Grade 1, Grade 2, … Cohort summary`). It is auto-generated and gloriously long, so it is not reproduced here. Read it in the [full ipo-charts.md on GitHub](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/ipo-charts.md); its length is a feature, not a flaw — it is the machine listing every output one reload must refresh. |
|||||||
| 138 | ||||||||
| 139 | > **Your design log:** the `refresh` row has a huge Output column but a tiny Input column (just Name, Criteria). Why does one small input produce so many outputs? (What does "reload every tab" have to do with NFR1, "fresh reads, no caches"?) |
|||||||
| 140 | ||||||||
| 141 | ### Pseudocode ← FR5 + corrections 06/07 |
|||||||
| 142 | ||||||||
| 143 | FR5 quoted exactly: |
|||||||
| 144 | ||||||||
| 145 | > The app **displays an AI-suggested score + evidence** when present in the markdown (produced externally — see §6). The app is read-only toward these fields. |
|||||||
| 146 | ||||||||
| 147 | The app *shows* the AI score; it never trusts it blindly. Deciding the **final** score is a human job, and the pseudocode has two algorithms precisely to make that split explicit. Algorithm 1 (above) is automated. **Algorithm 2 is a teacher procedure the app deliberately never automates.** Design note 1, quoted exactly: |
|||||||
| 148 | ||||||||
| 149 | > **The final score is never computed** — Algorithm 2 contains teacher decisions ("teacher's choice", "teacher's judgement") by design. The app automates the references, not the judgement. |
|||||||
| 150 | ||||||||
| 151 | The reconcile view is Algorithm 2 on screen: |
|||||||
| 152 | ||||||||
| 153 |  |
|||||||
| 154 | ||||||||
| 155 | Three reference scores are shown side by side — Calculated (8), AI (8), and a place for the cross-mark — and the teacher types the **Final** and a note. The app presents; the human decides. Algorithm 2's decision structure, quoted from the pseudocode: |
|||||||
| 156 | ||||||||
| 157 | ``` |
|||||||
| 158 | IF references = {calculated} THEN // no second opinion available |
|||||||
| 159 | final ← calculated |
|||||||
| 160 | ELSE IF Max(references) − Min(references) = 0 THEN |
|||||||
| 161 | final ← calculated // unanimous |
|||||||
| 162 | ELSE IF Max(references) − Min(references) ≤ 1 THEN |
|||||||
| 163 | final ← teacher's choice IN [Min(references), Max(references)] |
|||||||
| 164 | ELSE |
|||||||
| 165 | // Major disagreement (gap ≥ 2): do not split the difference. |
|||||||
| 166 | final ← teacher's judgement after review |
|||||||
| 167 | END IF |
|||||||
| 168 | ``` |
|||||||
| 169 | ||||||||
| 170 | On screen, Calculated 8 and AI 8 agree — the `Max − Min = 0` branch — so the note reads "AI (8) matches calculated (8) — confirmed." |
|||||||
| 171 | ||||||||
| 172 | > **Your design log:** the last branch forbids "split the difference" when references disagree by 2 or more. Quote design note 3 and explain what a gap of 2 is taken to *mean* about the evidence. |
|||||||
| 173 | ||||||||
| 174 | ### Object descriptions ← the problem domain |
|||||||
| 175 | ||||||||
| 176 | The object descriptions model the **problem domain** — the classes you would design *before* choosing an implementation style. (The real app is built function-over-data, not from these classes; more on that below.) The class diagram, verbatim from the artefact: |
|||||||
| 177 | ||||||||
| 178 | ```mermaid |
|||||||
| 179 | classDiagram |
|||||||
| 180 | class GradeBook { |
|||||||
| 181 | -students_dir: Path |
|||||||
| 182 | +list_students() list~str~ |
|||||||
| 183 | +load(name) Student |
|||||||
| 184 | +save(student) void |
|||||||
| 185 | +cohort_matrix() list~CohortRow~ |
|||||||
| 186 | } |
|||||||
| 187 | ||||||||
| 188 | class Student { |
|||||||
| 189 | +name: str |
|||||||
| 190 | +comment: str |
|||||||
| 191 | +advice: str |
|||||||
| 192 | +criterion_result(cid) int |
|||||||
| 193 | +total1() int |
|||||||
| 194 | +total2() int |
|||||||
| 195 | +total() int |
|||||||
| 196 | } |
|||||||
| 197 | ||||||||
| 198 | class CriterionGrade { |
|||||||
| 199 | +indicator_scores: list~int~ |
|||||||
| 200 | +ai: int |
|||||||
| 201 | +ai_evidence: str |
|||||||
| 202 | +cross: int |
|||||||
| 203 | +cross_note: str |
|||||||
| 204 | +final: int |
|||||||
| 205 | +final_note: str |
|||||||
| 206 | +weighted() float |
|||||||
| 207 | +calculated() int |
|||||||
| 208 | +is_reconciled() bool |
|||||||
| 209 | } |
|||||||
| 210 | ||||||||
| 211 | class IndicatorEvidence { |
|||||||
| 212 | +observation: dict~Band,str~ |
|||||||
| 213 | +validation: dict~Band,str~ |
|||||||
| 214 | +highest_band(category) Band |
|||||||
| 215 | +validation_gap() bool |
|||||||
| 216 | } |
|||||||
| 217 | ||||||||
| 218 | class Criterion { |
|||||||
| 219 | +id: str |
|||||||
| 220 | +name: str |
|||||||
| 221 | } |
|||||||
| 222 | ||||||||
| 223 | class Indicator { |
|||||||
| 224 | +name: str |
|||||||
| 225 | +weight: int |
|||||||
| 226 | +descriptor_table: str |
|||||||
| 227 | +band_of(score) Band |
|||||||
| 228 | } |
|||||||
| 229 | ||||||||
| 230 | class Band { |
|||||||
| 231 | <<enumeration>> |
|||||||
| 232 | VERY_LOW_1_2 |
|||||||
| 233 | LOW_3_4 |
|||||||
| 234 | MEDIUM_5_6 |
|||||||
| 235 | HIGH_7_8 |
|||||||
| 236 | VERY_HIGH_9_10 |
|||||||
| 237 | } |
|||||||
| 238 | ||||||||
| 239 | GradeBook "1" o-- "0..*" Student : loads / saves |
|||||||
| 240 | Student "1" *-- "0..10" CriterionGrade : grades |
|||||||
| 241 | CriterionGrade "0..*" --> "1" Criterion : graded against |
|||||||
| 242 | CriterionGrade "1" *-- "2..4" IndicatorEvidence : evidence |
|||||||
| 243 | Criterion "1" *-- "2..4" Indicator : assessed by |
|||||||
| 244 | Indicator ..> Band : maps scores to |
|||||||
| 245 | ``` |
|||||||
| 246 | ||||||||
| 247 | Notice the line shapes. Teaching point 1, quoted exactly: |
|||||||
| 248 | ||||||||
| 249 | > **Composition vs association** — a `Student` *owns* their `CriterionGrade`s (delete the student, the grades go too: filled diamond), but a grade merely *refers to* its `Criterion` — the rubric exists independently and is shared by every student (arrow, not diamond). |
|||||||
| 250 | ||||||||
| 251 | So `Student *-- CriterionGrade` is a filled diamond (composition: the grades belong to that student and die with them), while `CriterionGrade --> Criterion` is a plain arrow (association: the rubric is shared, not owned). The diamond is not decoration — it encodes who owns what. |
|||||||
| 252 | ||||||||
| 253 | > **Class discussion** — the app's author chose to *not* build these classes, using dicts and pure functions instead. From the artefact: |
|||||||
| 254 | > |
|||||||
| 255 | > > the implementation chose dicts + pure functions over these classes. What did that trade away (encapsulation, invariants living next to the data) and what did it buy (markdown round-tripping is trivial, functions are easy to unit test, no object/file mapping layer)? Both are valid detailed designs; the object description is how you *communicate* the domain either way. |
|||||||
| 256 | ||||||||
| 257 | --- |
|||||||
| 258 | ||||||||
| 259 | ## Your turn — trace `validation_gap` through three tools |
|||||||
| 260 | ||||||||
| 261 | You have seen "computed, never stored" appear in four tools. Now trace a different idea **yourself**. The anti-AI-cheating check — *the standard observed in class was not reproduced under assessment conditions* — lives, like that sentence, in three artefacts at once: |
|||||||
| 262 | ||||||||
| 263 | 1. **Pseudocode**, as the guard at the top of Algorithm 2: a `FOR EACH indicator` loop that flags `REVIEW` when `HighestBand(indicator.validation) < HighestBand(indicator.observation)` — in [pseudocode-final-score.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/pseudocode-final-score.md). |
|||||||
| 264 | 2. **Object descriptions**, as the method `validation_gap()` on `IndicatorEvidence` — in [object-descriptions.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/object-descriptions.md). |
|||||||
| 265 | 3. **Data dictionary**, as the two evidence fields it compares: `…evidence[i].observation` and `…evidence[i].validation` — in [data-dictionary.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/data-dictionary.md). |
|||||||
| 266 | ||||||||
| 267 | Open all three and answer in your design log: |
|||||||
| 268 | ||||||||
| 269 | 1. The pseudocode guard and the `validation_gap()` method describe the *same* comparison. Quote the condition from each and show they are the same test written two ways. |
|||||||
| 270 | 2. The data dictionary says `validation` is "Evidence under assessment conditions (no AI / outside help); confirms the judgement." Why does a *lower* validation band than observation band suggest a problem worth reviewing? |
|||||||
| 271 | 3. Is `validation_gap` a **stored** value or a **derived** one? Which tool would you cite to justify your answer, and how does that connect back to "computed, never stored"? |
|||||||
| 272 | ||||||||
| 273 | --- |
|||||||
| 274 | ||||||||
| 275 | ## The real files |
|||||||
| 276 | ||||||||
| 277 | Open these on GitHub and read the originals. Each is the artefact a section above quotes. |
|||||||
| 278 | ||||||||
| 279 | | Artefact | Link | |
|||||||
| 280 | | --- | --- | |
|||||||
| 281 | | SRS (FR/NFR tables, §7 data model, MoSCoW scope) | [SRS/SRS.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/SRS/SRS.md) | |
|||||||
| 282 | | Data dictionary (stored §4, derived §5) | [C05/data-dictionary.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/data-dictionary.md) | |
|||||||
| 283 | | IPO charts (system-level + generated event rows) | [C05/ipo-charts.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/ipo-charts.md) | |
|||||||
| 284 | | Pseudocode (Algorithm 1 automated, Algorithm 2 teacher procedure) | [C05/pseudocode-final-score.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/pseudocode-final-score.md) | |
|||||||
| 285 | | Object descriptions (class diagram + teaching points) | [C05/object-descriptions.md](https://github.com/vce-soft-dev/SD26-Students/blob/main/Proj-SAT-Grader-UI/C05/object-descriptions.md) | |
|||||||
| 286 | ||||||||
| 287 | > [!NOTE] |
|||||||
| 288 | > The `SD26-Students` repository is **private**. To open these links you must be signed in to GitHub with your class account. If you get a 404, you are not signed in — log in and try again. |
|||||||
| 289 | ||||||||
| 290 | --- |
|||||||
| 291 | ||||||||
| 292 | ## Check Your Understanding |
|||||||
| 293 | ||||||||
| 294 | 1. One SRS sentence appears in all four design tools. Quote it, then name the **form** it takes in each tool: the data dictionary, the object descriptions, the pseudocode, and the IPO charts. |
|||||||
| 295 | ||||||||
| 296 | >| The sentence is SRS §7: "Derived values (bands, calculated scores, totals, ranks) are computed, never stored." In the **data dictionary** it is a separate §5 "Derived values (computed, never stored)" table. In the **object descriptions** it is the attribute-vs-method split — `final` is a stored attribute, `calculated()` is a derived method. In the **pseudocode** it is Algorithm 1, which derives the calculated score from inputs every time. In the **IPO charts** it is the `live_summary` / `band_of` rows that recompute on every keystroke — only possible because the values are never stored. |
|||||||
| 297 | ||||||||
| 298 | 2. Why is `final` an **attribute** but `calculated()` a **method**? |
|||||||
| 299 | ||||||||
| 300 | >| `final` is the teacher's reconciled decision — a value you *store*, because it cannot be re-derived from anything (it is a judgement). `calculated()` is a weighted average of the indicator scores — a value you *derive on demand* from inputs that already exist, so storing it would break "computed, never stored". Attribute = stored input; method = derived output. |
|||||||
| 301 | ||||||||
| 302 | 3. Algorithm 2 contains the words "teacher's judgement" instead of a formula. Why is that a deliberate design decision, not a missing piece of the algorithm? |
|||||||
| 303 | ||||||||
| 304 | >| Design note 1 says so: "The final score is never computed … the app automates the references, not the judgement." FR5 makes the app read-only toward the AI score, and reconciling calculated vs AI vs cross-mark is a moderation decision a human must own. Replacing the judgement with a formula (e.g. averaging) would make the app decide grades — and design note 3 explicitly forbids averaging across a disagreement of 2 or more, because a large gap signals mis-banded evidence to re-examine, not a number to split. |
|||||||
| 305 | ||||||||
| 306 | 4. What makes the IPO charts unable to drift apart from the build? |
|||||||
| 307 | ||||||||
| 308 | >| They are **generated from the app's own event wiring** by `tools/generate_ipo.py` — each chart is read straight out of the Gradio `trigger.change(process, [inputs], [outputs])` handlers. The build *is* the source of the chart, so you regenerate after any wiring change (`uv run python tools/generate_ipo.py`) and the design updates with it. A hand-written chart can fall out of date; a generated one cannot. |
|||||||
| 309 | ||||||||
| 310 | --- |
|||||||
| 311 | ||||||||
| 312 | ## See also |
|||||||
| 313 | ||||||||
| 314 | - [From SRS to Detailed Designs — Mock-ups](From%20SRS%20to%20Detailed%20Designs%20-%20Mock-ups) — the sibling page: traces a *screen* (FR3, FR9, FR6) from SRS → wireframe → build → correction, where this page traces the *data and logic*. |
|||||||
| 315 | - [Data Dictionary](Data%20Dictionary) — teaches the data-dictionary tool in general (headings, why "format" is not "type"); this page shows it working with the other three on a real project. |
|||||||
| 316 | - [IPO Charts - Process Means Steps](IPO%20Charts%20-%20Process%20Means%20Steps) — teaches the IPO tool in general (Process = numbered steps); this page shows a generated IPO chart in context. |
|||||||
| 317 | - [VCAA Pseudocode Not Python](VCAA%20Pseudocode%20Not%20Python) — teaches language-independent pseudocode in general; this page shows two real algorithms doing the work. |
|||||||
| 318 | - [Object Descriptions and Class Diagrams](Object%20Descriptions%20and%20Class%20Diagrams) — teaches the object-description tool in general (attributes, methods, reading a class diagram); this page shows a real class diagram tied to the data rule. |
|||||||
| 319 | ||||||||
| 320 | --- |
|||||||
| 321 | ||||||||
| 322 | ← Back to [C05 Home](/sd/C05/C05-home) · [VCE Software Development Hub](/sd/VCE%20Software%20Development%20Hub) |
|||||||
