Commit 2ebc08
2026-06-11 07:46:24 lisa: Add C05 page: From SRS to Detailed Designs — Data and Logic Traces one SRS sentence ('computed, never stored') through all four C05-1 data/logic tools — data dictionary, IPO charts, pseudocode, object descriptions — using the real SAT-grader project as a worked example with faded guidance. Sibling of the Mock-ups page; links added both ways and from C05-home. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>| sd/C05/C05-home.md .. | |
| @@ 12,6 12,7 @@ | |
| - [C04 → C05 — Choose, then Detail](/sd/C05/C04%20to%20C05%20-%20Choose%20then%20Detail) — how C05 (detail the chosen idea) differs from C04 (choose *which* idea); why C05 means "buildable", not "prettier" | |
| - [From SRS to Detailed Designs — Mock-ups](/sd/C05/From%20SRS%20to%20Detailed%20Designs%20-%20Mock-ups) — one real project (the SAT grader) traced from SRS requirement → C04 wireframe → C05 detailed design → build → correction; one trace fully worked, two faded for you to finish | |
| + | - [From SRS to Detailed Designs — Data and Logic](/sd/C05/From%20SRS%20to%20Detailed%20Designs%20-%20Data%20and%20Logic) — the same SAT grader project, but the *data/logic* tools: how one SRS sentence ("computed, never stored") drives the data dictionary, IPO charts, pseudocode and object descriptions as four views of one design |
| - [Sketch vs Mock-up](/sd/C05/Sketch%20vs%20Mock-up) — why a rough sketch is not a mock-up, and what "annotated" actually means (the 3–4 / 5–6 boundary) | |
| - [Data Dictionary](/sd/C05/Data%20Dictionary) — when to use it, the headings to include, a worked example, and why "format" is not "type" | |
| - [IPO Charts — Process Means Steps](/sd/C05/IPO%20Charts%20-%20Process%20Means%20Steps) — why the Process column must be numbered algorithm steps, not a label for the output | |
| /dev/null .. sd/C05/From SRS to Detailed Designs - Data and Logic.md | |
| @@ 0,0 1,322 @@ | |
| + | # From SRS to Detailed Designs — Data and Logic |
| + | |
| + | The Hamilton and Alexandra College · Year 12 · 2026 |
| + | |
| + | 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. |
| + | |
| + | 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. |
| + | |
| + | Here is that sentence. It is from §7 (Data model) of the real SRS, quoted exactly: |
| + | |
| + | > Derived values (bands, calculated scores, totals, ranks) are **computed, never stored**. |
| + | |
| + | 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. |
| + | |
| + | --- |
| + | |
| + | ## The four tools are one design |
| + | |
| + | 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. |
| + | |
| + | ```mermaid |
| + | flowchart TD |
| + | SRS["C03 · SRS §7<br/>Data model<br/>'computed, never stored'"] |
| + | SRS --> DD["Data dictionary<br/><i>what is stored vs derived</i>"] |
| + | SRS --> OD["Object descriptions<br/><i>attribute vs method</i>"] |
| + | SRS --> PC["Pseudocode<br/><i>how a value is derived</i>"] |
| + | SRS --> IPO["IPO charts<br/><i>input → process → output</i>"] |
| + | DD --> UI["Built UI"] |
| + | OD --> UI |
| + | PC --> UI |
| + | IPO --> UI |
| + | UI --> SEE["You can see the rule<br/>on screen:<br/>totals, bands, live summary"] |
| + | ``` |
| + | |
| + | 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. |
| + | |
| + | --- |
| + | |
| + | ## Fully worked: "computed, never stored", through all four tools |
| + | |
| + | 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. |
| + | |
| + | ### Tool 1 — Data dictionary: a separate section for what is *not* stored |
| + | |
| + | 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: |
| + | |
| + | > ## 5. Derived values (computed, never stored) |
| + | |
| + | A few of its rows: |
| + | |
| + | | Value | Derivation | Example | |
| + | | --- | --- | --- | |
| + | | Total 1 | Sum of criterion results for C01–C05 (Unit 3 Outcome 2) | `15` | |
| + | | Total 2 | Sum of criterion results for C06–C10 (Unit 4 Outcome 1) | `0` | |
| + | | Rank | Cohort summary row order: sorted by Total, descending | top row | |
| + | |
| + | Now look at the built Leaderboard. Those rows are not abstractions — they are columns on screen: |
| + | |
| + |  |
| + | |
| + | 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. |
| + | |
| + | > [!NOTE] |
| + | > 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. |
| + | |
| + | ### Tool 2 — Object descriptions: stored is an attribute, derived is a method |
| + | |
| + | The object descriptions say the same thing in object-oriented language. Teaching point 3, quoted exactly: |
| + | |
| + | > **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". |
| + | |
| + | 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. |
| + | |
| + | ### Tool 3 — Pseudocode: how the derived value is actually computed |
| + | |
| + | 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]`): |
| + | |
| + | - For each scored indicator, add `indicatorScore × weight` to `totalWeighted` and `weight` to `totalWeight`: `8 × 60 = 480`, `7 × 40 = 280`, so `totalWeighted = 760`, `totalWeight = 100`. |
| + | - `weighted ← totalWeighted / totalWeight` → `760 / 100 = 7.6`. |
| + | - `RETURN RoundHalfUp(weighted)` → `7.6 → 8`. |
| + | |
| + | 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. |
| + | |
| + | ### Tool 4 — IPO charts: it can recompute live *because* nothing is stored |
| + | |
| + | The IPO charts have an event row that only makes sense if derived values are never stored. Quoted exactly from the event-level table: |
| + | |
| + | > `live_summary` — Recompute the criterion score as indicator scores are typed. |
| + | |
| + | And a sibling row: |
| + | |
| + | > `band_of` — Which rubric band a score falls in. |
| + | |
| + | 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: |
| + | |
| + |  |
| + | |
| + | 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. |
| + | |
| + | Four tools, four costumes, one sentence. That is what "four views of one design" means. |
| + | |
| + | --- |
| + | |
| + | ## Each tool, anchored to a requirement (your turn to finish each) |
| + | |
| + | 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. |
| + | |
| + | ### Data dictionary ← FR2 + SRS §7 |
| + | |
| + | FR2 quoted exactly: |
| + | |
| + | > All data is persisted as **markdown files** (one file per student) — the single source of truth, editable by hand or by AI tools. |
| + | |
| + | "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. |
| + | |
| + | > **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".) |
| + | |
| + | ### IPO charts ← the context diagram |
| + | |
| + | 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: |
| + | |
| + | | Input | Process | Output | |
| + | | --- | --- | --- | |
| + | | 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) | |
| + | |
| + | 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. |
| + | |
| + | > [!TIP] |
| + | > 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. |
| + | |
| + | Here is one clean event row — `band_of`, the band highlight you saw on the Grade tab: |
| + | |
| + | | Event (trigger) | Input | Process | Output | |
| + | | --- | --- | --- | --- | |
| + | | Indicator score → change ×4 | Indicator score | `band_of` — Which rubric band a score falls in. | Band | |
| + | |
| + | 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. |
| + | |
| + | > **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"?) |
| + | |
| + | ### Pseudocode ← FR5 + corrections 06/07 |
| + | |
| + | FR5 quoted exactly: |
| + | |
| + | > 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. |
| + | |
| + | 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: |
| + | |
| + | > **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. |
| + | |
| + | The reconcile view is Algorithm 2 on screen: |
| + | |
| + |  |
| + | |
| + | 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: |
| + | |
| + | ``` |
| + | IF references = {calculated} THEN // no second opinion available |
| + | final ← calculated |
| + | ELSE IF Max(references) − Min(references) = 0 THEN |
| + | final ← calculated // unanimous |
| + | ELSE IF Max(references) − Min(references) ≤ 1 THEN |
| + | final ← teacher's choice IN [Min(references), Max(references)] |
| + | ELSE |
| + | // Major disagreement (gap ≥ 2): do not split the difference. |
| + | final ← teacher's judgement after review |
| + | END IF |
| + | ``` |
| + | |
| + | On screen, Calculated 8 and AI 8 agree — the `Max − Min = 0` branch — so the note reads "AI (8) matches calculated (8) — confirmed." |
| + | |
| + | > **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. |
| + | |
| + | ### Object descriptions ← the problem domain |
| + | |
| + | 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: |
| + | |
| + | ```mermaid |
| + | classDiagram |
| + | class GradeBook { |
| + | -students_dir: Path |
| + | +list_students() list~str~ |
| + | +load(name) Student |
| + | +save(student) void |
| + | +cohort_matrix() list~CohortRow~ |
| + | } |
| + | |
| + | class Student { |
| + | +name: str |
| + | +comment: str |
| + | +advice: str |
| + | +criterion_result(cid) int |
| + | +total1() int |
| + | +total2() int |
| + | +total() int |
| + | } |
| + | |
| + | class CriterionGrade { |
| + | +indicator_scores: list~int~ |
| + | +ai: int |
| + | +ai_evidence: str |
| + | +cross: int |
| + | +cross_note: str |
| + | +final: int |
| + | +final_note: str |
| + | +weighted() float |
| + | +calculated() int |
| + | +is_reconciled() bool |
| + | } |
| + | |
| + | class IndicatorEvidence { |
| + | +observation: dict~Band,str~ |
| + | +validation: dict~Band,str~ |
| + | +highest_band(category) Band |
| + | +validation_gap() bool |
| + | } |
| + | |
| + | class Criterion { |
| + | +id: str |
| + | +name: str |
| + | } |
| + | |
| + | class Indicator { |
| + | +name: str |
| + | +weight: int |
| + | +descriptor_table: str |
| + | +band_of(score) Band |
| + | } |
| + | |
| + | class Band { |
| + | <<enumeration>> |
| + | VERY_LOW_1_2 |
| + | LOW_3_4 |
| + | MEDIUM_5_6 |
| + | HIGH_7_8 |
| + | VERY_HIGH_9_10 |
| + | } |
| + | |
| + | GradeBook "1" o-- "0..*" Student : loads / saves |
| + | Student "1" *-- "0..10" CriterionGrade : grades |
| + | CriterionGrade "0..*" --> "1" Criterion : graded against |
| + | CriterionGrade "1" *-- "2..4" IndicatorEvidence : evidence |
| + | Criterion "1" *-- "2..4" Indicator : assessed by |
| + | Indicator ..> Band : maps scores to |
| + | ``` |
| + | |
| + | Notice the line shapes. Teaching point 1, quoted exactly: |
| + | |
| + | > **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). |
| + | |
| + | 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. |
| + | |
| + | > **Class discussion** — the app's author chose to *not* build these classes, using dicts and pure functions instead. From the artefact: |
| + | > |
| + | > > 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. |
| + | |
| + | --- |
| + | |
| + | ## Your turn — trace `validation_gap` through three tools |
| + | |
| + | 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: |
| + | |
| + | 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). |
| + | 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). |
| + | 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). |
| + | |
| + | Open all three and answer in your design log: |
| + | |
| + | 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. |
| + | 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? |
| + | 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"? |
| + | |
| + | --- |
| + | |
| + | ## The real files |
| + | |
| + | Open these on GitHub and read the originals. Each is the artefact a section above quotes. |
| + | |
| + | | Artefact | Link | |
| + | | --- | --- | |
| + | | 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) | |
| + | | 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) | |
| + | | 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) | |
| + | | 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) | |
| + | | 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) | |
| + | |
| + | > [!NOTE] |
| + | > 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. |
| + | |
| + | --- |
| + | |
| + | ## Check Your Understanding |
| + | |
| + | 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. |
| + | |
| + | >| 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. |
| + | |
| + | 2. Why is `final` an **attribute** but `calculated()` a **method**? |
| + | |
| + | >| `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. |
| + | |
| + | 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? |
| + | |
| + | >| 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. |
| + | |
| + | 4. What makes the IPO charts unable to drift apart from the build? |
| + | |
| + | >| 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. |
| + | |
| + | --- |
| + | |
| + | ## See also |
| + | |
| + | - [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*. |
| + | - [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. |
| + | - [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. |
| + | - [VCAA Pseudocode Not Python](VCAA%20Pseudocode%20Not%20Python) — teaches language-independent pseudocode in general; this page shows two real algorithms doing the work. |
| + | - [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. |
| + | |
| + | --- |
| + | |
| + | ← Back to [C05 Home](/sd/C05/C05-home) · [VCE Software Development Hub](/sd/VCE%20Software%20Development%20Hub) |
| /dev/null .. sd/C05/From SRS to Detailed Designs - Data and Logic/01-grade-tab.png | |
| /dev/null .. sd/C05/From SRS to Detailed Designs - Data and Logic/correction-06-after-score-reconcile.png | |
| /dev/null .. sd/C05/From SRS to Detailed Designs - Data and Logic/correction-08-after-leaderboard-cohort.png | |
| sd/C05/From SRS to Detailed Designs - Mock-ups.md .. | |
| @@ 167,6 167,7 @@ | |
| - [Connect the Dots](Connect%20the%20Dots) — the theory this page demonstrates: annotate → link to the SRS → trace one feature all the way through. | |
| - [C04 to C05 - Choose then Detail](C04%20to%20C05%20-%20Choose%20then%20Detail) — why C04 (choose *which* idea) and C05 (detail it until it is buildable) are different jobs; the breadth → depth shift behind every trace above. | |
| + | - [From SRS to Detailed Designs — Data and Logic](From%20SRS%20to%20Detailed%20Designs%20-%20Data%20and%20Logic) — the sibling trace on the same project: how one SRS sentence drives the data dictionary, IPO charts, pseudocode and object descriptions. |
| --- | |
