Compare commits

..
Author SHA1 Message Date
Tirsvad 64511c9fef Resolve pending commit links
Tests / Run the tests (pull_request) Successful in 52s
2026-10-13 16:21:33 +08:00
Tirsvad dfaa8400c3 Add Version History row to the traceability matrix
No issue closed: documentation housekeeping.
2026-10-13 16:21:32 +08:00
Tirsvad 8f73cd8cba Merge pull request 'Add static workflow test for ci.yml' (#35) from mil-001-workflow-test into main
Tests / Run the tests (push) Successful in 43s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:59:42 +02:00
Tirsvad 329cc1484c Resolve pending commit links
Tests / Run the tests (pull_request) Successful in 44s
2026-10-13 15:59:35 +08:00
Tirsvad 7202aac595 Add static workflow test for ci.yml
Closes #34

Task: MIL-001#7
2026-10-13 15:59:25 +08:00
Tirsvad 6fb75ddb86 Add task 7 to MIL-001: static workflow test
Refs #6
2026-10-13 15:57:31 +08:00
Tirsvad b52a739649 Merge pull request 'Correct wiki folder references to wiki/' (#33) from fix-wiki-path-refs into main
Tests / Run the tests (push) Successful in 40s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:56:37 +02:00
Tirsvad d3d2d03cd5 Resolve pending commit links
Tests / Run the tests (pull_request) Successful in 41s
2026-10-13 15:56:21 +08:00
Tirsvad d85cfe5c4b Correct the wiki folder references to wiki/
No issue closed: documentation correction only.
2026-10-13 15:56:19 +08:00
Tirsvad 1b217785c6 Merge pull request 'RC-025: CI workflow verified on the instance' (#32) from ci-verified into main
Tests / Run the tests (push) Canceled after 0s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:52:43 +02:00
Tirsvad d2f36bfde3 Record RC-025: CI workflow verified on the instance
Tests / Run the tests (pull_request) Successful in 42s
No issue closed: the workflow task #6 was closed by an earlier pull request.
2026-10-13 15:52:36 +08:00
Tirsvad c4e88c6da6 Merge pull request 'Move wiki sources to wiki/' (#31) from fix-wiki-location into main
Tests / Run the tests (push) Successful in 42s
TirSystem/github-action: Publish wiki / publish-wiki (push) Successful in 5s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:44:06 +02:00
Tirsvad 632fa61b89 Move the wiki sources to wiki/ and tidy version history statuses
Tests / Run the tests (pull_request) Successful in 42s
No issue closed: all issues of MIL-001 to MIL-004 are closed.
2026-10-13 15:43:56 +08:00
Tirsvad d825bef0f1 Merge pull request 'MIL-004 Wiki in English, Danish and Bahasa Malaysia' (#30) from mil-004-wiki-publication into main
Tests / Run the tests (push) Canceled after 0s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:42:38 +02:00
Tirsvad 9e41ae87b9 Add the wiki sources in English, Danish and Bahasa Malaysia
Tests / Run the tests (pull_request) Successful in 41s
Closes #21
Closes #22
Closes #23
Closes #24
2026-10-13 15:42:30 +08:00
Tirsvad 57e12637f0 Merge pull request 'Fix Doxygen warnings' (#29) from fix-doxygen-warnings into main
Tests / Run the tests (push) Canceled after 0s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-13 09:41:23 +02:00
29 changed files with 1030 additions and 164 deletions
+142 -141
View File
@@ -1,141 +1,142 @@
# Squirrel Census # Squirrel Census
Day 25 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*: count the Day 25 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*: count the
squirrels of the 2018 Central Park Squirrel Census by primary fur colour (gray, squirrels of the 2018 Central Park Squirrel Census by primary fur colour (gray,
cinnamon, black) and export the counts to `squirrel_count.csv`. Python 3.13 or cinnamon, black) and export the counts to `squirrel_count.csv`. Python 3.13 or
later, no runtime dependencies, with tests and source documentation. later, no runtime dependencies, with tests and source documentation.
![Program run][img-run] ![Program run][img-run]
## Requirements ## Requirements
- Python 3.13 or later (`python --version` on Windows, `python3 --version` on Linux and macOS). - Python 3.13 or later (`python --version` on Windows, `python3 --version` on Linux and macOS).
- `venv`, which ships with Python (on Debian: the `python3-venv` package). - `venv`, which ships with Python (on Debian: the `python3-venv` package).
- The 2018 census file. It is already in the repository under `data/`. - The 2018 census file. It is already in the repository under `data/`.
- Optional: [Doxygen][doxygen] 1.9 or later, only to build the source documentation. - Optional: [Doxygen][doxygen] 1.9 or later, only to build the source documentation.
There are no runtime dependencies: the program uses only the Python standard library There are no runtime dependencies: the program uses only the Python standard library
([ADR-0001][adr-0001]). `pytest` is needed only to run the tests. ([ADR-0001][adr-0001]). `pytest` is needed only to run the tests.
## Set up ## Set up
Create a local virtual environment named `.venv` in the project folder, upgrade `pip` Create a local virtual environment named `.venv` in the project folder, upgrade `pip`
and install the project with its development tools (pytest, ruff, mypy). and install the project with its development tools (pytest, ruff, mypy).
### Windows powershell ### Windows powershell
```powershell ```powershell
python -m venv .venv python -m venv .venv
.\.venv\Scripts\Activate.ps1 .\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip python -m pip install --upgrade pip
python -m pip install -e ".[dev]" python -m pip install -e ".[dev]"
``` ```
If PowerShell refuses to run the activation script, allow it for the current session: If PowerShell refuses to run the activation script, allow it for the current session:
`Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned`. `Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned`.
### Linux debian ### Linux debian
```bash ```bash
sudo apt install python3 python3-venv sudo apt install python3 python3-venv
python3 -m venv .venv python3 -m venv .venv
source .venv/bin/activate source .venv/bin/activate
python -m pip install --upgrade pip python -m pip install --upgrade pip
python -m pip install -e ".[dev]" python -m pip install -e ".[dev]"
``` ```
### MacOS ### MacOS
```bash ```bash
python3 -m venv .venv python3 -m venv .venv
source .venv/bin/activate source .venv/bin/activate
python -m pip install --upgrade pip python -m pip install --upgrade pip
python -m pip install -e ".[dev]" python -m pip install -e ".[dev]"
``` ```
On macOS, Python 3.13 can be installed with `brew install python@3.13`. On macOS, Python 3.13 can be installed with `brew install python@3.13`.
## Run ## Run
With the virtual environment active, run from the project folder: With the virtual environment active, run from the project folder:
```bash ```bash
python -m squirrel python -m squirrel
``` ```
The program reads `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, prints The program reads `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, prints
the colour counts and writes `squirrel_count.csv`: the colour counts and writes `squirrel_count.csv`:
```text ```text
Gray: 2473 Gray: 2473
Cinnamon: 392 Cinnamon: 392
Black: 103 Black: 103
``` ```
Use other files by passing them as arguments, `python -m squirrel <census file> <summary file>`. Use other files by passing them as arguments, `python -m squirrel <census file> <summary file>`.
If the census file does not exist the program prints a message and exits with status 2. If the census file does not exist the program prints a message and exits with status 2.
## Run the tests ## Run the tests
```bash ```bash
python -m pytest python -m pytest
``` ```
![Test run][img-tests] ![Test run][img-tests]
The tests use small fixture rows; one test also checks the real 2018 census file when The tests use small fixture rows; one test also checks the real 2018 census file when
it is present. it is present.
## Continuous integration ## Continuous integration
The workflow [`.gitea/workflows/ci.yml`][ci] runs for every push to `main` and for every The workflow [`.gitea/workflows/ci.yml`][ci] runs for every push to `main` and for every
pull request. It sets up Python 3.13, creates a `.venv`, upgrades `pip`, installs the pull request. It sets up Python 3.13, creates a `.venv`, upgrades `pip`, installs the
project with `.[dev]` and runs `python -m pytest`. It uses `github.*` contexts only, so project with `.[dev]` and runs `python -m pytest`. It uses `github.*` contexts only, so
it also runs on GitHub Actions. it also runs on GitHub Actions.
## Build the source documentation ## Build the source documentation
The source is documented with Doxygen comments and configured by [`Doxyfile`][doxyfile]. The source is documented with Doxygen comments and configured by [`Doxyfile`][doxyfile].
```bash ```bash
doxygen Doxyfile doxygen Doxyfile
``` ```
Open `docs/doxygen/html/index.html` in a browser. The output folder is ignored by git. Open `docs/doxygen/html/index.html` in a browser. The output folder is ignored by git.
## Project layout ## Project layout
```text ```text
.gitea/workflows/ci.yml continuous integration workflow .gitea/workflows/ci.yml continuous integration workflow
data/ the 2018 census file data/ the 2018 census file
docs/ business case, plan, milestones, models, reviews, ADRs docs/ business case, plan, milestones, models, reviews, ADRs
docs/images/ screenshots used by this README and the wiki docs/images/ screenshots used by this README and the wiki
src/squirrel/ the package: census.py, cli.py, constants.py src/squirrel/ the package: census.py, cli.py, constants.py
tests/ pytest tests tests/ pytest tests
Doxyfile Doxygen configuration wiki/ wiki pages in English, Danish (.da) and Bahasa Malaysia (.ms)
pyproject.toml project configuration (Python >=3.13, no runtime dependencies) Doxyfile Doxygen configuration
squirrel_count.csv the result of the assignment pyproject.toml project configuration (Python >=3.13, no runtime dependencies)
``` squirrel_count.csv the result of the assignment
```
The project documents, in reading order: [Business Case][bc], [Stakeholder
Analysis][sa], [Project Plan][pp], [Use Case][uc], [Domain Model][dm], [ADR-0001][adr-0001]. The project documents, in reading order: [Business Case][bc], [Stakeholder
The repository also has a wiki in English, Danish and Bahasa Malaysia. Analysis][sa], [Project Plan][pp], [Use Case][uc], [Domain Model][dm], [ADR-0001][adr-0001].
The repository also has a wiki in English, Danish and Bahasa Malaysia.
## License
## License
GNU Affero General Public License v3.0 or later. See [LICENSE][license].
GNU Affero General Public License v3.0 or later. See [LICENSE][license].
---
---
[img-run]: docs/images/run.png
[img-tests]: docs/images/tests.png [img-run]: docs/images/run.png
[doxygen]: https://www.doxygen.nl/ [img-tests]: docs/images/tests.png
[adr-0001]: docs/adr/adr-0001-standard-library-instead-of-pandas.md [doxygen]: https://www.doxygen.nl/
[ci]: .gitea/workflows/ci.yml [adr-0001]: docs/adr/adr-0001-standard-library-instead-of-pandas.md
[doxyfile]: Doxyfile [ci]: .gitea/workflows/ci.yml
[bc]: docs/business-case.md [doxyfile]: Doxyfile
[sa]: docs/stakeholder-analysis.md [bc]: docs/business-case.md
[pp]: docs/project-plan.md [sa]: docs/stakeholder-analysis.md
[uc]: docs/uc-001/uc.md [pp]: docs/project-plan.md
[dm]: docs/domain-model.md [uc]: docs/uc-001/uc.md
[license]: LICENSE [dm]: docs/domain-model.md
[license]: LICENSE
+1 -1
View File
@@ -16,7 +16,7 @@ document of a type. `Primary File` may contain a glob (e.g.
| PP | Project Plan | docs/project-plan.md | 002 | | PP | Project Plan | docs/project-plan.md | 002 |
| MIL | Milestone / Gateway | docs/milestones/*.md | 005 | | MIL | Milestone / Gateway | docs/milestones/*.md | 005 |
| ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0002 | | ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0002 |
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 025 | | RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 031 |
| DICT | Domain Dictionary | docs/dictionary.md | 002 | | DICT | Domain Dictionary | docs/dictionary.md | 002 |
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 | | TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
| UCD | Use Case Diagram | docs/use-case-diagram.md | 002 | | UCD | Use Case Diagram | docs/use-case-diagram.md | 002 |
+4 -4
View File
@@ -11,8 +11,8 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [UCD-001] | [259d017] |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [UCD-001] | [259d017] | | 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Corrected the wiki folder `docs/wiki/` to `wiki/` | [d85cfe5] |
--- ---
## Executive Summary ## Executive Summary
@@ -91,7 +91,7 @@ The project supports the participant's goal of finishing the 100 Days of Code bo
| The lecture uses Pandas but the repository must have no runtime dependencies | The solution differs from the lecture code | Use the standard library `csv` module; record the decision in an architecture decision record (ADR) and keep the lecture's step names as function names | | The lecture uses Pandas but the repository must have no runtime dependencies | The solution differs from the lecture code | Use the standard library `csv` module; record the decision in an architecture decision record (ADR) and keep the lecture's step names as function names |
| The census file is large and not part of the repository | Others cannot run the program | Keep the census file under `data/` and let the program accept a path argument | | The census file is large and not part of the repository | Others cannot run the program | Keep the census file under `data/` and let the program accept a path argument |
| Tokens in `.env` leak into the repository | Credential exposure | `.env` is git-ignored, never read by the project and never printed | | Tokens in `.env` leak into the repository | Credential exposure | `.env` is git-ignored, never read by the project and never printed |
| Wiki push is not available on the host | Wiki pages are not published | Keep the pages in the repository under `docs/wiki/` and report the failure | | Wiki push is not available on the host | Wiki pages are not published | Keep the pages in the repository under `wiki/` and report the failure |
| Fur colour spelling differs in the data | Wrong counts | Count exact values `Gray`, `Cinnamon`, `Black` and test with fixture rows | | Fur colour spelling differs in the data | Wrong counts | Count exact values `Gray`, `Cinnamon`, `Black` and test with fixture rows |
## Assumptions ## Assumptions
@@ -133,6 +133,6 @@ Proceed — the scope is small, the risks are mitigated and the result is direct
--- ---
[f1b3c03]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/f1b3c034dc3880b7884646b4a4ed28e5f98fbcd3
[UCD-001]: ./use-case-diagram.md [UCD-001]: ./use-case-diagram.md
[259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e [259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e
[d85cfe5]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/d85cfe5c4b62b2e1759f1c47b25bdb787ba6fd68
+1 -1
View File
@@ -11,7 +11,7 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [DM-002] | [259d017] | | 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [DM-002] | [259d017] |
--- ---
+4 -3
View File
@@ -11,8 +11,8 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] | | 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added task 7: static workflow test (RC-010 action item) | [6fb75dd] |
--- ---
## Purpose ## Purpose
@@ -67,10 +67,11 @@ A branch merged to `main` containing `.gitignore`, `pyproject.toml`, `src/squirr
| 4 | Add Doxyfile | Create a `Doxyfile` that reads `src/` and writes to `docs/doxygen/`, with Python optimisation enabled, so the source documentation can be built with `doxygen Doxyfile`. | No | | | 4 | Add Doxyfile | Create a `Doxyfile` that reads `src/` and writes to `docs/doxygen/`, with Python optimisation enabled, so the source documentation can be built with `doxygen Doxyfile`. | No | |
| 5 | Add CI workflow | Add a Gitea Actions workflow that sets up Python 3.13, creates a venv, upgrades pip, installs the dev extra and runs pytest on push and pull request. It backs the "Continuous integration" section of the README. | No | | | 5 | Add CI workflow | Add a Gitea Actions workflow that sets up Python 3.13, creates a venv, upgrades pip, installs the dev extra and runs pytest on push and pull request. It backs the "Continuous integration" section of the README. | No | |
| 6 | Set repository description and topics | Use the Gitea API with the token from `.env` (read by the shell only, never by the project) to set a description and topics such as `python`, `csv`, `squirrel-census`, `udemy`, `100-days-of-code`, `pytest`. Satisfies stakeholder S03. | No | | | 6 | Set repository description and topics | Use the Gitea API with the token from `.env` (read by the shell only, never by the project) to set a description and topics such as `python`, `csv`, `squirrel-census`, `udemy`, `100-days-of-code`, `pytest`. Satisfies stakeholder S03. | No | |
| 7 | Add static workflow test | Add `tests/test_workflow.py`, run by pytest on every pull request, that parses `.gitea/workflows/ci.yml` with a safe YAML loader and checks the required keys, explicit permissions, runner and timeout, named steps, exact-tag action pins and the five-line limit on `run:` blocks. Closes criterion 24 (optional) of the workflow review RC-010. | No | RC-010 |
--- ---
[BC-001]: ../business-case.md [BC-001]: ../business-case.md
[f1b3c03]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/f1b3c034dc3880b7884646b4a4ed28e5f98fbcd3
[US-001]: ../user-stories.md [US-001]: ../user-stories.md
[259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e [259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e
[6fb75dd]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/6fb75ddb8671636869b859d8718d3f3f8783659c
+4 -4
View File
@@ -11,8 +11,8 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] | | 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Corrected the wiki folder `docs/wiki/` to `wiki/` | [d85cfe5] |
--- ---
## Purpose ## Purpose
@@ -29,7 +29,7 @@ Wiki pages `Home`, `Install`, `Usage` and `Description` in English plus `-da` an
| --- | --- | --- | --- | | --- | --- | --- | --- |
| 1 | Each wiki page exists in English, Danish (`-da`) and Bahasa Malaysia (`-ms`) | All present | Any missing | | 1 | Each wiki page exists in English, Danish (`-da`) and Bahasa Malaysia (`-ms`) | All present | Any missing |
| 2 | The sidebar links every page in all three languages | All linked | Missing link | | 2 | The sidebar links every page in all three languages | All linked | Missing link |
| 3 | Wiki pages are on the git host wiki, or kept under `docs/wiki/` with the failure reported | Published or reported | Neither | | 3 | Wiki pages are on the git host wiki, or kept under `wiki/` with the failure reported | Published or reported | Neither |
| 4 | Screenshots appear on the wiki pages | Present | Missing | | 4 | Screenshots appear on the wiki pages | Present | Missing |
## Dependencies ## Dependencies
@@ -69,6 +69,6 @@ Wiki pages `Home`, `Install`, `Usage` and `Description` in English plus `-da` an
--- ---
[BC-001]: ../business-case.md [BC-001]: ../business-case.md
[f1b3c03]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/f1b3c034dc3880b7884646b4a4ed28e5f98fbcd3
[US-001]: ../user-stories.md [US-001]: ../user-stories.md
[259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e [259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e
[d85cfe5]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/d85cfe5c4b62b2e1759f1c47b25bdb787ba6fd68
+4 -4
View File
@@ -11,8 +11,8 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] |
| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | CrossReference: added [US-001] | [259d017] | | 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Corrected the wiki folder `docs/wiki/` to `wiki/` | [d85cfe5] |
--- ---
## Purpose ## Purpose
@@ -75,7 +75,7 @@ A No-Go at a gateway stops the later gateways; their dates move by the days the
| Risk | Impact | Mitigation | | Risk | Impact | Mitigation |
| --- | --- | --- | | --- | --- | --- |
| CI runner is not available on the git host | The CI workflow cannot be shown green | Run the same commands locally and report the missing runner | | CI runner is not available on the git host | The CI workflow cannot be shown green | Run the same commands locally and report the missing runner |
| Wiki repository cannot be pushed | G4 deliverable is not published | Keep the pages under `docs/wiki/` and report it | | Wiki repository cannot be pushed | G4 deliverable is not published | Keep the pages under `wiki/` and report it |
| Doxygen is not installed locally | The documentation build cannot be verified | Report as not verified; document the command | | Doxygen is not installed locally | The documentation build cannot be verified | Report as not verified; document the command |
## Open Issues ## Open Issues
@@ -92,10 +92,10 @@ A No-Go at a gateway stops the later gateways; their dates move by the days the
[MIL-002]: ./milestones/mil-002-census-analysis.md [MIL-002]: ./milestones/mil-002-census-analysis.md
[MIL-003]: ./milestones/mil-003-documentation.md [MIL-003]: ./milestones/mil-003-documentation.md
[MIL-004]: ./milestones/mil-004-wiki-publication.md [MIL-004]: ./milestones/mil-004-wiki-publication.md
[f1b3c03]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/f1b3c034dc3880b7884646b4a4ed28e5f98fbcd3
[MS-124]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/124 [MS-124]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/124
[MS-125]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/125 [MS-125]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/125
[MS-126]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/126 [MS-126]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/126
[MS-127]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/127 [MS-127]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/milestone/127
[US-001]: ./user-stories.md [US-001]: ./user-stories.md
[259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e [259d017]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/259d017ad257059330eb9a8bdbf940c9d082664e
[d85cfe5]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/d85cfe5c4b62b2e1759f1c47b25bdb787ba6fd68
@@ -0,0 +1,44 @@
# RC Review of ci.yml, delta re-review of criterion 22
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-025 |
| CrossReference | [WF-MIL-001], [QC-WF-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
---
## Artifact Under Review
- Instance reviewed: [WF-MIL-001]
- Checklist used: [QC-WF-001]
- Scope: delta re-review of criterion 22 of QC-WF-001; reason: the condition of RC-010 (run 1012 queued); earlier record RC-010
- Language and domain: n/a
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 22 | Every workflow feature used is verified on the instance that runs it, and the host and version are recorded; a feature the target hosts differ on is noted in the header (Mandatory) | Pass | Gitea 1.27.3, runner labels ubuntu-latest. `ci.yml` completed with success on the instance: pull_request runs 1037, 1040 and 1043, and the push run 1044 on main (commit c4e88c6). Header states the host and that only github.* contexts are used. |
## Overall Verdict
Go — criterion 22, the only open Mandatory criterion of RC-010, now passes; the other rows of RC-010 still hold, so the workflow is Go. Closes the condition of RC-010.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[WF-MIL-001]: ../../../.gitea/workflows/ci.yml
[QC-WF-001]: ../../../framework/qc/code/qc-workflow.md
@@ -0,0 +1,56 @@
# RC-026 Review of BC-001
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-026 |
| CrossReference | [BC-001], [QC-BC-001], [QC-LANG-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [d85cfe5] |
---
## Artifact Under Review
- Instance reviewed: [BC-001]
- Checklist used: [QC-BC-001] and [QC-LANG-001]
- Scope: delta re-review of the criterion that covers the changed text and criteria 1, 2, 6, 7, 8 of QC-LANG-001: the path `docs/wiki/` was corrected to `wiki/`
- Language and domain: en / it
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 2 | Risks are identified with documented impact and mitigation (Mandatory) | Pass | The changed text is a folder path in a risk mitigation or a Go criterion; it is still objectively checkable and has a mitigation. |
## Language and Domain Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder (Mandatory) | Pass | Language and Domain rows unchanged. |
| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list (Mandatory) | Pass | Unchanged. |
| 6 | Metadata keys, section headings, IDs and statuses are in English (Mandatory) | Pass | Keys, headings and statuses are English. |
| 7 | No translated twin (`<name>.<language>.md`) exists beside the document (Mandatory) | Pass | No translated twin. |
| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again (Mandatory) | Pass | Language unchanged. |
## Overall Verdict
Go — only a folder path was corrected; the earlier review of the content still holds.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[BC-001]: ../../business-case.md
[QC-BC-001]: ../../../framework/qc/artifacts/qc-business-case.md
[QC-LANG-001]: ../../../framework/qc/artifacts/qc-language-domain.md
[d85cfe5]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/d85cfe5c4b62b2e1759f1c47b25bdb787ba6fd68
@@ -0,0 +1,56 @@
# RC-027 Review of MIL-004
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-027 |
| CrossReference | [MIL-004], [QC-MIL-001], [QC-LANG-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [d85cfe5] |
---
## Artifact Under Review
- Instance reviewed: [MIL-004]
- Checklist used: [QC-MIL-001] and [QC-LANG-001]
- Scope: delta re-review of the criterion that covers the changed text and criteria 1, 2, 6, 7, 8 of QC-LANG-001: the path `docs/wiki/` was corrected to `wiki/`
- Language and domain: en / it
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 2 | Explicit Go/No-Go criteria are stated for each gate (Mandatory) | Pass | The changed text is a folder path in a risk mitigation or a Go criterion; it is still objectively checkable and has a mitigation. |
## Language and Domain Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder (Mandatory) | Pass | Language and Domain rows unchanged. |
| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list (Mandatory) | Pass | Unchanged. |
| 6 | Metadata keys, section headings, IDs and statuses are in English (Mandatory) | Pass | Keys, headings and statuses are English. |
| 7 | No translated twin (`<name>.<language>.md`) exists beside the document (Mandatory) | Pass | No translated twin. |
| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again (Mandatory) | Pass | Language unchanged. |
## Overall Verdict
Go — only a folder path was corrected; the earlier review of the content still holds.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[MIL-004]: ../../milestones/mil-004-wiki-publication.md
[QC-MIL-001]: ../../../framework/qc/artifacts/qc-milestones-gateways.md
[QC-LANG-001]: ../../../framework/qc/artifacts/qc-language-domain.md
[d85cfe5]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/d85cfe5c4b62b2e1759f1c47b25bdb787ba6fd68
+57
View File
@@ -0,0 +1,57 @@
# RC-028 Review of MIL-001
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-028 |
| CrossReference | [MIL-001], [QC-MIL-001], [QC-LANG-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [6fb75dd] |
---
## Artifact Under Review
- Instance reviewed: [MIL-001]
- Checklist used: [QC-MIL-001] and [QC-LANG-001]
- Scope: delta re-review of criteria 1 and 2 and criteria 1, 2, 6, 7, 8 of QC-LANG-001: task 7 added to the Tasks section
- Language and domain: en / it
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | A concrete deliverable is defined for every gate (Mandatory) | Pass | Deliverable unchanged; the new task adds a test file to the same CI deliverable. |
| 2 | Explicit Go/No-Go criteria are stated for each gate (Mandatory) | Pass | Go / No-Go criteria unchanged and still objectively checkable; the new test runs under criterion 3 (pytest exits 0). |
## Language and Domain Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder (Mandatory) | Pass | Unchanged. |
| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list (Mandatory) | Pass | Unchanged. |
| 6 | Metadata keys, section headings, IDs and statuses are in English (Mandatory) | Pass | Keys, headings and statuses are English. |
| 7 | No translated twin (`<name>.<language>.md`) exists beside the document (Mandatory) | Pass | No translated twin. |
| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again (Mandatory) | Pass | Language unchanged. |
## Overall Verdict
Go — one task row was added at the request of S01 in chat; the gate criteria and deliverable are unchanged.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[MIL-001]: ../../milestones/mil-001-project-scaffold.md
[QC-MIL-001]: ../../../framework/qc/artifacts/qc-milestones-gateways.md
[QC-LANG-001]: ../../../framework/qc/artifacts/qc-language-domain.md
[6fb75dd]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/6fb75ddb8671636869b859d8718d3f3f8783659c
@@ -0,0 +1,60 @@
# RC Review of the workflow test
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-029 |
| CrossReference | [PY-MIL-001-7], [QC-PY-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [7202aac] |
---
## Artifact Under Review
- Instance reviewed: [PY-MIL-001-7]
- Checklist used: [QC-PY-001]
- Scope: full review of tests/test_workflow.py and the dev extra of pyproject.toml
- Language and domain: n/a
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) (Mandatory) | Pass | Functions, constants (`MAX_RUN_LINES`) and class (`UniqueKeyLoader`) follow PEP 8 casing. |
| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes (Mandatory) | Pass | Names state purpose (`exceeds_line_limit`, `load_workflow`). |
| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions (Mandatory) | Pass | `ruff check` and `ruff format --check` pass with no suppressions. |
| 4 | Every function and method signature is type-annotated, including `-> None` (Mandatory) | Pass | Every function is annotated; `mypy --strict` passes on 11 files; `Any` is justified by a comment. |
| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) (Mandatory) | Pass | The duplicate-key loader raises `ValueError` with the key named; no bare except. |
| 6 | No mutable default arguments and no shadowed builtins (Mandatory) | Pass | No mutable defaults; no builtins shadowed. |
| 7 | Files, locks and connections are managed with context managers (Mandatory) | Pass | The workflow file is read through `pathlib` and the YAML loader, which close the file. |
| 8 | Public modules, classes and functions have docstrings that say what, not how (Optional) | Pass | Helpers and tests have docstrings. |
| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output (Mandatory) | Pass | No print and no logging; no secrets. |
| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded (Mandatory) | N-A | Test code; no class or operation of a design class diagram. |
| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network (Mandatory) | Pass | 14 tests, one behaviour each, plus a negative self-test of the line limit; no order or network dependence. |
| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment (Optional) | Pass | `mypy --strict` passes; `Any` is commented. |
| 13 | Dependencies are declared and pinned in the project's dependency file, none unused (Optional) | Pass | `pyyaml` and `types-PyYAML` are dev dependencies pinned exactly; no runtime dependency added. |
| 14 | Each piece of knowledge (a business rule, constant, format, validation or query) is defined in one place; code is merged only where it expresses the same knowledge, not where it merely looks alike (Mandatory) | Pass | The line limit is the single constant `MAX_RUN_LINES`, matching the rule in the YAML convention. |
| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles (Mandatory) | Pass | The test imports the standard library and `yaml`; it imports no application code. |
| 16 | SOLID holds: a class or module has one reason to change; new behaviour is added by extension, not by editing a type test in several places; subclasses honour the contract of their base; protocols are narrow; high-level code depends on protocols or abstract types and receives its implementations (Mandatory) | Pass | One module of small single-purpose helpers and tests. |
## Overall Verdict
Go — all Mandatory criteria pass; criterion 10 is not applicable.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[PY-MIL-001-7]: ../../../tests/test_workflow.py
[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md
[7202aac]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/7202aac5956ef92ab6a4efc6cb1917de075d771a
@@ -0,0 +1,45 @@
# RC Review of ci.yml, delta re-review of criterion 24
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-030 |
| CrossReference | [WF-MIL-001], [QC-WF-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [7202aac] |
---
## Artifact Under Review
- Instance reviewed: [WF-MIL-001]
- Checklist used: [QC-WF-001]
- Scope: delta re-review of criterion 24 of QC-WF-001; reason: action item of RC-010; earlier records RC-010 and RC-025
- Language and domain: n/a
- Language reviewer: none (the stand-in reviewer reads English and the `it` domain)
- Mode: autonomous, not independent (reviewer: AI as stand-in for S01)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 24 | A static test of the repository's workflows exists and runs on every pull request: valid YAML, required keys, explicit permissions and runner, no inline script above the limit (Optional) | Pass | `tests/test_workflow.py` runs in the pytest step of `ci.yml` on every pull request: it checks safe-loader parsing, required keys, duplicate keys, explicit permissions and runner, timeout, step names, exact-tag pins and the five-line limit on `run:` blocks. 33 tests pass locally. |
## Overall Verdict
Go — criterion 24 (Optional) now passes; the other rows of RC-010 and RC-025 still hold. Closes the second action item of RC-010.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | S01 | - |
---
[WF-MIL-001]: ../../../.gitea/workflows/ci.yml
[QC-WF-001]: ../../../framework/qc/code/qc-workflow.md
[7202aac]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/7202aac5956ef92ab6a4efc6cb1917de075d771a
+14 -5
View File
@@ -9,7 +9,8 @@
## Version History ## Version History
| Date | Status | Author | Reviewer | Change | Commit | | Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] | | 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [f1b3c03] |
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Rows added for UCD-001, US-001, UC-001, SSD-001, DM-001, DM-002, ADR-0001 and the source files; Last Reviewed updated up to RC-030<br>Version History rows added for edits made since the first version (the git history holds each edit) | [dfaa840] |
--- ---
@@ -23,13 +24,13 @@ updated whenever an artifact instance is created or reviewed.
| Artifact Instance | Type | Language | Domain | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) | | Artifact Instance | Type | Language | Domain | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| [BC-001] | Business Case | en | it | - | [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004] | [RC-001], [RC-019] | | [BC-001] | Business Case | en | it | - | [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004] | [RC-001], [RC-019], [RC-026] |
| [SA-001] | Stakeholder Analysis | en | it | [BC-001] | [PP-001] | [RC-002] | | [SA-001] | Stakeholder Analysis | en | it | [BC-001] | [PP-001] | [RC-002] |
| [PP-001] | Project Plan | en | it | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004] | - (no checklist; accepted by S01 in chat) | | [PP-001] | Project Plan | en | it | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004] | - (no checklist; accepted by S01 in chat) |
| [MIL-001] | Milestone | en | it | [BC-001], [PP-001] | - | [RC-003], [RC-020] | | [MIL-001] | Milestone | en | it | [BC-001], [PP-001] | - | [RC-003], [RC-020], [RC-028] |
| [MIL-002] | Milestone | en | it | [BC-001], [PP-001], [MIL-001] | - | [RC-004], [RC-021] | | [MIL-002] | Milestone | en | it | [BC-001], [PP-001], [MIL-001] | - | [RC-004], [RC-021] |
| [MIL-003] | Milestone | en | it | [BC-001], [PP-001], [MIL-002] | - | [RC-005], [RC-022] | | [MIL-003] | Milestone | en | it | [BC-001], [PP-001], [MIL-002] | - | [RC-005], [RC-022] |
| [MIL-004] | Milestone | en | it | [BC-001], [PP-001], [MIL-003] | - | [RC-006], [RC-023] | | [MIL-004] | Milestone | en | it | [BC-001], [PP-001], [MIL-003] | - | [RC-006], [RC-023], [RC-027] |
| [DICT-001] | Domain Dictionary | en | it | [BC-001], [SA-001] | - | [RC-007], [RC-018] | | [DICT-001] | Domain Dictionary | en | it | [BC-001], [SA-001] | - | [RC-007], [RC-018] |
| [UCD-001] | Use Case Diagram | en | it | [SA-001], [BC-001] | [US-001], [UC-001] | [RC-011] | | [UCD-001] | Use Case Diagram | en | it | [SA-001], [BC-001] | [US-001], [UC-001] | [RC-011] |
| [US-001] | User Story | en | it | [UCD-001], [BC-001], [MIL-002] | [UC-001] | [RC-012] | | [US-001] | User Story | en | it | [UCD-001], [BC-001], [MIL-002] | [UC-001] | [RC-012] |
@@ -40,7 +41,8 @@ updated whenever an artifact instance is created or reviewed.
| [ADR-0001] | Architecture Decision Record | - | - | [BC-001], [SA-001], [MIL-002] | `src/squirrel/census.py` | [RC-017] | | [ADR-0001] | Architecture Decision Record | - | - | [BC-001], [SA-001], [MIL-002] | `src/squirrel/census.py` | [RC-017] |
| `src/squirrel/census.py`, `cli.py`, `__main__.py`, `tests/` | Python Source Code | - | - | [UC-001], [SSD-001], [ADR-0001] | - | [RC-024] | | `src/squirrel/census.py`, `cli.py`, `__main__.py`, `tests/` | Python Source Code | - | - | [UC-001], [SSD-001], [ADR-0001] | - | [RC-024] |
| `src/squirrel/constants.py`, `tests/test_constants.py` | Python Source Code | - | - | [MIL-001] | - | [RC-008] | | `src/squirrel/constants.py`, `tests/test_constants.py` | Python Source Code | - | - | [MIL-001] | - | [RC-008] |
| `.gitea/workflows/ci.yml` | CI Workflow | - | - | [MIL-001] | - | [RC-009], [RC-010] | | `tests/test_workflow.py` | Python Source Code | - | - | [MIL-001], [RC-010] | - | [RC-029] |
| `.gitea/workflows/ci.yml` | CI Workflow | - | - | [MIL-001] | - | [RC-009], [RC-010], [RC-025], [RC-030] |
## Coverage Notes ## Coverage Notes
@@ -89,3 +91,10 @@ updated whenever an artifact instance is created or reviewed.
[RC-022]: ./reviews/rc-022-mil-003-delta.md [RC-022]: ./reviews/rc-022-mil-003-delta.md
[RC-023]: ./reviews/rc-023-mil-004-delta.md [RC-023]: ./reviews/rc-023-mil-004-delta.md
[RC-024]: ./reviews/rc-024-python-census.md [RC-024]: ./reviews/rc-024-python-census.md
[RC-025]: ./reviews/rc-025-ci-workflow-delta.md
[RC-026]: ./reviews/rc-026-business-case-wiki-path.md
[RC-027]: ./reviews/rc-027-mil-004-wiki-path.md
[RC-028]: ./reviews/rc-028-mil-001-task-7.md
[RC-029]: ./reviews/rc-029-python-workflow-test.md
[RC-030]: ./reviews/rc-030-ci-workflow-delta-24.md
[dfaa840]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/commit/dfaa8400c3bd24b086a2c3eab1bef1e4e7ea6b45
+2 -1
View File
@@ -21,7 +21,8 @@ classifiers = [
] ]
[project.optional-dependencies] [project.optional-dependencies]
dev = ["pytest==9.1.1", "ruff==0.17.0", "mypy==2.4.0"] dev = ["pytest==9.1.1", "ruff==0.17.0", "mypy==2.4.0",
"pyyaml==6.0.3", "types-PyYAML==6.0.12.20260906"]
[tool.setuptools.packages.find] [tool.setuptools.packages.find]
where = ["src"] where = ["src"]
+167
View File
@@ -0,0 +1,167 @@
"""Static checks of the CI workflow (QC-WF-001 criterion 24, MIL-001 task 7)."""
import re
from collections.abc import Hashable, Iterator
from pathlib import Path
from typing import Any
import pytest
import yaml
ROOT = Path(__file__).parents[1]
WORKFLOW_PATH = ROOT / ".gitea" / "workflows" / "ci.yml"
GITHUB_WORKFLOW_PATH = ROOT / ".github" / "workflows" / "ci.yml"
MAX_RUN_LINES = 5
EXACT_TAG = re.compile(r"@v\d+\.\d+\.\d+$")
FULL_SHA = re.compile(r"@[0-9a-f]{40}$")
# Parsed YAML is untyped data, so Any is the honest type here.
Workflow = dict[Any, Any]
class UniqueKeyLoader(yaml.SafeLoader):
"""Safe loader that rejects a mapping with a repeated key."""
def construct_mapping(
self, node: yaml.MappingNode, deep: bool = False
) -> dict[Hashable, Any]:
"""Build the mapping, raising ValueError on a duplicate key."""
seen: set[Hashable] = set()
for key_node, _ in node.value:
key = self.construct_object(key_node, deep=deep)
if key in seen:
raise ValueError(f"duplicate key {key!r} at {key_node.start_mark}")
seen.add(key)
return super().construct_mapping(node, deep=deep)
def load_workflow() -> Workflow:
"""Parse the workflow with the safe loader."""
loaded = yaml.safe_load(WORKFLOW_PATH.read_text(encoding="utf-8"))
assert isinstance(loaded, dict)
return loaded
def triggers(workflow: Workflow) -> Any:
"""Return the trigger section; YAML 1.1 reads the key `on` as True."""
return workflow["on"] if "on" in workflow else workflow[True]
def trigger_names(workflow: Workflow) -> set[str]:
"""Return the names of the events that trigger the workflow."""
section = triggers(workflow)
if isinstance(section, str):
return {section}
return {str(name) for name in section}
def jobs(workflow: Workflow) -> dict[str, Workflow]:
"""Return the jobs by id."""
found: dict[str, Workflow] = workflow["jobs"]
return found
def steps(job: Workflow) -> list[Workflow]:
"""Return the steps of a job."""
found: list[Workflow] = job.get("steps", [])
return found
def all_steps(workflow: Workflow) -> Iterator[Workflow]:
"""Yield every step of every job."""
for job in jobs(workflow).values():
yield from steps(job)
def exceeds_line_limit(script: str, limit: int = MAX_RUN_LINES) -> bool:
"""Tell whether a script has more lines than the limit, as written.
Blank lines and comments count.
"""
return len(script.splitlines()) > limit
def test_workflow_parses_with_required_keys() -> None:
"""The file is valid YAML with a name, a trigger and jobs."""
workflow = load_workflow()
assert "name" in workflow
assert "on" in workflow or True in workflow
assert "jobs" in workflow
def test_workflow_has_no_duplicate_keys() -> None:
"""No mapping in the file repeats a key."""
text = WORKFLOW_PATH.read_text(encoding="utf-8")
assert yaml.load(text, Loader=UniqueKeyLoader) is not None
def test_duplicate_key_loader_rejects_repeated_key() -> None:
"""The duplicate-key loader bites on a repeated key."""
with pytest.raises(ValueError, match="duplicate key"):
yaml.load("a: 1\na: 2\n", Loader=UniqueKeyLoader)
def test_permissions_are_declared() -> None:
"""Permissions are set at workflow level or on every job."""
workflow = load_workflow()
if "permissions" in workflow:
return
assert all("permissions" in job for job in jobs(workflow).values())
def test_every_job_has_runner_and_timeout() -> None:
"""Each job names its runner and a timeout."""
for job_id, job in jobs(load_workflow()).items():
assert "runs-on" in job, job_id
assert "timeout-minutes" in job, job_id
def test_every_step_has_a_name() -> None:
"""Each step carries a name."""
for job_id, job in jobs(load_workflow()).items():
for step in steps(job):
assert "name" in step, f"{job_id}: {step}"
def test_step_names_are_unique_within_a_job() -> None:
"""No two steps of one job share a name."""
for job_id, job in jobs(load_workflow()).items():
names = [step["name"] for step in steps(job) if "name" in step]
assert len(names) == len(set(names)), job_id
def test_uses_are_pinned_to_exact_release_or_sha() -> None:
"""Each action is pinned to an exact tag or a full commit SHA."""
for step in all_steps(load_workflow()):
if "uses" in step:
ref = str(step["uses"])
assert EXACT_TAG.search(ref) or FULL_SHA.search(ref), ref
def test_run_blocks_stay_within_line_limit() -> None:
"""No inline script is longer than the limit."""
for step in all_steps(load_workflow()):
if "run" in step:
assert not exceeds_line_limit(str(step["run"])), step.get("name")
def test_line_limit_check_rejects_six_lines() -> None:
"""The line-limit helper counts lines as written, blank lines included."""
assert exceeds_line_limit("a\nb\nc\nd\ne\nf\n")
assert exceeds_line_limit("a\nb\nc\nd\ne\n\n")
assert not exceeds_line_limit("a\nb\n\nc\nd\n")
def test_workflow_uses_no_secrets() -> None:
"""The file refers to no secret."""
assert "secrets." not in WORKFLOW_PATH.read_text(encoding="utf-8")
def test_workflow_is_not_triggered_by_pull_request_target() -> None:
"""The privileged pull_request_target trigger is not used."""
assert "pull_request_target" not in trigger_names(load_workflow())
def test_workflow_is_not_duplicated_for_github() -> None:
"""The same workflow does not also live under .github/workflows."""
assert not GITHUB_WORKFLOW_PATH.exists()
+32
View File
@@ -0,0 +1,32 @@
🌐 [English](Description) · **Dansk** · [Bahasa Melayu](Description.ms)
# Beskrivelse
## Hvad programmet gør
Programmet følger lektionens trin:
1. `read_csv` læser optællingsfilen.
2. `count_by_fur_color` tæller observationerne af Gray, Cinnamon og Black.
3. `build_summary` gør tallene til rækkerne i en opsummering.
4. `write_csv` skriver opsummeringen til `squirrel_count.csv`.
På optællingsfilen fra 2018 er resultatet Gray 2473, Cinnamon 392 og Black 103. Observationer uden pelsfarve tælles ikke med i nogen af dem.
## Hvorfor ikke Pandas
Lektionen bruger Pandas. Dette projekt bruger kun Pythons standardbibliotek (`csv` og `collections.Counter`), så der ikke er noget at installere for at køre det. Beslutningen er beskrevet som ADR-0001 i repositoryet.
## Opbygning
| Sti | Indhold |
| --- | --- |
| `src/squirrel/census.py` | De fire trin ovenfor |
| `src/squirrel/cli.py` | Kommandolinjen, `python -m squirrel` |
| `src/squirrel/constants.py` | Alle konstanter, defineret ét sted |
| `tests/` | pytest-testene |
| `docs/` | Business case, plan, modeller, reviewposter |
## Kvalitet
Alle dokumenter og al kode er gennemgået mod tjeklisterne i SQA- og QC-frameworket i autonom tilstand: reviewer er en AI-stedfortræder, så reviewene er ikke uafhængige.
+32
View File
@@ -0,0 +1,32 @@
🌐 **English** · [Dansk](Description.da) · [Bahasa Melayu](Description.ms)
# Description
## What it does
The program follows the steps of the lecture:
1. `read_csv` reads the census file.
2. `count_by_fur_color` counts the sightings of Gray, Cinnamon and Black.
3. `build_summary` turns the counts into the rows of a summary.
4. `write_csv` writes the summary to `squirrel_count.csv`.
On the 2018 census file the result is Gray 2473, Cinnamon 392 and Black 103. Sightings without a fur colour are counted in none of them.
## Why no Pandas
The lecture uses Pandas. This project uses only the Python standard library (`csv` and `collections.Counter`) so that there is nothing to install to run it. The decision is recorded as ADR-0001 in the repository.
## Layout
| Path | Content |
| --- | --- |
| `src/squirrel/census.py` | The four steps above |
| `src/squirrel/cli.py` | The command line, `python -m squirrel` |
| `src/squirrel/constants.py` | Every literal, defined once |
| `tests/` | The pytest tests |
| `docs/` | Business case, plan, models, review records |
## Quality
Every document and every piece of code was reviewed against the checklists of the SQA and QC framework, in autonomous mode: the reviewer is an AI stand-in, so the reviews are not independent.
+32
View File
@@ -0,0 +1,32 @@
🌐 [English](Description) · [Dansk](Description.da) · **Bahasa Melayu**
# Penerangan
## Apa yang dilakukan program
Program mengikut langkah dalam pelajaran:
1. `read_csv` membaca fail banci.
2. `count_by_fur_color` mengira pemerhatian Gray, Cinnamon dan Black.
3. `build_summary` menukar kiraan kepada baris ringkasan.
4. `write_csv` menulis ringkasan ke `squirrel_count.csv`.
Pada fail banci 2018 hasilnya ialah Gray 2473, Cinnamon 392 dan Black 103. Pemerhatian tanpa warna bulu tidak dikira dalam mana-mana satu.
## Mengapa tidak menggunakan Pandas
Pelajaran menggunakan Pandas. Projek ini hanya menggunakan pustaka standard Python (`csv` dan `collections.Counter`) supaya tiada apa-apa untuk dipasang bagi menjalankannya. Keputusan itu direkodkan sebagai ADR-0001 dalam repositori.
## Susun atur
| Laluan | Kandungan |
| --- | --- |
| `src/squirrel/census.py` | Empat langkah di atas |
| `src/squirrel/cli.py` | Baris perintah, `python -m squirrel` |
| `src/squirrel/constants.py` | Semua pemalar, ditakrif sekali |
| `tests/` | Ujian pytest |
| `docs/` | Kes perniagaan, pelan, model, rekod semakan |
## Kualiti
Setiap dokumen dan kod disemak berdasarkan senarai semak rangka kerja SQA dan QC dalam mod autonomi: penyemak ialah pengganti AI, jadi semakan itu tidak bebas.
+15
View File
@@ -0,0 +1,15 @@
🌐 [English](Home) · **Dansk** · [Bahasa Melayu](Home.ms)
# Egern-optælling
Dag 25 i Udemys *100 Days of Code: The Complete Python Pro Bootcamp*: tæl egernene i Central Parks egern-optælling fra 2018 efter primær pelsfarve (grå, kanel, sort) og eksportér tallene til `squirrel_count.csv`.
![Programkørsel](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
| Side | Læs den, når du vil |
| --- | --- |
| [Installation](Install.da) | Oprette et `.venv` og installere projektet på Windows PowerShell, Linux Debian eller macOS |
| [Brug](Usage.da) | Køre programmet og testene |
| [Beskrivelse](Description.da) | Forstå hvordan koden er bygget, og hvorfor den ikke har kørselsafhængigheder |
Koden, testene og projektdokumenterne ligger i [repositoryet](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel).
+15
View File
@@ -0,0 +1,15 @@
🌐 **English** · [Dansk](Home.da) · [Bahasa Melayu](Home.ms)
# Squirrel Census
Day 25 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*: count the squirrels of the 2018 Central Park Squirrel Census by primary fur colour (gray, cinnamon, black) and export the counts to `squirrel_count.csv`.
![Program run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
| Page | Read it when you want to |
| --- | --- |
| [Install](Install) | Create a `.venv` and install the project on Windows PowerShell, Linux Debian or macOS |
| [Usage](Usage) | Run the program and the tests |
| [Description](Description) | Understand how the code is built and why it has no runtime dependencies |
The code, the tests and the project documents are in the [repository](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel).
+15
View File
@@ -0,0 +1,15 @@
🌐 [English](Home) · [Dansk](Home.da) · **Bahasa Melayu**
# Banci Tupai
Hari ke-25 dalam *100 Days of Code: The Complete Python Pro Bootcamp* Udemy: kira tupai dalam Banci Tupai Central Park 2018 mengikut warna bulu utama (kelabu, kayu manis, hitam) dan eksport kiraan ke `squirrel_count.csv`.
![Larian program](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
| Halaman | Baca apabila anda mahu |
| --- | --- |
| [Pemasangan](Install.ms) | Mencipta `.venv` dan memasang projek di Windows PowerShell, Linux Debian atau macOS |
| [Penggunaan](Usage.ms) | Menjalankan program dan ujian |
| [Penerangan](Description.ms) | Memahami cara kod dibina dan sebab ia tiada kebergantungan masa jalan |
Kod, ujian dan dokumen projek berada dalam [repositori](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel).
+35
View File
@@ -0,0 +1,35 @@
🌐 [English](Install) · **Dansk** · [Bahasa Melayu](Install.ms)
# Installation
Projektet kræver **Python 3.13 eller nyere**. Det har ingen kørselsafhængigheder; `pytest`, `ruff` og `mypy` er udviklingsværktøjer.
## Windows PowerShell
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## Linux Debian
```bash
sudo apt install python3 python3-venv
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## macOS
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
Næste: [Brug](Usage.da).
+35
View File
@@ -0,0 +1,35 @@
🌐 **English** · [Dansk](Install.da) · [Bahasa Melayu](Install.ms)
# Install
The project needs **Python 3.13 or later**. It has no runtime dependencies; `pytest`, `ruff` and `mypy` are development tools.
## Windows PowerShell
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## Linux Debian
```bash
sudo apt install python3 python3-venv
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## macOS
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
Next: [Usage](Usage).
+35
View File
@@ -0,0 +1,35 @@
🌐 [English](Install) · [Dansk](Install.da) · **Bahasa Melayu**
# Pemasangan
Projek ini memerlukan **Python 3.13 atau lebih baharu**. Ia tiada kebergantungan masa jalan; `pytest`, `ruff` dan `mypy` ialah alat pembangunan.
## Windows PowerShell
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## Linux Debian
```bash
sudo apt install python3 python3-venv
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
## macOS
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
Seterusnya: [Penggunaan](Usage.ms).
+33
View File
@@ -0,0 +1,33 @@
🌐 [English](Usage) · **Dansk** · [Bahasa Melayu](Usage.ms)
# Brug
## Kør programmet
Med det virtuelle miljø aktivt, fra projektmappen:
```bash
python -m squirrel
```
Programmet læser `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, skriver tallene for hver pelsfarve og gemmer `squirrel_count.csv`.
![Programkørsel](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
Brug andre filer med `python -m squirrel <optællingsfil> <opsummeringsfil>`. Findes optællingsfilen ikke, skriver programmet `Census file not found` og afslutter med status 2.
## Kør testene
```bash
python -m pytest
```
![Testkørsel](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/tests.png)
## Byg kildedokumentationen
```bash
doxygen Doxyfile
```
Åbn `docs/doxygen/html/index.html`.
+33
View File
@@ -0,0 +1,33 @@
🌐 **English** · [Dansk](Usage.da) · [Bahasa Melayu](Usage.ms)
# Usage
## Run the program
With the virtual environment active, from the project folder:
```bash
python -m squirrel
```
The program reads `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, prints the colour counts and writes `squirrel_count.csv`.
![Program run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
Use other files with `python -m squirrel <census file> <summary file>`. If the census file does not exist, the program prints `Census file not found` and exits with status 2.
## Run the tests
```bash
python -m pytest
```
![Test run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/tests.png)
## Build the source documentation
```bash
doxygen Doxyfile
```
Open `docs/doxygen/html/index.html`.
+33
View File
@@ -0,0 +1,33 @@
🌐 [English](Usage) · [Dansk](Usage.da) · **Bahasa Melayu**
# Penggunaan
## Jalankan program
Dengan persekitaran maya aktif, dari folder projek:
```bash
python -m squirrel
```
Program membaca `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, mencetak kiraan setiap warna bulu dan menulis `squirrel_count.csv`.
![Larian program](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/run.png)
Gunakan fail lain dengan `python -m squirrel <fail banci> <fail ringkasan>`. Jika fail banci tidak wujud, program mencetak `Census file not found` dan keluar dengan status 2.
## Jalankan ujian
```bash
python -m pytest
```
![Larian ujian](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-squirrel/raw/branch/main/docs/images/tests.png)
## Bina dokumentasi sumber
```bash
doxygen Doxyfile
```
Buka `docs/doxygen/html/index.html`.
+24
View File
@@ -0,0 +1,24 @@
<!-- Generated from wiki; edit the source pages, not the published wiki. -->
**Squirrel Census**
**English**
- [Home](Home)
- [Install](Install)
- [Usage](Usage)
- [Description](Description)
**Dansk**
- [Hjem](Home.da)
- [Installation](Install.da)
- [Brug](Usage.da)
- [Beskrivelse](Description.da)
**Bahasa Melayu**
- [Utama](Home.ms)
- [Pemasangan](Install.ms)
- [Penggunaan](Usage.ms)
- [Penerangan](Description.ms)