Add the plan baseline: business case, stakeholders, plan, design and milestones
Business Case, Stakeholder Analysis, Project Plan, use case chain (UCD, US, UC, DM, SSD, OC, SD, DCD, DICT), three ADRs, milestones MIL-001 to MIL-007, the traceability matrix and 22 review records (autonomous mode, AI as stand-in for S01).
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# MIL-001: Project foundation
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-001 |
|
||||
| CrossReference | [BC-001], [US-001], [DCD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether the project can start building features: the repository has its configuration, layer skeleton, tooling and run instructions, so that every later milestone adds behaviour to a ready structure.
|
||||
|
||||
## Deliverable
|
||||
|
||||
A repository in which `pip install -e ".[dev]"` works in a fresh `.venv`, `pytest` runs (with the placeholder test passing), the four layer packages and the three test folders exist, and the README explains how to create the virtual environment, run the program and run the tests.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `pyproject.toml` declares Python `>=3.13`, an empty `dependencies` list, the extras `speech` and `dev`, and the pytest, ruff and mypy configuration | Present and `pip install -e ".[dev]"` succeeds in a fresh `.venv` | Missing or install fails |
|
||||
| 2 | `.gitignore` is a Python ignore file and also ignores `.venv/`, `.env`, `data/words_to_learn.csv` and `docs/doxygen/` | `git check-ignore` reports each path | A path is not ignored |
|
||||
| 3 | `src/flash_card/` has `domain`, `application`, `infrastructure` and `presentation` packages and `constants.py`; `tests/` has `unit`, `integration`, `e2e` | Every folder exists | A folder is missing |
|
||||
| 4 | `doxygen Doxyfile` runs without error | Exit code 0 | Any error |
|
||||
| 5 | README follows the framework template and gives the `.venv` and `python -m pip install --upgrade pip` commands | `check-readme.sh` reports no finding | Any finding |
|
||||
| 6 | `pytest` exits with 0 | Exit code 0 | Any failure |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| BC-001, SA-001, PP-001 accepted | Required by the plan-first gate before a milestone |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 3 (no runtime dependencies) and objective 4 (repository others can use) | [BC-001] |
|
||||
| Success criteria 3 and 4 | [BC-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-14 — the first day of the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Add pyproject.toml | Declare the project `flash-card` for Python 3.13 or later with no runtime dependencies, an optional `speech` extra (`gTTS`, `playsound==1.2.2`) and a `dev` extra (`pytest`, `ruff`, `mypy`), and configure pytest (`src` on the path, `tests` folder), ruff and mypy. Meets objective 3 of the Business Case and ADR-0001. | No | ADR-0001 |
|
||||
| 2 | Add Python .gitignore | Ignore Python build and cache output, `.venv/`, the local `.env` with tokens that is never imported into the project, the generated `docs/doxygen/` and the learner's own `data/words_to_learn.csv`. | No | |
|
||||
| 3 | Create the layer skeleton and constants.py | Create `src/flash_card/` with the packages `domain`, `application`, `infrastructure`, `presentation` and `constants.py` (background colour, fonts, delay 3000 ms, file names), and `tests/unit`, `tests/integration`, `tests/e2e`, as ADR-0002 and DCD-001 set out. | No | ADR-0002, DCD-001 |
|
||||
| 4 | Add the Doxyfile | Add a `Doxyfile` for `src/` with Python optimisation, output in `docs/doxygen/`, so that the Doxygen comments written in every later milestone produce documentation. | No | |
|
||||
| 5 | Write the first README with the .venv instructions | Create README.md from the framework template with overview, requirements, and the commands to create and activate `.venv`, upgrade pip with `python -m pip install --upgrade pip`, install, run and test, for Windows and Linux/macOS. | No | |
|
||||
| 6 | Add the word list to the repository | Commit `data/ms-da.csv` (1000 Malay words with Danish translation, semicolon separated, header `ms;da`) and describe its origin and that it is machine translated, in `data/README.md`. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[DCD-001]: ../dcd.md
|
||||
@@ -0,0 +1,74 @@
|
||||
# MIL-002: Step 1 - User interface
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-002 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether the window of assignment step 1 is complete: a card with a language name and a word, and the two buttons, laid out as the wireframe shows.
|
||||
|
||||
## Deliverable
|
||||
|
||||
The program starts and shows the window described in `docs/uc-001/wireframe.md`: a 2 x 2 grid where the card (a canvas with the front image and two texts) spans both columns, and the unknown and known buttons are below it. The card shows placeholder text; no data is read yet. The four images are generated by a script of this repository.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `python -m flash_card` opens a window titled "Flashy" with background `#B1DDC6` and padding 50 px | Observed, and asserted by the e2e test where a display exists | Different title, colour or padding |
|
||||
| 2 | The canvas is 800 x 526 and holds one image and two texts (Arial 40 italic, Arial 60 bold) | Asserted by the e2e test | Any difference |
|
||||
| 3 | The buttons use `wrong.png` and `right.png` with no border and sit in row 1, columns 0 and 1 | Asserted by the e2e test | Any difference |
|
||||
| 4 | The view holds no rule: the view model gives the texts | View model unit tests pass without Tkinter | A rule is in the view |
|
||||
| 5 | The code review against QC-PY-001 has no failed Mandatory criterion | `RC-*` verdict Go | Verdict No-Go |
|
||||
| 6 | `pytest` exits with 0 | Exit code 0 | Any failure |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-001 | The configuration, layer skeleton and tooling |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 1, step 1 of the assignment | [BC-001] |
|
||||
| US-001.01 See a flash card | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-15 — within the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Generate the card and button images | Write `tools/generate_images.py`, a standard library script that draws `card_front.png`, `card_back.png` (800 x 526, rounded card), `right.png` and `wrong.png` (button icons) with a PNG writer, so no course asset is redistributed; commit the four generated files in `src/flash_card/presentation/assets/`. | No | |
|
||||
| 2 | Show the flash card window | Build `FlashCardView` with Tkinter: window title, padding, background, a 2 x 2 grid, the card canvas spanning two columns with image and two texts, and the two image buttons, as in the wireframe. Keep `PhotoImage` objects as attributes so they are not garbage collected. | Yes | US-001.01, wireframe.md |
|
||||
| 3 | Add the view model, entry point and composition root | `FlashCardViewModel` exposes the language name and word (placeholders at this step), `presentation/app.py` builds and runs the view, and `python -m flash_card` calls it. | Yes | US-001.01 |
|
||||
| 4 | Test the view model and the window | Unit tests of the view model; an e2e test that creates the window, reads the canvas and button configuration and destroys it, skipped when no display is available. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[UC-001]: ../uc-001/uc.md
|
||||
@@ -0,0 +1,76 @@
|
||||
# MIL-003: Step 2 - New flash cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-003 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-001], [DCD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether assignment step 2 works: the word list is read from `data/ms-da.csv` and each press of a button shows a new random card.
|
||||
|
||||
## Deliverable
|
||||
|
||||
The program reads the word list and shows a random Malay word with the language name "Malay". Pressing the known or the unknown button shows another random word. The domain classes, the CSV reader and the use case that draws cards exist with tests.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `CsvVocabularyRepository` reads `data/ms-da.csv` into 1000 cards with the language pair `ms`, `da` | Integration test passes on the real file | Any other count or pair |
|
||||
| 2 | A file with a missing header, a row with other than two cells, or no file raises a specific `VocabularyError` subclass | Unit tests pass | An unspecific exception or a silent skip |
|
||||
| 3 | A button press shows a card different from the current one when the deck has two or more cards, and the same card when it has one | Unit tests pass | Any other behaviour |
|
||||
| 4 | Blank lines in the CSV file are ignored | Unit test passes | A blank line becomes a card |
|
||||
| 5 | The domain and application layers import no `tkinter`, `csv` or `random` module; randomness comes in through the injected `choose` function | `grep` check in the review record | An outward import |
|
||||
| 6 | Code review against QC-PY-001 has no failed Mandatory criterion; `pytest` exits with 0 | `RC-*` verdict Go and exit code 0 | Otherwise |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-002 | The window and view model this step feeds with data |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 1, step 2; objective 2 (Malay to Danish list) | [BC-001] |
|
||||
| US-001.02 Get a new card | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-16 — within the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Add the domain classes | `Card`, `LanguagePair`, `Vocabulary` (frozen dataclasses), `Deck` (draw, remove) and the errors `VocabularyError`, `VocabularyFormatError`, `VocabularyNotFoundError`, `EmptyDeckError`, with the `VocabularyRepository` port. | No | DCD-001 |
|
||||
| 2 | Read the word list from CSV | `CsvVocabularyRepository` reads a semicolon separated file with a two-code header using `csv`, `pathlib` and UTF-8, and ignores blank lines; this replaces `pandas` from the assignment (ADR-0001). | No | ADR-0001, DCD-001 |
|
||||
| 3 | Draw a random card | `StudySession.next_card` returns a `CardDto` chosen at random from the deck and not equal to the current card when other cards exist; `open_study_session` builds the session from the repository. | Yes | US-001.02 |
|
||||
| 4 | Show a new card on each button press | `FlashCardViewModel` and `FlashCardView` get `next_card`; both buttons call it so that the card changes, as in the assignment. | Yes | US-001.02 |
|
||||
| 5 | Test the reader, the deck and the session | Unit tests for the domain and the session (with an injected `choose`), integration test of the reader on the real word list, and a view model test. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[UC-001]: ../uc-001/uc.md
|
||||
[DCD-001]: ../dcd.md
|
||||
@@ -0,0 +1,73 @@
|
||||
# MIL-004: Step 3 - Flip the cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-004 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether assignment step 3 works: three seconds after a card appears, it turns over and shows the Danish translation.
|
||||
|
||||
## Deliverable
|
||||
|
||||
After 3000 ms the card shows `card_back.png`, the language name "Danish", the translation, and white text. A button press shows the front of a new card with black text and restarts the timer; a press before the 3000 ms have passed cancels the earlier timer.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `FlashCardViewModel.flip_card` changes the side to the back, the language name to the back language and the text to the translation | Unit test passes | Any other state |
|
||||
| 2 | `next_card` returns the side to the front | Unit test passes | Side stays on the back |
|
||||
| 3 | The view schedules `flip_card` with `after(3000, ...)` and cancels the earlier timer with `after_cancel` before scheduling a new one | e2e test with a recording scheduler, or a unit test of the view with a fake root | Timer leaks or fires twice |
|
||||
| 4 | The back uses `card_back.png` and white text; the front uses `card_front.png` and black text | e2e test reads the canvas item configuration | Any difference |
|
||||
| 5 | `PhotoImage` objects are created once, outside the callbacks | Code review | An image is created in a function |
|
||||
| 6 | Code review against QC-PY-001 has no failed Mandatory criterion; `pytest` exits with 0 | `RC-*` verdict Go and exit code 0 | Otherwise |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-003 | Cards with a front and a back to turn |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 1, step 3 | [BC-001] |
|
||||
| US-001.03 See the translation | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-17 — within the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Add the card side to the view model | `Side` enum (front, back) and `flip_card` on the view model, so the language name and text change with the side without Tkinter. | Yes | US-001.03 |
|
||||
| 2 | Flip the card after 3000 ms in the view | `FlashCardView.flip_card` swaps image, text colour, title and word with `itemconfig`; `flip_timer` holds the `after` id and is cancelled with `after_cancel` on every button press, as the assignment's hints say. | Yes | US-001.03 |
|
||||
| 3 | Test the flip | View model unit tests for both sides, and an e2e test with the real timer replaced by a recording `after`/`after_cancel` pair. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[UC-001]: ../uc-001/uc.md
|
||||
@@ -0,0 +1,77 @@
|
||||
# MIL-005: Step 4 - Save progress
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-005 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-001], [DCD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether assignment step 4 works: a known word stops coming up, and the words still to learn are kept in `words_to_learn.csv` and used on the next start.
|
||||
|
||||
## Deliverable
|
||||
|
||||
Pressing the known button removes the current card from the words to learn and saves them to `data/words_to_learn.csv`. A start with that file uses it; a start without it uses `data/ms-da.csv`. When no word is left the card shows "Nothing left to learn".
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | With the 3 word example of the assignment, marking the second known leaves the other two in the saved file, in order, with the original header | Integration test passes | Any other content |
|
||||
| 2 | A start with an existing progress file draws only from that file; a start without it draws from the word list | Integration test passes | Any other source |
|
||||
| 3 | The unknown button never changes the file | Unit test passes | File changed |
|
||||
| 4 | Marking the last card known results in a finished state and does not raise | Unit test passes | An exception |
|
||||
| 5 | The program does not overwrite the progress file when it cannot be read; it reports a `VocabularyFormatError` | Unit test passes | File overwritten |
|
||||
| 6 | The progress file has the same format as the word list, so that it can be used as a word list | Integration test round trip passes | Different format |
|
||||
| 7 | Code review against QC-PY-001 has no failed Mandatory criterion; `pytest` exits with 0 | `RC-*` verdict Go and exit code 0 | Otherwise |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-004 | The finished card and the full card cycle |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 1, step 4 | [BC-001] |
|
||||
| US-001.04 Keep my progress | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-18 — within the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Add the progress port and its CSV adapter | `ProgressRepository` (`load` returns the deck or `None`, `save`) and `CsvProgressRepository` sharing the reading and writing code of the word list adapter, so the file format is defined once. | No | DCD-001 |
|
||||
| 2 | Remove a known card and save | `Deck.remove`, `StudySession.mark_known` removing the current card and saving the deck; `open_study_session` prefers the progress file as the assignment says. | Yes | US-001.04 |
|
||||
| 3 | Show the finished state | When the deck is empty the session returns no card, the view model shows "Nothing left to learn" and the buttons do nothing. | Yes | US-001.04 |
|
||||
| 4 | Wire the known button | `is_known` on the view model and view calls `mark_known` and then `next_card`; the unknown button only calls `next_card`. | Yes | US-001.04 |
|
||||
| 5 | Test progress | Unit tests for deck, session and finished state; integration tests of the three word example, the restart and the round trip, using `tmp_path`. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[UC-001]: ../uc-001/uc.md
|
||||
[DCD-001]: ../dcd.md
|
||||
@@ -0,0 +1,77 @@
|
||||
# MIL-006: Spoken Malay word
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-006 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-001], [DCD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether the Product Owner's extra works without harming the core program: the Malay word is spoken when its card is shown, and the program is unchanged when the speech extra is not installed.
|
||||
|
||||
## Deliverable
|
||||
|
||||
`pip install -e ".[speech]"` makes the program speak the Malay word on each new card. Without the extra, without a network, or with `--no-speech`, the program works silently and shows no error.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `StudySession.next_card` calls `SpeechPort.speak(text, "ms")` once per drawn card, and never for the finished state | Unit test with a fake port passes | Any other number of calls |
|
||||
| 2 | `GttsSpeech` imports `gtts` and `playsound` only when it speaks, writes the audio to a temporary file and removes it | Unit test with injected fakes passes | Import at module level or a leftover file |
|
||||
| 3 | A failure of the service or the player is logged and not raised | Unit test passes | Exception reaches the caller |
|
||||
| 4 | Without the extra installed, `build_speech` returns `NullSpeech` and the program starts | Unit test with a blocked import passes | Start fails |
|
||||
| 5 | `dependencies` in `pyproject.toml` is still empty and the extra pins `playsound==1.2.2` | File check in the review record | Any runtime dependency |
|
||||
| 6 | Speaking does not block the Tkinter main loop | The adapter speaks in a daemon thread; unit test asserts `speak` returns before the player finishes | The window freezes while speaking |
|
||||
| 7 | Code review against QC-PY-001 has no failed Mandatory criterion; `pytest` exits with 0 | `RC-*` verdict Go and exit code 0 | Otherwise |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-005 | The complete card cycle the speech hooks into |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 2 (spoken Malay word), objective 3 (no runtime dependencies) | [BC-001] |
|
||||
| US-001.05 Hear the Malay word | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-19 — within the delivery window that ends 2026-10-21 ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Add the speech port and the silent adapter | `SpeechPort` in the application layer and `NullSpeech` in infrastructure, so that `StudySession` always has a speaker and has no `if speech` checks. | No | ADR-0001, DCD-001 |
|
||||
| 2 | Speak the Malay word on each new card | `StudySession.next_card` asks the port to speak the front text in the front language code. | Yes | US-001.05 |
|
||||
| 3 | Add the gTTS adapter | `GttsSpeech` creates the audio with `gTTS`, plays it with `playsound` in a daemon thread, removes the temporary file and logs failures; third-party imports happen on first use. | Yes | US-001.05 |
|
||||
| 4 | Choose the speaker in the composition root and add --no-speech | `build_speech` returns `GttsSpeech` when `gtts` and `playsound` can be imported and `NullSpeech` otherwise; the command line option `--no-speech` forces silence. | No | |
|
||||
| 5 | Declare the extra and test the adapters | The `speech` extra in `pyproject.toml`; unit tests with fake `gtts`, player and port, none of which uses the network. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
[UC-001]: ../uc-001/uc.md
|
||||
[DCD-001]: ../dcd.md
|
||||
@@ -0,0 +1,79 @@
|
||||
# MIL-007: Documentation and publication
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-007 |
|
||||
| CrossReference | [BC-001], [US-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether the project can be handed to its readers: S02 can run it and compare their solution, and S03 can understand what it is from the repository page.
|
||||
|
||||
## Deliverable
|
||||
|
||||
The final README with screenshots, the wiki in English, Danish and Bahasa Malaysia (same page set), the generated Doxygen documentation, the final traceability matrix, and the repository description and topics set on the git host.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `check-readme.sh` reports no finding and the README has the front and back screenshot | No finding; both files exist and are linked | Any finding |
|
||||
| 2 | `docs/wiki/` holds the same pages in `<Page>.md`, `<Page>-da.md` and `<Page>-ms.md` and a `_Sidebar.md` that lists the three languages | File list compared | A page is missing in a language |
|
||||
| 3 | The screenshots are taken from the running program, not drawn by hand | Capture script is in `tools/` and the images show the window of this program | Mock-up |
|
||||
| 4 | The README gives the `.venv` and pip upgrade commands, and the run and test commands in five commands or fewer | Count in the review record | More than five |
|
||||
| 5 | The repository has a description and at least 5 topics on the git host | Read back from the API | Any missing |
|
||||
| 6 | `doxygen Doxyfile` builds without warnings about undocumented public items of `src/` | Output of the run | Warnings |
|
||||
| 7 | The traceability matrix has a row for every created artifact and the last `RC-*` of each | Row count in the review record | A missing row |
|
||||
| 8 | `check-languages.sh` and `check-plan.sh` report no finding | Exit code 0 | Any finding |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-006 | The documentation describes the finished program |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| Objective 4 (a repository others can use); success criteria 4, 5, 6, 7 | [BC-001] |
|
||||
| All stories (the wiki maps each to a step) | [US-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S01 |
|
||||
| Approving reviewer | S01 (AI as stand-in in autonomous mode) |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-10-21 — the end of the delivery window ([BC-001] constraint).
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Capture screenshots of the running program | Write `tools/capture_screenshots.py` that starts the program, waits for the front, grabs the window, waits 3 s for the back and grabs it again; save `docs/images/screenshot-front.png` and `screenshot-back.png`. The tool needs Pillow, which is a tool-only dependency and not a project dependency. | No | |
|
||||
| 2 | Finish the README | Complete the README from the framework template with the screenshots, the assignment-to-code map, the optional speech extra, the data attribution, and the commands to run the program and the tests. | No | |
|
||||
| 3 | Write the wiki in English | Pages `Home`, `Install`, `Usage`, `Architecture` in `docs/wiki/` with the language line and a sidebar. | No | |
|
||||
| 4 | Translate the wiki to Danish and Bahasa Malaysia | The same four pages as `<Page>-da.md` and `<Page>-ms.md`; commands, file names and IDs stay in English. | No | |
|
||||
| 5 | Build the Doxygen documentation | Run `doxygen Doxyfile` and fix undocumented public items; the generated `docs/doxygen/` is ignored by git and described in the README. | No | |
|
||||
| 6 | Set the repository description and topics | Update the description and topics of the repository on the git host through its API, using the token from `.env`, which is not read into the project. | No | |
|
||||
| 7 | Publish the wiki pages | Push `docs/wiki/` to the repository's wiki over SSH after the merge, because the opt-in publish workflow needs a runner and a secret the project does not have. | No | |
|
||||
| 8 | Close the traceability matrix | One row per artifact with its latest review record, and the end-of-run summary of the autonomous run. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[US-001]: ../user-stories.md
|
||||
Reference in New Issue
Block a user