11 Commits
Author SHA1 Message Date
Tirsvad 64e3f04c6a Merge pull request 'MIL-002 Game logic: data, art, constants and pure functions' (#24) from mil-002-game-logic into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 4s
Reviewed-on: #24
2026-10-04 17:36:11 +02:00
TirsvadandClaude Sonnet 5.5 037900df94 Resolve pending commit links for MIL-002 acceptance
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 23:35:18 +08:00
Tirsvad ee58fcdc1c Add game data, art, constants and game logic
Add the assignment data set (50 accounts), the logo and vs art, the
constants module, and the pure functions get_random_account,
pick_pair, format_data and check_answer, all with Doxygen comments.
pick_pair never returns the same account twice; check_answer accepts
either choice on a tie. Cover them with pytest tests (22 passing).

The art is built from concatenated raw lines so the backslashes survive
and Doxygen does not read the backticks as markup.

Accept MIL-002 after review RC-005 and add it to the Traceability
Matrix.

Task: MIL-002#1
Task: MIL-002#2
Task: MIL-002#3
Task: MIL-002#4
Task: MIL-002#5
Task: MIL-002#6
Closes #6
Closes #7
Closes #8
Closes #9
Closes #10
Closes #11
2026-10-04 23:34:48 +08:00
Tirsvad b1f4116bc1 Merge pull request 'MIL-001 Project setup: pyproject, skeleton and Doxyfile' (#23) from mil-001-project-setup into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 7s
Reviewed-on: #23
2026-10-04 17:30:02 +02:00
Tirsvad 115e543ee3 Add project configuration, skeleton and Doxyfile
Add pyproject.toml (Python >=3.13, no runtime dependencies, pytest as a
dev extra), the src/higher_lower package with an empty constants module
and an entry-point stub, a smoke test, and the Doxyfile for the Doxygen
comments in the source. Ignore the Doxygen output in .gitignore.

Verified in a fresh .venv: pip install -e ".[dev]", pytest (2 passed),
python -m higher_lower and doxygen Doxyfile without warnings.

Task: MIL-001#1
Task: MIL-001#2
Task: MIL-001#3
Task: MIL-001#4
Closes #1
Closes #2
Closes #3
Closes #4
2026-10-04 23:29:03 +08:00
Tirsvad 4b1228fec0 Merge pull request 'Add inception baseline and milestone plan for Higher Lower' (#22) from g1-inception-baseline into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #22
2026-10-04 17:24:33 +02:00
Tirsvad 2782f29c66 Merge branch 'main' into g1-inception-baseline 2026-10-04 17:24:20 +02:00
TirsvadandClaude Sonnet 5.5 529b964481 Resolve pending commit links for accepted documents
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 23:23:54 +08:00
Tirsvad a1ff73580f Accept BC, SA, PP and MIL-001 after review
Review BC-001, SA-001, PP-001 and MIL-001 and record the results as
RC-001 to RC-004. All four verdicts are Go, so their Version History
rows become Accepted and the previous rows Deprecated. MIL-002 to
MIL-004 stay Proposed.

BC-001 failed criterion 1 (cost-benefit not justified as qualitative).
Add the justification and a target-completion constraint (2026-10-14)
that PP-001 and MIL-001 are checked against.

Add the Traceability Matrix (TM-001) and register RC and TM in the
artifact registry. PP has no QC checklist, so RC-003 checks the plan
against BC-001 and the milestones instead. Author and reviewer are
both S01, a deviation noted in each record.

Refs #5
2026-10-04 23:23:12 +08:00
Tirsvad a999fcda34 Merge pull request 'G1 inception baseline' (#21) from g1-inception-baseline into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #21
2026-10-04 17:15:12 +02:00
TirsvadandClaude Sonnet 5.5 cb28865787 Resolve pending commit links in Version History
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 23:11:32 +08:00
26 changed files with 4041 additions and 106 deletions
+3
View File
@@ -174,3 +174,6 @@ cython_debug/
# PyPI configuration file
.pypirc
# Doxygen output
docs/doxygen/
+2967
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -15,6 +15,8 @@ document of a type. `Primary File` may contain a glob (e.g.
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
| PP | Project Plan | docs/project-plan.md | 002 |
| MIL | Milestone / Gateway | docs/milestones/*.md | 005 |
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 006 |
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
## Languages
+9 -2
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | BC-001 |
| CrossReference | [SA-001], [PP-001] |
| CrossReference | [SA-001], [PP-001], [RC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Added target-date constraint and cost-benefit justification<br>Accepted after review RC-001 | [a1ff735] |
---
@@ -99,6 +100,7 @@ Supports the author's goal of completing the 100 Days of Code bootcamp with prof
- No runtime dependencies unless needed.
- Do not commit, push or open a PR without the author's request.
- Product Owner language: English.
- Target completion 2026-10-14 (proposed by S01; no external deadline).
## Cost–Benefit Assessment
@@ -106,6 +108,8 @@ Supports the author's goal of completing the 100 Days of Code bootcamp with prof
| --- | --- |
| About one to two evenings of the author's time | A shareable, tested, documented reference solution |
The comparison is qualitative on purpose: this is a personal learning project with no revenue or budget, so a monetary ROI would be artificial. The cost is the author's time; the benefit is the shareable reference solution and practice gained.
## Stakeholders
| Stakeholder ID (SA) | Interest in this project |
@@ -122,3 +126,6 @@ Proceed — the scope is small, the risks are low and the result serves all thre
[SA-001]: ./stakeholder-analysis.md
[PP-001]: ./project-plan.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
[RC-001]: ./sqa/reviews/rc-001-business-case.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+6 -2
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | MIL-001 |
| CrossReference | [BC-001], [PP-001] |
| CrossReference | [BC-001], [PP-001], [RC-004] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after review RC-004 | [a1ff735] |
---
@@ -69,3 +70,6 @@ Decide whether the project foundation (configuration, layout, tooling files and
[BC-001]: ../business-case.md
[PP-001]: ../project-plan.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
[RC-004]: ../sqa/reviews/rc-004-mil-001.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+6 -2
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | MIL-002 |
| CrossReference | [BC-001], [PP-001] |
| CrossReference | [BC-001], [PP-001], [RC-005] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after review RC-005 | [ee58fcd] |
---
@@ -71,3 +72,6 @@ The assignment data set and art as modules, constants in `constants.py`, and the
[BC-001]: ../business-case.md
[PP-001]: ../project-plan.md
[MIL-001]: ./mil-001-project-setup.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
[RC-005]: ../sqa/reviews/rc-005-mil-002.md
[ee58fcd]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ee58fcdc1c9c83b0721022d623e4989591a47987
+2 -1
View File
@@ -9,7 +9,7 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
---
@@ -70,3 +70,4 @@ An interactive console game started with `python -m higher_lower`, built on the
[BC-001]: ../business-case.md
[PP-001]: ../project-plan.md
[MIL-002]: ./mil-002-game-logic.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
+2 -1
View File
@@ -9,7 +9,7 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
---
@@ -69,3 +69,4 @@ Decide whether the repository is ready to be shared with S02 and S03: documented
[BC-001]: ../business-case.md
[PP-001]: ../project-plan.md
[MIL-003]: ./mil-003-console-game.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
+6 -2
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | PP-001 |
| CrossReference | [BC-001], [SA-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004] |
| CrossReference | [BC-001], [SA-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [RC-003] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after review RC-003 | [a1ff735] |
---
@@ -93,3 +94,6 @@ A No-Go on any phase moves all later windows by the rework time.
[Milestone MIL-002]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/milestones/37
[Milestone MIL-003]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/milestones/38
[Milestone MIL-004]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/milestones/39
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
[RC-003]: ./sqa/reviews/rc-003-project-plan.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+48
View File
@@ -0,0 +1,48 @@
# SQA Review Record: Business Case
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-001 |
| CrossReference | [BC-001], [QC-BC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [a1ff735] |
---
## Artifact Under Review
- Instance reviewed: [BC-001]
- Checklist used: [QC-BC-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | ROI/Cost-Benefit analysis is quantitative, or where qualitative, is explicitly justified | Pass | Qualitative; justification paragraph added under Cost–Benefit Assessment (personal project, no revenue or budget). |
| 2 | Risks are identified with documented impact and mitigation | Pass | Three risks, each with impact and mitigation. |
| 3 | Success criteria are measurable, stating explicit targets | Pass | Five criteria with target and measure. |
| 4 | Scope explicitly separates In Scope vs Out of Scope | Pass | Separate subsections. |
| 5 | Stakeholders are cross-referenced to Stakeholder Analysis IDs | Pass | S01–S03 used; the table only states interest. |
| 6 | Methodology and quality-standard foundation are stated explicitly (Optional) | Pass | SQA/QC framework and ISO/IEC 25010:2023 named. |
| 7 | Assumptions and constraints are explicit and distinguished | Pass | Separate sections; target date added to Constraints. |
| 8 | Document supports executive decision-making with a clear recommendation | Pass | Recommendation: Proceed, with rationale. |
## Overall Verdict
Go — all mandatory and optional criteria pass. Reviewer and author are both S01: the project has a single participant, so the framework's author/reviewer separation cannot be met. S01 accepted this deviation when requesting acceptance (2026-10-04).
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | — | — |
---
[BC-001]: ../../business-case.md
[QC-BC-001]: ../../../framework/qc/qc-business-case.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
@@ -0,0 +1,48 @@
# SQA Review Record: Stakeholder Analysis
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-002 |
| CrossReference | [SA-001], [QC-SA-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [a1ff735] |
---
## Artifact Under Review
- Instance reviewed: [SA-001]
- Checklist used: [QC-SA-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Power/Interest grid is filled for every stakeholder | Pass | S01–S03 all classified. |
| 2 | Each stakeholder has a unique, stable ID | Pass | S01, S02, S03. |
| 3 | Roles and organizational context defined with explicit Power and Interest levels | Pass | Summary table. |
| 4 | Communication needs mapped to phases or milestones (Optional) | Pass | Communication Requirements table cites MIL-001 to MIL-004. |
| 5 | Conflicting interests identified with mitigation | Pass | One conflict (tooling versus simple repository), mitigated. |
| 6 | Stakeholder concerns traced to Business Case objectives | Pass | Business Goal Alignment table cites O1–O5. |
| 7 | Concerns expressed in business language and FURPS+ (Optional) | Pass | FURPS+ mapping table. |
| 8 | Understandable by non-technical stakeholders (Optional) | Pass | Plain language, short document. |
## Overall Verdict
Go — all criteria pass. Reviewer and author are both S01: the project has a single participant, so the framework's author/reviewer separation cannot be met. S01 accepted this deviation when requesting acceptance (2026-10-04).
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | — | — |
---
[SA-001]: ../../stakeholder-analysis.md
[QC-SA-001]: ../../../framework/qc/qc-stakeholder-analysis.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+45
View File
@@ -0,0 +1,45 @@
# SQA Review Record: Project Plan
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-003 |
| CrossReference | [PP-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [a1ff735] |
---
## Artifact Under Review
- Instance reviewed: [PP-001]
- Checklist used: none exists for this type (`PP` has no QC checklist); criteria below follow `references/PP.md` "Validating".
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Every MIL-* gateway is scheduled | Pass | MIL-001 to MIL-004 listed with window, decision date and owner. |
| 2 | Schedule is consistent with the Business Case constraint | Pass | Ends 2026-10-14, matching the target-date constraint added to BC-001. |
| 3 | Gateway Schedule, Gantt, Scope Coverage, Dependencies, Plan Risks and Open Issues sections are present | Pass | All required sections present. |
| 4 | Each phase links to its synced Milestone | Pass | Milestones 36–39 linked. |
| 5 | Every Business Case scope item maps to a gateway | Pass | Scope Coverage table. |
## Overall Verdict
Go — no QC checklist exists for PP, so the plan was checked against BC-001 and the MIL-* documents. Open issues (README template, Python version, dates) remain listed in the plan. Reviewer and author are both S01: the project has a single participant, so the framework's author/reviewer separation cannot be met. S01 accepted this deviation when requesting acceptance (2026-10-04).
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Provide README template before MIL-004 task 1 | S01 | 2026-10-13 |
| Confirm requires-python (>=3.13 or 3.14+) | S01 | 2026-10-06 |
---
[PP-001]: ../../project-plan.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+46
View File
@@ -0,0 +1,46 @@
# SQA Review Record: MIL-001 Project setup
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-004 |
| CrossReference | [MIL-001], [QC-MIL-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [a1ff735] |
---
## Artifact Under Review
- Instance reviewed: [MIL-001]
- Checklist used: [QC-MIL-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | A concrete deliverable is defined for every gate | Pass | Config files, skeleton, passing smoke test, repository metadata. |
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Six objectively checkable criteria. |
| 3 | Dependencies on other milestones are explicitly mapped (Optional) | Pass | First phase; stated as none. |
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O2, O4, O5. |
| 5 | Milestone owner and approving reviewer are identified | Pass | S01 and S01. |
| 6 | Milestone has a target date consistent with project constraints | Pass | 2026-10-06, inside the 2026-10-14 constraint in BC-001. |
## Overall Verdict
Go — all criteria pass. MIL-002 to MIL-004 stay Proposed. Reviewer and author are both S01: the project has a single participant, so the framework's author/reviewer separation cannot be met. S01 accepted this deviation when requesting acceptance (2026-10-04).
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Confirm requires-python before issue #1 starts | S01 | 2026-10-06 |
---
[MIL-001]: ../../milestones/mil-001-project-setup.md
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+46
View File
@@ -0,0 +1,46 @@
# SQA Review Record: MIL-002 Game logic
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-005 |
| CrossReference | [MIL-002], [QC-MIL-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [ee58fcd] |
---
## Artifact Under Review
- Instance reviewed: [MIL-002]
- Checklist used: [QC-MIL-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | A concrete deliverable is defined for every gate | Pass | Data and art modules, constants, four named functions, Doxygen comments, pytest tests. |
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Six objectively checkable criteria. |
| 3 | Dependencies on other milestones are explicitly mapped (Optional) | Pass | Depends on MIL-001, with the reason. |
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O1, O2, O3. |
| 5 | Milestone owner and approving reviewer are identified | Pass | S01 and S01. |
| 6 | Milestone has a target date consistent with project constraints | Pass | 2026-10-09, inside the 2026-10-14 constraint in BC-001. |
## Overall Verdict
Go — all criteria pass. Code under `src/` and `tests/` for MIL-002 may start once the MIL-001 deliverables exist (its dependency). MIL-003 and MIL-004 stay Proposed. Reviewer and author are both S01: the project has a single participant, so the framework's author/reviewer separation cannot be met. S01 accepted this deviation when requesting acceptance (2026-10-04).
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Deliver MIL-001 (issues #1-#4) before starting MIL-002 tasks | S01 | 2026-10-06 |
---
[MIL-002]: ../../milestones/mil-002-game-logic.md
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
[ee58fcd]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ee58fcdc1c9c83b0721022d623e4989591a47987
+54
View File
@@ -0,0 +1,54 @@
# Traceability Matrix
## Metadata
| Key | Value |
| --- | --- |
| ID | TM-001 |
| CrossReference | [BC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | [a1ff735] |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Added RC-005 review of MIL-002 | [ee58fcd] |
---
## Purpose
Tracks backward/forward links between artifact instances so that the Business Case traceability
target is measurable. A row is added or updated whenever an artifact instance is created or reviewed.
## Traceability Table
| Artifact Instance | Type | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) |
| --- | --- | --- | --- | --- |
| [BC-001] | BC | - | [SA-001], [PP-001] | [RC-001] |
| [SA-001] | SA | [BC-001] | [PP-001] | [RC-002] |
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004] | [RC-003] |
| [MIL-001] | MIL | [BC-001], [PP-001] | - | [RC-004] |
| [MIL-002] | MIL | [BC-001], [PP-001], [MIL-001] | - | [RC-005] |
| [MIL-003] | MIL | [BC-001], [PP-001] | - | - |
| [MIL-004] | MIL | [BC-001], [PP-001] | - | - |
## Coverage Notes
- No use cases, user stories or design artifacts exist yet (UC-001 is planned for MIL-003).
- `-` in Upstream means foundational; in Downstream, nothing is built on it yet; in Last Reviewed, no `RC-*` exists yet.
---
[BC-001]: ../business-case.md
[SA-001]: ../stakeholder-analysis.md
[PP-001]: ../project-plan.md
[MIL-001]: ../milestones/mil-001-project-setup.md
[MIL-002]: ../milestones/mil-002-game-logic.md
[MIL-003]: ../milestones/mil-003-console-game.md
[MIL-004]: ../milestones/mil-004-docs-release.md
[RC-001]: ./reviews/rc-001-business-case.md
[RC-002]: ./reviews/rc-002-stakeholder-analysis.md
[RC-003]: ./reviews/rc-003-project-plan.md
[RC-004]: ./reviews/rc-004-mil-001.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
[RC-005]: ./reviews/rc-005-mil-002.md
[ee58fcd]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ee58fcdc1c9c83b0721022d623e4989591a47987
+7 -3
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | SA-001 |
| CrossReference | [BC-001], [PP-001] |
| CrossReference | [BC-001], [PP-001], [RC-002] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-04 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | pending |
| 2026-10-04 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [ddfe96f] |
| 2026-10-04 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after review RC-002 | [a1ff735] |
---
@@ -70,9 +71,12 @@ Identify who is affected by the Higher Lower project and what each needs, using
| Stakeholder | Decision | Date |
| --- | --- | --- |
| S01 | Pending review | |
| S01 | Go (RC-002) | 2026-10-04 |
---
[BC-001]: ./business-case.md
[PP-001]: ./project-plan.md
[ddfe96f]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/ddfe96ffa459d5e4b2e30d71bd53878aba2cfc5d
[RC-002]: ./sqa/reviews/rc-002-stakeholder-analysis.md
[a1ff735]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/014-higher_lower/commit/a1ff73580fdcfad5bbb3854298fdfa0c16ada853
+22
View File
@@ -0,0 +1,22 @@
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "higher-lower"
version = "0.1.0"
description = "Higher Lower console game: guess which Instagram account has more followers (Udemy 100 Days of Code, day 14)."
readme = "README.md"
requires-python = ">=3.13"
license = { file = "LICENSE" }
dependencies = []
[project.optional-dependencies]
dev = ["pytest>=8"]
[tool.setuptools.packages.find]
where = ["src"]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
+3
View File
@@ -0,0 +1,3 @@
"""@package higher_lower
@brief Higher Lower console game: guess which Instagram account has more followers.
"""
+14
View File
@@ -0,0 +1,14 @@
"""@file __main__.py
@brief Entry point for `python -m higher_lower`.
"""
def main() -> None:
"""@brief Start the game.
Placeholder: the game loop is implemented in MIL-003.
"""
if __name__ == "__main__":
main()
+31
View File
@@ -0,0 +1,31 @@
"""@file art.py
@brief ASCII art shown by the game, as given by the assignment.
The lines are raw strings so the backslashes in the art survive unchanged.
They are concatenated line by line, rather than written as one multi-line
string, so Doxygen does not read the backticks in the art as markup.
"""
## The game logo.
logo = (
"\n"
r" __ ___ __ " "\n"
r" / / / (_)___ _/ /_ ___ _____" "\n"
r" / /_/ / / __ `/ __ \/ _ \/ ___/" "\n"
r" / __ / / /_/ / / / / __/ / " "\n"
r"/_/ ///_/\__, /_/ /_/\___/_/ " "\n"
r" / / /____/_ _____ _____" "\n"
r" / / / __ \ | /| / / _ \/ ___/" "\n"
r" / /___/ /_/ / |/ |/ / __/ / " "\n"
r"/_____/\____/|__/|__/\___/_/ " "\n"
)
## The "vs" shown between the two accounts.
vs = (
"\n"
r" _ __ " "\n"
r"| | / /____" "\n"
r"| | / / ___/" "\n"
r"| |/ (__ ) " "\n"
r"|___/____(_)" "\n"
)
+28
View File
@@ -0,0 +1,28 @@
"""@file constants.py
@brief Constants shared by the game modules.
"""
## Keys of an account dictionary.
KEY_NAME = "name"
KEY_FOLLOWER_COUNT = "follower_count"
KEY_DESCRIPTION = "description"
KEY_COUNTRY = "country"
## The two choices the player can type, in lower case.
CHOICE_A = "a"
CHOICE_B = "b"
## Score at the start of a game.
START_SCORE = 0
## How an account is described to the player.
ACCOUNT_TEMPLATE = "{name}, a {description}, from {country}"
## Texts shown to the player.
MSG_COMPARE_A = "Compare A: {account}."
MSG_AGAINST_B = "Against B: {account}."
PROMPT_GUESS = "Who has more followers? Type 'A' or 'B': "
MSG_INVALID_CHOICE = "Please type 'A' or 'B'."
MSG_CORRECT = "You're right! Current score: {score}."
MSG_WRONG = "Sorry, that's wrong. Final score: {score}"
MSG_WIN = "You went through every account! Final score: {score}"
+324
View File
@@ -0,0 +1,324 @@
"""@file game_data.py
@brief The accounts the player compares, as given by the assignment.
The order is kept as in the assignment; the game compares follower counts,
never list positions.
"""
from typing import TypedDict
class Account(TypedDict):
"""@brief One account the player can be asked about.
follower_count is in millions of Instagram followers.
"""
name: str
follower_count: int
description: str
country: str
data: list[Account] = [
{
"name": "Instagram",
"follower_count": 346,
"description": "Social media platform",
"country": "United States",
},
{
"name": "Cristiano Ronaldo",
"follower_count": 215,
"description": "Footballer",
"country": "Portugal",
},
{
"name": "Ariana Grande",
"follower_count": 183,
"description": "Musician and actress",
"country": "United States",
},
{
"name": "Dwayne Johnson",
"follower_count": 181,
"description": "Actor and professional wrestler",
"country": "United States",
},
{
"name": "Selena Gomez",
"follower_count": 174,
"description": "Musician and actress",
"country": "United States",
},
{
"name": "Kylie Jenner",
"follower_count": 172,
"description": "Reality TV personality and businesswoman and Self-Made Billionaire",
"country": "United States",
},
{
"name": "Kim Kardashian",
"follower_count": 167,
"description": "Reality TV personality and businesswoman",
"country": "United States",
},
{
"name": "Lionel Messi",
"follower_count": 149,
"description": "Footballer",
"country": "Argentina",
},
{
"name": "Beyoncé",
"follower_count": 145,
"description": "Musician",
"country": "United States",
},
{
"name": "Neymar",
"follower_count": 138,
"description": "Footballer",
"country": "Brasil",
},
{
"name": "National Geographic",
"follower_count": 135,
"description": "Magazine",
"country": "United States",
},
{
"name": "Justin Bieber",
"follower_count": 133,
"description": "Musician",
"country": "Canada",
},
{
"name": "Taylor Swift",
"follower_count": 131,
"description": "Musician",
"country": "United States",
},
{
"name": "Kendall Jenner",
"follower_count": 127,
"description": "Reality TV personality and Model",
"country": "United States",
},
{
"name": "Jennifer Lopez",
"follower_count": 119,
"description": "Musician and actress",
"country": "United States",
},
{
"name": "Nicki Minaj",
"follower_count": 113,
"description": "Musician",
"country": "Trinidad and Tobago",
},
{
"name": "Nike",
"follower_count": 109,
"description": "Sportswear multinational",
"country": "United States",
},
{
"name": "Khloé Kardashian",
"follower_count": 108,
"description": "Reality TV personality and businesswoman",
"country": "United States",
},
{
"name": "Miley Cyrus",
"follower_count": 107,
"description": "Musician and actress",
"country": "United States",
},
{
"name": "Katy Perry",
"follower_count": 94,
"description": "Musician",
"country": "United States",
},
{
"name": "Kourtney Kardashian",
"follower_count": 90,
"description": "Reality TV personality",
"country": "United States",
},
{
"name": "Kevin Hart",
"follower_count": 89,
"description": "Comedian and actor",
"country": "United States",
},
{
"name": "Ellen DeGeneres",
"follower_count": 87,
"description": "Comedian",
"country": "United States",
},
{
"name": "Real Madrid CF",
"follower_count": 86,
"description": "Football club",
"country": "Spain",
},
{
"name": "FC Barcelona",
"follower_count": 85,
"description": "Football club",
"country": "Spain",
},
{
"name": "Rihanna",
"follower_count": 81,
"description": "Musician and businesswoman",
"country": "Barbados",
},
{
"name": "Demi Lovato",
"follower_count": 80,
"description": "Musician and actress",
"country": "United States",
},
{
"name": "Victoria's Secret",
"follower_count": 69,
"description": "Lingerie brand",
"country": "United States",
},
{
"name": "Zendaya",
"follower_count": 68,
"description": "Actress and musician",
"country": "United States",
},
{
"name": "Shakira",
"follower_count": 66,
"description": "Musician",
"country": "Colombia",
},
{
"name": "Drake",
"follower_count": 65,
"description": "Musician",
"country": "Canada",
},
{
"name": "Chris Brown",
"follower_count": 64,
"description": "Musician",
"country": "United States",
},
{
"name": "LeBron James",
"follower_count": 63,
"description": "Basketball player",
"country": "United States",
},
{
"name": "Vin Diesel",
"follower_count": 62,
"description": "Actor",
"country": "United States",
},
{
"name": "Cardi B",
"follower_count": 67,
"description": "Musician",
"country": "United States",
},
{
"name": "David Beckham",
"follower_count": 82,
"description": "Footballer",
"country": "United Kingdom",
},
{
"name": "Billie Eilish",
"follower_count": 61,
"description": "Musician",
"country": "United States",
},
{
"name": "Justin Timberlake",
"follower_count": 59,
"description": "Musician and actor",
"country": "United States",
},
{
"name": "UEFA Champions League",
"follower_count": 58,
"description": "Club football competition",
"country": "Europe",
},
{
"name": "NASA",
"follower_count": 56,
"description": "Space agency",
"country": "United States",
},
{
"name": "Emma Watson",
"follower_count": 56,
"description": "Actress",
"country": "United Kingdom",
},
{
"name": "Shawn Mendes",
"follower_count": 57,
"description": "Musician",
"country": "Canada",
},
{
"name": "Virat Kohli",
"follower_count": 55,
"description": "Cricketer",
"country": "India",
},
{
"name": "Gigi Hadid",
"follower_count": 54,
"description": "Model",
"country": "United States",
},
{
"name": "Priyanka Chopra Jonas",
"follower_count": 53,
"description": "Actress and musician",
"country": "India",
},
{
"name": "9GAG",
"follower_count": 52,
"description": "Social media platform",
"country": "China",
},
{
"name": "Ronaldinho",
"follower_count": 51,
"description": "Footballer",
"country": "Brasil",
},
{
"name": "Maluma",
"follower_count": 50,
"description": "Musician",
"country": "Colombia",
},
{
"name": "Camila Cabello",
"follower_count": 49,
"description": "Musician",
"country": "Cuba",
},
{
"name": "NBA",
"follower_count": 47,
"description": "Club Basketball Competition",
"country": "United States",
},
]
+78
View File
@@ -0,0 +1,78 @@
"""@file game_logic.py
@brief Pure functions of the game: drawing accounts, describing them and checking guesses.
"""
import random
from collections.abc import Sequence
from higher_lower.constants import (
ACCOUNT_TEMPLATE,
CHOICE_A,
CHOICE_B,
KEY_DESCRIPTION,
KEY_NAME,
KEY_COUNTRY,
)
from higher_lower.game_data import Account, data
_DEFAULT_RNG = random.Random()
def get_random_account(
accounts: Sequence[Account] = data,
rng: random.Random | None = None,
) -> Account:
"""@brief Return one random account.
@param accounts The accounts to draw from.
@param rng Random generator; pass a seeded one to make the draw repeatable.
@return A random entry of accounts.
"""
return (rng or _DEFAULT_RNG).choice(accounts)
def pick_pair(
accounts: Sequence[Account] = data,
rng: random.Random | None = None,
) -> tuple[Account, Account]:
"""@brief Return two different random accounts.
@param accounts The accounts to draw from; needs at least two entries.
@param rng Random generator; pass a seeded one to make the draw repeatable.
@return The accounts A and B, never the same entry.
@throws ValueError If accounts has fewer than two entries.
"""
first, second = (rng or _DEFAULT_RNG).sample(accounts, 2)
return first, second
def format_data(account: Account) -> str:
"""@brief Describe an account for the player.
@param account The account to describe.
@return Text such as "Nike, a Sportswear multinational, from United States".
"""
return ACCOUNT_TEMPLATE.format(
name=account[KEY_NAME],
description=account[KEY_DESCRIPTION],
country=account[KEY_COUNTRY],
)
def check_answer(guess: str, a_followers: int, b_followers: int) -> bool:
"""@brief Tell whether the guess names the account with more followers.
Equal follower counts make either choice correct.
@param guess "a" or "b", in any case.
@param a_followers Follower count of account A.
@param b_followers Follower count of account B.
@return True if the guess is right.
@throws ValueError If guess is neither "a" nor "b".
"""
choice = guess.lower()
if choice == CHOICE_A:
return a_followers >= b_followers
if choice == CHOICE_B:
return b_followers >= a_followers
raise ValueError(f"guess must be {CHOICE_A!r} or {CHOICE_B!r}, got {guess!r}")
+46
View File
@@ -0,0 +1,46 @@
"""@file test_game_data.py
@brief Tests for the assignment data set and art.
"""
from higher_lower.art import logo, vs
from higher_lower.constants import (
KEY_COUNTRY,
KEY_DESCRIPTION,
KEY_FOLLOWER_COUNT,
KEY_NAME,
)
from higher_lower.game_data import data
EXPECTED_KEYS = {KEY_NAME, KEY_FOLLOWER_COUNT, KEY_DESCRIPTION, KEY_COUNTRY}
def test_data_has_fifty_accounts() -> None:
"""@brief The assignment data set has 50 entries."""
assert len(data) == 50
def test_every_account_has_the_required_keys() -> None:
"""@brief Every entry has exactly the four assignment keys."""
assert all(set(account) == EXPECTED_KEYS for account in data)
def test_follower_counts_are_positive_integers() -> None:
"""@brief Follower counts are positive integers."""
assert all(
isinstance(account[KEY_FOLLOWER_COUNT], int) and account[KEY_FOLLOWER_COUNT] > 0
for account in data
)
def test_account_names_are_unique() -> None:
"""@brief No account appears twice."""
names = [account[KEY_NAME] for account in data]
assert len(names) == len(set(names))
def test_art_is_available() -> None:
"""@brief The logo and the vs art keep their shape, including backslashes."""
assert len(logo.splitlines()) == 10
assert "\\" in logo
assert len(vs.splitlines()) == 6
assert "|___/____(_)" in vs
+89
View File
@@ -0,0 +1,89 @@
"""@file test_game_logic.py
@brief Tests for the pure game functions.
"""
import random
import pytest
from higher_lower.constants import KEY_NAME
from higher_lower.game_data import Account, data
from higher_lower.game_logic import (
check_answer,
format_data,
get_random_account,
pick_pair,
)
def test_get_random_account_returns_an_entry_of_the_data() -> None:
"""@brief The drawn account comes from the data set."""
assert get_random_account(rng=random.Random(1)) in data
def test_get_random_account_is_repeatable_with_a_seed() -> None:
"""@brief The same seed draws the same account."""
assert get_random_account(rng=random.Random(7)) == get_random_account(
rng=random.Random(7)
)
def test_pick_pair_never_returns_the_same_account() -> None:
"""@brief A and B are always different entries."""
rng = random.Random(0)
for _ in range(200):
first, second = pick_pair(rng=rng)
assert first[KEY_NAME] != second[KEY_NAME]
def test_pick_pair_with_two_accounts_returns_both() -> None:
"""@brief With only two accounts, the pair holds both of them."""
two = data[:2]
first, second = pick_pair(two, random.Random(3))
assert {first[KEY_NAME], second[KEY_NAME]} == {a[KEY_NAME] for a in two}
def test_pick_pair_with_one_account_raises() -> None:
"""@brief A pair cannot be drawn from a single account."""
with pytest.raises(ValueError):
pick_pair(data[:1])
def test_format_data_describes_the_account() -> None:
"""@brief The description holds name, description and country."""
account: Account = {
"name": "Nike",
"follower_count": 109,
"description": "Sportswear multinational",
"country": "United States",
}
assert (
format_data(account)
== "Nike, a Sportswear multinational, from United States"
)
@pytest.mark.parametrize(
("guess", "a_followers", "b_followers", "expected"),
[
("a", 200, 100, True),
("a", 100, 200, False),
("b", 100, 200, True),
("b", 200, 100, False),
("A", 200, 100, True),
("B", 100, 200, True),
("a", 100, 100, True),
("b", 100, 100, True),
],
)
def test_check_answer(
guess: str, a_followers: int, b_followers: int, expected: bool
) -> None:
"""@brief The answer is right for the higher account, and for either on a tie."""
assert check_answer(guess, a_followers, b_followers) is expected
def test_check_answer_rejects_an_unknown_choice() -> None:
"""@brief A guess other than a or b is an error."""
with pytest.raises(ValueError):
check_answer("c", 1, 2)
+16
View File
@@ -0,0 +1,16 @@
"""@file test_smoke.py
@brief Smoke test: the package and its entry point can be imported.
"""
import higher_lower
from higher_lower import __main__ as entry_point
def test_package_imports() -> None:
"""@brief The package imports without side effects."""
assert higher_lower.__doc__
def test_entry_point_is_callable() -> None:
"""@brief The entry point exists and can be called."""
assert entry_point.main() is None