Add planning baseline: BC, SA, PP and two gateways

Create the Business Case, Stakeholder Analysis (S01 course participant,
S02 Udemy coursists, S03 GitHub viewers), Project Plan and the milestone
documents MIL-001 (project setup, 6 tasks) and MIL-002 (game
implementation, 8 tasks) for the console Blackjack game.

Register PP and MIL in the artifact registry, set the PO language to en,
and link the synced Gitea milestones in the Gateway Schedule.

Refs #1
Refs #2
Refs #3
Refs #4
Refs #5
Refs #6
Refs #7
Refs #8
Refs #9
Refs #10
Refs #11
Refs #12
Refs #13
Refs #14
This commit is contained in:
2026-10-04 21:38:09 +08:00
parent 52febca25e
commit 1d35410b8d
123 changed files with 5978 additions and 0 deletions
@@ -0,0 +1,94 @@
---
name: coding-conventions
description: Programming conventions for writing or reviewing source code — naming, layout, formatting and language idioms — for Python, C, C++, C# and Shell (bash). Use when writing, editing, reviewing or refactoring code in one of those languages, choosing names, setting up a formatter/linter config, or adding conventions for another language. Holds the rules shared by every language and points to a per-language sub-skill.
---
# Coding Conventions
One skill for all languages. This file holds what is true in every language;
everything specific to one language is in a sub-skill that is read only when
that language is in hand:
| Language | Sub-skill | QC checklist |
| --- | --- | --- |
| Python | `references/python.md` | `framework/qc/qc-programming-python.md` (`QC-PY-001`) |
| C | `references/c.md` | `framework/qc/qc-programming-c.md` (`QC-CL-001`) |
| C++ | `references/cpp.md` | `framework/qc/qc-programming-cpp.md` (`QC-CPP-001`) |
| C# | `references/csharp.md` | `framework/qc/qc-programming-csharp.md` (`QC-CS-001`) |
| Shell (bash) | `references/shell.md` | `framework/qc/qc-programming-shell.md` (`QC-SH-001`) |
Read the sub-skill for the language you are working in, then write or review
the code. To review, use the language's QC checklist and record the result as
an `RC-*` (see the `artifact` skill).
## Precondition: a planned task
Before writing or editing code under `src/` or `tests/`, name the task row
(`MIL-NNN`, task N) or the synced issue, and the use case or design artifact
it implements, or say it is a plain technical task. If you cannot, refuse and
use the `project-planning` skill instead (rule: `framework/process/plan-first-gate.md`).
Reviewing code needs no task.
## Rules for every language
1. **The existing code wins.** In a file or project that already has a
convention, follow it, even if the sub-skill says otherwise. Do not mix
styles within a file; do not reformat code you are not changing.
2. **Naming follows the language, not your habits.** Casing differs per
language (table below). Never carry one language's casing into another.
3. **A name says what, not how.** Name by purpose in the domain's language
(IT Professional English, as the registry's `Languages` section says), not by
type or implementation (`customer_list`, not `arr2`).
4. **Length follows scope.** Short names (`i`, `n`) only for tiny scopes;
wider scope, longer name. No abbreviations except ones the whole domain
uses (`id`, `url`, `http`).
5. **Booleans read as a question:** `is_valid`, `has_items`, `can_retry`
(cased per language). No negated names (`is_not_ready`).
6. **Functions are verbs, types are nouns.** A function that returns a value
without side effects may be a noun (`total`, `Total`) where the language
community does so.
7. **Formatting is done by the formatter,** not by hand and not in review
comments. Each sub-skill names the formatter and linter; commit its
configuration file with the code.
8. **Comments say why,** never what the code already says. Public APIs get
the language's documentation-comment form.
9. **No dead or commented-out code, no unexplained magic numbers.** Name the
constant.
10. **Errors are handled or propagated, never swallowed.** Each sub-skill says
how its language does this.
## Casing at a glance
| Element | Python | C | C++ | C# |
| --- | --- | --- | --- | --- |
| Type / class | `PascalCase` | `snake_case_t` | `PascalCase` | `PascalCase` |
| Function / method | `snake_case` | `snake_case` | `snake_case` | `PascalCase` |
| Variable / parameter | `snake_case` | `snake_case` | `snake_case` | `camelCase` |
| Constant | `UPPER_SNAKE` | `UPPER_SNAKE` | `kPascalCase` | `PascalCase` |
| Private member | `_leading` | file-scope `static` | `trailing_` | `_camelCase` |
| Namespace / module | `snake_case` module | `mod_` prefix | `snake_case` | `PascalCase` |
| File | `snake_case.py` | `snake_case.c/.h` | `snake_case.cpp/.h` | `PascalCase.cs` |
The table is a summary; the sub-skill is authoritative. Shell (bash) is not in
the table: functions and variables are `snake_case`, constants and environment
variables `UPPER_SNAKE`, files `kebab-case.sh`.
## Governance boundary
Conventions are **defined and governed** here but **not enforced** by this
framework: writing a linter or CI job that enforces them is outside the
framework's scope. The formatter and linter names in each sub-skill are the
recommended tools, not a pipeline. A new or changed convention follows the
process in the project's Coding Standards Governance document and is recorded
in `framework/CHANGELOG.md`. No project data belongs in this skill.
## Adding a language
1. Add `references/<language>.md` with these sections: Standard base, Naming,
Formatting, Language rules, Errors, Tests, Tooling.
2. Add `framework/qc/qc-<language>.md` (`QC-<SHORT>-001`) using the `QC` type
of the `artifact` skill, tagging every criterion with an ISO/IEC 25010:2023
characteristic and a Level.
3. Add the row to the table above, the casing table, and a row for the
language in `framework/registry/artifact-catalog.md`; note it in
`framework/CHANGELOG.md`; run `bash framework/scripts/install-skills.sh`.
@@ -0,0 +1,71 @@
# C conventions
C has no single official style guide. This sub-skill fixes one consistent
style built on common practice; MISRA C and SEI CERT C are the references for
safety-critical or security-sensitive code.
## Standard base
ISO C11 or C17 as set by the project's compiler flag (`-std=c11`). Compile
with warnings on (`-Wall -Wextra -Wpedantic`); treat warnings as errors in
release builds.
## Naming
| Element | Convention | Example |
| --- | --- | --- |
| Function, variable, parameter | `snake_case` | `parse_header`, `byte_count` |
| Public symbol | module prefix plus `snake_case` (C has no namespaces) | `stay_reader_open()` |
| File-local function / variable | `static`, no prefix needed | `static int next_token(...)` |
| Type (`struct`, `enum`, `typedef`) | `snake_case_t`, module prefix for public types | `stay_reader_t` |
| Enum constant, macro, constant | `UPPER_SNAKE` with the module prefix | `STAY_READER_OK` |
| Header / source file | `snake_case.h` / `snake_case.c`, same base name | `stay_reader.h` |
| Header guard | `MODULE_FILE_H` (or `#pragma once` if the project allows) | `STAY_READER_H` |
- Do not use reserved identifiers: a leading underscore followed by an
uppercase letter, any double underscore, or a leading underscore at file
scope.
- POSIX reserves the `_t` suffix; keep the module prefix on public types so
they cannot collide.
- Macros are a last resort; prefer `static inline` functions and `enum` or
`const` values.
## Formatting
- One formatter configuration for the project (`clang-format`); 4 spaces (or
the project's setting), no tabs mixed in.
- Braces on every `if`, `else`, `for`, `while`, even for one statement.
- One declaration per line; declare variables at first use, initialised.
- Headers: include what you use, only what you use; public headers are
self-contained; add `extern "C"` guards when C++ code consumes them.
## Language rules
- Check every return value that can fail; check every allocation.
- Every `malloc`/`open`/`lock` has one clear owner and one matching release;
release on every exit path (single exit or `goto cleanup`).
- Use `size_t` for sizes and indices, fixed-width types (`<stdint.h>`) for
data layout, `const` wherever data is not modified, `restrict` only with
care.
- Bounds are explicit: pass a length with every buffer; use `snprintf`,
never `sprintf`, `strcpy` or `gets`.
- No undefined behaviour: no signed overflow, no out-of-range shifts, no use
after free, no uninitialised reads.
- Avoid global mutable state; if unavoidable, `static` and documented.
## Errors
Return a status code (an `enum`) or `-1`/`NULL` plus an error out-parameter;
document which in the header. Never ignore a failing call. Read `errno`
immediately after the failing call.
## Tests
A unit-test framework (for example Unity or CMocka); run under sanitizers
(`-fsanitize=address,undefined`) in at least one build.
## Tooling
`clang-format`, `clang-tidy` or `cppcheck`, compiler warnings, sanitizers.
Review with `QC-CL-001`.
@@ -0,0 +1,70 @@
# C++ conventions
## Standard base
ISO C++17 or later as set by the project (`-std=c++20`); the C++ Core
Guidelines are the rule source. C++ has no official naming style, so the
style below is used unless the project already has another (rule 1 of the
overall skill).
## Naming
| Element | Convention | Example |
| --- | --- | --- |
| Class, struct, enum, concept, type alias | `PascalCase` | `StayReader`, `Stay` |
| Function, method, variable, parameter | `snake_case` | `read_stays()`, `byte_count` |
| Data member (private) | `snake_case` with trailing underscore | `buffer_` |
| Struct public data member | `snake_case`, no underscore | `check_in` |
| Constant (`constexpr`, namespace-scope `const`) | `kPascalCase` | `kMaxRetries` |
| Enum class value | `PascalCase` | `Status::NotFound` |
| Namespace | short `snake_case`; no `using namespace` in headers | `billing` |
| Template parameter | `PascalCase` | `typename ItemT` |
| Macro | `UPPER_SNAKE` with project prefix; avoid macros | `BILLING_ASSERT` |
| Header / source file | `snake_case.h` / `snake_case.cpp`, same base name | `stay_reader.h` |
| Header guard | `#pragma once` (or `PROJECT_PATH_FILE_H`) | |
## Formatting
- `clang-format` with one checked-in config; 4 spaces (or the project's
setting); braces on every control-flow body.
- Include order: matching header, project headers, third party, standard
library; each group sorted.
- One declaration per line; declare at first use, initialise with `{}`.
## Language rules
- **Ownership:** RAII everywhere. No owning raw pointers, no naked
`new`/`delete`; use `std::unique_ptr` by default, `std::shared_ptr` only for
real shared ownership, created with `std::make_unique`/`make_shared`.
- Follow the rule of zero; if you define one of destructor, copy or move,
define or delete all five.
- Pass by `const&` (large, read-only) or by value (small or sink); use
`std::span` and `std::string_view` for non-owning views, `std::optional` for
"maybe", `std::variant` for alternatives.
- `const` and `constexpr` by default; mark single-argument constructors
`explicit`; mark `override`/`final`; `[[nodiscard]]` on results that must
be used.
- Prefer algorithms and range-for over hand-written loops; `enum class` over
plain `enum`; `nullptr` over `NULL` or `0`; `using` over `typedef`.
- No C-style casts; use `static_cast` and friends. No mutable global state.
- Headers are self-contained and contain declarations, templates and
`inline` definitions only.
## Errors
Use exceptions for exceptional failures, or `std::expected` and error codes
where the project forbids exceptions; one choice per project. Destructors
never throw. Catch by `const&`; never `catch (...)` without rethrowing or
logging.
## Tests
GoogleTest, Catch2 or doctest; run under sanitizers (`address`, `undefined`)
in at least one build.
## Tooling
`clang-format`, `clang-tidy` with the Core Guidelines checks, compiler
warnings (`-Wall -Wextra -Wpedantic`), sanitizers.
Review with `QC-CPP-001`.
@@ -0,0 +1,72 @@
# C# conventions
## Standard base
Microsoft's C# coding conventions and .NET Framework Design Guidelines, with
the analyzers that ship in the SDK. Target the language version of the
project's `LangVersion` / target framework.
## Naming
| Element | Convention | Example |
| --- | --- | --- |
| Namespace | `PascalCase`, matches folder path | `Billing.Stays` |
| Class, struct, record, enum, delegate | `PascalCase` (nouns) | `StayReader` |
| Interface | `I` + `PascalCase` | `IStayReader` |
| Method, property, event, public field | `PascalCase` | `ReadStays()`, `CheckIn` |
| Constant, `static readonly` | `PascalCase` | `MaxRetries` |
| Enum value | `PascalCase`; `[Flags]` enums are plural | `Status.NotFound` |
| Parameter, local variable | `camelCase` | `byteCount` |
| Private / internal field | `_camelCase` | `_buffer` |
| Generic type parameter | `T` or `T` + `PascalCase` | `T`, `TKey` |
| Async method | ends in `Async` | `ReadStaysAsync()` |
| Exception, attribute | end in `Exception` / `Attribute` | `InvalidDateException` |
| Boolean | `Is`, `Has`, `Can` prefix | `IsActive` |
| File | the type's name, one top-level type per file | `StayReader.cs` |
- Two-letter acronyms are upper case (`IO`); longer ones are `PascalCase`
(`Xml`, `Http`).
## Formatting
- `.editorconfig` checked in; `dotnet format` applies it. 4 spaces, Allman
braces, braces on every control-flow body.
- File-scoped namespaces (`namespace X;`); `using` directives outside the
namespace, `System` first.
- `var` when the type is obvious from the right-hand side, explicit type
otherwise.
## Language rules
- Enable nullable reference types (`<Nullable>enable</Nullable>`) and treat
nullable warnings as errors; do not suppress with `!` without a comment.
- `IDisposable` owners use `using`; implement the dispose pattern only when
needed.
- `async`/`await` all the way; no `.Result` or `.Wait()`; no `async void`
except event handlers; pass `CancellationToken` through public async APIs.
- Prefer properties over public fields, `readonly` and `init` for
immutability, `record` for value-like data, pattern matching and switch
expressions over long `if` chains.
- LINQ for queries, loops for side effects; do not enumerate a sequence twice.
- String interpolation over concatenation; `StringBuilder` in loops;
`DateTimeOffset` over `DateTime` for points in time; `decimal` for money.
- XML documentation comments (`///`) on public types and members.
## Errors
Throw specific exceptions (`ArgumentNullException`, custom types); validate
arguments at the public boundary (`ArgumentNullException.ThrowIfNull`). Catch
the narrowest type; `throw;` (not `throw ex;`) to rethrow. Never an empty
`catch`.
## Tests
xUnit, NUnit or MSTest; names like `Method_Condition_Expected`; one behaviour
per test; no dependence on order, time or the network.
## Tooling
`dotnet format`, the .NET analyzers (`AnalysisLevel`, `EnforceCodeStyleInBuild`)
and optionally StyleCop.Analyzers, configured in `.editorconfig`.
Review with `QC-CS-001`.
@@ -0,0 +1,66 @@
# Python conventions
## Standard base
PEP 8 (style), PEP 257 (docstrings), PEP 484 and later (type hints). Target
the Python version declared in `pyproject.toml`.
## Naming
| Element | Convention | Example |
| --- | --- | --- |
| Package / module | short `snake_case` | `billing`, `stay_reader.py` |
| Class, exception | `PascalCase`; exceptions end in `Error` | `StayReader`, `InvalidDateError` |
| Function, method, variable, parameter | `snake_case` | `total_price`, `read_stays()` |
| Constant (module level) | `UPPER_SNAKE` | `MAX_RETRIES` |
| Internal (not public API) | one leading underscore | `_parse_row` |
| Type variable | short `PascalCase`; `_co` / `_contra` for variance | `T`, `KeyT`, `ItemT_co` |
| Boolean | `is_`, `has_`, `can_` prefix | `is_active` |
| Test file / function | `test_<module>.py` / `test_<behavior>_<condition>` | `test_total_when_empty` |
- Avoid name mangling (`__name`) unless you need it to prevent a subclass clash.
- Never use `l`, `O` or `I` as single-letter names.
- Do not shadow builtins (`list`, `id`, `type`); add a trailing underscore
(`type_`) only as a last resort.
## Formatting
- 4 spaces, no tabs. Maximum line length set once in the formatter config
(88 with `ruff format`; 79 if the project follows PEP 8 strictly).
- Imports at the top, grouped standard library / third party / local, one
blank line between groups, no wildcard imports.
- Double quotes for strings unless the formatter says otherwise.
- Trailing commas in multi-line literals and calls.
## Language rules
- Annotate every function signature (parameters and return, `-> None` too).
Modern syntax: `X | None`, `list[str]`. Avoid `Any` without a comment.
- `pathlib` over `os.path`; f-strings over `%` or `.format`; `enum` over
magic strings; `dataclass` (frozen where possible) over ad-hoc dicts.
- No mutable default arguments; no bare `except:`; no `print` for logging
(use `logging`).
- Use context managers (`with`) for files, locks and connections.
- Prefer comprehensions over `map`/`filter` with lambdas; keep them simple.
- Docstrings (PEP 257) on public modules, classes and functions; say what,
not how.
## Errors
Raise specific exceptions; catch the narrowest type; re-raise with
`raise ... from err` to keep the cause. Do not use exceptions for normal
control flow.
## Tests
`pytest`; one behaviour per test; `tmp_path` for files; fakes over mocks where
a simple fake is possible; tests do not depend on order or on the network.
## Tooling
`ruff` (lint and format) and `mypy --strict` (types), configured in
`pyproject.toml`. Architecture rules (layers, ports, dataframes) are in
`.agents/rules/python.md` and the `python-developer` agent; this sub-skill
covers naming and style only.
Review with `QC-PY-001`.
@@ -0,0 +1,62 @@
# Shell conventions (bash)
## Standard base
Bash 4 or later, POSIX `test` semantics through `[[ ]]`. Start every script
with `#!/usr/bin/env bash` and `set -euo pipefail`. State the bash version and
the external tools it needs in the header comment.
## Naming
| Element | Convention | Example |
| --- | --- | --- |
| Script file | `kebab-case.sh`, executable | `check-plan.sh`, `new-artifact.sh` |
| Function | `snake_case`, a verb | `read_registry`, `die` |
| Local variable, parameter | `snake_case`, declared with `local` | `msgfile`, `changed` |
| Constant, environment variable | `UPPER_SNAKE` | `PLAN_GATE`, `PROJECT_ROOT` |
| Boolean | `is_` / `has_` prefix, value `0` or `1` | `is_enabled=1` |
- Name a script and its functions by what they do, not how.
- Do not shadow a command with a function of the same name.
## Formatting
- 2 spaces, no tabs. One command per line; `then` and `do` on the same line as
`if` and `for`. Keep lines near 80 characters; break long pipelines at `|`.
- Format with `shfmt -i 2 -ci`; lint with `shellcheck`. Commit the project's
`.editorconfig` or `.shellcheckrc` with the code.
## Language rules
- **Quote every expansion** (`"$var"`, `"${arr[@]}"`); use arrays, not
space-separated strings, for lists. Use `[[ ]]`, not `[ ]`, and `$(...)`,
not backticks.
- Declare function variables `local`; no globals except constants.
- Parse options with `case` and `shift`, check required arguments with
`"${1:?usage: ...}"`, and print a usage line on bad input.
- Read input with `read -r`; iterate files with globs or `find -print0`, never
by parsing `ls`.
- Use `mktemp` for temporary files and remove them with `trap ... EXIT`; never
a fixed `/tmp` name.
## Errors and exit codes
- Errors go to standard error, start with `error:`, say what is wrong and what
to do, and end the script with a non-zero exit code (`die` helper).
- `0` is success, `1` a failed check or bad input, `2` a usage error; document
any other code in the header.
- Never swallow a failure with `|| true` without a comment that says why.
## Safety
- A script that changes state outside its own directory defaults to a dry run
or asks for an explicit flag (`--apply`, `--force`); say so in the header.
- Never echo a token or password, put one on a command line, or commit one;
read secrets from the environment or a gitignored file.
- Do not `eval` input; do not build a command from unvalidated text.
## Tools
Formatter `shfmt`, linter `shellcheck`, syntax check `bash -n`. These are the
recommended tools, not a pipeline: enforcing them in CI is outside this
framework's scope.