Compare commits

..
Author SHA1 Message Date
Tirsvad 90262b0dac Resolve pending commit links 2026-10-29 11:45:36 +08:00
Tirsvad 1f281294cc Update the framework to 351ddf0, take the git-workflows milestone workflow, new wiki sidebar, RC-028 and RC-029 2026-10-29 11:45:34 +08:00
Tirsvad c09106961c Merge pull request 'Update the framework to 0.18.0+' (#60) from update-framework into main
Publish accepted milestones / publish (push) Failing after 4s
TirSystem/git-workflows: Sync GitHub mirror metadata / sync-metadata (push) Successful in 7s
2026-10-28 17:11:26 +01:00
7 changed files with 171 additions and 41 deletions
+22 -28
View File
@@ -8,24 +8,18 @@
# deleted. Each run updates the issues of every accepted milestone (the sync is # deleted. Each run updates the issues of every accepted milestone (the sync is
# idempotent, but the host records the edit). # idempotent, but the host records the edit).
# #
# INSTALLING THIS FILE IS THE STANDING AUTHORIZATION TO PUBLISH. A project opts # INSTALLING THIS FILE IS THE STANDING AUTHORIZATION TO PUBLISH. This project
# in by copying it; an agent does not install it on its own. # installed it on 2026-10-29 at the request of S01.
# #
# Copy it to .gitea/workflows/sync-milestones.yml (Gitea Actions) or # Secrets, each the bare Gitea token of the organization (no JSON):
# .github/workflows/sync-milestones.yml (GitHub Actions). Then: # TOKEN_FOR_GITEA_REPO checks out the project and the framework repository, a
# 1. Create a CI secret and put its name in the two `secrets.` lines below # private submodule, so it needs read on repositories; TOKEN_FOR_GITEA_ISSUES
# (TOKEN_FOR_GITEA_ISSUES is the name the # publishes and needs read and write on issues and milestones only. Gitea does
# framework uses). Gitea does not accept secret names that # not accept secret names that start with GITEA_ or GITHUB_.
# start with GITEA_ or GITHUB_. #
# 2. Give the token the smallest scope that works: read and write on issues # Run it once by hand from the Actions page with dry_run left on: it prints
# and milestones. If the framework submodule is a private repository, the
# token must also be able to read it (it is used to check it out).
# 3. Run it once by hand from the Actions page with dry_run left on: it prints
# the plan and creates nothing. Turn dry_run off only for a real run. # the plan and creates nothing. Turn dry_run off only for a real run.
# A runner must be registered for the repository (or its organisation). # A runner must be registered for the repository (or its organisation).
#
# The steps are one command each: the logic is framework/scripts/ci-publish-milestones.sh,
# a file that is linted and tested (QC-WF-001 criterion 20).
name: Publish accepted milestones name: Publish accepted milestones
@@ -57,29 +51,29 @@ jobs:
- name: Check out the project - name: Check out the project
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
with: with:
token: ${{ secrets.TOKEN_FOR_GITEA_ISSUES }} token: ${{ secrets.TOKEN_FOR_GITEA_REPO }}
# The framework submodule is registered with an SSH address, which the runner # .gitmodules uses ssh:// URLs and the runner has no SSH key, so the
# cannot use. The address is rewritten to HTTPS for this step only, and the token # submodules (framework, and framework/qc inside it) are fetched over HTTPS
# goes in through the environment, never on a command line. .gitmodules stays. # with the same token (TOKEN_FOR_GITEA_REPO). The token goes through the environment, not a
- name: Fetch the framework submodule over HTTPS # command line.
- name: Check out the framework submodules over HTTPS
env: env:
GIT_CONFIG_COUNT: "2" GIT_CONFIG_COUNT: "2"
GIT_CONFIG_KEY_0: url.https://git.tirsystem.com/.insteadOf GIT_CONFIG_KEY_0: "url.https://git.tirsystem.com/.insteadOf"
GIT_CONFIG_VALUE_0: ssh://git@git.tirsystem.com:10022/ GIT_CONFIG_VALUE_0: "ssh://git@git.tirsystem.com:10022/"
GIT_CONFIG_KEY_1: http.https://git.tirsystem.com/.extraheader GIT_CONFIG_KEY_1: "http.extraheader"
GIT_CONFIG_VALUE_1: "Authorization: token ${{ secrets.TOKEN_FOR_GITEA_ISSUES }}" GIT_CONFIG_VALUE_1: "Authorization: token ${{ secrets.TOKEN_FOR_GITEA_REPO }}"
run: git submodule update --init --recursive run: |
set -euo pipefail
git submodule update --init --recursive --depth=1
- name: Make sure curl and jq are available - name: Make sure curl and jq are available
run: bash framework/scripts/ci-publish-milestones.sh ensure-tools run: bash framework/scripts/ci-publish-milestones.sh ensure-tools
- name: Publish accepted milestones - name: Publish accepted milestones
env: env:
# Gitea reads TOKEN_FOR_GITEA_ISSUES, GitHub's gh reads GH_TOKEN; both
# come from the one secret named above.
TOKEN_FOR_GITEA_ISSUES: ${{ secrets.TOKEN_FOR_GITEA_ISSUES }} TOKEN_FOR_GITEA_ISSUES: ${{ secrets.TOKEN_FOR_GITEA_ISSUES }}
GH_TOKEN: ${{ secrets.TOKEN_FOR_GITEA_ISSUES }}
# Empty on a push (a real run); "true" or "false" on a manual run. # Empty on a push (a real run); "true" or "false" on a manual run.
DRY_RUN: ${{ inputs.dry_run }} DRY_RUN: ${{ inputs.dry_run }}
run: bash framework/scripts/ci-publish-milestones.sh publish run: bash framework/scripts/ci-publish-milestones.sh publish
+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 | 011 | | MIL | Milestone / Gateway | docs/milestones/*.md | 011 |
| ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0004 | | ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0004 |
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 028 | | RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 030 |
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 | | TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
| DICT | Domain Dictionary | docs/dictionary.md | 002 | | DICT | Domain Dictionary | docs/dictionary.md | 002 |
+59
View File
@@ -0,0 +1,59 @@
# SQA Review Record
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-028 |
| CrossReference | [MIL-008], [QC-WIKI-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-29 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S02 | Review record, the wiki in docs/wiki after the sidebar change of framework 0.19.0 | [1f28129] |
---
## Artifact Under Review
- Instance reviewed: [MIL-008]
- Checklist used: [QC-WIKI-001] (`QC-WIKI-001`)
- Scope: the wiki in docs/wiki after the sidebar change of framework 0.19.0
- Language and domain: n/a
- Language reviewer: none
- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S02`)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The wiki has a `_Sidebar.md`, because the host lists subpages only through it | Pass | `docs/wiki/_Sidebar.md` exists. |
| 2 | The sidebar starts with the wiki's title in bold, then one list of the pages in the primary language (English), `Home` first | Pass | The sidebar starts with the title in bold, then one English page list with `Home` first. |
| 3 | The page list holds a link to every English page of the wiki, and no link points to a page that does not exist | Pass | The list links to all 12 English pages (Home, Getting-Started, Step-1 to Step-9, Troubleshooting); every target exists in `docs/wiki/` and on the published wiki (HTTP 200 checked for Home, Home-da, Home-ms, Getting-Started, Step-1, Step-9-ms, Troubleshooting-da). |
| 4 | A `**Related**` section follows the page list only when the wiki has related wikis (for example the checklists wiki for a framework wiki); each entry is a link to that wiki's Home. A wiki with nothing related has no such section | N-A | The wiki has no related wikis, so it has no `Related` section. |
| 5 | A `**Languages**` section is the last section of the sidebar. It has one line per language, the language written in that language, linking to that language's `Home` page | Pass | `**Languages**` is the last section with `English: [Home](Home)`, `Dansk: [Hjem](Home-da)` and `Bahasa Melayu: [Utama](Home-ms)`. |
| 6 | The sidebar does not repeat the page list per language | Pass | The page list appears once. |
| 7 | A sidebar produced by a generator carries a comment that says so and names the generator; the generator is changed, not the page | N-A | The sidebar is written by hand in the repository (a one-off helper made it, which is not part of the project), so it carries no generator comment. |
| 8 | The wiki has a `Languages` line on each page (criterion 11), so the sidebar is not the only way to switch language | Pass | Each page starts with the language line (criterion 11). |
| 9 | Every wiki exists in English and, as a minimum, in the language the project's registry names as the PO language; further languages are added on top, never instead of English | Pass | English and Danish and Bahasa Malaysia exist; the registry names English as the PO language. |
| 10 | Every English page has a page in each other language of the wiki: the page sets are identical | Pass | Each language has the same 12 pages (checked by file name: `<Page>.md`, `<Page>-da.md`, `<Page>-ms.md`). |
| 11 | Every page starts with the language line, with the current language in bold and a link to the same page in each other language | Pass | Each page starts with the language line with the current language in bold and a link to the same page in the other two languages. |
| 12 | A page in a language other than English is named `<Page>-<code>.md`, with a BCP 47 code; English has no suffix | Pass | Danish and Bahasa Malaysia pages are named `<Page>-da.md` and `<Page>-ms.md`; English has no suffix. |
| 13 | Code blocks, commands, file names and IDs stay in English in every language | Pass | Commands, code blocks, file names and IDs are English on every page. |
| 14 | The sidebar, every page and every link were checked on the published wiki after the change, not only in the repository | Pending | The new sidebar is checked on the published wiki only after the merge (the wiki is published from `main` by the instance workflow); the links of the pages were checked on the published wiki before this change. |
| 15 | A change to the layout rules (sections, order, naming) is made in the generator or template and in this checklist's source rules together | N-A | No change to the layout rules was made. |
## Overall Verdict
Go-with-conditions - the wiki meets every Mandatory criterion of QC-WIKI-001 in the repository, with the sidebar in the shape that framework 0.19.0 sets. Criterion 14 (the sidebar checked on the published wiki) is Pending until the merge has been published. QC-WIKI-001 itself is `Proposed`. The review is not independent: the AI wrote and reviewed it as stand-in for S02, and S01 can challenge it in the end-of-run summary.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Open the published wiki once after the merge and check the sidebar | S01 | when convenient |
---
[MIL-008]: ../../milestones/mil-008-documentation.md
[QC-WIKI-001]: ../../../framework/qc/artifacts/qc-wiki.md
[1f28129]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/049-snack-and-lift/commit/1f281294cca20462b0925c84889d33fd69329a5c
@@ -0,0 +1,69 @@
# SQA Review Record
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-029 |
| CrossReference | [MIL-008], [QC-WF-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-29 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S02 | Review record, the workflow sync-milestones.yml, now the file of TirSystem/git-workflows | [1f28129] |
---
## Artifact Under Review
- Instance reviewed: [MIL-008]
- Checklist used: [QC-WF-001] (`QC-WF-001`)
- Scope: the workflow sync-milestones.yml, now the file of TirSystem/git-workflows
- Language and domain: n/a
- Language reviewer: none
- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S02`)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The file meets the YAML checklist ([QC-YML-001]) | Pending | `yamllint` is not installed on the stand-in's machine, so the YAML checklist QC-YML-001 was not run; the files parse (actionlint reads them) and use 2-space indentation. |
| 2 | The file is in `.gitea/workflows/` or `.github/workflows/` with the extension `.yml` or `.yaml`, and the same workflow does not exist in both directories | Pass | `sync-milestones.yml` is in `.gitea/workflows/` with the extension `.yml` and not in `.github/workflows/`. `publish-wiki.yml` was removed (see the verdict). |
| 3 | The file declares `name`, `on` and `jobs`; `on` lists explicit events and, where it matters, `branches` or `paths` | Pass | The file declares `name`, `on` and `jobs`; `on` lists `push` on `main` with `paths`, and `workflow_dispatch`. |
| 4 | A header comment states the purpose, the triggers, the inputs, the secrets it needs, what it changes outside the repository, and the decision or milestone it implements | Pass | The header states the purpose, triggers, secrets, what changes outside the repository and the installation steps (from the git-workflows file, with the installation date set); the decision is MIL-008 task 5. |
| 5 | Every job and step has a descriptive `name`, unique within its job | Pass | Every step has a descriptive name. |
| 6 | The file passes `actionlint` (or the project's workflow validation test) and the tool version is stated | Pass | `actionlint` 1.7.12 reports no finding (exit code 0). |
| 7 | Every job declares `permissions` explicitly with the least access that works (`contents: read` or none by default); write access only on the job that needs it | Pass | The job sets `contents: read`. |
| 8 | Every action used is pinned to a full commit SHA or an exact release tag, never to a branch; a moving major tag (`@v1`) is accepted only for an action published by the same organisation under a stated release policy | Pass | `actions/checkout@v4.2.2` is an exact release tag. |
| 9 | No secret is written in the file; a secret is read as `secrets.NAME`, passed to a step through `env:`, never placed on a command line or echoed | Pass | The file reads `secrets.TOKEN_FOR_GITEA_REPO` (checkout) and `secrets.TOKEN_FOR_GITEA_ISSUES` (publish) only; no secret value is in the repository. The checkout token reaches git through `GIT_CONFIG_*` environment variables, never a command line. |
| 10 | Untrusted text (`inputs.*`, event fields such as a title, branch name or label, step outputs derived from them) is never interpolated into a `run:` script; it is passed through `env:` and used as a quoted variable | Pass | No `run:` block interpolates `inputs.*` or event text; `DRY_RUN` is passed through `env:`. |
| 11 | A trigger that gives a run secrets or a write token on code from a fork or an untrusted branch (`pull_request_target`, `workflow_run`) does not check out or execute that code | Pass | The workflow does not use `pull_request_target` or `workflow_run`. |
| 12 | A workflow that changes state outside the repository (release, tag, publish, sync, deploy) is started by hand or by a protected branch, and a manual run defaults to a dry run with an explicit input to apply | Pass | It runs on a push to `main` or by hand; the manual run defaults to a dry run. |
| 13 | The token the workflow uses has only the scope the job needs, and where the host's built-in token is enough it is used instead of a personal token | Pending | The scope of both tokens is set by S01; the earlier dry run got HTTP 403 with the issues token on the framework repository, which is why the file uses the repository token for the checkout. |
| 14 | Every job sets `runs-on` to an explicit label and `timeout-minutes` | Pass | The job sets `runs-on: ubuntu-latest` and `timeout-minutes: 15`. |
| 15 | `concurrency` is set where two runs would conflict: a check cancels the older run (`cancel-in-progress: true`); a publishing job queues (`cancel-in-progress: false`) | Pass | `concurrency` is set with `cancel-in-progress: false`. |
| 16 | Triggers are filtered (`branches`, `paths`, `types`) so the workflow runs only for the changes it concerns | Pass | The triggers are filtered by `branches: [main]` and `paths`. |
| 17 | Tools and dependencies are installed at pinned versions; a version is a workflow input with a default or a value in one place | Pass | The workflow installs nothing itself; `curl` and `jq` are checked by the framework script. |
| 18 | A dependency cache is used where the install is slow enough to matter | N-A | No dependency is installed that a cache would speed up. |
| 19 | A failing step names the tool, the file and the reason in its log (annotation or `::error::` line) | Pending | Not verified: the log messages come from the framework script and the reusable workflow, which the stand-in did not run. |
| 20 | A `run:` block is within the limit on embedded program text of criterion 7 of [QC-YML-001]; a longer script is a file (`tools/`, or a shared repository fetched at a pinned ref) that the step calls with one command, and the workflow passes its settings through `env:` | Pass | Each `run:` block is one command; the logic is in `framework/scripts/ci-publish-milestones.sh`. |
| 21 | Logic used by more than one workflow or repository is a reusable workflow (`workflow_call`) or a composite action; each input has a `description`, a `type` and a `default` where one is sensible | Pass | The workflow calls one framework script; the input of `workflow_dispatch` has a description, type and default. |
| 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 | Pending | Not yet run with the new secrets: `TOKEN_FOR_GITEA_REPO` and `TOKEN_FOR_GITEA_ISSUES` do not exist yet, so the file is not verified end to end. |
| 23 | A reusable workflow states, in its header, how a caller pins it and the script it fetches, so the workflow and its script are the same release | N-A | The file is not a reusable workflow. |
| 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 | N-A | No static test of the workflows exists in this project; the checks are `actionlint` on request. |
## Overall Verdict
Go-with-conditions - the milestone workflow is the file that TirSystem/git-workflows provides (the framework 0.19.0 retired its own template) and passes `actionlint`. It checks out with `TOKEN_FOR_GITEA_REPO` and fetches the private framework over HTTPS. Mandatory criteria 1 (`yamllint` was not run) and 22 (feature checked on the instance) are Pending until S01 has created the two secrets. The review is not independent: the AI wrote and reviewed it as stand-in for S02, and S01 can challenge it in the end-of-run summary.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Create the organization secrets `TOKEN_FOR_GITEA_REPO` (read on repositories, including TirSystem/SQA-QC-Framework) and `TOKEN_FOR_GITEA_ISSUES` (issues and milestones), then run the workflow once by hand with dry_run on | S01 | before the next merge to main |
| Run `yamllint` on `.gitea/workflows/` | S01 | when convenient |
---
[MIL-008]: ../../milestones/mil-008-documentation.md
[QC-WF-001]: ../../../framework/qc/code/qc-workflow.md
[1f28129]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/049-snack-and-lift/commit/1f281294cca20462b0925c84889d33fd69329a5c
+1 -1
View File
@@ -44,7 +44,7 @@ Tracks backward and forward links between artifact instances so that the Busines
| Source and tests of [MIL-005] | Python source code | - | - | [MIL-005], [ADR-0002] | - | RC-019 (Go-with-conditions) | | Source and tests of [MIL-005] | Python source code | - | - | [MIL-005], [ADR-0002] | - | RC-019 (Go-with-conditions) |
| Source and tests of [MIL-006] | Python source code | - | - | [MIL-006], [ADR-0002] | - | RC-020 (Go-with-conditions) | | Source and tests of [MIL-006] | Python source code | - | - | [MIL-006], [ADR-0002] | - | RC-020 (Go-with-conditions) |
| Source and tests of [MIL-007] | Python source code | - | - | [MIL-007], [ADR-0002] | - | RC-021 (Go-with-conditions) | | Source and tests of [MIL-007] | Python source code | - | - | [MIL-007], [ADR-0002] | - | RC-021 (Go-with-conditions) |
| Workflows and wiki of [MIL-008] | Workflow files, wiki pages | - | - | [MIL-008] | - | RC-022, RC-027 (Go-with-conditions) | | Workflows and wiki of [MIL-008] | Workflow files, wiki pages | - | - | [MIL-008] | - | RC-022, RC-027, RC-029 (Go-with-conditions) |
## Concern Coverage ## Concern Coverage
+17 -9
View File
@@ -1,11 +1,19 @@
**English** **Snack and Lift bot**
- [Home](Home) · [Getting started](Getting-Started) · [Troubleshooting](Troubleshooting) - [Home](Home)
- [1](Step-1) · [2](Step-2) · [3](Step-3) · [4](Step-4) · [5](Step-5) · [6](Step-6) · [7](Step-7) · [8](Step-8) · [9](Step-9) - [Getting started](Getting-Started)
- [Step 1: Setup, Chrome profile and navigation](Step-1)
- [Step 2: Automated login](Step-2)
- [Step 3: Book the next Tuesday class](Step-3)
- [Step 4: Check if a class is already booked](Step-4)
- [Step 5: Counters and a summary](Step-5)
- [Step 6: Every Tuesday and Thursday class](Step-6)
- [Step 7: Verify on the My Bookings page](Step-7)
- [Step 8: Time travel quality assurance](Step-8)
- [Step 9: Resilience against network failures](Step-9)
- [Troubleshooting](Troubleshooting)
**Dansk** **Languages**
- [Forside](Home-da) · [Kom i gang](Getting-Started-da) · [Fejlfinding](Troubleshooting-da)
- [1](Step-1-da) · [2](Step-2-da) · [3](Step-3-da) · [4](Step-4-da) · [5](Step-5-da) · [6](Step-6-da) · [7](Step-7-da) · [8](Step-8-da) · [9](Step-9-da)
**Bahasa Melayu** - English: [Home](Home)
- [Utama](Home-ms) · [Mula menggunakan](Getting-Started-ms) · [Menyelesaikan masalah](Troubleshooting-ms) - Dansk: [Hjem](Home-da)
- [1](Step-1-ms) · [2](Step-2-ms) · [3](Step-3-ms) · [4](Step-4-ms) · [5](Step-5-ms) · [6](Step-6-ms) · [7](Step-7-ms) · [8](Step-8-ms) · [9](Step-9-ms) - Bahasa Melayu: [Utama](Home-ms)