From b267f21a989507974c65f05f23f5b8f412f226c5 Mon Sep 17 00:00:00 2001 From: Wes Dean Date: Wed, 16 Sep 2026 01:24:42 -0400 Subject: [PATCH] docs: adopt coding standards v1.0.9 --- .codingstandardrc | 4 + AGENTS.md | 9 + README.md | 9 + ...ate-Rather-Than-Installation-Procedures.md | 2 +- ...Package-Managers-as-the-Source-of-Truth.md | 2 +- ...e-the-Bootstrap-Engine-from-User-Intent.md | 2 +- ...-Experience-Around-Progressive-Adoption.md | 2 +- ...rface-While-Allowing-Internal-Evolution.md | 2 +- ...able-and-Reviewable-Bootstrap-Execution.md | 2 +- ...-Human-Centered-Package-Manifest-Format.md | 2 +- ...ap-Engine-as-a-Single-Executable-Script.md | 2 +- ...tion-Artifact-from-Modular-Source-Files.md | 2 +- ...lease-Artifacts-Through-GitHub-Releases.md | 2 +- ...he-Local-and-CI-Orchestration-Interface.md | 2 +- ...ely-and-Avoid-Surprising-System-Changes.md | 2 +- ...ifest-Parsing-from-Package-Installation.md | 2 +- ...ning-Phase-Before-Making-System-Changes.md | 2 +- ...n-and-Explain-Modes-for-Planned-Changes.md | 2 +- ...e-Operations-to-Native-Package-Managers.md | 2 +- ...DR-018-Define-a-Stable-Manifest-Grammar.md | 2 +- ...ine-Stable-Version-Constraint-Semantics.md | 2 +- ...-020-Provide-Human-Centered-Diagnostics.md | 2 +- ...ne-Around-Well-Defined-Responsibilities.md | 2 +- ...fine-a-Stable-Package-Backend-Interface.md | 2 +- ...t-Configuration-Over-Implicit-Discovery.md | 2 +- ...ble-and-Explicit-Command-Line-Interface.md | 2 +- ...gging-with-Progressive-Levels-of-Detail.md | 2 +- ...26-Define-a-Stable-Exit-Code-Philosophy.md | 2 +- ...-Establish-Trust-Through-Inspectability.md | 2 +- ...8-Favor-the-Principle-of-Least-Surprise.md | 2 +- ...re-Reproducible-and-Verifiable-Releases.md | 2 +- ...R-030-Preserve-Stable-Public-Interfaces.md | 2 +- ...Versioning-and-Deliberate-Compatibility.md | 2 +- ...3-Prefer-Composition-Over-Special-Cases.md | 2 +- doc/adr/ADR-034-Keep-the-Core-Engine-Small.md | 2 +- doc/adr/ADR-035-Prefer-Data-Over-Code.md | 2 +- ...6-Make-Architectural-Decisions-Explicit.md | 2 +- ...tablish-a-Deliberate-Deprecation-Policy.md | 2 +- ...duce-Experimental-Features-Deliberately.md | 2 +- ...ble-Behavior-Rather-Than-Implementation.md | 2 +- .../ADR-040-Prefer-Deterministic-Behavior.md | 2 +- ...at-Documentation-as-Part-of-the-Product.md | 2 +- ...042-Minimize-the-Trusted-Computing-Base.md | 2 +- ...le-Concepts-Over-Clever-Implementations.md | 2 +- ...R-044-Optimize-for-the-Next-Contributor.md | 2 +- ...entation-Driven-Test-Second-Development.md | 2 +- ...reflight-All-Manifests-Before-Execution.md | 2 +- .../ADR-056-adopt-shared-coding-standards.md | 158 +++ doc/adr/templates/template.md | 19 +- doc/decisions.md | 125 ++- doc/standards/awk/documentation-standard.md | 916 ++++++++++++++++++ doc/standards/bash/documentation-standard.md | 489 ++++++++++ .../examples/awk/documentation/example.awk | 129 +++ .../examples/bash/documentation/example.bash | 118 +++ .../examples/general/clean-coding/bash.md | 352 +++++++ .../javascript/documentation/example.js | 29 + .../examples/php/documentation/example.php | 179 ++++ .../examples/python/documentation/example.py | 142 +++ .../general/clean-architecture-standard.md | 685 +++++++++++++ .../general/clean-coding-standard.md | 373 +++++++ .../conventional-commit-release-governance.md | 324 +++++++ .../development-workflow-governance.md | 547 +++++++++++ .../javascript/documentation-standard.md | 480 +++++++++ doc/standards/php/documentation-standard.md | 526 ++++++++++ .../python/documentation-standard.md | 858 ++++++++++++++++ 65 files changed, 6457 insertions(+), 102 deletions(-) create mode 100644 .codingstandardrc create mode 100644 doc/adr/ADR-056-adopt-shared-coding-standards.md create mode 100644 doc/standards/awk/documentation-standard.md create mode 100644 doc/standards/bash/documentation-standard.md create mode 100644 doc/standards/examples/awk/documentation/example.awk create mode 100644 doc/standards/examples/bash/documentation/example.bash create mode 100644 doc/standards/examples/general/clean-coding/bash.md create mode 100644 doc/standards/examples/javascript/documentation/example.js create mode 100644 doc/standards/examples/php/documentation/example.php create mode 100644 doc/standards/examples/python/documentation/example.py create mode 100644 doc/standards/general/clean-architecture-standard.md create mode 100644 doc/standards/general/clean-coding-standard.md create mode 100644 doc/standards/general/conventional-commit-release-governance.md create mode 100644 doc/standards/general/development-workflow-governance.md create mode 100644 doc/standards/javascript/documentation-standard.md create mode 100644 doc/standards/php/documentation-standard.md create mode 100644 doc/standards/python/documentation-standard.md diff --git a/.codingstandardrc b/.codingstandardrc new file mode 100644 index 0000000..9f7fea0 --- /dev/null +++ b/.codingstandardrc @@ -0,0 +1,4 @@ +source = "https://github.com/wesley-dean/coding_standards.git" +version = "coding_standards@v1.0.9" +sha256 = "86e91725f30dc5d91a3c7f7158e17d6a8538519b3be10709440e179027c37a03" +destination = "doc/standards" diff --git a/AGENTS.md b/AGENTS.md index ea69afd..f87ec3d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -280,3 +280,12 @@ to understand. Keep the bootstrap engine small, inspectable, well-documented, well-tested, reusable, and faithful to the project's ADRs. + +## Shared Coding Standards + +This repository adopts the complete pinned `coding_standards@v1.0.9` snapshot under `doc/standards/`; `.codingstandardrc` records its verified release digest. Applicable imported standards are governing requirements unless an accepted local ADR or explicit policy refines them. Presence does not imply applicability, examples remain illustrative, imported standards are not edited locally, and upgrades are reviewed repository changes rather than automatic synchronization. + +Authoritative shared documentation standards used here: + +- Bash: `doc/standards/bash/documentation-standard.md` + diff --git a/README.md b/README.md index 5571107..f373b22 100644 --- a/README.md +++ b/README.md @@ -390,3 +390,12 @@ are future work. ## License See [`LICENSE`](LICENSE) for license information. + +## Shared Coding Standards + +This repository adopts the complete pinned `coding_standards@v1.0.9` snapshot under `doc/standards/`; `.codingstandardrc` records its verified release digest. Applicable imported standards are governing requirements unless an accepted local ADR or explicit policy refines them. Presence does not imply applicability, examples remain illustrative, imported standards are not edited locally, and upgrades are reviewed repository changes rather than automatic synchronization. + +Authoritative shared documentation standards used here: + +- Bash: `doc/standards/bash/documentation-standard.md` + diff --git a/doc/adr/ADR-002-Describe-Desired-State-Rather-Than-Installation-Procedures.md b/doc/adr/ADR-002-Describe-Desired-State-Rather-Than-Installation-Procedures.md index a109976..bbae2a5 100644 --- a/doc/adr/ADR-002-Describe-Desired-State-Rather-Than-Installation-Procedures.md +++ b/doc/adr/ADR-002-Describe-Desired-State-Rather-Than-Installation-Procedures.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-003-Treat-Native-Package-Managers-as-the-Source-of-Truth.md b/doc/adr/ADR-003-Treat-Native-Package-Managers-as-the-Source-of-Truth.md index ea94ad8..690ab13 100644 --- a/doc/adr/ADR-003-Treat-Native-Package-Managers-as-the-Source-of-Truth.md +++ b/doc/adr/ADR-003-Treat-Native-Package-Managers-as-the-Source-of-Truth.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-004-Separate-the-Bootstrap-Engine-from-User-Intent.md b/doc/adr/ADR-004-Separate-the-Bootstrap-Engine-from-User-Intent.md index 1178dc7..23f0adf 100644 --- a/doc/adr/ADR-004-Separate-the-Bootstrap-Engine-from-User-Intent.md +++ b/doc/adr/ADR-004-Separate-the-Bootstrap-Engine-from-User-Intent.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-005-Design-the-Bootstrap-Experience-Around-Progressive-Adoption.md b/doc/adr/ADR-005-Design-the-Bootstrap-Experience-Around-Progressive-Adoption.md index 09d8b92..13f9512 100644 --- a/doc/adr/ADR-005-Design-the-Bootstrap-Experience-Around-Progressive-Adoption.md +++ b/doc/adr/ADR-005-Design-the-Bootstrap-Experience-Around-Progressive-Adoption.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-006-Preserve-a-Stable-Bootstrap-Interface-While-Allowing-Internal-Evolution.md b/doc/adr/ADR-006-Preserve-a-Stable-Bootstrap-Interface-While-Allowing-Internal-Evolution.md index 5a80a16..1fcc80f 100644 --- a/doc/adr/ADR-006-Preserve-a-Stable-Bootstrap-Interface-While-Allowing-Internal-Evolution.md +++ b/doc/adr/ADR-006-Preserve-a-Stable-Bootstrap-Interface-While-Allowing-Internal-Evolution.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-007-Prefer-Inspectable-and-Reviewable-Bootstrap-Execution.md b/doc/adr/ADR-007-Prefer-Inspectable-and-Reviewable-Bootstrap-Execution.md index 84a274a..bfffb4e 100644 --- a/doc/adr/ADR-007-Prefer-Inspectable-and-Reviewable-Bootstrap-Execution.md +++ b/doc/adr/ADR-007-Prefer-Inspectable-and-Reviewable-Bootstrap-Execution.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-008-Define-a-Human-Centered-Package-Manifest-Format.md b/doc/adr/ADR-008-Define-a-Human-Centered-Package-Manifest-Format.md index 4cb82f1..a271b8b 100644 --- a/doc/adr/ADR-008-Define-a-Human-Centered-Package-Manifest-Format.md +++ b/doc/adr/ADR-008-Define-a-Human-Centered-Package-Manifest-Format.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-009-Distribute-the-Bootstrap-Engine-as-a-Single-Executable-Script.md b/doc/adr/ADR-009-Distribute-the-Bootstrap-Engine-as-a-Single-Executable-Script.md index 0468fdb..596f688 100644 --- a/doc/adr/ADR-009-Distribute-the-Bootstrap-Engine-as-a-Single-Executable-Script.md +++ b/doc/adr/ADR-009-Distribute-the-Bootstrap-Engine-as-a-Single-Executable-Script.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-010-Build-the-Distribution-Artifact-from-Modular-Source-Files.md b/doc/adr/ADR-010-Build-the-Distribution-Artifact-from-Modular-Source-Files.md index 1ee4275..6b73d2f 100644 --- a/doc/adr/ADR-010-Build-the-Distribution-Artifact-from-Modular-Source-Files.md +++ b/doc/adr/ADR-010-Build-the-Distribution-Artifact-from-Modular-Source-Files.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-011-Publish-Release-Artifacts-Through-GitHub-Releases.md b/doc/adr/ADR-011-Publish-Release-Artifacts-Through-GitHub-Releases.md index 3b6b35b..67154f0 100644 --- a/doc/adr/ADR-011-Publish-Release-Artifacts-Through-GitHub-Releases.md +++ b/doc/adr/ADR-011-Publish-Release-Artifacts-Through-GitHub-Releases.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-012-Use-Make-as-the-Local-and-CI-Orchestration-Interface.md b/doc/adr/ADR-012-Use-Make-as-the-Local-and-CI-Orchestration-Interface.md index 13969af..53943bb 100644 --- a/doc/adr/ADR-012-Use-Make-as-the-Local-and-CI-Orchestration-Interface.md +++ b/doc/adr/ADR-012-Use-Make-as-the-Local-and-CI-Orchestration-Interface.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-013-Fail-Conservatively-and-Avoid-Surprising-System-Changes.md b/doc/adr/ADR-013-Fail-Conservatively-and-Avoid-Surprising-System-Changes.md index 61beb22..513754e 100644 --- a/doc/adr/ADR-013-Fail-Conservatively-and-Avoid-Surprising-System-Changes.md +++ b/doc/adr/ADR-013-Fail-Conservatively-and-Avoid-Surprising-System-Changes.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-014-Separate-Manifest-Parsing-from-Package-Installation.md b/doc/adr/ADR-014-Separate-Manifest-Parsing-from-Package-Installation.md index aa4c5f3..79863c5 100644 --- a/doc/adr/ADR-014-Separate-Manifest-Parsing-from-Package-Installation.md +++ b/doc/adr/ADR-014-Separate-Manifest-Parsing-from-Package-Installation.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-015-Perform-a-Planning-Phase-Before-Making-System-Changes.md b/doc/adr/ADR-015-Perform-a-Planning-Phase-Before-Making-System-Changes.md index e952e09..760c411 100644 --- a/doc/adr/ADR-015-Perform-a-Planning-Phase-Before-Making-System-Changes.md +++ b/doc/adr/ADR-015-Perform-a-Planning-Phase-Before-Making-System-Changes.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-016-Provide-Dry-Run-and-Explain-Modes-for-Planned-Changes.md b/doc/adr/ADR-016-Provide-Dry-Run-and-Explain-Modes-for-Planned-Changes.md index 562b3ca..9cfe48c 100644 --- a/doc/adr/ADR-016-Provide-Dry-Run-and-Explain-Modes-for-Planned-Changes.md +++ b/doc/adr/ADR-016-Provide-Dry-Run-and-Explain-Modes-for-Planned-Changes.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-017-Delegate-Package-Operations-to-Native-Package-Managers.md b/doc/adr/ADR-017-Delegate-Package-Operations-to-Native-Package-Managers.md index 7fcee8e..ac7fc16 100644 --- a/doc/adr/ADR-017-Delegate-Package-Operations-to-Native-Package-Managers.md +++ b/doc/adr/ADR-017-Delegate-Package-Operations-to-Native-Package-Managers.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-018-Define-a-Stable-Manifest-Grammar.md b/doc/adr/ADR-018-Define-a-Stable-Manifest-Grammar.md index ac4475a..2077a98 100644 --- a/doc/adr/ADR-018-Define-a-Stable-Manifest-Grammar.md +++ b/doc/adr/ADR-018-Define-a-Stable-Manifest-Grammar.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-019-Define-Stable-Version-Constraint-Semantics.md b/doc/adr/ADR-019-Define-Stable-Version-Constraint-Semantics.md index 16bf605..e19bb64 100644 --- a/doc/adr/ADR-019-Define-Stable-Version-Constraint-Semantics.md +++ b/doc/adr/ADR-019-Define-Stable-Version-Constraint-Semantics.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-020-Provide-Human-Centered-Diagnostics.md b/doc/adr/ADR-020-Provide-Human-Centered-Diagnostics.md index 5e0ad92..f589595 100644 --- a/doc/adr/ADR-020-Provide-Human-Centered-Diagnostics.md +++ b/doc/adr/ADR-020-Provide-Human-Centered-Diagnostics.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-021-Layer-the-Bootstrap-Engine-Around-Well-Defined-Responsibilities.md b/doc/adr/ADR-021-Layer-the-Bootstrap-Engine-Around-Well-Defined-Responsibilities.md index 409265c..64ad10c 100644 --- a/doc/adr/ADR-021-Layer-the-Bootstrap-Engine-Around-Well-Defined-Responsibilities.md +++ b/doc/adr/ADR-021-Layer-the-Bootstrap-Engine-Around-Well-Defined-Responsibilities.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-022-Define-a-Stable-Package-Backend-Interface.md b/doc/adr/ADR-022-Define-a-Stable-Package-Backend-Interface.md index 9d1df44..4a2618a 100644 --- a/doc/adr/ADR-022-Define-a-Stable-Package-Backend-Interface.md +++ b/doc/adr/ADR-022-Define-a-Stable-Package-Backend-Interface.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-023-Prefer-Explicit-Configuration-Over-Implicit-Discovery.md b/doc/adr/ADR-023-Prefer-Explicit-Configuration-Over-Implicit-Discovery.md index 56cd300..7c7a047 100644 --- a/doc/adr/ADR-023-Prefer-Explicit-Configuration-Over-Implicit-Discovery.md +++ b/doc/adr/ADR-023-Prefer-Explicit-Configuration-Over-Implicit-Discovery.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-024-Provide-a-Stable-and-Explicit-Command-Line-Interface.md b/doc/adr/ADR-024-Provide-a-Stable-and-Explicit-Command-Line-Interface.md index a2eba53..3116392 100644 --- a/doc/adr/ADR-024-Provide-a-Stable-and-Explicit-Command-Line-Interface.md +++ b/doc/adr/ADR-024-Provide-a-Stable-and-Explicit-Command-Line-Interface.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-025-Provide-Human-Centered-Logging-with-Progressive-Levels-of-Detail.md b/doc/adr/ADR-025-Provide-Human-Centered-Logging-with-Progressive-Levels-of-Detail.md index 6c2b50d..83fe6fa 100644 --- a/doc/adr/ADR-025-Provide-Human-Centered-Logging-with-Progressive-Levels-of-Detail.md +++ b/doc/adr/ADR-025-Provide-Human-Centered-Logging-with-Progressive-Levels-of-Detail.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-026-Define-a-Stable-Exit-Code-Philosophy.md b/doc/adr/ADR-026-Define-a-Stable-Exit-Code-Philosophy.md index baf7d54..2694730 100644 --- a/doc/adr/ADR-026-Define-a-Stable-Exit-Code-Philosophy.md +++ b/doc/adr/ADR-026-Define-a-Stable-Exit-Code-Philosophy.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-027-Establish-Trust-Through-Inspectability.md b/doc/adr/ADR-027-Establish-Trust-Through-Inspectability.md index be687ba..e97f07d 100644 --- a/doc/adr/ADR-027-Establish-Trust-Through-Inspectability.md +++ b/doc/adr/ADR-027-Establish-Trust-Through-Inspectability.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-028-Favor-the-Principle-of-Least-Surprise.md b/doc/adr/ADR-028-Favor-the-Principle-of-Least-Surprise.md index 8b40f9c..1a1f18a 100644 --- a/doc/adr/ADR-028-Favor-the-Principle-of-Least-Surprise.md +++ b/doc/adr/ADR-028-Favor-the-Principle-of-Least-Surprise.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-029-Ensure-Reproducible-and-Verifiable-Releases.md b/doc/adr/ADR-029-Ensure-Reproducible-and-Verifiable-Releases.md index b98252b..fec5e6c 100644 --- a/doc/adr/ADR-029-Ensure-Reproducible-and-Verifiable-Releases.md +++ b/doc/adr/ADR-029-Ensure-Reproducible-and-Verifiable-Releases.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-030-Preserve-Stable-Public-Interfaces.md b/doc/adr/ADR-030-Preserve-Stable-Public-Interfaces.md index 6336c3f..4b912f8 100644 --- a/doc/adr/ADR-030-Preserve-Stable-Public-Interfaces.md +++ b/doc/adr/ADR-030-Preserve-Stable-Public-Interfaces.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-031-Adopt-Semantic-Versioning-and-Deliberate-Compatibility.md b/doc/adr/ADR-031-Adopt-Semantic-Versioning-and-Deliberate-Compatibility.md index 1311c39..d15503d 100644 --- a/doc/adr/ADR-031-Adopt-Semantic-Versioning-and-Deliberate-Compatibility.md +++ b/doc/adr/ADR-031-Adopt-Semantic-Versioning-and-Deliberate-Compatibility.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-033-Prefer-Composition-Over-Special-Cases.md b/doc/adr/ADR-033-Prefer-Composition-Over-Special-Cases.md index 229d4f0..11185cf 100644 --- a/doc/adr/ADR-033-Prefer-Composition-Over-Special-Cases.md +++ b/doc/adr/ADR-033-Prefer-Composition-Over-Special-Cases.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-034-Keep-the-Core-Engine-Small.md b/doc/adr/ADR-034-Keep-the-Core-Engine-Small.md index 96b0628..2352260 100644 --- a/doc/adr/ADR-034-Keep-the-Core-Engine-Small.md +++ b/doc/adr/ADR-034-Keep-the-Core-Engine-Small.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-035-Prefer-Data-Over-Code.md b/doc/adr/ADR-035-Prefer-Data-Over-Code.md index e0cd364..2d77670 100644 --- a/doc/adr/ADR-035-Prefer-Data-Over-Code.md +++ b/doc/adr/ADR-035-Prefer-Data-Over-Code.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-036-Make-Architectural-Decisions-Explicit.md b/doc/adr/ADR-036-Make-Architectural-Decisions-Explicit.md index 1d81376..8aa9bd8 100644 --- a/doc/adr/ADR-036-Make-Architectural-Decisions-Explicit.md +++ b/doc/adr/ADR-036-Make-Architectural-Decisions-Explicit.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-037-Establish-a-Deliberate-Deprecation-Policy.md b/doc/adr/ADR-037-Establish-a-Deliberate-Deprecation-Policy.md index 3e42075..2889b1b 100644 --- a/doc/adr/ADR-037-Establish-a-Deliberate-Deprecation-Policy.md +++ b/doc/adr/ADR-037-Establish-a-Deliberate-Deprecation-Policy.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-038-Introduce-Experimental-Features-Deliberately.md b/doc/adr/ADR-038-Introduce-Experimental-Features-Deliberately.md index e3241b3..03ff103 100644 --- a/doc/adr/ADR-038-Introduce-Experimental-Features-Deliberately.md +++ b/doc/adr/ADR-038-Introduce-Experimental-Features-Deliberately.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-039-Test-Observable-Behavior-Rather-Than-Implementation.md b/doc/adr/ADR-039-Test-Observable-Behavior-Rather-Than-Implementation.md index 9a9b0e2..9d8445c 100644 --- a/doc/adr/ADR-039-Test-Observable-Behavior-Rather-Than-Implementation.md +++ b/doc/adr/ADR-039-Test-Observable-Behavior-Rather-Than-Implementation.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-040-Prefer-Deterministic-Behavior.md b/doc/adr/ADR-040-Prefer-Deterministic-Behavior.md index 2ef7d8d..2e65aac 100644 --- a/doc/adr/ADR-040-Prefer-Deterministic-Behavior.md +++ b/doc/adr/ADR-040-Prefer-Deterministic-Behavior.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-041-Treat-Documentation-as-Part-of-the-Product.md b/doc/adr/ADR-041-Treat-Documentation-as-Part-of-the-Product.md index e19b19e..175fd8f 100644 --- a/doc/adr/ADR-041-Treat-Documentation-as-Part-of-the-Product.md +++ b/doc/adr/ADR-041-Treat-Documentation-as-Part-of-the-Product.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-042-Minimize-the-Trusted-Computing-Base.md b/doc/adr/ADR-042-Minimize-the-Trusted-Computing-Base.md index 5240e35..4f30f34 100644 --- a/doc/adr/ADR-042-Minimize-the-Trusted-Computing-Base.md +++ b/doc/adr/ADR-042-Minimize-the-Trusted-Computing-Base.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-043-Favor-Stable-Concepts-Over-Clever-Implementations.md b/doc/adr/ADR-043-Favor-Stable-Concepts-Over-Clever-Implementations.md index ee3e7aa..a5ade01 100644 --- a/doc/adr/ADR-043-Favor-Stable-Concepts-Over-Clever-Implementations.md +++ b/doc/adr/ADR-043-Favor-Stable-Concepts-Over-Clever-Implementations.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-044-Optimize-for-the-Next-Contributor.md b/doc/adr/ADR-044-Optimize-for-the-Next-Contributor.md index 17d8f7b..949d202 100644 --- a/doc/adr/ADR-044-Optimize-for-the-Next-Contributor.md +++ b/doc/adr/ADR-044-Optimize-for-the-Next-Contributor.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-046-Adopt-Documentation-Driven-Test-Second-Development.md b/doc/adr/ADR-046-Adopt-Documentation-Driven-Test-Second-Development.md index ca781eb..fad285f 100644 --- a/doc/adr/ADR-046-Adopt-Documentation-Driven-Test-Second-Development.md +++ b/doc/adr/ADR-046-Adopt-Documentation-Driven-Test-Second-Development.md @@ -4,7 +4,7 @@ Date: 2026-07-04 ## Status -Proposed +Accepted ## Intent and Scope diff --git a/doc/adr/ADR-049-Preflight-All-Manifests-Before-Execution.md b/doc/adr/ADR-049-Preflight-All-Manifests-Before-Execution.md index f94a089..ce49d76 100644 --- a/doc/adr/ADR-049-Preflight-All-Manifests-Before-Execution.md +++ b/doc/adr/ADR-049-Preflight-All-Manifests-Before-Execution.md @@ -4,7 +4,7 @@ Date: 2026-07-11 ## Status -Proposed +Accepted ## Intent and Documentation Posture diff --git a/doc/adr/ADR-056-adopt-shared-coding-standards.md b/doc/adr/ADR-056-adopt-shared-coding-standards.md new file mode 100644 index 0000000..5eceefa --- /dev/null +++ b/doc/adr/ADR-056-adopt-shared-coding-standards.md @@ -0,0 +1,158 @@ +# ADR-056: Adopt Shared Coding Standards + +Date: 2026-09-15 + +## Status + +Accepted + +## Context + +`bootstrap` already has repository-specific governance in its README, agent +guidance, specifications where applicable, and Architecture Decision Records. +Related repositories also share reusable coding, documentation, architecture, +release, and development-workflow standards through +`wesley-dean/coding_standards`. + +Maintaining independent repository-local copies of reusable standards creates a +drift risk and makes it harder for contributors and automated agents to determine +which rule is current. Fetching standards dynamically during ordinary development +or CI would create the opposite problem: the effective governance could change +without a reviewed repository change and could become unavailable offline. + +The repository therefore needs a versioned, inspectable adoption model that keeps +shared standards locally available while preserving the authority of accepted +repository-specific decisions. + +## Conditions and Assumptions + +This decision is made with the following conditions and assumptions: + +- `wesley-dean/coding_standards` publishes immutable versioned release artifacts; +- `coding_standards@v1.0.9` is the release selected for this adoption; +- the published `coding_standards.tar.gz` archive has been verified against its + published checksum and expected SHA-256 digest before materialization; +- the complete release snapshot is the unit of adoption rather than a hand-picked + subset; +- accepted repository-specific ADRs, explicit security policy, compatibility + requirements, and documented public contracts remain higher-precedence local + governance when they intentionally refine a shared standard; and +- language-specific standards are applicable only when their subject matter is + relevant to maintained content in this repository. + +## Decision Drivers + +The decision prioritizes: + +- one reviewable source of reusable engineering standards across related projects; +- deterministic governance from an ordinary checkout, including offline review; +- explicit provenance for the exact adopted release; +- preservation of repository-specific architectural authority; +- elimination of duplicate live documentation-standard paths; +- visible, reviewable standards upgrades rather than silent synchronization; and +- clear guidance for both human contributors and automated coding agents. + +## Decision + +The repository SHALL commit the complete released `coding_standards@v1.0.9` +snapshot beneath `doc/standards/`. + +The project-root `.codingstandardrc` SHALL record: + +- source: `https://github.com/wesley-dean/coding_standards.git`; +- version: `coding_standards@v1.0.9`; +- archive SHA-256: + `86e91725f30dc5d91a3c7f7158e17d6a8538519b3be10709440e179027c37a03`; and +- managed destination: `doc/standards`. + +The release tag resolves to upstream commit +`22e42d2583cc98d4a7db8c48e1ab0c459f76946e`. + +Applicable imported standards are repository governance. Presence in the complete +snapshot does not itself make a standard applicable, and content beneath +`doc/standards/examples/` remains illustrative unless a governing standard +explicitly promotes it. + +Imported files SHALL NOT be edited locally. Shared changes belong upstream in +`wesley-dean/coding_standards`; repository-specific exceptions or refinements +belong in this repository's normal governance. + +A future standards upgrade SHALL replace the complete managed snapshot, update +`.codingstandardrc`, and be reviewed as an ordinary repository change. The +repository SHALL NOT add a permanent standards downloader, background updater, +Make synchronization target, dependency-manifest entry, or automatic standards +upgrade workflow as part of this adoption. + +## Alternatives Considered + +### Keep independent repository-local standards + +Rejected because independently maintained copies predictably drift and leave +contributors to infer which repository contains the canonical wording. This +approach also multiplies maintenance work when a shared rule changes. + +### Import only standards that appear applicable today + +Rejected because a partial snapshot weakens provenance, makes upgrades harder to +audit, and can silently omit a new cross-cutting standard introduced by the +selected release. Applicability is determined by subject matter and local +governance, not by deleting files from the released snapshot. + +### Fetch the latest standards dynamically + +Rejected because a moving network dependency would allow effective governance to +change without a repository diff, would reduce reproducibility, and would make +normal development dependent on upstream availability. + +### Install permanent synchronization tooling + +Rejected because the expected update frequency does not justify another maintained +repository mechanism. A standards upgrade should remain an intentional reviewable +maintenance event. + +## Tradeoffs and Consequences + +The repository gains a deterministic, locally inspectable standards library and a +clear provenance record. Humans and automated agents can read the same governing +material without network access, and shared-standard changes appear as ordinary +reviewable diffs. + +The repository accepts additional tracked documentation volume, including standards +for languages that may not currently apply. That is intentional: complete snapshot +provenance is preferred over minimizing file count. Contributors must still use +judgment about applicability and must follow higher-precedence accepted local ADRs +where an intentional refinement exists. + +Future shared-standard changes require a deliberate snapshot replacement and +`.codingstandardrc` update rather than an in-place local edit. + +## Expected Outcomes + +After adoption: + +- the exact shared standards release is discoverable from `.codingstandardrc`; +- the complete standards library is available beneath `doc/standards/`; +- current repository guidance directs contributors and agents to that managed tree; +- duplicate repository-local documentation standards no longer compete with the + shared documentation standards; and +- standards changes remain explicit pull-request review surfaces. + +## Compatibility and Migration + +This decision changes repository governance and maintained documentation only. It +does not intentionally change runtime behavior, public interfaces, supported input +or output formats, portability commitments, generated product artifacts, or +release semantics. + +Where a duplicate repository-local documentation-standard path existed, references +to that live path are migrated to the corresponding file beneath `doc/standards/`. +Historical ADR text remains historical evidence and is not rewritten merely to +make old decisions use the new path. + +## Relationships to Prior Decisions + +Existing accepted ADRs remain authoritative for `bootstrap` architecture, public +behavior, compatibility, security boundaries, build and release contracts, and +other repository-specific decisions. This ADR establishes a reusable +shared-standards governance layer beneath those decisions; it does not supersede +them merely because an imported standard discusses the same general subject. diff --git a/doc/adr/templates/template.md b/doc/adr/templates/template.md index f8050cd..62128d9 100644 --- a/doc/adr/templates/template.md +++ b/doc/adr/templates/template.md @@ -8,7 +8,11 @@ There are placeholders used in this template: - NUMBER: the ADR's number - TITLE: the title of the ADR - DATE: the date the ADR was drafted (YYYY-MM-DD format) -- STATUS: the status of the ADR (Accepted, Proposed, etc.) + +Every committed ADR uses `Accepted` as its status. For ADRs prepared in a pull +request, merging the pull request is generally understood to constitute +acceptance; supersession and similar historical relationships belong in the ADR +narrative rather than in alternate status values. Replace the placeholders when drafting the ADR before committing it. @@ -32,15 +36,14 @@ This is the date that the ADR was drafted written in YYYY-MM-DD format. ## Status -STATUS +Accepted ## Intent and Documentation Posture diff --git a/doc/decisions.md b/doc/decisions.md index 117475d..ae47de1 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -5,11 +5,20 @@ consequential engineering decisions recorded in `doc/adr/ADR*.md`. It does not replace the ADR corpus. When a summary is incomplete, ambiguous, or inconsistent with its source ADR, the source ADR is authoritative. -Each entry below reports the status recorded by its source ADR. A `Proposed` -entry is summarized because it is part of the repository's decision history; its -presence here does not promote it to `Accepted`. Where a later ADR explicitly -supersedes or refines part of an earlier decision, the summary notes that -relationship. +## Maintenance + +Every ADR in this repository uses `Accepted` as its status. Merging a pull +request that contains a new or materially changed ADR is generally understood to +accept that ADR; supersession, replacement, deprecation, and similar relationships +belong in the ADR narrative rather than in alternate status values. Each ADR +should have a generally three-to-five-sentence summary here with a direct +reference to the governing ADR. Adding or materially changing an ADR requires +reviewing and updating that summary in the same pull request, including earlier +summaries affected by a superseding or refining decision. + +Where a later ADR explicitly supersedes or refines part of an earlier decision, +the summary notes that relationship so the effective decision can be discovered +without rewriting the historical ADR. ## ADR-000: Capability Scope, Epistemic Honesty, and Separation of Concerns @@ -25,7 +34,7 @@ Source: [ADR-000](adr/ADR-000-capability-scope-and-epistemic-honesty.md) ## ADR-001: Use a Single Bash 5+ Script as the Bootstrap Entry Point -**Status:** Proposed +**Status:** Accepted Bootstrap proposes Bash 5+ as the universal first-run surface so a fresh system can begin becoming useful from one inspectable script with minimal prerequisites. @@ -37,7 +46,7 @@ Source: [ADR-001](adr/ADR-001-bash-tooling.md) ## ADR-002: Describe Desired State Rather Than Installation Procedures -**Status:** Proposed +**Status:** Accepted Configuration should describe what a system should become rather than embed the commands used to construct it. Procedural implementation belongs in the @@ -48,7 +57,7 @@ Source: [ADR-002](adr/ADR-002-Describe-Desired-State-Rather-Than-Installation-Pr ## ADR-003: Treat Native Package Managers as the Source of Truth -**Status:** Proposed +**Status:** Accepted Bootstrap should interpret package intent while leaving dependency resolution, version semantics, repository trust, package authenticity, and installation @@ -59,7 +68,7 @@ Source: [ADR-003](adr/ADR-003-Treat-Native-Package-Managers-as-the-Source-of-Tru ## ADR-004: Separate the Bootstrap Engine from User Intent -**Status:** Proposed +**Status:** Accepted Reusable Bootstrap behavior should remain separate from user- or organization-specific policy such as manifests, profiles, dotfiles, and host @@ -70,7 +79,7 @@ Source: [ADR-004](adr/ADR-004-Separate-the-Bootstrap-Engine-from-User-Intent.md) ## ADR-005: Design the Bootstrap Experience Around Progressive Adoption -**Status:** Proposed +**Status:** Accepted Bootstrap should provide useful value at the smallest level of adoption and make later capabilities additive rather than mandatory prerequisites. Users should @@ -81,7 +90,7 @@ Source: [ADR-005](adr/ADR-005-Design-the-Bootstrap-Experience-Around-Progressive ## ADR-006: Preserve a Stable Bootstrap Interface While Allowing Internal Evolution -**Status:** Proposed +**Status:** Accepted The command-line interface, manifest semantics, and user workflow should remain small and stable while internal implementations may evolve. Refactoring, @@ -92,7 +101,7 @@ Source: [ADR-006](adr/ADR-006-Preserve-a-Stable-Bootstrap-Interface-While-Allowi ## ADR-007: Prefer Inspectable and Reviewable Bootstrap Execution -**Status:** Proposed +**Status:** Accepted The preferred execution path should let users inspect Bootstrap before it runs, with `vet` and manual download-and-review workflows favored over blind remote @@ -103,7 +112,7 @@ Source: [ADR-007](adr/ADR-007-Prefer-Inspectable-and-Reviewable-Bootstrap-Execut ## ADR-008: Define a Human-Centered Package Manifest Format -**Status:** Proposed +**Status:** Accepted The package manifest should be plain UTF-8 text with one package requirement per logical line, comments and blank lines for readability, insignificant surrounding @@ -114,7 +123,7 @@ Source: [ADR-008](adr/ADR-008-Define-a-Human-Centered-Package-Manifest-Format.md ## ADR-009: Distribute the Bootstrap Engine as a Single Executable Artifact -**Status:** Proposed +**Status:** Accepted Bootstrap may be maintained as modular source, while users receive standalone executable Bash artifacts rather than the source tree. The original decision @@ -126,7 +135,7 @@ Source: [ADR-009](adr/ADR-009-Distribute-the-Bootstrap-Engine-as-a-Single-Execut ## ADR-010: Build the Distribution Artifact from Modular Source Files -**Status:** Proposed +**Status:** Accepted Maintained Bash source should be organized by responsibility and assembled by the build system into generated distribution output under `dist/`, which is not a @@ -138,7 +147,7 @@ Source: [ADR-010](adr/ADR-010-Build-the-Distribution-Artifact-from-Modular-Sourc ## ADR-011: Publish Release Artifacts Through GitHub Releases -**Status:** Proposed +**Status:** Accepted GitHub Releases should be the canonical publication mechanism for generated Bootstrap artifacts built from tagged, validated source, while `dist/` remains @@ -149,7 +158,7 @@ Source: [ADR-011](adr/ADR-011-Publish-Release-Artifacts-Through-GitHub-Releases. ## ADR-012: Use Make as the Local and CI Orchestration Interface -**Status:** Proposed +**Status:** Accepted Make should provide the canonical project interface for recurring development, validation, testing, build, and release-preparation operations. CI workflows @@ -160,7 +169,7 @@ Source: [ADR-012](adr/ADR-012-Use-Make-as-the-Local-and-CI-Orchestration-Interfa ## ADR-013: Fail Conservatively and Avoid Surprising System Changes -**Status:** Proposed +**Status:** Accepted Bootstrap should stop with useful diagnostics when user intent is malformed, ambiguous, or unsupported rather than guess. Package removals must not occur @@ -171,7 +180,7 @@ Source: [ADR-013](adr/ADR-013-Fail-Conservatively-and-Avoid-Surprising-System-Ch ## ADR-014: Separate Manifest Parsing from Package Installation -**Status:** Proposed +**Status:** Accepted Bootstrap should completely parse and validate manifests into an internal representation before package installation begins. Installation consumes that @@ -183,7 +192,7 @@ Source: [ADR-014](adr/ADR-014-Separate-Manifest-Parsing-from-Package-Installatio ## ADR-015: Perform a Planning Phase Before Making System Changes -**Status:** Proposed +**Status:** Accepted After parsing, Bootstrap should construct a complete execution plan describing the intended operation for each request before making system modifications. Planning @@ -194,7 +203,7 @@ Source: [ADR-015](adr/ADR-015-Perform-a-Planning-Phase-Before-Making-System-Chan ## ADR-016: Provide Dry-Run and Explain Modes for Planned Changes -**Status:** Proposed +**Status:** Accepted Bootstrap should provide non-mutating dry-run behavior that performs parsing, validation, package-manager queries, and planning without changing the system. @@ -205,7 +214,7 @@ Source: [ADR-016](adr/ADR-016-Provide-Dry-Run-and-Explain-Modes-for-Planned-Chan ## ADR-017: Delegate Package Operations to Native Package Managers -**Status:** Proposed +**Status:** Accepted Package discovery, dependency resolution, version comparison, and installation should use native package-manager facilities instead of custom Bootstrap @@ -217,7 +226,7 @@ Source: [ADR-017](adr/ADR-017-Delegate-Package-Operations-to-Native-Package-Mana ## ADR-018: Define a Stable Manifest Grammar -**Status:** Proposed +**Status:** Accepted The manifest language should remain intentionally minimal: blank lines, comments, one package requirement per logical line, and optional version constraints. @@ -228,7 +237,7 @@ Source: [ADR-018](adr/ADR-018-Define-a-Stable-Manifest-Grammar.md) ## ADR-019: Define Stable Version Constraint Semantics -**Status:** Proposed +**Status:** Accepted The initial manifest grammar proposes package-only requirements plus `=`, `==`, `>`, and `>=` constraints, with `=` and `==` treated as equivalent exact-version @@ -240,7 +249,7 @@ Source: [ADR-019](adr/ADR-019-Define-Stable-Version-Constraint-Semantics.md) ## ADR-020: Provide Human-Centered Diagnostics -**Status:** Proposed +**Status:** Accepted Diagnostics should be written for humans first and, where practical, explain what happened, where it happened, why Bootstrap stopped, and what the user can do next. @@ -251,7 +260,7 @@ Source: [ADR-020](adr/ADR-020-Provide-Human-Centered-Diagnostics.md) ## ADR-021: Layer the Bootstrap Engine Around Well-Defined Responsibilities -**Status:** Proposed +**Status:** Accepted Bootstrap should be organized as a pipeline of configuration loading, manifest parsing, validation, planning, backend execution, and reporting/diagnostics. @@ -262,7 +271,7 @@ Source: [ADR-021](adr/ADR-021-Layer-the-Bootstrap-Engine-Around-Well-Defined-Res ## ADR-022: Define a Stable Package Backend Interface -**Status:** Proposed +**Status:** Accepted Operating-system-specific package behavior should be isolated behind a small backend interface that exposes capabilities without leaking native command syntax @@ -274,7 +283,7 @@ Source: [ADR-022](adr/ADR-022-Define-a-Stable-Package-Backend-Interface.md) ## ADR-023: Prefer Explicit Configuration Over Implicit Discovery -**Status:** Proposed +**Status:** Accepted Primary inputs should be supplied explicitly whenever practical, while any default locations must be few, deterministic, documented, and easy to explain. @@ -285,7 +294,7 @@ Source: [ADR-023](adr/ADR-023-Prefer-Explicit-Configuration-Over-Implicit-Discov ## ADR-024: Provide a Stable and Explicit Command-Line Interface -**Status:** Proposed +**Status:** Accepted The CLI should be a stable public contract built around clear, orthogonal, deterministic options, with long options preferred for clarity and contradictory @@ -296,7 +305,7 @@ Source: [ADR-024](adr/ADR-024-Provide-a-Stable-and-Explicit-Command-Line-Interfa ## ADR-025: Provide Human-Centered Logging with Progressive Levels of Detail -**Status:** Proposed +**Status:** Accepted Default logging should communicate meaningful execution phases, decisions, installation progress, and completion without exposing unnecessary implementation @@ -307,7 +316,7 @@ Source: [ADR-025](adr/ADR-025-Provide-Human-Centered-Logging-with-Progressive-Le ## ADR-026: Define a Stable Exit Code Philosophy -**Status:** Proposed +**Status:** Accepted Exit statuses should form a stable public contract representing broad outcome categories rather than every internal failure condition. Nonzero statuses should @@ -318,7 +327,7 @@ Source: [ADR-026](adr/ADR-026-Define-a-Stable-Exit-Code-Philosophy.md) ## ADR-027: Establish Trust Through Inspectability -**Status:** Proposed +**Status:** Accepted Bootstrap should earn trust through transparent source, build, release, planning, logging, diagnostics, and documentation rather than require opaque trust in the @@ -330,7 +339,7 @@ Source: [ADR-027](adr/ADR-027-Establish-Trust-Through-Inspectability.md) ## ADR-028: Favor the Principle of Least Surprise -**Status:** Proposed +**Status:** Accepted When several behaviors are reasonable, Bootstrap should favor the most explicit, deterministic, documented, and predictable one. Hidden state, guesses, and silent @@ -341,7 +350,7 @@ Source: [ADR-028](adr/ADR-028-Favor-the-Principle-of-Least-Surprise.md) ## ADR-029: Ensure Reproducible and Verifiable Releases -**Status:** Proposed +**Status:** Accepted Release artifacts should be generated from version-controlled source through a documented build process and tied to immutable source revisions. Rebuilds should @@ -352,7 +361,7 @@ Source: [ADR-029](adr/ADR-029-Ensure-Reproducible-and-Verifiable-Releases.md) ## ADR-030: Preserve Stable Public Interfaces -**Status:** Proposed +**Status:** Accepted Manifest semantics, CLI behavior, exit-code categories, documented behavior, and release artifact formats should be treated as architectural contracts. @@ -364,7 +373,7 @@ Source: [ADR-030](adr/ADR-030-Preserve-Stable-Public-Interfaces.md) ## ADR-031: Adopt Semantic Versioning and Deliberate Compatibility -**Status:** Proposed +**Status:** Accepted Bootstrap proposes Semantic Versioning so release numbers communicate expected compatibility impact: patches correct defects without public-interface changes, @@ -376,7 +385,7 @@ Source: [ADR-031](adr/ADR-031-Adopt-Semantic-Versioning-and-Deliberate-Compatibi ## ADR-033: Prefer Composition Over Special Cases -**Status:** Proposed +**Status:** Accepted New capabilities should reuse and compose existing parsing, planning, backend, logging, diagnostic, and execution concepts wherever practical. Feature-specific @@ -387,7 +396,7 @@ Source: [ADR-033](adr/ADR-033-Prefer-Composition-Over-Special-Cases.md) ## ADR-034: Keep the Core Engine Small -**Status:** Proposed +**Status:** Accepted The core should remain focused on manifest interpretation, validation, execution planning, backend delegation, logging, and diagnostics. Optional policy or @@ -398,7 +407,7 @@ Source: [ADR-034](adr/ADR-034-Keep-the-Core-Engine-Small.md) ## ADR-035: Prefer Data Over Code -**Status:** Proposed +**Status:** Accepted User intent should be represented as declarative data rather than executable configuration whenever practical. New needs should first be addressed through @@ -410,7 +419,7 @@ Source: [ADR-035](adr/ADR-035-Prefer-Data-Over-Code.md) ## ADR-036: Make Architectural Decisions Explicit -**Status:** Proposed +**Status:** Accepted Significant architectural decisions should be recorded in ADRs that preserve the problem, context, selected approach, rationale, alternatives, and consequences. @@ -421,7 +430,7 @@ Source: [ADR-036](adr/ADR-036-Make-Architectural-Decisions-Explicit.md) ## ADR-037: Establish a Deliberate Deprecation Policy -**Status:** Proposed +**Status:** Accepted Public behavior should normally be deprecated before removal, with the replacement, rationale, and migration path documented and removal generally deferred to a @@ -432,7 +441,7 @@ Source: [ADR-037](adr/ADR-037-Establish-a-Deliberate-Deprecation-Policy.md) ## ADR-038: Introduce Experimental Features Deliberately -**Status:** Proposed +**Status:** Accepted Experimental capabilities may be used to evaluate ideas without creating stable compatibility commitments, but they must be explicitly identified, documented, @@ -443,7 +452,7 @@ Source: [ADR-038](adr/ADR-038-Introduce-Experimental-Features-Deliberately.md) ## ADR-039: Test Observable Behavior Rather Than Implementation -**Status:** Proposed +**Status:** Accepted Automated tests should primarily protect observable contracts such as parsing results, CLI behavior, diagnostics, logging, exit categories, planning, and @@ -455,7 +464,7 @@ Source: [ADR-039](adr/ADR-039-Test-Observable-Behavior-Rather-Than-Implementatio ## ADR-040: Prefer Deterministic Behavior -**Status:** Proposed +**Status:** Accepted Given equivalent inputs and operating conditions, Bootstrap should produce the same observable behavior whenever practical. Unavoidable variability introduced @@ -466,7 +475,7 @@ Source: [ADR-040](adr/ADR-040-Prefer-Deterministic-Behavior.md) ## ADR-041: Treat Documentation as Part of the Product -**Status:** Proposed +**Status:** Accepted Documentation should be treated as part of Bootstrap's product surface and kept reasonably current with user-visible behavior. ADRs preserve architectural @@ -477,7 +486,7 @@ Source: [ADR-041](adr/ADR-041-Treat-Documentation-as-Part-of-the-Product.md) ## ADR-042: Minimize the Trusted Computing Base -**Status:** Proposed +**Status:** Accepted Bootstrap should minimize the software that must be trusted in its critical runtime path and prefer existing platform capabilities where they provide the @@ -488,7 +497,7 @@ Source: [ADR-042](adr/ADR-042-Minimize-the-Trusted-Computing-Base.md) ## ADR-043: Favor Stable Concepts Over Clever Implementations -**Status:** Proposed +**Status:** Accepted Competing designs should favor the solution that is easier to explain, document, inspect, maintain, and reconcile with existing architectural concepts rather than @@ -499,7 +508,7 @@ Source: [ADR-043](adr/ADR-043-Favor-Stable-Concepts-Over-Clever-Implementations. ## ADR-044: Optimize for the Next Contributor -**Status:** Proposed +**Status:** Accepted Design choices should reduce the context and cognitive load required by the next person who must understand or change the project, including the original author @@ -523,7 +532,7 @@ Source: [ADR-045](adr/ADR-045-documentation-first-source-code-commenting-standar ## ADR-046: Adopt Documentation-Driven, Test-Second Development -**Status:** Proposed +**Status:** Accepted Development should proceed from documented intent to the smallest correct implementation and then immediately to automated tests of the observable @@ -558,7 +567,7 @@ Source: [ADR-048](adr/ADR-048-Execution-SHALL-Consume-Only-Resolved-Actions.md) ## ADR-049: Preflight All Manifests Before Execution -**Status:** Proposed +**Status:** Accepted A single invocation should accept one or more ordered manifest operands while preserving each record's original source path and line number. Bootstrap should @@ -656,3 +665,19 @@ separately maintained STRIDE threat model and its Mermaid diagrams; routine ADR relationship graph generation remains outside the documentation build. Source: [ADR-055](adr/ADR-055-Publish-Ephemeral-ADR-Navigation-as-the-Reference-Landing-Page.md) + +## ADR-056: Adopt shared coding standards + +**Status:** Accepted + +The repository adopts the complete verified `coding_standards@v1.0.9` snapshot +beneath `doc/standards/`, with exact release provenance recorded in +`.codingstandardrc`. Applicable imported standards govern where relevant while +accepted repository-specific ADRs and explicit local policy retain precedence for +intentional refinements; presence in the snapshot does not itself imply +applicability. Duplicate live documentation-standard files are removed where +present so shared documentation rules have one authoritative managed path, while +historical ADR text remains unchanged. Future standards upgrades replace the +complete snapshot through normal review rather than local edits or automatic +synchronization. See +[ADR-056](adr/ADR-056-adopt-shared-coding-standards.md). diff --git a/doc/standards/awk/documentation-standard.md b/doc/standards/awk/documentation-standard.md new file mode 100644 index 0000000..0eb1f7d --- /dev/null +++ b/doc/standards/awk/documentation-standard.md @@ -0,0 +1,916 @@ +# AWK Documentation Standard + +This document defines the normative source-documentation standard for maintained +AWK files in projects that adopt it. The standard deliberately prefers verbose, +explanatory documentation. Source brevity is not a goal when brevity would +force a future maintainer to infer intent, contracts, assumptions, failure +semantics, state ownership, portability constraints, security boundaries, or +architectural relationships from executable code alone. + +This standard is modeled after the documentation approach used for maintained +Bash projects and is intentionally compatible with the `awk-doxygen` tooling +model. The syntax and structure described here are requirements, not examples +of a general style that may be replaced with something merely similar. + +AWK has a substantially different execution model from Bash. Functions have +real return values rather than shell-style exit statuses, variables are created +through use rather than declarations, function-local variables are commonly +represented by omitted formal parameters, and much program behavior lives in +`BEGIN`, `END`, and pattern/action rules rather than named functions. This +standard therefore preserves the documentation philosophy of the Bash model +while defining AWK-specific contracts rather than mechanically copying Bash +semantics. + +Maintainers should not reduce source documentation merely to optimize release +size. If a project produces stripped, generated, or minified consumer +artifacts, that distribution policy is separate from the maintained +source-documentation standard. Prefer thorough, detailed, in-depth commentary +over brevity. The goal is for the work to be accessible, readable, and +maintainable while targeting developers with basic AWK competence. + +Pay particular attention to assumptions and preconditions. Consider that the +reader may be a human new to the project or an AI/LLM operating with focused +context that may not retain the complete project history or the consequences of +prior decisions. + +## Language and Portability Floor + +Unless governing project documentation states otherwise, maintained AWK source +covered by this standard should be documented as portable AWK rather than as a +specific implementation such as GNU awk, mawk, or BusyBox awk. + +When source depends on implementation-specific behavior or extensions, the +relevant documentation must identify that dependency explicitly. Do not +describe code as portable AWK when correctness actually depends on an +implementation-specific feature. + +Examples of portability-sensitive concerns include: + +* implementation-specific built-in variables or functions; +* implementation-specific regular-expression behavior; +* implementation-specific command-line options; +* implementation-specific array behavior; +* implementation-specific namespace or indirect-call features; +* multibyte and locale behavior; +* non-portable uses of `getline`, redirection, or process control; and +* assumptions about which `awk` implementation `/usr/bin/awk` or the user's + `PATH` selects. + +Portability claims are part of the interface contract and must be documented +with the same care as input and output behavior. + +## Comment Syntax + +Doxygen documentation lines begin with exactly two hash characters: + +```awk +## @file lib/example.awk +## @brief Provides an example capability. +## @details +## This module exists to preserve a specific contract. The details explain why +## the capability belongs here, how callers should use it, and what assumptions +## future changes must preserve. +``` + +Use ordinary single-hash comments for narrow implementation annotations that are +not intended to become part of generated reference documentation. Prefer +Doxygen comments whenever the material helps explain an interface, invariant, +module responsibility, non-obvious decision, maintenance constraint, +portability assumption, data-shape contract, state transition, or security +boundary. + +The project does not use another Doxygen comment dialect in maintained AWK +source. Do not replace these blocks with `#**`, `##<`, or another convention +without an architectural decision that explicitly changes the `awk-doxygen` +integration. + +Lines in documentation commentary should be limited to 80 characters or less, +except for unbreakable content such as long URLs or literal values whose form is +part of the contract. + +## Relationship to awk-doxygen + +`awk-doxygen` is the designated Doxygen filter for projects adopting this +standard. It converts intentionally documented AWK constructs into a +Doxygen-friendly intermediate representation. The generated representation is +an indexing target for Doxygen; it is not intended to be compiled or executed. + +The tooling model is documentation-led rather than parser-led. The filter +should recognize only the subset of AWK structure required to associate +explicit Doxygen blocks with functions, documented variables, `BEGIN`/`END` +blocks, and pattern/action rules. It must not claim to be a complete AWK parser. + +The structural vocabulary defined by this standard includes: + +* `@file` for file-level documentation; +* `@fn` for named AWK functions; +* `@param` for caller-supplied function parameters; +* `@local` for conventional omitted formals used as function-local storage; +* `@var` for significant documented global variables or arrays; and +* `@rule` for named documentation identities assigned to AWK rules, including + `BEGIN`, `END`, and ordinary pattern/action rules. + +Ordinary Doxygen commands such as `@brief`, `@details`, `@returns`, `@retval`, +`@note`, `@warning`, `@see`, `@par`, `@code`, and `@endcode` retain their normal +role unless this standard defines a more specific AWK interpretation. + +`@local` and `@rule` are AWK-source structural directives. They exist so the +filter can preserve AWK semantics without pretending that conventional locals +are ordinary public parameters or that anonymous rules are named source-level +functions. The generated Doxygen representation may suppress or translate +these directives as necessary. + +When `@fn`, `@var`, or `@rule` is used, the documented identity must agree with +the construct being documented according to the validation rules established by +`awk-doxygen`. Documentation identity is part of the maintained-source +contract, not decorative prose. + +Where practical, the filter should preserve source line correspondence so that +Doxygen diagnostics and generated references remain close to the original AWK +locations. Tooling should favor one-for-one line translation over expanding +short source blocks into substantially longer generated structures. + +## File Blocks + +Every maintained AWK source file must contain a file-level Doxygen block near +the start of the file: + +```awk +## @file lib/redaction.awk +## @brief Provides the core redaction pipeline. +## @details +## Explain the module's responsibility, state ownership, security boundary, +## interactions with record processing, and assumptions future changes must +## preserve. +``` + +If the file is directly executable and governing project policy requires a +shebang, the shebang may precede the Doxygen block: + +```awk +#!/usr/bin/awk -f +## @file bin/example.awk +## @brief Processes example input records. +## @details +## Explain why the program exists, the expected record stream, output contract, +## and portability assumptions. +``` + +A shebang is not required merely because a file contains AWK. Source intended +to be invoked with `awk -f file.awk` may begin directly with the Doxygen file +block. The project must not invent a shebang requirement in the documentation +standard when execution policy belongs elsewhere. + +The file details must explain the module's responsibility, its relationship to +neighboring modules or invoking shell code, important global state it owns, +record-processing assumptions, and constraints that affect safe modification. +A useful file block answers "why does this AWK program or module exist?" as well +as "what functions and rules does it contain?" + +When applicable, the file block should identify: + +* the expected input-record model; +* assumptions about `FS`, `RS`, `OFS`, `ORS`, or other built-in variables; +* whether input is expected on standard input, named files, or both; +* whether `ARGV` is inspected or modified; +* whether `ENVIRON` participates in configuration; +* whether output is intended for another machine-readable stage; +* whether output ordering is significant; +* whether global arrays or counters carry state across records; +* whether `BEGIN` or `END` establishes or finalizes important invariants; +* whether the program executes subprocesses or writes files; and +* which AWK implementation or portability floor is required. + +Security-sensitive modules must explicitly identify the boundary they enforce +and link to governing ADRs when that context materially improves review. + +## Function Blocks + +All maintained AWK functions must use the following vocabulary as applicable: + +```awk +## @fn example_lookup(name) +## @brief Looks up a named example. +## @details +## Explain the contract, assumptions, side effects, global state interaction, +## and why the function exists. Describe non-obvious behavior and interactions +## with other functions or rules. +## +## @param name Logical name to look up. +## @local value Scratch value used while resolving the lookup. +## +## @par STDIN +## Nothing is read directly from STDIN. +## @par STDOUT +## Nothing is written to STDOUT. +## @par STDERR +## A diagnostic may be written when the request is invalid. +## +## @returns The matching string, or the empty string when no match exists. +## +## @par Examples +## @code +## value = example_lookup("demo") +## @endcode +function example_lookup(name, value) { + # implementation +} +``` + +Document caller-supplied parameters in declaration order. Document conventional +locals after the caller-supplied parameters and mark them with `@local` rather +than `@param`. + +`@details` should explain the function's contract, meaningful preconditions, +state dependencies, side effects, failure behavior, and non-obvious invariants. +For functions whose behavior depends on record context, identify which built-in +values such as `$0`, `NF`, `NR`, `FNR`, `FILENAME`, `FS`, or `RS` are read or +modified. + +### Caller Parameters and Conventional Locals + +Portable AWK does not have a dedicated local-variable declaration. A common +portable convention is to place parameters that callers are expected to omit +after additional spacing in the function parameter list: + +```awk +function parse(line, separator, fields, count) { +``` + +Syntactically, `fields` and `count` are function parameters. Semantically, the +program intends them as local storage because normal callers omit them. + +This standard distinguishes these roles explicitly: + +```awk +## @param line Record to parse. +## @param separator Field separator. +## @local fields Scratch array populated while parsing. +## @local count Number of fields discovered. +function parse(line, separator, fields, count) { +``` + +`@param` means the value is part of the caller-visible interface. `@local` +means the formal parameter is intentionally omitted by normal callers and is +used as function-local storage. + +The spacing convention may improve human readability, but spacing itself is not +an AWK semantic boundary. Documentation and tooling must not claim otherwise. +The `@param` / `@local` distinction records intended interface semantics. + +A caller that explicitly supplies a value for a documented `@local` is relying +on behavior outside the documented public contract unless project governance +states otherwise. + +### Local Arrays + +AWK arrays can be passed to functions, and a conventional omitted formal may be +used as a local array. Document the intended shape and lifecycle when that +matters: + +```awk +## @local parts Scratch array containing split fields for the current call. +``` + +Do not imply that AWK provides automatic block scope or automatic array cleanup. +If correctness depends on `delete array[index]`, `delete array`, or recreating an +empty scratch array by convention, explain that behavior. + +### STDIN, STDOUT, and STDERR + +Every maintained function must contain exactly one `@par STDIN`, one +`@par STDOUT`, and one `@par STDERR`. + +These paragraphs document direct stream interaction performed by the function, +not the AWK program's overall record-processing environment. + +```awk +## @par STDIN +## Nothing is read directly from STDIN. +## @par STDOUT +## One normalized record is written when validation succeeds. +## @par STDERR +## A diagnostic is written when the record cannot be normalized. +``` + +Most helper functions do not independently read standard input because AWK's +main execution engine reads records before invoking pattern/action code. State +that explicitly rather than silently omitting the contract. + +If a function uses `getline`, document the actual input source and its effect on +AWK record state. A bare `getline` can affect `$0`, `NF`, `NR`, or `FNR` +depending on form and implementation semantics. Do not summarize such behavior +merely as "reads input." + +For STDERR, document the redirection mechanism used by the supported portability +floor when material. Do not claim that a particular pseudo-device path is +portable unless project governance establishes it. + +### Using @returns and @retval + +`@returns` documents the value produced by the AWK `return` statement, or the +absence of a meaningful return value. + +```awk +## @returns The normalized key. +``` + +A function that intentionally returns a boolean-like numeric value may document +discrete return meanings with `@retval`: + +```awk +## @returns A numeric truth value. +## @retval 1 The supplied value is valid. +## @retval 0 The supplied value is invalid. +``` + +In this standard, `@retval` refers to discrete AWK function return values. It +does not refer to the AWK process exit status. + +This distinction is important because AWK functions and the AWK process have +separate contracts. `return 1` returns `1` to the AWK caller. `exit 1` +terminates processing with a process-level status. Documentation must not +conflate the two. + +If a function has no meaningful return value, say so explicitly: + +```awk +## @returns No meaningful value; callers use the function for its side effects. +``` + +Do not use `@returns` to describe text written by `print` or `printf`. That is +the STDOUT contract. + +### Process Exit Behavior + +If a function may execute `exit`, that is a material control-flow side effect +and must be documented in `@details` or a dedicated `@par Process Exit` section. + +For example: + +```awk +## @par Process Exit +## Terminates the AWK program with status 65 when configuration is malformed. +``` + +Do not document process exit statuses with function `@retval` directives. + +Process-level exit behavior associated with `BEGIN`, ordinary rules, or `END` +should be documented on the relevant rule or at file level. + +### Side Effects and Global State + +AWK functions can read and modify global variables without declarations. Any +material caller-visible or program-visible side effect must be documented. + +Examples include: + +* modifying a global scalar or array; +* changing `FS`, `OFS`, `RS`, `ORS`, or another built-in variable; +* changing `$0` or an individual field; +* invoking `sub()` or `gsub()` without an explicit target; +* writing to files or pipes; +* calling `close()` on resources; +* consuming additional input through `getline`; +* mutating `ARGV` or `ENVIRON`; and +* terminating processing with `exit`. + +A dedicated section is appropriate when the side effects are significant: + +```awk +## @par Side Effects +## Updates the global `seen` array and increments `accepted_count`. +``` + +For security-sensitive functions, `@details` must explain important +preconditions, ordering assumptions, data exposure boundaries, and values that +must never be emitted. + +## Variables and Arrays + +AWK variables are created through use rather than explicit declarations. The +documentation standard therefore does not require a fictitious declaration line +for every documented value. + +Document significant global variables and arrays whose meaning, lifecycle, +ownership, or public compatibility role is not self-evident. Typical candidates +include: + +* configuration values; +* global counters; +* registries; +* lookup tables; +* security-sensitive state; +* cross-record state; +* state shared between `BEGIN`, ordinary rules, functions, and `END`; and +* variables whose value participates in a stable external contract. + +Use `@var` for significant documented globals: + +```awk +## @var record_count +## @brief Number of accepted input records. +## @details +## This global counter is initialized in BEGIN and incremented only after a +## record passes validation. +``` + +For arrays, document key and value semantics: + +```awk +## @var cache +## @brief Maps normalized keys to cached values. +## @details +## Keys are lowercase normalized identifiers. Values are the exact strings +## emitted by the lookup stage. Entries persist for the lifetime of the AWK +## process. +``` + +Do not document every temporary global merely because AWK lacks a declaration +keyword. Documentation volume should preserve reasoning rather than create +noise that obscures important state. + +### Variable Type Claims + +AWK scalar values can participate in numeric and string contexts. Avoid +pretending that a scalar has a stronger static type than the language provides. + +Prefer descriptions such as: + +```text +Numeric count of accepted records. +String containing the normalized identifier. +Boolean-like numeric value: 1 for true and 0 for false. +``` + +over fictitious language types. + +Arrays are semantically distinct from scalars and should be documented as arrays +when significant. + +### Global Versus Local Ownership + +Because AWK lacks lexical local declarations in portable code, documentation is +important for ownership. When a global name is intentionally shared between +rules and functions, identify its owner and allowed mutation points. + +When an omitted formal is used as local storage, document it with `@local` +rather than `@var`. + +## BEGIN, END, and Pattern/Action Rules + +A substantial portion of AWK behavior exists outside named functions. This +standard uses `@rule` to assign stable documentation identities to these +constructs without pretending they are AWK functions. + +### BEGIN Rules + +Document consequential `BEGIN` blocks with a stable rule identity: + +```awk +## @rule initialize +## @brief Initializes parsing configuration and global state. +## @details +## Establishes the field separator and initializes counters before the first +## input record is processed. +BEGIN { + FS = ":" + record_count = 0 +} +``` + +The rule name is documentation metadata. It is not an AWK identifier and does +not change runtime behavior. + +Document assumptions established by `BEGIN` that later functions or rules rely +upon. If command-line assignments may override values, explain precedence. + +### END Rules + +Document consequential `END` blocks similarly: + +```awk +## @rule summarize +## @brief Emits the final processing summary. +## @details +## Reads counters accumulated by ordinary rules and writes one summary record. +END { + print record_count +} +``` + +Document whether `END` executes after early `exit`, whether its output is always +produced, and what global state it expects to remain valid when those details +matter to the program contract. + +### Ordinary Pattern/Action Rules + +Use `@rule` for ordinary pattern/action rules whose role deserves maintained +reference documentation: + +```awk +## @rule comment_lines +## @brief Ignores source comment records. +## @details +## Matches records whose first non-space character is `#`. These records do +## not contribute to the accepted-record count. +/^[[:space:]]*#/ { + next +} +``` + +The rule's documentation identity should describe its role rather than attempt +to reproduce the complete pattern text. + +Document: + +* what causes the rule to match; +* what state it reads and modifies; +* whether it emits output; +* whether it invokes `next`, `nextfile`, or `exit`; +* ordering relationships with other rules; +* whether earlier rules can modify `$0` or fields before this rule runs; and +* assumptions about default actions when an explicit action is absent. + +### Pattern-Only and Action-Only Rules + +AWK permits pattern-only rules and action-only rules. Documentation must make +the implicit behavior explicit when it matters. + +For a pattern without an action, identify that AWK's default action prints the +record. For an action without a pattern, identify that the action runs for +every input record reaching that point. + +Do not let concise AWK syntax hide a substantial output or control-flow +contract. + +### Multiple BEGIN or END Blocks + +When a program contains multiple `BEGIN` or `END` blocks, each documented block +must have a distinct `@rule` identity. Documentation should explain ordering +dependencies when correctness relies on source order. + +## Record and Field Semantics + +AWK's implicit record model is part of many interfaces and should be documented +when non-trivial. + +Relevant state includes: + +* `$0`, the current record; +* `$1` through `$NF`, the current fields; +* `NF`; +* `NR` and `FNR`; +* `FILENAME`; +* `FS` and `OFS`; +* `RS` and `ORS`; +* `SUBSEP`; and +* implementation-specific record-related variables when explicitly supported. + +If an operation changes a field and thereby reconstructs `$0`, document the +observable consequence when output formatting or exact record preservation +matters. + +If `sub()` or `gsub()` omits its target and therefore operates on `$0`, document +that side effect when it is not obvious from the function or rule contract. + +If behavior depends on a particular `FS` or `RS`, identify where that value is +established and whether callers may override it. + +## Input Sources and getline + +`getline` deserves explicit documentation because its forms have materially +different state and I/O behavior. + +When a function or rule uses `getline`, document: + +* whether input comes from the current input stream, a named file, or a command; +* whether the result replaces `$0` or is stored in another variable; +* whether `NR`, `FNR`, `NF`, or fields are affected; +* how end-of-file and read errors are distinguished; +* whether the source must be closed with `close()`; +* whether a subprocess is created; and +* portability assumptions associated with the selected form. + +Do not summarize all `getline` usage as "reads another line." The state effects +are part of the contract. + +## Output, Files, Pipes, and close() + +Document non-trivial output destinations and resource lifecycle. + +For `print` or `printf` redirected to a file or pipe, explain: + +* the destination; +* whether output appends or truncates; +* the data format; +* whether ordering matters; +* whether the destination name can be influenced by input; +* whether `close()` is required to bound open descriptors or restart commands; +* whether command execution crosses a security boundary; and +* what happens when output fails. + +Do not describe a pipe command assembled from untrusted data as safe merely +because AWK invokes it indirectly. + +## Regular Expressions + +Document regex intent when the expression is central to a parser, validator, +redactor, security boundary, or externally visible matching contract. + +Distinguish regex literals from dynamically constructed regex strings when that +difference affects escaping or interpretation. + +When a regex is derived from data, document whether the data is intended to be +interpreted as regex syntax or literal text. Do not call data "escaped" or +"literal" unless the implementation actually provides that guarantee. + +Locale and multibyte assumptions must be documented when they affect character +classes, ranges, case conversion, length, matching, or substring behavior. + +## String and Numeric Semantics + +AWK values can carry string and numeric interpretations. Documentation should +identify externally meaningful coercion behavior when correctness depends on +it. + +Examples include: + +* preserving leading zeroes; +* comparing version-like strings lexically rather than numerically; +* accepting numeric prefixes in otherwise textual input; +* converting empty strings to zero in numeric context; +* formatting numbers through `OFMT` or `CONVFMT`; and +* relying on exact textual round trips. + +Do not imply strong static typing. Document the semantic expectation and +observable behavior instead. + +## ARGV, Command-Line Assignments, and ENVIRON + +If AWK code interprets `ARGV`, command-line variable assignments, or `ENVIRON`, +document the configuration boundary explicitly. + +For `ARGV`, identify whether entries are inspected, removed, replaced, or added. +Changing `ARGV` can alter which files AWK subsequently processes. + +For command-line assignments such as: + +```text +awk -v mode=strict -f program.awk input +``` + +or: + +```text +awk -f program.awk mode=strict input +``` + +document timing and precedence when they matter. Do not treat these forms as +interchangeable if initialization timing affects behavior. + +For `ENVIRON`, identify the expected variable names, defaults, validation rules, +and whether values cross a security boundary. + +## Process Execution and Security Boundaries + +AWK can execute external commands through `system()` and command pipes. These +operations create a materially different security boundary from ordinary text +processing. + +Security-sensitive documentation should identify: + +* which strings influence the command; +* whether command text is fixed or constructed; +* whether input can introduce shell syntax; +* whether a shell is involved; +* what output or exit information is consumed; +* whether the command is expected to mutate external state; +* what happens on failure; and +* which ADR governs the accepted risk or mitigation when appropriate. + +Do not describe shell-command construction as escaped, quoted, or safe unless a +real mechanism establishes that property for the complete execution path. + +## Security-Sensitive Documentation + +For parsing, validation, redaction, transformation, output, subprocess, and file +handling code, comments should make it possible for a reviewer to answer +questions such as: + +* what untrusted or sensitive state the function or rule receives; +* whether data is interpreted as text, regex syntax, file paths, or command text; +* whether values can reach STDOUT, STDERR, files, or subprocesses; +* what happens when validation or transformation fails; +* whether original input is emitted after failure; +* whether replacement text is interpreted; +* whether output structure can be changed by input; +* whether locale or multibyte behavior matters; +* what portability assumptions affect protection; +* whether global state can retain sensitive material across records; and +* which ADR establishes the relevant security promise. + +Do not use comments to imply stronger runtime protection than AWK provides. +Terms such as "private," "secure memory," or "isolated" must not be used for +ordinary process variables or arrays unless a real mechanism supports the +claim. + +## Examples + +Examples are strongly preferred for public, parsing, transformation, redaction, +formatting, emission, configuration, or otherwise non-trivial interfaces. + +Function examples should demonstrate AWK call syntax: + +```awk +## @par Examples +## @code +## normalized = normalize_key(raw) +## @endcode +``` + +Rule examples may show representative input and output when that communicates +the contract better than executable syntax: + +```awk +## @par Examples +## @code +## Input: alpha:beta +## Output: alpha +## @endcode +``` + +Examples should demonstrate intended use, not manufacture a second test suite +inside comments. + +## Internal Helpers + +Projects may establish naming conventions for internal AWK helpers. Such a +convention is not a privacy mechanism and is not a reason to omit documentation +from a security-critical or semantically important helper. + +Document internal functions when their contract, assumptions, state mutation, +or failure behavior would otherwise need to be rediscovered from implementation. + +## Document Intent, Not Syntax + +Avoid comments such as "increment the counter" immediately above: + +```awk +count++ +``` + +Prefer comments that explain why the counter exists, why incrementing occurs at +that stage, what invariant the count represents, or why a seemingly unusual +implementation is necessary. + +If code and documentation disagree, treat the disagreement as a defect to +investigate. Do not automatically rewrite the comment to match current code; +the code may be the part that drifted from the intended contract. + +## Relationship to ADRs + +Doxygen documentation owns implementation-level intent. ADRs own durable +architectural reasoning, promises, non-promises, compatibility and portability +decisions, adversary/failure models, rejected alternatives, and accepted +tradeoffs. + +Source comments may link to an ADR when a local implementation exists +specifically to satisfy an architectural constraint. + +Do not copy an entire ADR into source comments. Do not invent historical +rationale when no source supports it. State uncertainty or add an ADR when a +new consequential decision is required. + +A project's `doc/decisions.md`, when present, provides concise ADR summaries and +does not replace either the full ADR or local Doxygen contract. + +## Generated Reference Documentation + +Generated Doxygen output is derivative and is not a maintained source of truth. +The maintained AWK source and its governing documentation remain authoritative. + +Projects may build, strip, package, or otherwise transform maintained AWK source +for distribution. Those transformations must not become a reason to reduce the +quality of source documentation. + +When `awk-doxygen` emits a pseudo-language representation for Doxygen, the +representation should preserve source intent while making only those structural +translations required for indexing. It must not manufacture semantic certainty +that is absent from the maintained AWK source. + +## General File Structure Pattern + +A maintained AWK file should generally follow this order where applicable: + +1. optional governed shebang; +2. `@file`; +3. `@brief` for the file; +4. substantive `@details` for the file; +5. `@author`, `@copyright`, `@see`, `@note`, and `@warning` as needed; +6. significant documented global variables and arrays; +7. functions; +8. documented `BEGIN` rules; +9. documented ordinary pattern/action rules; and +10. documented `END` rules. + +Actual executable ordering may require `BEGIN`, rules, functions, or related +constructs to appear differently. AWK does not require functions to precede +calls in source. Preserve execution and readability requirements rather than +reordering merely to satisfy this illustrative structure. + +## General Function Structure Pattern + +1. `@fn` +2. `@brief` +3. `@details` +4. additional `@note`, `@warning`, `@see`, `@par Side Effects`, and + `@par Process Exit` directives as needed +5. blank line +6. zero or more `@param` directives in caller-visible declaration order +7. zero or more `@local` directives in declaration order +8. blank line +9. exactly one `@par STDIN` +10. exactly one `@par STDOUT` +11. exactly one `@par STDERR` +12. blank line +13. exactly one `@returns` +14. zero or more `@retval` directives for discrete AWK return values +15. `@par Examples` when an example improves understanding +16. `@code` +17. example lines +18. `@endcode` + +## General Rule Structure Pattern + +1. `@rule` +2. `@brief` +3. `@details` +4. additional `@note`, `@warning`, `@see`, `@par Side Effects`, and + `@par Process Exit` directives as needed +5. `@par STDOUT` and `@par STDERR` when the rule emits directly +6. `@par Examples` when useful +7. `@code` +8. representative input/output or usage lines +9. `@endcode` + +Rule documentation should describe implicit record input in `@details`; rules do +not need a fictitious `@param` for `$0`. + +## Review Standard + +Review documentation with the same seriousness as executable code. Ask whether +a maintainer unfamiliar with the current implementation could understand: + +* the responsibility of each module; +* the contract of each function; +* which formals are caller parameters and which are conventional locals; +* important return-value semantics; +* direct STDIN, STDOUT, and STDERR behavior; +* process-exit behavior; +* global state ownership and mutation; +* record and field assumptions; +* `BEGIN`, `END`, and pattern/action responsibilities; +* meaningful edge cases and failure modes; +* portability and implementation-specific assumptions; +* regex, locale, and multibyte expectations when relevant; +* subprocess, file, and output security boundaries; +* why non-obvious implementation choices exist; +* which architectural decisions constrain future changes; and +* what the implementation explicitly does not guarantee. + +There is no target comment-to-code ratio. The desired amount is "enough to +preserve the reasoning." In AWK programs with dense implicit behavior, this may +mean considerably more prose than teams accustomed to terse scripts expect, and +that is intentional. + +## Structural Checklist + +Before considering a maintained AWK file adequately documented, verify as +applicable: + +* the file has `## @file`, `## @brief`, and substantive `## @details`; +* any shebang reflects actual project execution policy rather than an invented + documentation requirement; +* portability assumptions and implementation-specific dependencies are explicit; +* all maintained functions have `@fn`, `@brief`, and `@details`; +* caller-supplied parameters are documented with `@param` in declaration order; +* conventional omitted-formal locals are documented with `@local` in declaration + order; +* every function contains exactly one `@par STDIN`, one `@par STDOUT`, one + `@par STDERR`, and one `@returns`; +* discrete function return values use `@retval` when that improves the contract; +* process exit behavior is not confused with AWK function return behavior; +* significant globals and arrays use `@var` where useful; +* significant `BEGIN`, `END`, and ordinary pattern/action rules use stable + `@rule` identities where generated reference documentation adds value; +* global state ownership, record mutation, and built-in variable dependencies + are documented when material; +* `getline`, file redirection, pipes, subprocesses, and `close()` semantics are + documented when used materially; +* public or non-trivial functions contain an example when an example improves + understanding; +* documentation blocks remain associated with the constructs consumed by + `awk-doxygen`; +* and security-sensitive code documents assumptions a future reviewer would + otherwise have to infer. diff --git a/doc/standards/bash/documentation-standard.md b/doc/standards/bash/documentation-standard.md new file mode 100644 index 0000000..9e6c28a --- /dev/null +++ b/doc/standards/bash/documentation-standard.md @@ -0,0 +1,489 @@ +# Bash Documentation Standard + +This document defines the normative source-documentation standard for maintained +Bash files in this project. The standard deliberately prefers verbose, +explanatory documentation. Source brevity is not a goal when brevity would +force a future maintainer to infer intent, contracts, assumptions, failure +semantics, security boundaries, or architectural relationships from executable +code alone. + +This is the same documentation model used across related projects such as +bashdeps, Bootstrap, mktext, adrctl, and template-bash. It is intentionally +compatible with the `bash-doxygen` tooling. The syntax and structure described +here are requirements, not examples of a general style that may be replaced with +something merely similar. + +The distribution pipeline separates maintenance representation from consumer +representation. The `.dev.bash` artifact retains documentation. Full-line +comments are removed from the ordinary `.bash` artifact, and Bash-Minifier +produces the `.min.bash` artifact. Maintainers therefore should not reduce +source documentation merely to optimize release size. Prefer thorough, +detailed, in-depth commentary over brevity. The goal is for the work to be +accessible, readable, and maintainable while targeting developers with basic +Bash competence. Pay special attention to the assumptions and preconditions +associated with the work that's being done. Consider that the reader may be +a human new to the project or an AI/LLM that may have a focused context and may +not retain a full view of the project or the consequences of decisions made and +documented here. + +## Comment Syntax + +Doxygen documentation lines begin with exactly two hash characters: + +```bash +## @file lib/example.bash +## @brief Provides an example capability. +## @details +## This module exists to preserve a specific contract. The details explain why +## the capability belongs here, how callers should use it, and what assumptions +## future changes must preserve. +``` + +Use ordinary single-hash comments for narrow implementation annotations that are +not intended to become part of generated reference documentation. Prefer +Doxygen comments whenever the material helps explain an interface, invariant, +module responsibility, non-obvious decision, maintenance constraint, portability +assumption, or security boundary. + +The project does not use another Doxygen comment dialect in maintained Bash +source. Do not replace these blocks with `#**`, `##<`, or another convention +without an architectural decision that explicitly changes the `bash-doxygen` +integration. + +Lines in the commentary should be limited to 80 characters or less, except for +unbreakable content such as long URLs. + +## Relationship to bash-doxygen + +`bash-doxygen` converts documented Bash declarations into a Doxygen-friendly +intermediate representation. It intentionally emits declarations only when they +are decorated with a Doxygen block. + +Documentation blocks must therefore remain contiguous and associated with the +function or variable declaration they document. + +The filter structurally understands `@file`, `@fn`, `@var`, and `@param` names +and preserves ordinary Doxygen commands such as `@brief`, `@details`, +`@returns`, `@retval`, `@note`, `@warning`, `@see`, `@par`, `@code`, and +`@endcode`. + +When `@fn` or `@var` is used, the documented name must agree with the +declaration that follows. Maintainers should prefer the explicit structural +commands because they allow tooling to catch documentation drift. + +## File Blocks + +Every maintained Bash source file must begin with: + +```bash +#!/usr/bin/env bash +# shellcheck shell=bash +## @file +## @brief +## @details +## +``` + +For example: + +```bash +#!/usr/bin/env bash +# shellcheck shell=bash +## @file lib/redaction.bash +## @brief Provides the core redaction pipeline. +## @details +## Explain the module's responsibility, state ownership, security boundary, +## interactions with formatting/emission, and assumptions future changes must +## preserve. +``` + +The details must explain the module's responsibility, its relationship to +neighboring modules, important state it owns, and assumptions that affect safe +modification. A useful file block answers "why does this module exist?" as well +as "what functions are in it?" + +Security-sensitive modules must explicitly identify the boundary they enforce +and link to governing ADRs when that context materially improves review. + +## Function Blocks + +All functions must use the following vocabulary as applicable: + +```bash +## @fn example_lookup() +## @brief Looks up a named example. +## @details +## Explain the contract, assumptions, side effects, and why the function exists. +## Describe non-obvious behavior and interactions with other modules. +## +## @param name Logical name to look up. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## The matching value when one exists. +## @par STDERR +## A diagnostic when the request is invalid or the lookup cannot be completed. +## +## @returns A single line of text containing the matching string. +## +## @retval 0 A matching value was found. +## @retval 64 The caller supplied invalid input. +## @retval 69 No matching value exists. +## +## @par Examples +## @code +## value="$(example_lookup demo)" +## @endcode +example_lookup() { + # implementation +} +``` + +Document parameters in call order. Document standard input, standard output +and standard error. Document exit statuses semantically rather than merely +saying "success" or "failure" when distinct outcomes matter. + +When a function may propagate exit statuses from another command without +translating them into a defined function-level status, do not attempt to +enumerate those values with `@retval`. + +Document the function's defined exit statuses with `@retval`, and use `@note` to +identify any additional statuses that may be propagated unchanged from another +command. + +```bash +## @retval 0 The operation completed successfully. +## @note Non-zero exit statuses from grep may be propagated unchanged. +``` + +If the propagated command is conditional or only applies to a particular failure +path, describe that condition explicitly. + +```bash +## @retval 0 The requested file was processed successfully. +## @retval 64 The caller supplied invalid input. +## @note If validation succeeds but awk fails, its non-zero exit status may be +## propagated unchanged. +``` + +Do not invent or normalize propagated exit statuses solely for documentation. +Use `@retval` only for exit statuses that form part of the function's defined +contract. + +Examples are strongly preferred for public, plugin, parsing, transformation, +redaction, formatting, emission, or otherwise non-trivial interfaces. Examples +should demonstrate intended use, not manufacture a second test suite inside +comments. + +For security-sensitive functions, `@details` must explain the important +preconditions, failure behavior, ordering assumptions, and what the function +must never emit or expose. + +Material side effects must be documented in `@details` or, when useful, in a +dedicated `@par Side Effects` section. This includes changes to caller-visible +variables, shell options, traps, files, directories, or other state outside the +function's local scope. + +### Paragraphs for STDIN, STDOUT, and STDERR + +Individual `@par` (paragraphs) must be included that describe the contracts +of what a function expects from STDIN and writes to STDOUT and STDERR. + +```bash +## @par STDIN +## The content to be searched. +## @par STDOUT +## The lines that match the provided pattern. +## @par STDERR +## Nothing is written to STDERR. +``` + +Exactly one `@par STDIN`, one `@par STDOUT`, and one `@par STDERR` are required +per function. + +### Using @returns and @retval + +Use `@retval` to document function exit statuses. Use `@returns` to document +the structural form of the function's STDOUT. + +These directives describe two separate aspects of a Bash function's behavior: + +* `@retval` documents one possible numeric exit status and what that status means. +* `@returns` documents the structural form of what, if anything, the function + writes to STDOUT. + +Use one `@retval` line for each documented exit status. + +```bash +## @retval 0 A matching value was found. +## @retval 1 No matching value was found. +## @retval 2 The supplied pattern was invalid. +``` + +Use `@returns` to describe the function's STDOUT contract. + +```bash +## @returns A list of matching strings, one per line. +``` + +When a function intentionally writes nothing to STDOUT, state that explicitly. + +```bash +## @returns Nothing is written to STDOUT. +``` + +All functions must have exactly one `@returns` statement and may have zero or +more `@retval` statements. + +A function may both write data to STDOUT and produce a meaningful exit status. +Document both behaviors independently. + +```bash +## @fn find_matches() +## @brief Finds values matching a supplied pattern. +## @details +## Searches the provided input values using the supplied pattern and writes each +## matching value to STDOUT. The function distinguishes between successful +## matches, no matches, and invalid patterns through its exit status. +## +## @param pattern The pattern to match. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## Each line contains a value that matched the supplied pattern. No output is +## produced when no values match. +## @par STDERR +## A diagnostic is written when the supplied pattern is invalid. +## +## @returns Zero or more newline-delimited strings. +## +## @retval 0 One or more matching values were found. +## @retval 1 No matching values were found. +## @retval 2 The supplied pattern was invalid. +## +## @par Examples +## @code +## find_matches '^[[:alpha:]]+$' +## matches="$(find_matches '^[[:alpha:]]+$')" +## @endcode +find_matches() { +``` + +Predicate-style functions commonly write nothing to STDOUT and communicate +their result entirely through the exit status. + +```bash +## @fn is_valid() +## @brief Determines whether a value is valid. +## @details +## Evaluates the supplied value against the function's validation rules. The +## validation result is communicated exclusively through the exit status; the +## function does not emit a value to STDOUT. +## +## @param value The value to inspect. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## Nothing is written to STDOUT. +## @par STDERR +## Nothing is written to STDERR. +## +## @returns Nothing is written to STDOUT. +## +## @retval 0 The value is valid. +## @retval 1 The value is invalid. +## +## @par Examples +## @code +## if is_valid "${value}"; then +## printf '%s\n' 'The value is valid.' +## fi +## @endcode +is_valid() { +``` + +Do not use `@returns` to describe an exit status, and do not use `@retval` to +describe text or other data written to STDOUT. Treat STDOUT and the function's +exit status as independent interfaces. + +#### Relationship Between @returns and @par STDOUT + +`@par STDOUT` describes the semantic meaning of that output and the conditions +under which it is produced. + +`@returns` describes the structural form of the function's STDOUT, such as +whether it emits a single string, zero or more newline-delimited values, or +nothing. + +```bash +## @par STDOUT +## Each line is a value that matched the supplied regular expression. +## No output is produced when no values match. +## +## @returns Zero or more newline-delimited strings. +``` + +## Variables and Constants + +Document exported variables, configuration knobs, registry structures, +security-sensitive arrays, and constants whose meaning is not self-evident. +Explain units, allowed values, mutability, ownership, lifecycle, and whether the +value participates in public API compatibility when those details matter. + +Use `@var` for significant documented variables where appropriate: + +```bash +## @var BASHLOG_DEFAULT_LEVEL +## @brief Default logging threshold used when no caller override exists. +readonly BASHLOG_DEFAULT_LEVEL='info' +``` + +Using `@var` allows `bash-doxygen` to verify that the documentation name matches +the following declaration. + +Do not document every local loop variable. Documentation volume should preserve +reasoning, not create noise that obscures it. + +## Internal Helpers + +A function beginning with `__bashlog_` is internal by project convention. That +prefix is not a privacy mechanism and is not a reason to omit documentation from +a security-critical helper. + +## Security-Sensitive Documentation + +For redaction, final rendering, and emission code, comments should make it +possible for a reviewer to answer questions such as: + +* what sensitive state the function receives or accesses; +* whether the value is plaintext in the current Bash process; +* whether data can reach a sink from this function; +* whether failure suppresses or emits the original message; +* what matcher semantics apply; +* whether replacement text is interpreted; +* whether locale or multibyte behavior matters; +* what assumptions depend on the Bash compatibility floor; +* and which ADR establishes the relevant security promise. + +Do not use comments to imply stronger runtime protection than Bash provides. +Terms such as "private," "secure memory," or "isolated" must not be used for +ordinary same-process variables unless a real mechanism supports the claim. + +## Document Intent, Not Syntax + +Avoid comments such as "increment the counter" immediately above +`((counter++))`. Prefer comments that explain why the counter exists, why an +operation occurs at that point, or why a seemingly unusual implementation is +necessary. + +If code and documentation disagree, treat the disagreement as a defect to +investigate. Do not automatically rewrite the comment to match current code; +the code may be the part that drifted from the intended contract. + +## Relationship to ADRs + +Doxygen documentation owns implementation-level intent. ADRs own durable +architectural reasoning, promises, non-promises, adversary/failure models, +rejected alternatives, and accepted tradeoffs. Source comments may link to an +ADR when a local implementation exists specifically to satisfy an architectural +constraint. + +Do not copy an entire ADR into source comments. Do not invent historical +rationale when no source supports it. State uncertainty or add an ADR when a +new consequential decision is required. + +`doc/decisions.md` provides only concise ADR summaries and does not replace +either the full ADR or local Doxygen contract. + +Once created, `doc/bashlog-spec.md` will own current public behavior. Doxygen +comments should agree with that specification for public functions while adding +implementation-level context that would be inappropriate in a consumer-facing +specification. + +## Generated Reference Documentation + +`make docs` generates reference documentation from maintained source using the +prepared `bash-doxygen` dependency. Generated output is derivative and is not a +maintained source of truth. + +The `.dev.bash` artifact intentionally retains Doxygen comments so reviewers can +inspect the fully assembled source in consumer order. The stripped and minified +artifacts intentionally allow that source documentation to remain verbose +without forcing all consumers to receive the same comment volume. + +## General File Structure Pattern + +1. shebang +2. shellcheck language identifier +3. `@file` +4. `@brief` for the file +5. `@details` for the file +6. `@author`, `@copyright`, `@see`, `@note`, `@warning` as-needed +7. global variables +8. functions + +## General Function Structure Pattern + +1. `@fn` +2. `@brief` +3. `@details` +4. additional `@note`, `@warning`, `@see`, and `@par Side Effects` directives + as needed; directives that qualify a specific section may appear adjacent to + that section +5. blank line +6. zero or more `@param` directives +7. blank line +8. exactly one `@par STDIN` +9. exactly one `@par STDOUT` +10. exactly one `@par STDERR` +11. blank line +12. exactly one `@returns` +13. zero or more `@retval` directives +14. `@par Examples` +15. `@code` +16. example lines +17. `@endcode` + +## Review Standard + +Review documentation with the same seriousness as executable code. Ask whether +a maintainer unfamiliar with the current implementation could understand: + +* the responsibility of each module; +* the contract of each function; +* important inputs, outputs, and exit-status semantics; +* invariants and ordering requirements; +* meaningful edge cases and failure modes; +* security-sensitive state and output boundaries; +* why non-obvious implementation choices exist; +* which architectural decisions constrain future changes; +* and what the implementation explicitly does not guarantee. + +There is no target comment-to-code ratio. The desired amount is "enough to +preserve the reasoning." In this project that may often be more prose than +teams accustomed to sparse Bash comments expect, and that is intentional. + +## Structural Checklist + +Before considering a maintained Bash file adequately documented, verify as +applicable: + +* the file starts with `#!/usr/bin/env bash`; +* the file has `# shellcheck shell=bash`; +* the file has `## @file`, `## @brief`, and substantive `## @details`; +* all functions have `@fn`, `@brief`, and `@details`; +* parameters are documented in call order; +* every function contains exactly one `@par STDIN`, one `@par STDOUT`, one + `@par STDERR`, and one `@returns`; +* meaningful exit statuses are documented with `@retval` or equivalent + Doxygen vocabulary; +* significant variables use `@var` where useful; +* public or non-trivial functions contain an example when an example improves + understanding; +* documentation blocks remain adjacent to the declarations consumed by + `bash-doxygen`; +* and security-sensitive code documents the assumptions a future reviewer would + otherwise have to infer. diff --git a/doc/standards/examples/awk/documentation/example.awk b/doc/standards/examples/awk/documentation/example.awk new file mode 100644 index 0000000..807ac58 --- /dev/null +++ b/doc/standards/examples/awk/documentation/example.awk @@ -0,0 +1,129 @@ +#!/usr/bin/awk -f +## @file standards/examples/awk/documentation/example.awk +## @brief Demonstrates the AWK documentation standard. +## @details +## This non-normative example shows representative file, variable, function, +## BEGIN-rule, ordinary-rule, and END-rule documentation. The program reads +## comma-separated name/value records, normalizes accepted names, and emits a +## final processing summary. + +## @var record_count +## @brief Number of accepted input records. +## @details +## This global counter is initialized in `initialize` and incremented only after +## a record passes validation and is emitted. + +## @var rejected_count +## @brief Number of rejected input records. +## @details +## This global counter is initialized in `initialize` and incremented whenever a +## record fails the expected two-field input contract. + +## @fn normalize_name(value) +## @brief Normalizes an example name. +## @details +## Converts ASCII uppercase letters to lowercase and replaces spaces with +## underscores. The function has no stream side effects and does not modify +## global state. +## +## @param value Name to normalize. +## @local result Scratch copy used while normalizing the value. +## +## @par STDIN +## Nothing is read directly from STDIN. +## @par STDOUT +## Nothing is written to STDOUT. +## @par STDERR +## Nothing is written to STDERR. +## +## @returns The normalized name string. +## +## @par Examples +## @code +## normalized = normalize_name("Demo Name") +## @endcode +function normalize_name(value, result) { + result = tolower(value) + gsub(/[[:space:]]+/, "_", result) + return result +} + +## @fn is_valid_record() +## @brief Determines whether the current input record has the expected shape. +## @details +## Reads the current record context and considers a record valid only when AWK +## has split it into exactly two fields. The function does not modify `$0`, +## `NF`, or any global state. +## +## @par STDIN +## Nothing is read directly from STDIN; the current AWK record is inspected. +## @par STDOUT +## Nothing is written to STDOUT. +## @par STDERR +## Nothing is written to STDERR. +## +## @returns A numeric truth value. +## @retval 1 The current record contains exactly two fields. +## @retval 0 The current record does not contain exactly two fields. +## +## @par Examples +## @code +## if (is_valid_record()) { +## # process the current record +## } +## @endcode +function is_valid_record() { + return (NF == 2) +} + +## @rule initialize +## @brief Initializes parsing configuration and global counters. +## @details +## Establishes comma-separated input and output before the first record is +## processed. The rule also initializes the counters used by later rules and +## the final summary. +BEGIN { + FS = "," + OFS = "," + record_count = 0 + rejected_count = 0 +} + +## @rule comment_lines +## @brief Ignores comment records. +## @details +## Matches records whose first non-space character is `#`. Comment records do +## not affect accepted or rejected counts. +/^[[:space:]]*#/ { + next +} + +## @rule invalid_records +## @brief Rejects records that do not contain exactly two fields. +## @details +## Increments `rejected_count`, writes a diagnostic containing the source record +## number, and prevents invalid input from reaching the accepted-record rule. +!is_valid_record() { + rejected_count++ + printf "invalid record at line %d\n", FNR > "/dev/stderr" + next +} + +## @rule accepted_records +## @brief Normalizes and emits accepted records. +## @details +## Normalizes the first field, preserves the second field as supplied, increments +## `record_count`, and writes one comma-separated output record. +is_valid_record() { + record_count++ + print normalize_name($1), $2 +} + +## @rule summarize +## @brief Emits the final processing summary. +## @details +## Writes accepted and rejected totals after input processing completes. The +## summary is emitted even when no ordinary input records were accepted. +END { + printf "accepted=%d rejected=%d\n", record_count, rejected_count +} diff --git a/doc/standards/examples/bash/documentation/example.bash b/doc/standards/examples/bash/documentation/example.bash new file mode 100644 index 0000000..fc5f3b1 --- /dev/null +++ b/doc/standards/examples/bash/documentation/example.bash @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +## @file standards/examples/bash/documentation/example.bash +## @brief Demonstrates the Bash documentation standard. +## @details +## This non-normative example shows representative file, variable, and function +## documentation using the maintained Bash Doxygen dialect. The example keeps +## stream behavior, return status, side effects, and examples explicit so a +## caller does not need to infer the contract from the implementation. + +## @var EXAMPLE_DEFAULT_PREFIX +## @brief Prefix used when formatting normalized example names. +## @details +## The value is immutable for the lifetime of this process and participates in +## the output contract of `format_name()`. +readonly EXAMPLE_DEFAULT_PREFIX='item' + +## @fn normalize_name() +## @brief Normalizes a caller-supplied example name. +## @details +## Converts ASCII uppercase letters to lowercase and rejects empty input. The +## function does not modify caller-visible shell state other than writing the +## normalized value to STDOUT on success. +## +## @param name Name supplied by the caller. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## The normalized name is written as one line when validation succeeds. +## @par STDERR +## A diagnostic is written when `name` is empty. +## +## @returns A single newline-terminated normalized string on success. +## +## @retval 0 The name was valid and was normalized successfully. +## @retval 64 The caller supplied an empty name. +## +## @par Examples +## @code +## normalized="$(normalize_name 'Demo')" +## @endcode +normalize_name() { + local name=${1-} + + if [[ -z ${name} ]]; then + printf '%s\n' 'name must not be empty' >&2 + return 64 + fi + + printf '%s\n' "${name,,}" +} + +## @fn format_name() +## @brief Formats a normalized name for display. +## @details +## Normalizes the supplied name through `normalize_name()` and prefixes the +## resulting value with `EXAMPLE_DEFAULT_PREFIX`. Validation failure from the +## normalization step is propagated unchanged. +## +## @param name Name supplied by the caller. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## One formatted name is written when normalization succeeds. +## @par STDERR +## Diagnostics produced by `normalize_name()` may be propagated unchanged. +## +## @returns A single newline-terminated formatted string on success. +## +## @retval 0 The supplied name was normalized and formatted successfully. +## @note Non-zero statuses from `normalize_name()` may be propagated unchanged. +## +## @par Examples +## @code +## formatted="$(format_name 'Demo')" +## @endcode +format_name() { + local name=${1-} + local normalized + + normalized="$(normalize_name "${name}")" || return $? + printf '%s:%s\n' "${EXAMPLE_DEFAULT_PREFIX}" "${normalized}" +} + +## @fn is_valid_name() +## @brief Determines whether an example name is valid. +## @details +## Treats a non-empty string containing only ASCII letters, digits, underscores, +## and hyphens as valid. The result is communicated exclusively through the +## function status and no value is emitted to STDOUT. +## +## @param name Name to inspect. +## +## @par STDIN +## Nothing is read from STDIN. +## @par STDOUT +## Nothing is written to STDOUT. +## @par STDERR +## Nothing is written to STDERR. +## +## @returns Nothing is written to STDOUT. +## +## @retval 0 The supplied name is valid. +## @retval 1 The supplied name is invalid. +## +## @par Examples +## @code +## if is_valid_name 'demo-1'; then +## printf '%s\n' 'valid' +## fi +## @endcode +is_valid_name() { + local name=${1-} + + [[ ${name} =~ ^[[:alnum:]_-]+$ ]] +} diff --git a/doc/standards/examples/general/clean-coding/bash.md b/doc/standards/examples/general/clean-coding/bash.md new file mode 100644 index 0000000..6438755 --- /dev/null +++ b/doc/standards/examples/general/clean-coding/bash.md @@ -0,0 +1,352 @@ +# Clean Coding Examples for Bash + +## Purpose + +This document provides Bash examples illustrating the +[Clean Coding Standard](../../../general/clean-coding-standard.md). + +The examples are illustrative rather than normative. They demonstrate ways the +general principles may be expressed in Bash, but they do not replace a Bash-specific +coding standard or repository-specific governance. + +## Functions Should Do One Thing + +A function with several independent responsibilities can be difficult to understand +and test: + +```bash +prepare_release() { + validate_configuration + tar -czf "$archive" "$build_dir" + sha256sum "$archive" >"$archive.sha256" + curl --fail --upload-file "$archive" "$release_url" +} +``` + +The same workflow can expose its responsibilities more clearly: + +```bash +validate_release() { + validate_configuration +} + +build_release_archive() { + tar -czf "$archive" "$build_dir" +} + +generate_release_checksum() { + sha256sum "$archive" >"$archive.sha256" +} + +publish_release() { + curl --fail --upload-file "$archive" "$release_url" +} + +prepare_release() { + validate_release + build_release_archive + generate_release_checksum + publish_release +} +``` + +`prepare_release` still coordinates several operations, but its responsibility is +now the release workflow. Lower-level mechanics are delegated to functions with +more specific responsibilities. + +## Separate Commands from Queries + +A query should avoid changing observable state unexpectedly. + +For example, this function appears to answer a question but also creates a file: + +```bash +configuration_exists() { + if [[ ! -f $config_file ]]; then + install_default_configuration + fi + + [[ -f $config_file ]] +} +``` + +Separating the observation from the mutation makes the behavior easier to reason +about: + +```bash +configuration_exists() { + [[ -f $config_file ]] +} + +install_default_configuration() { + cp "$default_config" "$config_file" +} + +if ! configuration_exists; then + install_default_configuration +fi +``` + +The command may still return a Bash exit status indicating success or failure. The +important distinction is that a caller does not need to invoke an apparently +observational function in order to trigger a state change. + +## Maintain One Level of Abstraction + +Mixing workflow decisions with low-level mechanics can obscure the primary flow: + +```bash +publish_artifacts() { + validate_release + + mkdir -p "$output_dir" + sha256sum "$artifact" >"$output_dir/$artifact_name.sha256" + printf '%s\n' "$metadata" >"$output_dir/metadata.json" + curl --fail --upload-file "$artifact" "$release_url" +} +``` + +A higher-level function can instead express the workflow: + +```bash +publish_artifacts() { + validate_release + prepare_release_metadata + generate_release_checksums + upload_release_artifacts +} +``` + +The lower-level file, hashing, serialization, and network operations still exist, +but the orchestration function communicates why they are being performed. + +## Make Side Effects Explicit + +A function named like a query should not unexpectedly change global state: + +```bash +get_repository_root() { + REPOSITORY_ROOT=$(git rev-parse --show-toplevel) +} +``` + +A function that prints the value can make the data flow more visible: + +```bash +repository_root() { + git rev-parse --show-toplevel +} + +repository_root=$(repository_root) +``` + +If modifying shared state is intentional, naming can make that purpose visible: + +```bash +set_repository_root() { + REPOSITORY_ROOT=$(git rev-parse --show-toplevel) +} +``` + +## Use Descriptive Names + +Generic names force the reader to inspect implementation details: + +```bash +process() { + sha256sum "$1" +} +``` + +A purpose-oriented name communicates more information: + +```bash +calculate_checksum() { + sha256sum "$1" +} +``` + +The same principle applies to variables. Prefer names that communicate the role of +a value when that role is not already obvious from a very small local context. + +## Prefer Explicit Behavior + +Dense expressions can save lines while increasing the amount of reasoning required +from the reader: + +```bash +[[ -f $config && -r $config ]] && source "$config" || return 1 +``` + +A more explicit form exposes the decision points: + +```bash +if [[ ! -f $config ]]; then + return 1 +fi + +if [[ ! -r $config ]]; then + return 1 +fi + +source "$config" +``` + +Whether `source` is appropriate is a separate security and interface decision. The +example illustrates control-flow clarity rather than recommending executable +configuration files. + +## Keep Interfaces Focused + +Boolean-like positional arguments can be difficult to interpret at the call site: + +```bash +render_report "$input" true false +``` + +Separate operations or explicit options can make intent clearer: + +```bash +render_summary_report "$input" +``` + +or, when one interface genuinely represents a cohesive operation: + +```bash +render_report --format summary --input "$input" +``` + +The goal is not to eliminate parameters mechanically. The interface should make +the caller's intent understandable without requiring the reader to remember what +`true` and `false` mean in each position. + +## Keep Control Flow Understandable + +Deep nesting can hide the primary path: + +```bash +publish_if_valid() { + if [[ -f $artifact ]]; then + if verify_checksum "$artifact"; then + if release_exists; then + upload_artifact "$artifact" + fi + fi + fi +} +``` + +Early returns can keep the successful path visible: + +```bash +publish_if_valid() { + [[ -f $artifact ]] || return 1 + verify_checksum "$artifact" || return 1 + release_exists || return 1 + + upload_artifact "$artifact" +} +``` + +This form is not universally preferable, but it illustrates the standard's guidance +to minimize unnecessary nesting and keep major decisions visible. + +## Avoid Unnecessary Duplication + +Duplicating the same policy in several places creates multiple sources of truth: + +```bash +validate_build_name() { + [[ $1 =~ ^[a-z0-9-]+$ ]] +} + +validate_release_name() { + [[ $1 =~ ^[a-z0-9-]+$ ]] +} +``` + +If the two functions genuinely enforce the same naming rule, a shared abstraction +can make that policy explicit: + +```bash +validate_artifact_name() { + [[ $1 =~ ^[a-z0-9-]+$ ]] +} + +validate_build_name() { + validate_artifact_name "$1" +} + +validate_release_name() { + validate_artifact_name "$1" +} +``` + +If build names and release names only happen to use the same expression today but +represent different policies, keeping them separate may be the better design. The +important question is whether the duplicated code represents duplicated knowledge. + +## Comments Explain Why + +A comment that restates the next command adds little information: + +```bash +# Create the directory. +mkdir -p "$cache_dir" +``` + +A comment can instead preserve a constraint that the code alone does not explain: + +```bash +# Keep the cache beneath the workspace because CI runners discard all other +# writable paths between jobs. +mkdir -p "$cache_dir" +``` + +The second comment records reasoning a future maintainer might otherwise have to +rediscover. + +## Errors Are Part of the Interface + +Discarding diagnostic context can make a failure difficult to investigate: + +```bash +curl --fail --silent "$url" -o "$destination" 2>/dev/null || return 1 +``` + +Preserving or adding useful context makes the failure more actionable: + +```bash +download_file() { + local url=$1 + local destination=$2 + + if ! curl --fail --show-error --silent "$url" -o "$destination"; then + printf 'error: failed to download %s\n' "$url" >&2 + return 1 + fi +} +``` + +The exact diagnostic policy belongs to the repository and its interfaces. The +example illustrates the principle that failures should be deliberate and should +retain enough context to understand what operation failed. + +## Review Questions for Bash + +When applying the general review questions to Bash, it may be useful to ask: + +- Does the function have one identifiable responsibility? +- Does a function that looks observational modify files, globals, environment, or + process state? +- Are workflow functions separated from shell and utility mechanics where doing so + improves readability? +- Can the purpose of functions and important variables be understood from their + names? +- Is the main execution path visible without tracing deeply nested conditionals? +- Are exit statuses and diagnostics handled deliberately? +- Does shared helper code represent a genuinely shared rule rather than merely + similar-looking commands? + +These questions remain heuristics. Repository governance and any Bash-specific +standard take precedence where they establish a more specific rule. diff --git a/doc/standards/examples/javascript/documentation/example.js b/doc/standards/examples/javascript/documentation/example.js new file mode 100644 index 0000000..72a722d --- /dev/null +++ b/doc/standards/examples/javascript/documentation/example.js @@ -0,0 +1,29 @@ +/** + * Load and validate application configuration. + * + * Reads a configuration document and returns the validated application + * configuration. The function does not modify the source file. + * + * @param {string} path - Path to the configuration document. + * @param {boolean} [strict=true] - Whether unknown keys are rejected. + * @returns {Promise} Validated configuration owned by the caller. + * @throws {TypeError} If `path` is not a non-empty string. + */ +async function loadConfiguration(path, strict = true) { + return readAndValidateConfiguration(path, strict); +} + +/** + * Yield validated records in source order. + * + * Iteration is lazy. Callers may stop before exhausting the source without + * retaining the underlying reader. + * + * @param {Iterable} lines - Source records to validate. + * @yields {Record} Validated records in source order. + */ +function* iterRecords(lines) { + for (const line of lines) { + yield validateRecord(line); + } +} diff --git a/doc/standards/examples/php/documentation/example.php b/doc/standards/examples/php/documentation/example.php new file mode 100644 index 0000000..437b934 --- /dev/null +++ b/doc/standards/examples/php/documentation/example.php @@ -0,0 +1,179 @@ + $values Normalized configuration values. + */ + public function __construct( + private readonly array $values, + ) { + } + + /** + * Return a configuration value by key. + * + * The method distinguishes between a missing key and a key whose value is + * explicitly null by requiring the caller to supply a default value. + * + * @param string $key Logical configuration key to read. + * @param scalar|null $default Value returned when the key is absent. + * @return scalar|null The stored value when present; otherwise $default. + */ + public function get(string $key, string|int|float|bool|null $default = null): string|int|float|bool|null + { + return $this->values[$key] ?? $default; + } +} + +/** + * Load and validate configuration from a PHP array. + * + * The function normalizes supported keys, rejects unsupported value shapes, and + * returns a configuration object that owns its normalized data. The caller's + * input array is not modified. + * + * @param array $input Untrusted configuration data to validate. + * @return Configuration A validated configuration owned by the caller. + * @throws InvalidArgumentException A key is empty or a value has an unsupported type. + * @see Configuration + */ +function loadConfiguration(array $input): Configuration +{ + $normalized = []; + + foreach ($input as $key => $value) { + if ($key === '') { + throw new InvalidArgumentException('Configuration keys must not be empty.'); + } + + if (!is_scalar($value) && $value !== null) { + throw new InvalidArgumentException( + sprintf('Unsupported value type for configuration key "%s".', $key), + ); + } + + $normalized[$key] = $value; + } + + return new Configuration($normalized); +} + +/** + * Normalize a repository identifier for use as a lookup key. + * + * Leading and trailing whitespace is removed and the remaining identifier is + * converted to lowercase. Empty identifiers are rejected rather than silently + * normalized to an unusable cache key. + * + * @param string $value Repository identifier supplied by the caller. + * @return string Canonical lowercase repository identifier. + * @throws InvalidArgumentException The identifier is empty after trimming. + */ +function normalizeRepositoryId(string $value): string +{ + $normalized = strtolower(trim($value)); + + if ($normalized === '') { + throw new InvalidArgumentException('Repository identifier must not be empty.'); + } + + return $normalized; +} + +/** + * Return the legacy default cache directory. + * + * @deprecated Use cacheDirectory() so callers can provide an explicit root. + * @return string Absolute path to the legacy cache directory. + * @see cacheDirectory() + */ +function legacyCacheDirectory(): string +{ + return '/var/cache/example'; +} + +/** + * Build a cache directory beneath a caller-supplied root. + * + * The function performs no filesystem mutation. It only returns the path the + * caller may later create or use. + * + * @param string $root Absolute cache root. + * @param string $namespace Logical namespace appended beneath the root. + * @return string Absolute cache directory path. + * @throws InvalidArgumentException The root is not absolute or the namespace is empty. + */ +function cacheDirectory(string $root, string $namespace): string +{ + if ($root === '' || $root[0] !== '/') { + throw new InvalidArgumentException('Cache root must be an absolute path.'); + } + + $namespace = trim($namespace); + if ($namespace === '') { + throw new InvalidArgumentException('Cache namespace must not be empty.'); + } + + return rtrim($root, '/') . '/' . $namespace; +} + +/** + * Persist configuration as JSON. + * + * Existing files are replaced atomically by writing to a temporary file in the + * destination directory and renaming it into place. A successful return means + * the final path contains the complete encoded document. + * + * @param Configuration $configuration Configuration to serialize. + * @param string $path Destination path to replace. + * @return void + * @throws RuntimeException Encoding, writing, or replacement fails. + */ +function persistConfiguration(Configuration $configuration, string $path): void +{ + $directory = dirname($path); + $temporary = tempnam($directory, 'config-'); + + if ($temporary === false) { + throw new RuntimeException('Unable to create temporary configuration file.'); + } + + try { + $payload = json_encode($configuration, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT); + if (file_put_contents($temporary, $payload . PHP_EOL) === false) { + throw new RuntimeException('Unable to write temporary configuration file.'); + } + + if (!rename($temporary, $path)) { + throw new RuntimeException('Unable to replace configuration file.'); + } + } finally { + if (is_file($temporary)) { + @unlink($temporary); + } + } +} + +/** + * Default retry delays in milliseconds. + * + * @var list + */ +const RETRY_DELAYS_MS = [100, 250, 500]; diff --git a/doc/standards/examples/python/documentation/example.py b/doc/standards/examples/python/documentation/example.py new file mode 100644 index 0000000..e8df779 --- /dev/null +++ b/doc/standards/examples/python/documentation/example.py @@ -0,0 +1,142 @@ +"""Demonstrate the Python documentation standard. + +This module is illustrative rather than normative. It shows representative +module, class, property, function, generator, context-manager, asynchronous, raw +string, exception, and intentionally unannotated documentation forms using the +canonical Python documentation standard. +""" + +from collections.abc import AsyncIterator, Iterator +from contextlib import contextmanager +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class Record: + """Represent one validated record. + + Instances are immutable value objects owned by the caller after construction. + + :param value: Canonical record value. + """ + + value: str + + +class Repository: + """Represent access to a repository while its resources are valid. + + Instances expose repository state for the lifetime established by the caller. + This example class does not perform real I/O; it exists only to demonstrate + documentation structure. + """ + + def __init__(self, root: Path) -> None: + """Initialize repository access for ``root``. + + :param root: Repository root represented by this instance. + """ + self._root = root + + @property + def root(self) -> Path: + """Return the repository root represented by this instance.""" + return self._root + + +def normalize_key(value: str) -> str: + """Normalize a lookup key. + + Leading and trailing whitespace is removed before the value is converted to + lowercase. The returned string does not alias mutable caller state. + + :param value: Untrusted key supplied by the caller. + :returns: Lowercase normalized key suitable for lookup. + :raises ValueError: The normalized value would be empty. + + Example:: + + normalized = normalize_key(" Demo ") + """ + normalized = value.strip().lower() + if not normalized: + raise ValueError("value must contain non-whitespace characters") + return normalized + + +def iter_records(path: Path) -> Iterator[Record]: + """Yield validated records from ``path``. + + Iteration is lazy. The file is opened when iteration begins and is closed + when iteration ends or the generator is finalized. + + :param path: Input file containing one record per line. + :yields: Validated records in source order. + Blank lines are ignored rather than emitted as empty records. + :raises OSError: The input cannot be opened or read. + :raises ValueError: A non-blank record cannot be normalized. + """ + with path.open("r", encoding="utf-8") as stream: + for line in stream: + if line.strip(): + yield Record(normalize_key(line)) + + +@contextmanager +def opened_repository(path: Path) -> Iterator[Repository]: + """Yield repository access for the duration of a context. + + The yielded object remains valid only until the context exits. Cleanup runs + whether the context body succeeds or raises. + + :param path: Repository root made available inside the context. + :yields: Repository access valid for the lifetime of the context. + """ + repository = Repository(path) + try: + yield repository + finally: + pass + + +async def iter_remote_records(source: str) -> AsyncIterator[Record]: + """Yield records from an asynchronous source. + + This illustrative implementation emits no records. A real implementation + would document cancellation, timeout, resource ownership, and cleanup + semantics appropriate to its transport. + + :param source: Logical remote source identifier. + :yields: Validated records as they become available. + """ + if source == "": + return + if False: + yield Record(source) + + +def load_unannotated(path): + """Load a configuration value from an intentionally unannotated interface. + + This example demonstrates the permitted type-field form for code whose + interface intentionally lacks Python annotations. + + :param path: Filesystem path to read. + :type path: pathlib.Path + :returns: Text read from the requested file. + :rtype: str + :raises OSError: The file cannot be opened or read. + """ + return path.read_text(encoding="utf-8") + + +def windows_pattern() -> str: + r"""Return a regular-expression fragment containing literal backslashes. + + A raw docstring is appropriate here because the documentation itself contains + backslashes whose literal spelling matters. + + :returns: Regular-expression fragment matching a Windows-style separator. + """ + return r"\\" diff --git a/doc/standards/general/clean-architecture-standard.md b/doc/standards/general/clean-architecture-standard.md new file mode 100644 index 0000000..35d826c --- /dev/null +++ b/doc/standards/general/clean-architecture-standard.md @@ -0,0 +1,685 @@ +# Clean Architecture Standard + +## Purpose + +Software architecture should protect the core behavior and policies of a system from unnecessary dependence on frameworks, infrastructure, delivery mechanisms, persistence technologies, and other implementation details. + +This standard establishes general architectural principles for structuring software so that important behavior remains understandable, testable, maintainable, and adaptable as external technologies change. + +These principles are influenced by Robert C. Martin's *Clean Architecture*, the Dependency Rule, the Stable Dependencies Principle, Hexagonal Architecture, Ports and Adapters, and related approaches to software design. + +This standard is authoritative for projects that adopt it. The referenced architectural approaches provide background and context; they do not override repository-specific requirements or architectural decisions. + +## Precedence + +Accepted Architecture Decision Records (ADRs), documented interfaces, security requirements, compatibility requirements, platform constraints, and repository-specific architectural standards take precedence over this general standard. + +Do not restructure an existing system solely to make it resemble a particular architectural diagram or textbook model. + +Architectural changes should be justified by system requirements, maintainability concerns, risk reduction, or established project goals rather than aesthetic preference. + +## Architecture Should Express Intent + +The structure of a system should communicate what the system does. + +Prefer architectures organized around meaningful system capabilities, domain concepts, or use cases rather than primarily around frameworks or technical mechanisms. + +For example, a system concerned with invoicing might expose concepts such as: + +```text +invoice +customer +payment +billing +tax +``` + +rather than making the primary structure: + +```text +controllers +repositories +database +framework +utils +``` + +Technical organization may still exist, but the purpose of the system should remain visible. + +A developer examining the repository should be able to determine the important responsibilities of the system without first understanding every framework or infrastructure component. + +## Follow the Dependency Rule + +Source-code dependencies should point toward the parts of the system containing the most important and stable policies. + +Core business or application logic should not depend directly on implementation details such as: + +- web frameworks; +- database libraries; +- message brokers; +- cloud SDKs; +- user-interface frameworks; +- command-line parsing libraries; +- serialization frameworks; +- logging implementations; +- network clients; or +- vendor-specific services. + +Infrastructure may depend on application policy. + +Application policy should not depend unnecessarily on infrastructure. + +Conceptually: + +```text +frameworks + | + v +adapters + | + v +application + | + v +domain +``` + +Dependencies point inward toward higher-level policy. + +The exact number and names of architectural layers are not prescribed by this standard. + +The direction of dependency is more important than reproducing a specific diagram. + +## Separate Policy from Mechanism + +Business rules, workflow decisions, validation policy, and other core behavior should be separated from the mechanisms used to deliver or persist that behavior. + +Examples of mechanisms include: + +- HTTP; +- command-line interfaces; +- databases; +- files; +- queues; +- email; +- cloud services; +- GUI frameworks; and +- external APIs. + +A rule such as: + +```text +An invoice may not be finalized without at least one line item. +``` + +is application or domain policy. + +The fact that an invoice is stored in PostgreSQL or submitted through an HTTP endpoint is an implementation mechanism. + +The policy should not require knowledge of those mechanisms unless the mechanism itself is genuinely part of the rule. + +## Treat Frameworks as Details + +Frameworks are tools used by the application. + +The application should not become unnecessarily shaped around the framework. + +Avoid allowing framework-specific types, annotations, lifecycle rules, or conventions to penetrate deeper into the system than necessary. + +Prefer boundary code that translates between framework concepts and application concepts. + +For example: + +```text +HTTP Request + | + v +HTTP Adapter + | + v +Application Request + | + v +Use Case +``` + +rather than requiring the use case itself to understand HTTP. + +Framework coupling may be acceptable when the cost of abstraction would exceed its benefit. Such coupling should be deliberate rather than accidental. + +## Treat Persistence as a Detail + +Core application behavior should not depend unnecessarily on a specific persistence technology. + +The application should express what information it needs rather than how that information is stored. + +Prefer application-facing abstractions such as: + +```text +find_customer() +save_invoice() +load_configuration() +``` + +over business logic that directly constructs database queries or manipulates storage-specific records. + +Persistence adapters may translate between application models and database representations. + +This does not require every project to implement a repository pattern, ORM abstraction, or custom persistence framework. + +Introduce abstractions when they protect meaningful policy or improve testability, maintainability, or portability. + +Do not create abstractions solely because an architectural pattern says that one should exist. + +## Keep External Systems at Boundaries + +External services should normally be accessed through explicit boundaries. + +Examples include: + +- payment providers; +- authentication systems; +- email services; +- cloud storage; +- source-control platforms; +- ticketing systems; +- third-party APIs; and +- operating-system services. + +Core behavior should depend on an interface representing the capability it needs rather than directly on a vendor-specific implementation when that distinction is meaningful. + +Conceptually: + +```text +Application + | + v +Payment Service Interface + ^ + | +Stripe Adapter +``` + +The application depends on the capability. + +The adapter depends on the external provider. + +## Use Dependency Inversion at Architectural Boundaries + +When high-level policy needs a capability supplied by a lower-level implementation, define the dependency in terms of the needs of the higher-level policy. + +For example: + +```text +Application Policy + | + v +Notification Interface + ^ + | +SMTP Adapter +``` + +The application defines or owns the contract it requires. + +The implementation satisfies that contract. + +This prevents core policy from depending directly on lower-level implementation details. + +Do not introduce dependency inversion mechanically. Use it where a dependency crosses a meaningful architectural boundary or where substitutability, isolation, testing, or changeability provides practical value. + +## Keep Boundaries Explicit + +Architectural boundaries should be visible in the codebase. + +A boundary may be represented through: + +- interfaces; +- functions; +- modules; +- packages; +- processes; +- services; +- message schemas; +- data-transfer objects; or +- other explicit contracts. + +The representation should be appropriate to the language and system. + +A boundary should clarify: + +- what crosses it; +- in which direction dependencies flow; +- who owns the contract; +- what behavior is expected; and +- what implementation details are intentionally hidden. + +Hidden or informal boundaries are difficult to enforce. + +## Keep Boundary Data Deliberate + +Data crossing an architectural boundary should be represented in forms appropriate to that boundary. + +Avoid leaking infrastructure-specific objects deeply into application code. + +Examples include: + +- database rows; +- ORM entities; +- HTTP request objects; +- framework contexts; +- vendor SDK objects; +- serialization-specific classes; and +- UI widgets. + +Translate these into application-appropriate representations where the separation provides meaningful architectural value. + +Do not create redundant translation layers when the boundary is trivial and provides no practical isolation. + +## Keep Use Cases Focused + +Application behavior should be organized around meaningful operations or use cases. + +Examples might include: + +```text +create_invoice +approve_payment +register_user +publish_release +rotate_credentials +generate_report +``` + +A use case should coordinate the policy required to accomplish a meaningful system action. + +It may invoke domain behavior, persistence interfaces, external-service interfaces, and other collaborators. + +A use case should not ordinarily contain low-level framework or infrastructure mechanics. + +## Keep Core Policy Testable + +Important application behavior should be testable without requiring unnecessary external infrastructure. + +Core tests should not require a real: + +- database; +- HTTP server; +- cloud environment; +- filesystem; +- message broker; +- external API; or +- GUI + +unless the behavior being tested genuinely depends on that mechanism. + +Architectural separation should make it possible to test policy independently from infrastructure. + +This does not eliminate integration or end-to-end testing. + +Infrastructure should also be tested at appropriate boundaries. + +## Do Not Let Infrastructure Define the Domain + +Database schemas, API payloads, framework models, or vendor objects should not automatically become the system's conceptual model. + +The domain model should reflect the concepts and rules that matter to the application. + +For example, a database may contain: + +```text +invoice_status CHAR(1) +``` + +while the application may reason about: + +```text +Draft +Pending +Paid +Cancelled +``` + +The storage representation is an implementation detail. + +The application concept is part of the system's meaning. + +## Prefer Stable Dependencies + +Code that changes frequently should generally depend on code that is more stable rather than forcing stable policy to depend on volatile implementation details. + +Examples of comparatively volatile components may include: + +- external APIs; +- UI frameworks; +- cloud providers; +- database technologies; +- authentication providers; +- deployment environments; and +- third-party libraries. + +Examples of comparatively stable components may include: + +- core business rules; +- domain concepts; +- application policies; and +- established contracts. + +When volatility differs significantly, place the dependency so that changes in volatile components do not unnecessarily propagate into stable policy. + +## Isolate Change + +Architecture should contain foreseeable change rather than allowing it to spread throughout the system. + +When a dependency is expected to vary, consider placing it behind a boundary. + +Examples include: + +```text +database implementation +payment provider +notification service +authentication mechanism +file format +deployment environment +``` + +However, do not introduce speculative abstraction around every dependency. + +A useful boundary protects against a realistic form of change, isolates a significant implementation detail, or makes important behavior easier to test and understand. + +## Avoid Premature Abstraction + +Clean Architecture does not require maximum indirection. + +Do not create: + +- an interface for every class; +- a repository for every data structure; +- an adapter for every function; +- a service layer that merely forwards calls; +- unnecessary DTO transformations; +- empty abstraction layers; or +- abstractions that exist solely to satisfy a diagram. + +Each architectural boundary should have a reason to exist. + +A boundary is justified when it protects policy, isolates volatility, improves testability, establishes a meaningful contract, or prevents inappropriate coupling. + +Abstraction without purpose increases complexity. + +## Avoid Circular Dependencies + +Architectural components should not form dependency cycles. + +For example: + +```text +A -> B -> C -> A +``` + +creates coupling that makes the components difficult to reason about, test independently, and change safely. + +When a cycle appears, examine whether: + +- responsibilities are incorrectly divided; +- a shared abstraction is missing; +- dependency inversion is appropriate; +- a component contains multiple concerns; or +- the purported architectural boundary is not meaningful. + +Cycles across major architectural boundaries should be treated as design problems unless explicitly justified. + +## Keep Direction of Control Separate from Direction of Dependency + +Runtime control flow and source-code dependency do not need to point in the same direction. + +For example, an application may invoke persistence behavior at runtime: + +```text +Use Case + | + v +Database +``` + +while the source-code dependency is inverted: + +```text +Use Case + | + v +Persistence Interface + ^ + | +Database Adapter +``` + +The use case controls the operation. + +The database adapter implements the application's required interface. + +This distinction is fundamental to maintaining architectural boundaries. + +## Separate Delivery from Application Behavior + +Delivery mechanisms should adapt external input into application operations. + +Delivery mechanisms may include: + +- HTTP controllers; +- CLI commands; +- GUI events; +- scheduled jobs; +- message consumers; and +- serverless handlers. + +They should generally be responsible for concerns such as: + +- parsing input; +- authentication context; +- protocol validation; +- translating external representations; +- invoking application behavior; and +- presenting results. + +They should not become the primary location for business rules. + +Prefer: + +```text +CLI Handler + | + v +CreateInvoice Use Case +``` + +rather than embedding invoicing policy directly into command-line parsing code. + +## Keep Infrastructure Replaceable Where It Matters + +A well-separated system should permit important implementation details to change without rewriting core application policy. + +Possible substitutions might include: + +```text +PostgreSQL -> SQLite +SMTP -> API-based email +CLI -> HTTP service +Local filesystem -> Object storage +Vendor A -> Vendor B +``` + +This does not mean every implementation detail must actually be interchangeable. + +Replaceability is primarily evidence that architectural dependencies have been separated appropriately. + +Do not build unused interchangeable implementations merely to demonstrate flexibility. + +## Preserve Domain Language + +Core application code should use terminology that reflects the problem domain. + +Prefer: + +```text +invoice +customer +subscription +release +credential +repository +``` + +over framework-centric terms where domain terminology would communicate intent more clearly. + +Shared terminology between software, documentation, requirements, and domain experts reduces translation cost and misunderstanding. + +## Make Architecture Inspectable + +Architectural intent should be discoverable from the repository. + +Important architectural decisions should be documented through appropriate mechanisms, including: + +- directory structure; +- module boundaries; +- interfaces; +- README documentation; +- architecture documentation; and +- Architecture Decision Records. + +When the reason for an architectural boundary is non-obvious, document it. + +Do not rely solely on institutional memory. + +## Record Meaningful Architectural Decisions + +Use an ADR when introducing or materially changing architecture involving: + +- major component boundaries; +- dependency direction; +- external integrations; +- security boundaries; +- persistence strategy; +- communication mechanisms; +- public interfaces; +- compatibility commitments; +- deployment architecture; or +- other consequential design decisions. + +An ADR should capture the context, decision, alternatives, tradeoffs, consequences, and relevant assumptions. + +Architectural intent that affects future implementation should be durable and reviewable. + +## Preserve Existing Contracts + +Architectural cleanup should not silently change established behavior. + +Before modifying a boundary, identify relevant: + +- public interfaces; +- data formats; +- error behavior; +- security expectations; +- compatibility requirements; +- persistent data; +- external integrations; and +- accepted ADRs. + +A cleaner internal architecture does not justify an unapproved external behavior change. + +## Guidance for Automated Agents + +When generating, modifying, or reviewing software: + +1. Identify the core application or domain policy involved in the requested change. +2. Identify frameworks, infrastructure, persistence, delivery mechanisms, and external services involved. +3. Keep core policy independent of implementation details where practical. +4. Ensure dependencies across architectural boundaries point toward higher-level policy. +5. Introduce interfaces at meaningful boundaries when inversion protects important behavior or isolates significant volatility. +6. Keep framework-specific and vendor-specific types near the boundaries where they are used. +7. Avoid placing business rules in controllers, handlers, persistence adapters, or framework glue. +8. Keep use cases focused on meaningful application operations. +9. Prefer domain terminology over infrastructure terminology in core code. +10. Preserve explicit architectural boundaries already established by the repository. +11. Respect accepted ADRs and documented architectural constraints. +12. Do not introduce abstraction solely to imitate a Clean Architecture diagram. +13. Do not introduce interfaces, adapters, repositories, or layers unless they serve a concrete architectural purpose. +14. Avoid circular dependencies. +15. Preserve existing public interfaces and compatibility requirements unless the requested work explicitly changes them. +16. Do not perform unrelated architectural refactoring outside the requested scope. +17. When a requested change materially alters architecture, identify whether an ADR is required. +18. When existing architecture conflicts with this standard, do not silently restructure it. Identify the conflict and follow repository governance. + +## Review Questions + +When reviewing architecture, consider: + +- Can I identify the core policies of the system? +- Does the repository structure communicate what the system does? +- Do core policies depend unnecessarily on frameworks or infrastructure? +- Do dependencies point toward more stable policy? +- Are external systems isolated behind meaningful boundaries? +- Are framework-specific objects leaking into core application logic? +- Are business rules implemented in delivery or persistence code? +- Are architectural boundaries explicit and understandable? +- Does each abstraction have a concrete reason to exist? +- Are there circular dependencies? +- Can important application behavior be tested without unnecessary infrastructure? +- Could a volatile implementation detail be changed without rewriting core policy? +- Does the architecture preserve domain terminology? +- Are meaningful architectural decisions documented? +- Is the architecture more complicated than the requirements justify? + +These questions are heuristics. They support engineering judgment rather than replace it. + +## Common Warning Signs + +The following conditions may indicate architectural problems: + +- controllers containing substantial business logic; +- domain objects importing framework classes; +- use cases constructing SQL directly; +- application policy depending on cloud SDKs; +- vendor-specific objects passed throughout the application; +- circular dependencies between major components; +- framework upgrades requiring widespread changes to core policy; +- tests of business rules requiring full infrastructure startup; +- directories organized entirely around technical mechanisms; +- interfaces that exist only because every class was given one; +- adapters that merely forward calls without isolating anything meaningful; +- business terminology replaced by framework terminology; and +- significant architectural behavior that exists only as undocumented convention. + +These are indicators for investigation rather than automatic defects. + +## Further Reading + +The following sources provide additional background for the principles described in this standard: + +- Robert C. Martin, *Clean Architecture: A Craftsman's Guide to Software Structure and Design*. In particular, see the discussion of the Dependency Rule, boundaries, use cases, entities, dependency inversion, and the separation of policy from implementation details. +- Robert C. Martin's writings on the Stable Dependencies Principle, Stable Abstractions Principle, and SOLID principles. +- Alistair Cockburn, "Hexagonal Architecture," also known as Ports and Adapters. +- Jeffrey Palermo, writings on Onion Architecture. +- Eric Evans, *Domain-Driven Design*, particularly where domain modeling and ubiquitous language intersect with architectural boundaries. +- Architecture Decision Records maintained by the project for decisions that govern or intentionally depart from general architectural guidance. + +## Summary + +Prefer architecture that: + +- makes the system's purpose visible; +- separates policy from implementation mechanisms; +- points dependencies toward higher-level, more stable policy; +- treats frameworks, databases, and external services as implementation details; +- keeps architectural boundaries explicit; +- protects core behavior from unnecessary infrastructure coupling; +- isolates meaningful volatility; +- preserves domain language; +- remains testable without unnecessary external systems; +- documents consequential decisions; and +- introduces abstraction only when the abstraction serves a concrete purpose. + +Clean Architecture is not the reproduction of a particular set of concentric circles or a prescribed number of layers. + +Its central concern is protecting important software policy from unnecessary dependence on details that are more likely to change. diff --git a/doc/standards/general/clean-coding-standard.md b/doc/standards/general/clean-coding-standard.md new file mode 100644 index 0000000..f6d14d3 --- /dev/null +++ b/doc/standards/general/clean-coding-standard.md @@ -0,0 +1,373 @@ +# Clean Coding Standard + +## Purpose + +Code should communicate its intent clearly, minimize unnecessary complexity, and make behavior straightforward to understand, test, modify, and review. + +This standard establishes general principles for writing and modifying code. It applies across programming languages unless a language-specific or project-specific standard establishes a more appropriate rule. + +These principles are influenced by Robert C. Martin's *Clean Code*, Bertrand Meyer's Command-Query Separation principle, and related software design practices. They are used here as engineering guidelines rather than as an assertion that every recommendation from those sources applies universally. + +## Precedence + +Repository-specific requirements, accepted Architecture Decision Records (ADRs), documented interfaces, compatibility requirements, and language-specific standards take precedence over this general standard. + +Do not perform unrelated refactoring solely to bring existing code into compliance with this standard unless that work is part of the requested scope. + +## Functions Should Do One Thing + +A function should have one clearly identifiable responsibility. + +The operations inside a function should contribute directly to that responsibility. If describing the function accurately requires combining multiple independent actions with words such as "and" or "then," consider whether those actions belong in separate functions. + +Prefer: + +```text +validate_configuration() +load_configuration() +write_configuration() +``` + +over: + +```text +validate_load_and_write_configuration() +``` + +This does not mean that a function may contain only one statement or invoke only one other function. A higher-level function may coordinate several lower-level operations when that coordination is itself the function's single responsibility. + +For example: + +```text +deploy_application() + validate_configuration() + build_application() + publish_application() +``` + +The responsibility of `deploy_application()` is deployment. The implementation details are delegated to functions operating at a lower level of abstraction. + +### Practical test + +When reviewing a function, ask: + +> What does this function do? + +A concise answer describing one responsibility is a good indication that the function is appropriately focused. + +If the answer becomes a list of substantially independent activities, the function should be examined for possible decomposition. + +## Separate Commands from Queries + +Follow the principle of **Command-Query Separation (CQS)** where practical. + +A function should normally behave as either: + +- a **query**, which returns information without changing observable state; or +- a **command**, which changes state without also being used to obtain information about that state. + +Prefer: + +```text +exists = user_exists(username) + +if ! exists: + create_user(username) +``` + +over an interface conceptually similar to: + +```text +created = create_user_if_missing(username) +``` + +when the return value ambiguously represents both an action and a question. + +Separating commands from queries makes code easier to reason about because a caller can determine whether an operation changes state from the operation's interface and purpose. + +### Exceptions + +Command-Query Separation is a design principle rather than an absolute prohibition. + +Some APIs legitimately return information about an operation they perform, such as: + +- a newly created object's identifier; +- the number of records changed; +- an operating system status code; +- an error or result describing whether the command succeeded; or +- a value that cannot reasonably be obtained separately without introducing race conditions or unnecessary work. + +When combining mutation and returned information is necessary, make the behavior explicit in the function's name, interface, documentation, or established language conventions. + +Avoid surprising side effects. + +## Maintain One Level of Abstraction + +Statements within a function should generally operate at a consistent level of abstraction. + +Avoid mixing high-level business or workflow logic with low-level implementation details. + +Prefer: + +```text +prepare_release() + validate_release() + build_artifacts() + generate_attestations() + publish_release() +``` + +over: + +```text +prepare_release() + validate_release() + mkdir(...) + open(...) + calculate_hash(...) + encode_json(...) + invoke_http_request(...) +``` + +The lower-level operations may be perfectly appropriate, but they usually belong behind functions whose names express why those operations are being performed. + +A reader should be able to understand the primary flow of a function without first understanding every implementation detail beneath it. + +## Make Side Effects Explicit + +Functions should not unexpectedly modify state. + +Potential side effects include: + +- modifying global variables; +- changing files; +- changing environment variables; +- modifying passed objects or data structures; +- altering persistent storage; +- changing process state; +- performing network operations; +- creating external resources; and +- changing configuration. + +When side effects are necessary, make them evident through naming, documentation, interfaces, or established conventions. + +A function that appears to retrieve information should not unexpectedly modify the system as part of retrieving it. + +## Use Descriptive Names + +Names should describe purpose rather than implementation mechanics whenever practical. + +Prefer names such as: + +```text +load_configuration +validate_repository +calculate_checksum +publish_release +``` + +over vague names such as: + +```text +process +handle +run +do_work +manage +``` + +A good function name should reduce the amount of implementation code a reader must inspect before understanding why the function exists. + +Names should also communicate meaningful side effects when those effects would otherwise be surprising. + +## Prefer Explicit Behavior + +Code should favor clarity over cleverness. + +Do not compress code merely to minimize line count. Prefer structures whose behavior can be understood by a developer unfamiliar with the implementation. + +Avoid requiring the reader to infer important behavior from: + +- undocumented side effects; +- obscure language features; +- hidden global state; +- ambiguous return values; +- excessive nesting; +- implicit ordering dependencies; or +- unnecessarily dense expressions. + +Concise code is useful when it remains clear. Brevity is not itself a measure of quality. + +## Keep Interfaces Focused + +Functions should accept the information required to perform their responsibility and avoid unnecessary parameters. + +A large or continually growing parameter list can indicate that: + +- the function has multiple responsibilities; +- related data should be represented by a cohesive structure; +- internal implementation details are leaking through the interface; or +- the abstraction is incorrectly defined. + +Do not create a data structure solely to reduce the apparent number of arguments. The resulting abstraction should represent a meaningful concept. + +Boolean arguments deserve particular scrutiny because calls such as: + +```text +render_report(true, false) +``` + +provide little information about what the arguments mean. + +Prefer explicit interfaces when practical. + +## Keep Control Flow Understandable + +Prefer straightforward control flow. + +When possible: + +- handle invalid or exceptional conditions early; +- minimize unnecessary nesting; +- keep the primary execution path visible; +- extract complex conditions into appropriately named functions or variables; and +- separate policy decisions from implementation mechanics. + +A reader should be able to identify the major decisions and execution path without mentally simulating the entire function. + +## Avoid Unnecessary Duplication + +Do not maintain multiple independent implementations of the same rule or algorithm without a reason. + +Duplication is particularly dangerous when the duplicated code represents: + +- validation rules; +- security policy; +- business rules; +- configuration interpretation; +- compatibility behavior; or +- calculations that must remain consistent. + +However, similar-looking code is not automatically the same abstraction. + +Do not create premature abstractions merely to eliminate a few repeated lines. Prefer duplication over an incorrect abstraction when the concepts are not genuinely the same. + +## Comments Explain Why + +Code should communicate what it does through its structure, names, and interfaces whenever practical. + +Comments and documentation should provide information that the code cannot adequately communicate itself, particularly: + +- why a decision was made; +- constraints affecting the implementation; +- non-obvious behavior; +- security considerations; +- compatibility requirements; +- external requirements; +- important assumptions; and +- references to ADRs or other governing documentation. + +Do not use comments as a substitute for making unnecessarily confusing code understandable. + +## Errors Are Part of the Interface + +Error behavior should be deliberate. + +A function should make failures visible according to the conventions of its language and project. + +Do not silently ignore errors unless ignoring the error is intentional, safe, and evident from the surrounding context. + +Error handling should preserve sufficient context to determine: + +- what operation failed; +- why it failed, when known; and +- what the caller can reasonably do about the failure. + +## Optimize for Reading + +Code is generally read more often than it is written. + +Optimize primarily for the developer who must understand the code later, including a developer who did not write it. + +That developer may be: + +- another contributor; +- a reviewer; +- an operator investigating an incident; +- an automated development agent; or +- the original author months or years later. + +Prefer code whose purpose and behavior can be determined locally without requiring unnecessary exploration of the codebase. + +## Guidance for Automated Agents + +When generating, modifying, or reviewing code: + +1. Identify the responsibility of each function being changed. +2. Avoid introducing functions with multiple independent responsibilities. +3. Separate state-changing commands from observational queries when practical. +4. Keep each function at a reasonably consistent level of abstraction. +5. Make side effects and state changes visible. +6. Prefer descriptive names over generic names. +7. Preserve straightforward control flow. +8. Avoid introducing unnecessary parameters or ambiguous Boolean arguments. +9. Remove duplication when the duplicated code represents the same underlying concept. +10. Do not create abstractions solely to eliminate superficial similarity. +11. Treat error behavior as part of the function's contract. +12. Prefer readability and inspectability over cleverness or minimal line count. +13. Preserve existing public interfaces and compatibility requirements unless the requested work explicitly changes them. +14. Follow repository governance, ADRs, and language-specific standards when they differ from this general guidance. +15. Do not expand the scope of a change merely to clean unrelated existing code. + +When a requested implementation appears to conflict with these principles, prefer an implementation that satisfies both the requested behavior and this standard. If a material conflict cannot be resolved without changing an established contract, architecture, or requirement, identify the conflict rather than silently changing that contract. + +## Review Questions + +When reviewing code, consider: + +- Can I describe each function's responsibility in one concise statement? +- Does a function both ask a question and change state unexpectedly? +- Are important side effects evident? +- Does the function stay at a reasonably consistent level of abstraction? +- Do names describe intent? +- Is the primary control flow easy to follow? +- Are errors handled deliberately? +- Does duplicated code represent genuinely duplicated knowledge? +- Would extracting code create a meaningful abstraction or merely move lines elsewhere? +- Can another developer understand the reason for unusual implementation decisions? +- Is the code more complex than the problem requires? + +These questions are heuristics. They should support engineering judgment rather than replace it. + +## Examples + +Language-specific examples demonstrating applications of this standard are maintained separately: + +- [Bash examples](../examples/general/clean-coding/bash.md) + +Examples are illustrative rather than normative. Where an example conflicts with this standard, this standard governs. + +## Further Reading + +The following sources provide additional background for the principles described in this standard: + +- Robert C. Martin, *Clean Code: A Handbook of Agile Software Craftsmanship*. In particular, see the material concerning functions, naming, comments, formatting, error handling, and software design principles. +- Bertrand Meyer, *Object-Oriented Software Construction*. Meyer introduced the Command-Query Separation principle. +- Martin Fowler, "Command Query Separation." Fowler provides a concise explanation of CQS, its purpose, and situations in which strict separation may not be desirable. +- Robert C. Martin's writings on the Single Responsibility Principle and the SOLID design principles. +- Architecture Decision Records maintained by the project for decisions that constrain or intentionally depart from general coding guidance. + +## Summary + +Prefer code that: + +- does one thing at a time; +- separates questions from state changes; +- maintains consistent levels of abstraction; +- makes side effects visible; +- names things according to their purpose; +- favors explicit, readable behavior; +- handles errors deliberately; and +- minimizes the amount of context required to understand it. + +Clean code is not code that conforms mechanically to a collection of rules. It is code whose purpose, behavior, constraints, and consequences are readily understandable by the people and systems responsible for maintaining it. diff --git a/doc/standards/general/conventional-commit-release-governance.md b/doc/standards/general/conventional-commit-release-governance.md new file mode 100644 index 0000000..08f7da2 --- /dev/null +++ b/doc/standards/general/conventional-commit-release-governance.md @@ -0,0 +1,324 @@ +# Conventional Commit and Release Versioning Governance + +## Status + +Recommended repository governance + +## Purpose + +This document defines repository-level governance for commit titles, pull request titles, merge commit titles, and semantic release classification. Its purpose is to make release intent explicit, reviewable, deterministic, and resistant to accidental or externally influenced version changes. + +Repositories adopting this document SHOULD treat it as governing policy unless a repository-specific ADR, policy, or release standard explicitly supersedes it. + +## Goals + +This policy is intended to: + +- make semantic release intent visible before merge; +- ensure the highest-impact change in a pull request determines the release significance; +- separate advisory issue metadata from trusted release inputs; +- support repositories that use squash merges, merge commits, or other merge strategies; +- encourage consistent Conventional Commit usage throughout development history; and +- prevent release classification from being derived implicitly from untrusted or ambiguous metadata. + +## Normative Language + +The terms MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as normative requirements. + +## Trust Boundary + +Issue titles, issue labels, issue comments, issue descriptions, and other issue metadata MUST be treated as advisory input only for release classification. + +Issue metadata MAY originate from, or be influenced by, external contributors, automated systems, imported content, triage workflows, or other actors outside the release decision itself. For that reason, issue metadata MUST NOT directly control semantic version increments. + +For example, an issue carrying an `enhancement` label MAY suggest that a `feat:` classification is appropriate. The label itself MUST NOT cause a minor release. A maintainer, reviewer, or trusted automation acting within the repository's normal review process MUST make the release-significance decision explicitly. + +Issue metadata MAY be used as a prompt for review. Tooling MAY warn that an issue labeled `enhancement` appears inconsistent with a patch-level pull request title, but tooling SHOULD require an explicit trusted classification before changing release behavior. + +## Conventional Commit Titles + +Repositories adopting this policy SHOULD use Conventional Commit-style titles throughout development. + +At minimum, pull request titles and the final commit title placed on the release branch MUST use an approved Conventional Commit classification. + +Examples include: + +```text +feat: add manifest update support +fix: reject malformed dependency entries +docs: describe release verification +test: cover empty manifest behavior +refactor: separate transport and validation logic +chore: update development tooling +``` + +Repositories MAY support additional Conventional Commit types when their release tooling recognizes them. + +### Breaking Changes + +Breaking changes MUST be declared explicitly. + +For maximum compatibility with release tooling, repositories SHOULD use a form that their versioning implementation is known to recognize. When compatibility is uncertain, the following form is preferred: + +```text +BREAKING CHANGE: revise manifest grammar +``` + +Repositories MAY use other Conventional Commit breaking-change syntax, such as `feat!:` or a `BREAKING CHANGE:` footer, only when the repository's release tooling is documented and tested to recognize that form. + +## Semantic Significance + +A pull request MUST be classified according to the highest semantic significance of any change it contains. + +The precedence is: + +1. breaking change; +2. backward-compatible feature; +3. patch-level change. + +A later patch-level commit MUST NOT reduce the release significance of an earlier feature or breaking change within the same pull request. + +For example, a pull request containing: + +```text +feat: add manifest manager +test: cover manifest manager behavior +fix: handle empty destination paths +docs: document manifest manager usage +``` + +is still a feature-bearing pull request. Its pull request title SHOULD therefore be: + +```text +feat: add manifest manager +``` + +Likewise, a pull request containing a breaking change together with features, fixes, tests, or documentation MUST be classified as a breaking change. + +## Pull Request Titles + +The pull request title MUST express the highest semantic significance of the complete pull request. + +The pull request title is the repository's reviewed declaration of release intent. It SHOULD remain accurate as the pull request evolves. + +If implementation work changes the semantic significance of the pull request, the pull request title MUST be updated before merge. + +Examples: + +```text +docs: explain checksum verification +``` + +```text +fix: preserve comments in generated artifacts +``` + +```text +feat: add offline dependency verification +``` + +```text +BREAKING CHANGE: remove legacy manifest syntax +``` + +Pull request titles SHOULD be reviewed with the same care as code changes because they may become release inputs. + +## Merge Strategy + +Repositories SHOULD prefer squash merges when practical. + +Squash merging provides a useful release boundary because one reviewed pull request becomes one commit on the target branch. This makes the pull request title a natural place to express the semantic significance of the complete change. + +When squash merging is used, the resulting squash commit title MUST carry the same semantic classification as the pull request. + +Repositories SHOULD configure their hosting platform so the pull request title becomes, or is used to form, the squash commit title when practical. Maintainers MUST verify the final commit title before completing the merge when the platform may generate a different title. + +### Repositories That Do Not Use Squash Merges + +Squash merging is preferred, but this policy does not require it. + +When a repository uses a traditional merge commit, the merge commit title that lands on the release branch MUST express the highest semantic significance of the pull request. + +A default merge title such as: + +```text +Merge pull request #123 from example/feature-branch +``` + +is unsuitable when release tooling derives semantic significance from the final commit title. + +Instead, the merge commit title SHOULD preserve the pull request's Conventional Commit classification, for example: + +```text +feat: add offline dependency verification +``` + +When a repository uses rebase merging or another strategy that places multiple commits directly onto the target branch, its release tooling MUST be designed so that semantic significance is deterministic. The repository SHOULD either: + +- calculate the highest semantic significance across all commits introduced by the pull request; or +- establish another explicitly governed release-classification mechanism. + +A repository MUST NOT depend on whichever commit happens to be last when that ordering can cause a lower-significance change to override a higher-significance change in the same pull request. + +## Commit Titles Within a Pull Request + +Individual commits SHOULD also follow Conventional Commit conventions. + +This improves reviewability, intermediate history, generated release notes, debugging, and maintenance. It also helps tools and reviewers understand the purpose of each change. + +Individual commit titles inside a pull request MUST NOT be assumed to control the final release version unless the repository's release tooling explicitly operates on those commits. + +The pull request title and final target-branch commit remain the authoritative declarations under this policy. + +## Release Classification + +Repositories SHOULD map semantic classifications to Semantic Versioning as follows: + +| Change classification | Typical Conventional Commit indicator | SemVer significance | +| --- | --- | --- | +| Breaking change | `BREAKING CHANGE:` or repository-supported equivalent | Major | +| Backward-compatible feature | `feat:` | Minor | +| Backward-compatible fix or maintenance | `fix:`, `docs:`, `test:`, `chore:`, and similar repository-supported types | Patch | + +Repositories operating in `0.x.y` development versions MAY define a different breaking-change policy when appropriate. Any such policy MUST be explicit and documented. + +Unknown or unrecognized commit prefixes SHOULD NOT silently request a minor or major release. Repositories SHOULD either reject unrecognized release titles or treat them according to a documented conservative fallback. + +## Guidance for Automated Tools and Agents + +Automated tools, coding agents, and repository assistants MUST treat issue metadata as untrusted advisory data for release classification. + +They MAY consider labels, issue wording, milestones, or comments when evaluating likely release significance. They MUST independently classify the implemented change and MUST express that classification through the governed pull request title or merge title. + +For example: + +- an issue labeled `enhancement` MAY suggest `feat:`; +- an issue labeled `bug` MAY suggest `fix:`; +- a label MUST NOT be copied mechanically into a release classification; +- discovered breaking behavior MUST take precedence over labels suggesting a lower-impact change; and +- the final pull request title MUST reflect the highest semantic significance of the complete implementation. + +Agents SHOULD use Conventional Commit titles for intermediate commits unless repository governance explicitly allows otherwise. + +Before opening or updating a pull request, automated tooling SHOULD review the complete change set and choose the highest applicable semantic classification. + +## Examples + +### Feature Followed by a Bug Fix + +Development history: + +```text +feat: add manifest manager +fix: handle an empty manifest +``` + +Pull request title: + +```text +feat: add manifest manager +``` + +Expected release significance: minor. + +The later `fix:` commit does not reduce the pull request's feature-level significance. + +### Documentation Added During a Feature + +Development history: + +```text +feat: add dependency pin verification +docs: describe pin verification +``` + +Pull request title: + +```text +feat: add dependency pin verification +``` + +Expected release significance: minor. + +### Breaking Change With Follow-Up Fixes + +Development history: + +```text +feat: redesign manifest parser +fix: preserve escaped delimiters +test: cover migration behavior +``` + +If the redesign breaks compatibility, the pull request title must reflect that higher significance: + +```text +BREAKING CHANGE: redesign manifest parser +``` + +Expected release significance: major, subject to any explicit `0.x.y` repository policy. + +### Misleading Issue Label + +Issue metadata: + +```text +label: enhancement +``` + +Implementation outcome: + +```text +fix: prevent duplicate dependency downloads +``` + +The pull request SHOULD remain patch-level if the completed work introduces no new backward-compatible functionality. The issue label is advisory and does not override the actual change. + +### Unlabeled Feature + +Issue metadata: + +```text +label: none +``` + +Implementation outcome: + +```text +feat: add offline verification mode +``` + +The pull request MUST be classified as a feature even though no issue label requested that classification. + +## Review Checklist + +Before merging a pull request, reviewers SHOULD verify that: + +- the pull request title follows the repository's Conventional Commit convention; +- the title reflects the highest semantic significance of the complete change; +- issue labels or other external metadata have not been treated as authoritative release inputs; +- any breaking change is declared using syntax recognized by the repository's release tooling; +- the final merge or squash commit title preserves the intended classification; and +- the expected semantic version increment matches the reviewed change. + +## Repository Adoption + +A repository adopting this policy SHOULD: + +1. document its supported Conventional Commit types; +2. document which title or commit the release workflow inspects; +3. prefer squash merging when practical; +4. configure squash commit titles to preserve pull request titles when supported; +5. ensure traditional merge commits preserve semantic classification when they are allowed; +6. validate pull request titles before merge when practical; and +7. test release automation so feature, patch, and breaking classifications produce the expected version increments. + +Repository-specific governance MAY strengthen these requirements. Any exception that changes the authoritative release signal or semantic precedence SHOULD be documented explicitly, preferably through the repository's established architecture or governance decision process. + +## Governing Principle + +Release significance is a reviewed project decision. + +External metadata may inform that decision. It does not make the decision. + +The pull request and the commit placed on the release branch MUST communicate the highest semantic significance of the complete change in a form that the repository's release tooling recognizes. diff --git a/doc/standards/general/development-workflow-governance.md b/doc/standards/general/development-workflow-governance.md new file mode 100644 index 0000000..5f97298 --- /dev/null +++ b/doc/standards/general/development-workflow-governance.md @@ -0,0 +1,547 @@ +# Development Workflow and Backlog Governance + +## Status + +Recommended repository governance + +## Purpose + +This document defines repository-level governance for controlling development +scope, capturing newly discovered ideas, structuring changes for review, and +maintaining a reviewable backlog. Its purpose is to preserve task boundaries, +planning visibility, and team-style engineering discipline even when a project is +maintained by one person or worked on as a hobby. + +Repositories adopting this document SHOULD treat it as governing policy unless a +repository-specific ADR, policy, security process, or other explicit governance +supersedes it. + +## Goals + +This policy is intended to: + +- keep in-flight work aligned with the task that authorized it; +- prevent unrelated ideas from silently expanding the scope of active work; +- ensure useful development ideas are captured rather than forgotten; +- keep future work visible, prioritizable, and reviewable in the backlog; +- make scope decisions explicit when reasonable people could classify an idea + differently; +- prefer surgical changes over opportunistic cleanup or expansion; +- use small, focused commits as understandable review units; +- collect related commits into cohesive, easily reviewed pull requests; +- make pull request readiness an explicit project signal; +- avoid stacked pull requests in repositories that use squash merging; +- give humans and automated coding agents the same expectations for scope control; + and +- encourage professional team practices regardless of project size or staffing. + +## Normative Language + +The terms MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as +normative requirements. + +## Professional Team Model + +A repository SHOULD be operated as though multiple professional contributors may +need to understand, review, prioritize, continue, or audit the work later. + +This expectation applies even when: + +- the repository is a hobby project; +- only one maintainer currently works on the project; +- an automated coding agent performs most or all implementation work; +- a change appears small enough that adding it opportunistically would be + convenient; or +- the maintainer already understands the surrounding context without written + documentation. + +Individual familiarity with a project is not a substitute for visible scope, +recorded decisions, and a maintained backlog. + +## Authorized Task Scope + +Development work MUST remain within the scope of the currently authorized task. + +The active task may be defined by one or more of the following: + +- a GitHub issue; +- a pull request description; +- explicit maintainer instructions; +- acceptance criteria; +- an ADR or other governing decision; +- a bug report; +- a planned maintenance item; or +- another repository-recognized work item. + +Implementations MAY include work that is reasonably necessary to complete the +current task correctly, including required tests, documentation, compatibility +adjustments, error handling, and directly necessary supporting changes. + +Work MUST NOT be added merely because it is nearby, interesting, cleaner, or +convenient while the relevant files are already being modified. + +## Surgical Changes + +Changes SHOULD be surgical: focused specifically on the request and the active +task, with the smallest practical set of modifications needed to satisfy the +established contract correctly. + +A surgical change is not necessarily a tiny change. It is a change whose parts +are all relevant to the task and whose scope can be explained coherently. +Required tests, documentation, compatibility work, and supporting implementation +remain appropriate when they are necessary to complete the task correctly. + +Contributors SHOULD avoid unrelated: + +- cleanup; +- formatting churn; +- renaming; +- modernization; +- dependency updates; +- refactoring; +- feature additions; and +- architectural changes. + +When one of those changes is independently valuable but unnecessary to the active +task, capture it in the backlog instead of expanding the implementation. + +## New Ideas Discovered During Development + +A development idea discovered while working on an active task MUST be evaluated +against the current task's scope before implementation. + +If the idea is outside the current task, it SHOULD be recorded as a separate issue +in the repository backlog rather than incorporated into the in-flight change. + +Examples include: + +- a useful feature unrelated to the current acceptance criteria; +- a refactoring opportunity that is not necessary for the requested behavior; +- a documentation improvement outside the area being changed; +- a performance optimization discovered while fixing a correctness bug; +- a tooling enhancement that would make future work more convenient; +- a cleanup opportunity in adjacent files; or +- a broader architectural improvement exposed by a narrow implementation task. + +Capturing an idea in the backlog does not imply that it will be implemented. It +means the idea remains visible so it can be reviewed, prioritized, refined, +rejected, or scheduled deliberately. + +## When Scope Is Ambiguous + +When it is genuinely unclear whether a newly discovered idea belongs in the +current task or should become a separate backlog item, the implementer MUST ask +for clarification before materially expanding the active task. + +The question should identify: + +- the newly discovered work; +- why it may be relevant to the current task; +- why it may represent separate scope; and +- the practical consequence of including or deferring it. + +A coding agent MUST NOT resolve material scope ambiguity by silently choosing the +larger implementation. + +If immediate clarification is unavailable and the current task can be completed +without the additional work, the conservative default is to preserve the current +task boundary and record the idea in the backlog. + +## Necessary Work Versus New Scope + +Not every newly discovered change is separate scope. + +Work normally remains part of the current task when it is necessary to satisfy the +established contract of that task. Examples include: + +- adding tests required to demonstrate the requested behavior; +- updating documentation made inaccurate by the current change; +- fixing a directly introduced regression; +- preserving an existing public interface while implementing the task; +- handling an error path required for the requested behavior to be correct; or +- making a narrowly necessary compatibility change without which the task cannot + function as specified. + +Work is more likely to be separate scope when the current task can be completed +correctly without it and the work introduces a distinct capability, policy, +refactoring objective, architectural decision, or maintenance concern. + +The size of a change is not the deciding factor. A one-line unrelated cleanup may +still be out of scope, while a larger supporting change may be necessary to fulfill +the active task correctly. + +## Backlog Issues + +A backlog issue SHOULD contain enough information for another contributor to +understand why the work was captured and decide what to do with it later. + +Where practical, include: + +- a concise description of the idea or problem; +- relevant context explaining where it was discovered; +- the expected value or reason for considering the work; +- known constraints or dependencies; +- links to related issues, pull requests, ADRs, or source locations; and +- any important distinction between the backlog item and the task during which it + was discovered. + +A backlog issue SHOULD describe the problem or desired outcome without prematurely +committing the project to a particular implementation unless that implementation +has already been decided through normal governance. + +## Commits + +Implementation work SHOULD be divided into small, focused commits when doing so +makes the development history easier to understand, inspect, review, test, or +revise. + +Each commit SHOULD represent one coherent step in the implementation. A commit +should be understandable on its own within the context of the active task and +should avoid mixing unrelated concerns merely to reduce the number of commits. + +Small commits are review structure, not a requirement to fragment naturally +atomic changes. A change that must move together to remain valid SHOULD remain +cohesive. + +Repositories SHOULD follow their governing commit-message convention, including +Conventional Commit requirements where applicable. + +Because adopting repositories use squash merges under this policy, intermediate +commits primarily support development and review. The final squash commit and its +pull request title represent the integrated change on the target branch. + +## Pull Requests + +A pull request SHOULD remain cohesive around its declared purpose and SHOULD be +sized so that another contributor can review it without reconstructing unrelated +workstreams. + +Related focused commits SHOULD be collected into one sensible pull request when +they collectively implement the same task. Splitting one task across several pull +requests solely to make each pull request smaller SHOULD be avoided when doing so +creates ordering dependencies or obscures the complete change. + +Newly discovered backlog items SHOULD NOT be folded into the pull request merely to +avoid opening another issue or future pull request. + +When an out-of-scope issue is discovered during pull request work, the pull request +MAY reference the new issue when that context helps reviewers understand what was +intentionally deferred. + +A reviewer SHOULD be able to determine which requirements the pull request intends +to satisfy without separating unrelated opportunistic changes from the primary +work. + +## Draft and Ready-for-Review Lifecycle + +New pull requests SHOULD be opened in draft mode. + +Draft status communicates that implementation, verification, documentation, +cleanup, or author review may still be in progress. A draft pull request MAY be +read, discussed, or inspected, but reviewers and maintainers SHOULD NOT interpret +its existence as a request to perform final review or merge it. + +Transitioning a pull request from Draft to Ready for review is an explicit project +signal. Once marked Ready for review, the author is declaring that: + +- the requested work is complete for the intended scope; +- the pull request description accurately represents the change; +- required verification has been performed to the extent available; +- known relevant documentation has been updated; +- the pull request is ready for normal review; and +- the pull request may be merged at any time once repository checks, review + requirements, and other merge gates are satisfied. + +A pull request SHOULD NOT be marked Ready for review merely to solicit preliminary +feedback while substantial known implementation work remains. Discussion during +implementation belongs on the draft pull request, issue, or other project channel. + +If substantive new work makes a Ready pull request incomplete again, the pull +request SHOULD return to draft status when the hosting platform and permissions +permit it. + +## Squash Merges + +Repositories adopting this workflow SHOULD use squash merges unless explicit +repository-specific governance establishes a different merge strategy. + +Under squash merging, the pull request is the primary integration unit. The +individual development commits remain useful for review and iteration, while the +final squash commit provides one coherent target-branch change representing the +completed pull request. + +The squash commit title MUST comply with the repository's governing release and +commit-title conventions. When Conventional Commit release governance applies, +the pull request title and resulting squash commit MUST preserve the reviewed +semantic classification of the complete change. + +## Do Not Stack Pull Requests + +Pull requests MUST NOT normally be stacked on top of unmerged pull requests. + +Each pull request SHOULD branch from and target the repository's normal integration +branch, usually the default branch, so that it can be reviewed, tested, merged, or +abandoned independently. + +A pull request SHOULD NOT depend on commits that exist only in another open pull +request. Such dependencies make the effective diff contingent on merge order, +complicate review, obscure which pull request owns a change, and work against the +single-integration-unit model created by squash merging. + +When later work genuinely depends on an unmerged pull request, prefer one of these +approaches: + +1. wait for the prerequisite pull request to merge, then branch from the updated + integration branch; +2. capture the dependent work in the backlog until the prerequisite is available; + or +3. ask the maintainer when sequencing materially affects delivery or correctness. + +An explicit repository-specific workflow MAY permit stacked pull requests, but +that exception SHOULD be deliberate and documented rather than inferred from +convenience. + +## Relationship to Architecture Decisions + +A newly discovered idea that would introduce meaningful architecture, interface, +compatibility, security-boundary, persistence, deployment, or other consequential +behavior MAY require an ADR before implementation according to the repository's +architecture governance. + +Creating a backlog issue does not replace an ADR when an architectural decision is +required. The issue records work to be considered; the ADR records the decision +that governs how consequential work will be performed. + +## Security-Sensitive Findings + +Security-sensitive findings MUST follow the repository's security reporting and +handling policy. + +A public backlog issue MUST NOT be created when doing so would disclose a +vulnerability, secret, exploit path, sensitive configuration, or other information +that the repository's security policy requires to remain private. + +The scope-control principle still applies: unrelated security remediation should +not be silently mixed into ordinary work. However, the finding must be captured +through the appropriate secure process rather than the normal public backlog. + +If a security finding creates an immediate risk that materially affects whether +the active task can proceed safely, the implementer SHOULD stop and escalate the +finding according to repository policy. + +## Defects Discovered During a Task + +A defect discovered during development is not automatically part of the current +task merely because the defect appears in code being touched. + +The defect MAY be fixed within the current task when: + +- the active change introduced the defect; +- the defect prevents the requested work from functioning correctly; +- the task explicitly includes correcting that behavior; or +- leaving the defect unresolved would make the completed change knowingly unsafe + or invalid under an established project contract. + +Otherwise, the defect SHOULD normally be captured as a separate backlog issue. + +When the distinction is unclear and resolving it would materially affect scope, +ask before proceeding. + +## Refactoring and Cleanup + +Refactoring, formatting, renaming, modernization, dependency changes, and cleanup +SHOULD be limited to what the active task requires. + +Do not broaden an implementation to clean surrounding code merely because the +opportunity is visible. + +A useful refactoring or cleanup idea discovered during an unrelated task SHOULD be +recorded as a backlog issue when it is worth preserving. + +Small mechanical changes MAY remain in scope when they are necessary to make the +requested modification safe, understandable, testable, or compliant with governing +standards. + +## Guidance for Automated Tools and Agents + +Automated tools, coding agents, and repository assistants MUST preserve task scope +as deliberately as human contributors. + +When working on a repository, an agent SHOULD: + +1. identify the current task and its acceptance criteria before implementation; +2. distinguish required supporting work from newly discovered independent work; +3. prefer surgical changes that avoid unrelated cleanup, features, refactoring, + or architectural work; +4. organize implementation into small, focused commits when that improves + inspectability and review; +5. collect those commits into a cohesive pull request for the task; +6. open new pull requests in draft mode; +7. mark a pull request Ready for review only when it can be reviewed and merged at + any time once normal repository gates are satisfied; +8. avoid stacking a pull request on another unmerged pull request; +9. capture valuable out-of-scope ideas as backlog issues when repository access + permits; +10. link backlog issues to the context in which they were discovered when useful; +11. ask when a material idea could reasonably belong either to the active task or + to the backlog; +12. prefer the narrower task boundary when clarification is unavailable and the + task can be completed correctly without expansion; +13. follow private security-reporting procedures instead of public issue creation + for sensitive findings; +14. avoid assuming that a maintainer's hobby project permits lower process + discipline; and +15. preserve enough written context that another contributor or later agent can + understand why work was included, deferred, or separated. + +An agent MUST NOT treat autonomy as permission to expand scope silently. + +## Examples + +### Adjacent Feature Idea + +Current task: + +```text +Fix incorrect parsing of empty configuration values. +``` + +While implementing the fix, the contributor notices that environment-variable +interpolation would be useful. + +Environment-variable interpolation is a separate feature. The parsing fix should +remain focused, and the interpolation idea should be captured as a backlog issue. + +### Required Supporting Test + +Current task: + +```text +Reject malformed dependency declarations. +``` + +The existing test suite has no malformed-input coverage. Adding focused tests for +the newly required rejection behavior is part of the current task because those +tests provide evidence that the requested behavior works. + +### Unrelated Cleanup + +Current task: + +```text +Document the release checksum format. +``` + +While editing the document, the contributor notices inconsistent headings in a +separate maintenance guide. The heading cleanup is not necessary to document the +checksum format and should not be added opportunistically. If worth preserving, +it should become a backlog issue. + +### Ambiguous Refactoring + +Current task: + +```text +Add support for a second output format. +``` + +The existing serializer can technically support the change, but extracting a +shared serialization abstraction may make the implementation substantially easier +to maintain. If the abstraction is a material design change and it is unclear +whether it belongs in the task, ask before expanding the implementation. + +### Dependent Follow-Up Work + +Pull request A introduces a new manifest parser and has not yet merged. A separate +idea would add a reporting feature that depends on that parser. + +Do not branch pull request B from pull request A merely to begin the reporting +feature immediately. Record the reporting work in the backlog or wait for pull +request A to merge, then create the follow-up branch from the updated integration +branch. + +### Draft Pull Request + +An agent has implemented most of a task but still needs to finish tests and update +usage documentation. The pull request may remain open in draft mode so its work +is visible and discussion can occur. + +Once the implementation, verification, and documentation are complete, the agent +marks the pull request Ready for review. That transition means a maintainer may +review and merge it whenever the repository's normal gates permit. + +### Security Finding + +Current task: + +```text +Improve command help text. +``` + +The contributor notices a possible credential exposure path in unrelated logging +code. The finding should not be added as a public backlog issue when disclosure +would create risk. It should be reported through the repository's security +process and escalated according to that policy. + +## Review Checklist + +Before marking a pull request Ready for review or approving it, reviewers SHOULD +verify that: + +- the change remains aligned with the declared task; +- the implementation is surgical and avoids unrelated modifications; +- commits are focused and understandable where multiple commits are used; +- the pull request is cohesive and independently reviewable; +- the pull request does not depend on an unmerged stacked pull request; +- required supporting changes are distinguishable from unrelated improvements; +- unrelated ideas discovered during development have not been silently included; +- worthwhile deferred ideas have been captured in the backlog where appropriate; +- any material scope ambiguity was resolved explicitly; +- security-sensitive findings were handled through the appropriate process; +- architectural decisions were not smuggled into implementation without required + governance; and +- Ready-for-review status accurately means the pull request can be reviewed and + merged once normal repository gates are satisfied. + +## Repository Adoption + +A repository adopting this policy SHOULD: + +1. maintain an issue tracker or equivalent visible backlog for deferred work; +2. make the active task identifiable through issues, pull requests, maintainer + instructions, or another reviewable mechanism; +3. tell contributors and coding agents to preserve task boundaries and prefer + surgical changes; +4. require clarification when material scope is ambiguous; +5. maintain a security reporting path for findings that must not enter the public + backlog; +6. use small, focused commits where they improve development and review; +7. collect related commits into cohesive pull requests; +8. open pull requests in draft mode and use Ready for review as the explicit + review-and-merge signal; +9. use squash merges unless repository-specific governance says otherwise; +10. avoid stacked pull requests and branch new work from the normal integration + branch; and +11. treat backlog hygiene as normal engineering work rather than optional project + administration. + +Repository-specific governance MAY define additional triage states, issue labels, +project boards, planning workflows, merge requirements, or thresholds for when a +new issue is required. Those refinements should preserve the core principles that +independent development ideas remain visible and separately reviewable, active +changes stay focused, and pull request state communicates readiness clearly. + +## Governing Principle + +The current task defines what is being changed now. The backlog preserves what may +be changed later. + +Make the current change surgical, organize it so another contributor can review it, +and use the pull request lifecycle to communicate whether the work is still in +progress or ready to merge. + +When a useful idea falls outside the current task, record it rather than losing it +or silently expanding scope. When the boundary is materially uncertain, ask. + +Professional engineering discipline is valuable even when the entire team is one +person. diff --git a/doc/standards/javascript/documentation-standard.md b/doc/standards/javascript/documentation-standard.md new file mode 100644 index 0000000..a102c17 --- /dev/null +++ b/doc/standards/javascript/documentation-standard.md @@ -0,0 +1,480 @@ +# JavaScript Documentation Standard + +This document defines the normative source-documentation standard for maintained +JavaScript files in projects that adopt it. The standard deliberately prefers +verbose, explanatory documentation. Source brevity is not a goal when brevity +would force a future maintainer to infer intent, contracts, assumptions, failure +semantics, state ownership, compatibility constraints, security boundaries, or +architectural relationships from executable code alone. + +This standard uses JavaScript-native JSDoc comments as the maintained source of +truth. It is intentionally compatible with JSDoc tooling and is designed to +support Doxygen reference generation through the +[`javascript-doxygen`](https://github.com/wesley-dean/javascript-doxygen) input +filter where translation is required. + +The standard does not require maintainers to write a second Doxygen-specific +comment dialect beside JSDoc. Maintained JavaScript should remain idiomatic +JavaScript, and compatibility translation belongs at the documentation-generation +boundary. + +Prefer thorough, detailed commentary over terse tag-only documentation. The goal +is for the source to remain understandable to a human new to the project and to an +AI/LLM operating with focused context that may not retain the complete project +history. + +## Precedence + +Repository-specific requirements, accepted Architecture Decision Records (ADRs), +documented public interfaces, compatibility requirements, security requirements, +and project-specific JavaScript standards take precedence over this standard. + +Do not perform unrelated documentation rewrites or refactoring solely to bring +existing code into compliance unless that work is part of the requested scope. + +## Maintained Source of Truth + +JSDoc comments are the maintained source of truth for generated JavaScript API +reference documentation. + +Do not maintain a second Doxygen-specific documentation block beside a JSDoc +comment. Do not duplicate parameter, return, exception, yield, type, or behavioral +contracts merely to satisfy Doxygen. + +The maintained source should remain consumable by JavaScript-native tooling without +first passing through `javascript-doxygen`. + +`javascript-doxygen` exists at the documentation-generation boundary. It may +translate governed JSDoc forms into a Doxygen-friendly representation without +changing JavaScript into another maintained source language. + +Conceptually: + +```text +maintained JavaScript source + | + | JSDoc comments + v + javascript-doxygen + | + | Doxygen-compatible translated representation + v + Doxygen +``` + +The generated representation is derivative. It is not a maintained source of +truth and must not be edited as though it were authoritative documentation. + +## JSDoc Comment Syntax + +Documentation comments must use JSDoc-style blocks beginning with exactly `/**`: + +```javascript +/** + * Describe the documented element. + */ +``` + +Place a documentation block immediately before the declaration or element it +documents unless a specific JSDoc construct intentionally documents a virtual or +otherwise non-adjacent symbol. + +Use a concise summary followed by a blank line and substantive explanatory prose +when more context is required: + +```javascript +/** + * Load and validate application configuration. + * + * Explain the boundary owned by this function, validation policy, caller-visible + * failure behavior, side effects, and assumptions that callers must preserve. + */ +``` + +Documentation lines should normally remain within the project's configured line +length. When no stricter project rule exists, prefer 80-character documentation +lines where practical. Long URLs, literal values, generated identifiers, type +expressions, and other unbreakable content may exceed that limit. + +Ordinary `/* ... */` comments and `//` comments are not substitutes for JSDoc when +an API element requires structured documentation. + +## Baseline Tag Vocabulary + +The baseline structured vocabulary should use standard JSDoc tags wherever +practical. The core contract tags are: + +```text +@param +@returns +@throws +@yields +@type +@typedef +@callback +@property +@see +@deprecated +``` + +Other standard JSDoc tags may be used when they communicate information that +belongs in the maintained contract. Projects may establish narrower or broader +tag policies through repository-specific governance. + +A tag should communicate information that belongs in the source contract. Do not +add tags merely because a documentation engine recognizes them. + +## Type Expressions + +JSDoc type expressions must be enclosed in braces when a tag carries an explicit +type: + +```text +{string} +{number} +{Configuration} +{Promise} +{Array} +{string|URL} +``` + +Use the project's established JSDoc type-expression conventions consistently. +The documentation type must not contradict the executable contract. + +JavaScript's runtime does not enforce JSDoc types. Static validation, where +required, belongs to configured JavaScript tooling such as TypeScript in +check-JavaScript mode, Closure tooling, ESLint plugins, or other project-specific +analysis. + +This standard does not define TypeScript or TSDoc documentation. A project whose +maintained source is TypeScript should adopt a TypeScript-specific documentation +standard rather than assuming this JavaScript standard applies unchanged. + +## Functions and Methods + +Maintained public and non-trivial functions and methods must document their +interface and non-obvious behavior sufficiently for a caller to use them without +reading the implementation. + +A complete function JSDoc block should generally look like: + +```javascript +/** + * Load and validate application configuration. + * + * Reads the requested configuration document and validates it before returning + * an application configuration object. The function does not modify the source + * file. + * + * @param {string} path - Path to the configuration document. + * @param {boolean} [strict=true] - Whether unknown keys are rejected. + * @returns {Promise} Validated configuration owned by the caller. + * @throws {TypeError} If `path` is not a non-empty string. + */ +async function loadConfiguration(path, strict = true) { + // implementation +} +``` + +Document parameters in declaration order when practical. + +### Parameters + +Use one `@param` tag for each meaningful documented parameter. + +The canonical required-parameter form is: + +```text +@param {Type} name - Description. +``` + +For example: + +```text +@param {string} path - Filesystem path interpreted relative to the project root. +``` + +The type expression is enclosed in braces, followed by the parameter name, a +space-hyphen-space separator, and substantive description text. + +The hyphen is part of the preferred maintained-source form because it clearly +separates the parameter declaration from descriptive prose and follows ordinary +JSDoc usage. + +Optional parameters use square brackets around the parameter name: + +```text +@param {boolean} [strict] - Whether unknown keys are rejected. +``` + +When a meaningful default belongs in the documentation contract, it may be +included in the bracketed name: + +```text +@param {boolean} [strict=true] - Whether unknown keys are rejected. +``` + +Do not document a parameter as optional merely because the implementation happens +to tolerate `undefined`; optionality is part of the caller-visible contract. + +Parameter descriptions should explain meaning that the type alone cannot express, +including as applicable: + +- allowed values or ranges; +- units; +- sentinel meanings such as `null` or `undefined`; +- mutability and ownership; +- whether an object or array may be modified; +- path interpretation; +- encoding assumptions; +- ordering requirements; +- callback lifecycle; +- whether a callback may be retained or invoked asynchronously; +- whether an iterable is consumed; and +- security-sensitive interpretation. + +Rest parameters should document the declared rest name and the semantics of the +collected values rather than merely saying "additional arguments." + +Destructured parameters require enough documentation to make the caller-visible +shape clear. Projects may use JSDoc property notation, a named `@typedef`, or +another standard JSDoc form when that communicates the contract more clearly than +an artificial synthetic parameter name. + +### Return Values + +Use `@returns` for meaningful return values: + +```text +@returns {Configuration} Validated configuration owned by the caller. +``` + +The preferred form is: + +```text +@returns {Type} Description. +``` + +Use `@returns` rather than `@return` in maintained source for consistency, even +though JSDoc recognizes both forms. + +The description must explain semantics rather than merely repeat the type. State +ownership, aliasing, special values, ordering, normalization, caching, laziness, +or other caller-visible behavior when those details matter. + +For asynchronous functions, document the resolved value through an appropriate +promise type when type information is part of the maintained contract: + +```text +@returns {Promise} Validated configuration owned by the caller. +``` + +Do not describe the promise itself as the useful result when callers primarily +care about its resolved value and rejection semantics. + +A function with no meaningful return value may omit `@returns` unless +project-specific tooling requires explicit documentation. + +### Exceptions and Rejections + +Use `@throws` for caller-visible errors that form part of the meaningful contract: + +```text +@throws {TypeError} If the supplied identifier is not a string. +@throws {RangeError} If the retry count is outside the supported range. +``` + +Document errors callers are expected to understand, handle, or treat as part of +the stable interface. Do not enumerate every implementation-level exception that +could theoretically escape. + +For asynchronous functions, document meaningful rejection conditions using the +project's established JSDoc convention. When `@throws` is used to describe both +synchronous throws and promise rejection conditions, the prose must make the +distinction clear when callers need to know it. + +### Generators and Yields + +Generator functions should document yielded values with `@yields` rather than +misrepresenting them as ordinary return values: + +```text +@yields {Record} Validated records in source order. +``` + +Document whether iteration is lazy, whether resources remain held between yields, +whether partial iteration is safe, what cleanup occurs when iteration stops early, +and how errors surface during iteration when those details matter. + +## Objects, Properties, Typedefs, and Callbacks + +Use `@typedef` when a named reusable documentation type improves clarity for +structured objects or conceptual values that do not have a dedicated runtime +class. + +Use `@property` to document meaningful properties of a documented object type. + +Use `@callback` for callback contracts that deserve a named reusable interface. +Callback documentation should describe parameter semantics, return behavior, +error handling, invocation timing, retention, repetition, and concurrency +expectations when those details matter. + +Use `@type` when documenting the type of a value, property, constant, or other +symbol for which a type expression is part of the maintained contract. + +Prefer named reusable types over repeatedly embedding long structural descriptions +when reuse materially improves readability. Avoid creating a `@typedef` merely to +hide a small, obvious object shape used once. + +## Classes and Constructors + +Public classes must document the abstraction represented by the class, its +responsibilities, important invariants, lifecycle, and meaningful relationships +with collaborators. + +Document constructor parameters using the ordinary `@param` rules when the +constructor accepts caller-supplied arguments. + +Do not restate every method in a class-level comment. Use the class documentation +to explain class-wide behavior that individual method comments cannot express, +such as: + +- ownership of external resources; +- lifecycle and disposal requirements; +- mutability and thread or event-loop assumptions; +- caching behavior; +- persistence boundaries; +- security-sensitive state; and +- relationships with other abstractions. + +## Modules and Files + +Use standard JSDoc module and file documentation when module-level generated +reference documentation is useful to the project. + +Module documentation should explain why the module exists, its architectural role, +important exports, shared state, initialization behavior, external interactions, +portability assumptions, and relevant security boundaries. + +Do not use module tags merely to force a documentation generator into a preferred +layout. Module documentation should correspond to an actual source-level or +architectural concept. + +## Side Effects + +Material side effects must be documented in descriptive prose or in another clear +project-standard form. + +Examples include: + +- modifying caller-supplied objects; +- changing module or process-global state; +- changing environment variables; +- writing files or persistent storage; +- performing network operations; +- invoking subprocesses; +- emitting logs, metrics, or audit records; +- registering or retaining callbacks; +- scheduling asynchronous work; +- acquiring locks or other shared resources; and +- modifying external resources. + +Documentation explains a contract; it does not make an unnecessarily surprising +side effect acceptable. + +## Relationship to `javascript-doxygen` + +[`javascript-doxygen`](https://github.com/wesley-dean/javascript-doxygen) is the +designated Doxygen input-filter project for repositories adopting this standard +when Doxygen requires translation of maintained JSDoc syntax. + +The filter must preserve JavaScript as the filtered source language and should +translate only governed documentation forms at the Doxygen boundary. It is a +documentation translator, not a replacement JavaScript parser, type checker, +linter, or runtime analyzer. + +The filter's implemented support boundary is governed by the +`javascript-doxygen` repository's accepted ADRs and executable regression tests. +Adoption of this standard does not imply that every valid JSDoc construct is +already translated by the filter. + +When a JSDoc form is valid under this standard but unsupported by the current +filter, the filter should prefer visible pass-through or another explicitly +governed false-negative behavior over inventing source semantics it cannot +establish safely. + +The filter must not require maintainers to duplicate the same documentation in +both JSDoc and Doxygen-specific forms. + +### Initial Structured Translation Contract + +The first structured form intended for `javascript-doxygen` support is the +canonical required-parameter syntax: + +```text +@param {Type} name - Description. +``` + +The maintained source remains exactly that JSDoc form. The filter repository is +responsible for governing and testing any Doxygen-facing representation it emits. +This standard deliberately does not make the generated representation part of the +maintained JavaScript source contract. + +Optional/default parameters, return values, exceptions, yields, typedefs, +callbacks, properties, modules, inline tags, and more complex type-expression +forms remain valid JSDoc source constructs where allowed by this standard, but +filter support for them must be claimed only when `javascript-doxygen` has +corresponding executable evidence. + +## Tooling Boundary + +Conformance with this standard is defined by maintained JavaScript source, not by +whether `javascript-doxygen` performs semantic program analysis. + +JavaScript-native tooling remains responsible for semantic checks such as +signature/documentation agreement, type consistency, unreachable or stale +contracts, callback misuse, and other source-language concerns. + +When tooling reports disagreement between code and documentation, treat the +mismatch as a defect to investigate. Do not automatically rewrite the comment to +match the current implementation; the implementation may be the part that has +drifted from the intended contract. + +## Non-Goals + +This standard does not require: + +- converting JavaScript to C or C++ for Doxygen; +- maintaining parallel Doxygen comment blocks; +- inferring undocumented runtime behavior; +- validating arbitrary JSDoc type expressions in the Doxygen filter; +- implementing a complete ECMAScript parser in AWK; +- treating every JSDoc tag as mandatory; or +- applying this JavaScript standard unchanged to TypeScript. + +## Review Checklist + +When reviewing maintained JavaScript documentation, verify that: + +- JSDoc comments begin with `/**` and are attached to the intended symbol; +- summaries explain purpose rather than restating names; +- public and non-trivial interfaces document caller-visible behavior; +- required parameters use `@param {Type} name - Description.` when a type is part + of the documented contract; +- parameter names agree with executable declarations; +- optionality and defaults are documented only when they are part of the public + contract; +- return, throw, and yield documentation describes semantics rather than types + alone; +- material side effects, ownership, lifecycle, and security assumptions are + visible; +- reusable object shapes and callbacks use appropriate JSDoc constructs; +- maintained source does not contain duplicate Doxygen-only documentation; and +- documentation claims remain consistent with executable behavior and repository + governance. + +## References + +- JSDoc documentation: +- JSDoc getting started: +- Doxygen documentation: diff --git a/doc/standards/php/documentation-standard.md b/doc/standards/php/documentation-standard.md new file mode 100644 index 0000000..cdac2ce --- /dev/null +++ b/doc/standards/php/documentation-standard.md @@ -0,0 +1,526 @@ +# PHP Documentation Standard + +This document defines the normative source-documentation standard for maintained +PHP files in projects that adopt it. The standard deliberately prefers verbose, +explanatory documentation. Source brevity is not a goal when brevity would force +a future maintainer to infer intent, contracts, assumptions, failure semantics, +state ownership, compatibility constraints, security boundaries, or architectural +relationships from executable code alone. + +This standard is Doxygen-first. Maintained PHP documentation must be written so +that Doxygen can consume it directly without a translation filter. Compatibility +with phpDocumentor is desirable when it does not weaken, contradict, or complicate +the Doxygen contract. Where Doxygen and phpDocumentor expectations differ, +Doxygen takes precedence. + +The preferred authoring style is therefore the common subset of PHPDoc-style +DocBlocks and Doxygen commands. The goal is one maintained documentation block +that Doxygen can consume natively and that phpDocumentor can also understand in +ordinary cases. + +## Precedence + +Repository-specific requirements, accepted Architecture Decision Records (ADRs), +documented public interfaces, compatibility requirements, security requirements, +and project-specific PHP standards take precedence over this standard. + +Do not perform unrelated documentation rewrites or refactoring solely to bring +existing code into compliance unless that work is part of the requested scope. + +## Tooling Priority + +The tooling priority for this standard is: + +1. Doxygen compatibility is required. +2. phpDocumentor compatibility is preferred when it does not conflict with + Doxygen. +3. If a documentation construct has materially different meanings or syntax in + the two systems, use the Doxygen-compatible form. + +No PHP documentation filter is required by this standard. Maintained PHP source +must remain directly consumable by Doxygen. + +Do not maintain parallel Doxygen and phpDocumentor blocks for the same element. +One DocBlock is the maintained source of truth. + +## DocBlock Syntax + +Use PHPDoc/Javadoc-style documentation blocks: + +```php +/** + * Describe the documented element. + */ +``` + +Use a concise summary followed by a blank line and substantive details when more +explanation is required: + +```php +/** + * Load and validate application configuration. + * + * Explain the boundary owned by this function, validation policy, caller-visible + * failure behavior, side effects, and assumptions that callers must preserve. + */ +``` + +Projects using Doxygen with this standard should enable: + +```ini +JAVADOC_AUTOBRIEF = YES +``` + +This permits the first sentence of a Javadoc-style DocBlock to serve as the brief +description while subsequent prose serves as the detailed description. It also +avoids requiring Doxygen-only `@brief` or `@details` commands in ordinary PHP +DocBlocks. + +Documentation lines should normally remain within the project's configured line +length. When no stricter project rule exists, prefer 80-character documentation +lines where practical. Long URLs, literal values, generated identifiers, and +other unbreakable content may exceed that limit. + +## Baseline Tag Vocabulary + +The baseline documentation vocabulary should remain within the shared, +well-understood PHPDoc/Doxygen subset wherever practical. + +The preferred core tags are: + +```text +@param +@return +@throws +@var +@see +@deprecated +``` + +Other tags may be used when Doxygen supports the intended semantics and the tag is +materially useful. phpDocumentor-specific tags are not automatically prohibited, +but they are outside the baseline standard unless a project-specific requirement +justifies them. + +Do not add a tag merely because one documentation engine recognizes it. The tag +must communicate information that belongs in the maintained contract. + +## Functions and Methods + +Maintained public and non-trivial functions and methods must document their +interface and non-obvious behavior sufficiently for a caller to use them without +reading the implementation. + +A complete function DocBlock should generally look like: + +```php +/** + * Load and validate application configuration. + * + * Reads the requested configuration document and validates it before returning + * an application configuration object. The function does not modify the source + * file. + * + * @param string $path Path to the configuration document. + * @param bool $strict Whether unknown configuration keys are rejected. + * @return Configuration Validated configuration owned by the caller. + * @throws InvalidArgumentException The path or configuration is invalid. + * @throws RuntimeException The configuration cannot be read. + */ +function loadConfiguration(string $path, bool $strict = true): Configuration +{ + // implementation +} +``` + +Document parameters in signature order when practical. + +### Parameters + +Use one `@param` tag for each meaningful documented parameter. + +The preferred form is: + +```text +@param Type $name Description. +``` + +For example: + +```text +@param string $path Filesystem path interpreted relative to the project root. +``` + +Doxygen explicitly supports PHP-style parameter documentation containing the type +before the parameter name. This form is also conventional PHPDoc and is therefore +preferred even when the native PHP signature already carries a type declaration. + +This duplication is intentional. The DocBlock type participates in the +structured documentation contract and may express useful PHPDoc forms that differ +from or refine the native declaration, such as documented collection element +semantics or pseudo-types. The DocBlock must not contradict the executable PHP +signature. + +Parameter descriptions should explain meaning that the type alone cannot express, +including as applicable: + +- allowed values or ranges; +- units; +- sentinel meanings such as `null`; +- mutability and ownership; +- whether an object or array may be modified; +- path interpretation; +- encoding assumptions; +- ordering requirements; +- callback lifecycle; and +- security-sensitive interpretation. + +### Return Values + +Use `@return` for meaningful return values: + +```text +@return Configuration Validated configuration owned by the caller. +``` + +Prefer the form: + +```text +@return Type Description. +``` + +The description must explain semantics rather than merely repeating the type. +Document ownership, aliasing, special values, ordering, normalization, or other +caller-visible behavior when those details matter. + +For functions that intentionally return no meaningful value, use the PHPDoc/Doxygen +form appropriate to the project's PHP compatibility floor, typically: + +```text +@return void +``` + +Do not invent a return contract for procedures whose useful behavior consists of +side effects. + +### Exceptions + +Use `@throws` for exceptions that form part of the meaningful caller-visible +contract: + +```text +@throws InvalidArgumentException The supplied identifier is invalid. +@throws RuntimeException The external service cannot be reached. +``` + +Document exceptions callers are expected to understand, handle, or treat as part +of the stable interface. Do not enumerate every implementation-level throwable +that could theoretically escape. + +When an exception from a dependency intentionally propagates unchanged, describe +that behavior when it is part of the supported interface rather than inventing a +wrapper exception solely for documentation consistency. + +## Types in DocBlocks + +Native PHP type declarations remain authoritative for executable behavior. +DocBlock types must agree with them. + +Unlike the Python standard, this standard intentionally retains type information +inside `@param`, `@return`, and `@var` tags because Doxygen's PHP parameter syntax +supports the phpDocumentor-style type form directly and because PHPDoc-aware tools +commonly rely on those fields. + +Where a DocBlock type conveys information that PHP's native type system does not +express conveniently, document it precisely. Examples may include collection +element types, constrained shapes, pseudo-types, or meaningful union forms when +those forms are accepted by the project's tooling. + +Do not use a richer DocBlock type to contradict a native declaration. If the +source signature and DocBlock disagree, treat the disagreement as a defect to +investigate. + +## Variables, Properties, and Constants + +Use `@var` when a property, constant-like value, or significant variable requires +structured type or semantic documentation: + +```php +/** + * Cache of repository metadata keyed by normalized repository identifier. + * + * @var array + */ +private array $cache = []; +``` + +Do not document every local variable merely to increase documentation volume. +Document state whose ownership, lifecycle, units, mutability, compatibility role, +or security meaning is not self-evident. + +For public properties, explain caller-visible mutation and lifecycle semantics. +For constants, explain units, compatibility meaning, sentinel semantics, or other +non-obvious interpretation. + +## Classes, Interfaces, Traits, and Enums + +Maintained public classes, interfaces, traits, and enums should have DocBlocks +that explain the abstraction they represent and the contract they establish. + +Class documentation should address as applicable: + +- responsibility and architectural role; +- important invariants; +- owned resources and mutable state; +- lifecycle and cleanup requirements; +- extension and inheritance expectations; +- concurrency assumptions; +- public properties whose meaning is not obvious; +- security boundaries; and +- relationships with relevant ADRs or specifications. + +Interface documentation should describe the behavioral contract implementers must +preserve rather than merely repeating method names. + +Trait documentation should explain the behavior and assumptions introduced into a +consuming class, including required methods, properties, or initialization order. + +Enum documentation should explain domain meaning and any compatibility promises +associated with cases or backing values. + +## Side Effects + +Material side effects must be documented in descriptive prose when they are part +of the caller-visible contract or materially affect maintenance. + +Examples include: + +- modifying caller-supplied arrays or objects; +- changing process-global or static state; +- modifying session state; +- reading or writing files; +- database operations; +- network requests; +- subprocess execution; +- logging or audit output; +- cache mutation; +- lock acquisition; and +- modifying external services or resources. + +A function that appears observational should not hide mutation merely because the +mutation is technically allowed by PHP. + +## Deprecated Interfaces + +Use `@deprecated` when an interface remains available but should no longer be used: + +```php +/** + * Resolve the legacy repository identifier. + * + * @deprecated Use normalizeRepositoryIdentifier() instead. + */ +``` + +When practical, explain the supported replacement and any migration constraint. +Do not use deprecation documentation as a substitute for actual compatibility or +removal policy. + +## Cross-References + +Use `@see` for references that materially help a maintainer or caller understand +the documented element: + +```text +@see RepositoryPolicy +@see normalizeRepositoryIdentifier() +``` + +Prefer references that remain meaningful in generated documentation. Do not add +large lists of loosely related symbols merely to increase connectivity. + +## Tags Outside the Baseline + +phpDocumentor supports tags beyond the baseline used by this standard, including +forms such as `@property`, `@property-read`, `@property-write`, `@method`, `@api`, +`@internal`, `@uses`, and `@used-by`. + +These tags are not part of the baseline standard merely because phpDocumentor +recognizes them. Use them only when: + +1. the project has a concrete need for the semantic contract; +2. Doxygen supports the intended representation adequately, or the tag remains + harmless and visible under the project's Doxygen configuration; and +3. repository-specific governance permits the additional vocabulary. + +When a phpDocumentor convention conflicts with Doxygen's interpretation, Doxygen +wins. + +Likewise, avoid introducing Doxygen-only commands into ordinary PHP DocBlocks when +an equivalent shared PHPDoc form communicates the same contract. Doxygen-only +commands may be used when no adequate shared form exists and the documentation +benefit justifies the reduced phpDocumentor compatibility. + +## Examples + +Examples are strongly preferred for public, parsing, transformation, security, +serialization, persistence, database, network, configuration, or otherwise +non-trivial interfaces. + +Keep examples readable in the source and useful in generated Doxygen output. +Do not manufacture a second test suite inside comments. + +If an example relies on omitted setup, make that omission explicit rather than +presenting incomplete code as directly executable. + +## Security-Sensitive Documentation + +For parsing, validation, authentication, authorization, redaction, +serialization, filesystem, subprocess, database, network, persistence, and +output code, DocBlocks should make it possible for a reviewer to answer questions +such as: + +- what untrusted or sensitive state the callable receives or accesses; +- how input is interpreted; +- what validation occurs before use; +- whether values can reach logs, files, databases, subprocesses, network services, + or other sinks; +- whether failure can expose original sensitive input; +- whether returned objects retain or alias sensitive state; +- whether temporary files, caches, or sessions retain information after use; +- what concurrency assumptions affect protection; +- which exceptions distinguish validation failure from infrastructure failure; +- what platform or library assumptions affect the security promise; and +- which ADR establishes the relevant security boundary when applicable. + +Do not use documentation to imply stronger runtime protection than PHP or the +implementation actually provides. + +## Document Intent, Not Syntax + +Avoid DocBlocks or comments that merely restate executable syntax. + +Prefer documentation that explains why a value or operation exists, what contract +it preserves, what invariant it represents, or why a seemingly unusual +implementation is necessary. + +If code and documentation disagree, treat the disagreement as a defect to +investigate. Do not automatically rewrite the documentation to match current +code; the code may be the part that drifted from the intended contract. + +## Relationship to ADRs + +DocBlocks own implementation-level and caller-facing intent. ADRs own durable +architectural reasoning, promises, non-promises, compatibility decisions, +security boundaries, failure models, rejected alternatives, and accepted +tradeoffs. + +Source documentation may link to an ADR when a local implementation exists +specifically to satisfy an architectural constraint. + +Do not copy an entire ADR into a DocBlock. Do not invent historical rationale +when no source supports it. + +## Generated Reference Documentation + +Generated Doxygen output is derivative and is not a maintained source of truth. +The maintained PHP source, native type declarations, DocBlocks, and governing +repository documentation remain authoritative. + +No translation filter is part of the baseline PHP documentation architecture. +Doxygen consumes maintained PHP source directly. + +Projects may additionally run phpDocumentor against the same maintained DocBlocks. +phpDocumentor output is secondary and must not drive source syntax away from the +Doxygen contract established by this standard. + +## Guidance for Automated Agents + +When generating, modifying, or reviewing PHP source: + +1. Treat Doxygen compatibility as required. +2. Prefer the common PHPDoc/Doxygen subset when it communicates the needed + contract. +3. Use `/** ... */` DocBlocks for generated API documentation. +4. Use summary-plus-description prose rather than Doxygen-only `@brief` and + `@details` when the shared form is sufficient. +5. Assume Doxygen is configured with `JAVADOC_AUTOBRIEF = YES` when this standard + is adopted. +6. Use `@param Type $name Description` for meaningful parameters. +7. Use `@return Type Description` for meaningful return values. +8. Use `@throws ExceptionType Description` for caller-visible contract + exceptions. +9. Use `@var` for significant typed state when useful. +10. Use `@see` and `@deprecated` when they materially improve the contract. +11. Keep DocBlock types consistent with native PHP type declarations. +12. Document semantics beyond types, including units, ownership, mutation, + normalization, special values, side effects, lifecycle, and failure behavior. +13. Do not create parallel Doxygen and phpDocumentor blocks. +14. Do not introduce phpDocumentor-specific tags merely because they exist. +15. If phpDocumentor and Doxygen conflict, follow Doxygen. +16. Respect accepted ADRs and repository-specific rules. +17. Do not expand requested scope merely to normalize unrelated DocBlocks. + +## General Function DocBlock Pattern + +A maintained public or non-trivial function or method should generally contain: + +1. a concise summary sentence; +2. a blank line; +3. substantive prose describing intent, assumptions, side effects, and + non-obvious behavior; +4. a blank line; +5. zero or more `@param` tags in signature order; +6. one `@return` tag when the callable returns meaningful data; +7. zero or more `@throws` tags for caller-visible contract exceptions; +8. additional prose or supported tags for lifecycle, security, compatibility, or + cross-reference information when useful; and +9. an example when it materially improves understanding. + +## Review Standard + +Review documentation with the same seriousness as executable code. Ask whether +a maintainer unfamiliar with the implementation could understand: + +- the responsibility of each class, interface, trait, enum, and significant + function; +- parameter semantics beyond the declared type; +- meaningful return behavior; +- caller-visible exceptions; +- state ownership and mutation; +- resource lifecycle and cleanup; +- external interactions and side effects; +- meaningful edge cases and failure modes; +- security-sensitive state and output boundaries; +- why non-obvious implementation choices exist; +- which architectural decisions constrain future changes; +- whether Doxygen can consume the DocBlock directly; and +- whether the chosen syntax remains reasonably compatible with phpDocumentor when + doing so does not conflict with Doxygen. + +There is no target comment-to-code ratio. The desired amount is enough to +preserve the reasoning. + +## Structural Checklist + +Before considering maintained PHP adequately documented, verify as applicable: + +- public classes, interfaces, traits, enums, functions, and non-trivial methods + have meaningful DocBlocks; +- generated documentation uses `/** ... */` blocks; +- summary and detailed prose explain intent rather than restating syntax; +- meaningful parameters use `@param Type $name Description`; +- meaningful return values use `@return Type Description`; +- caller-visible contract exceptions use `@throws`; +- DocBlock types agree with native PHP declarations; +- significant state uses `@var` when structured documentation is useful; +- deprecated interfaces use `@deprecated` with migration guidance where practical; +- useful cross-references use `@see`; +- side effects and external interactions are documented when material; +- security-sensitive code documents assumptions a future reviewer would otherwise + have to infer; +- repository-specific ADRs and contracts are respected; +- maintained source does not contain parallel Doxygen and phpDocumentor blocks; +- Doxygen compatibility is preserved; and +- phpDocumentor compatibility is retained where it does not conflict with the + Doxygen-first contract. diff --git a/doc/standards/python/documentation-standard.md b/doc/standards/python/documentation-standard.md new file mode 100644 index 0000000..2d92b1e --- /dev/null +++ b/doc/standards/python/documentation-standard.md @@ -0,0 +1,858 @@ +# Python Documentation Standard + +This document defines the normative source-documentation standard for maintained +Python files in projects that adopt it. The standard deliberately prefers +verbose, explanatory documentation. Source brevity is not a goal when brevity +would force a future maintainer to infer intent, contracts, assumptions, failure +semantics, state ownership, portability constraints, security boundaries, or +architectural relationships from executable code alone. + +This standard follows the same documentation philosophy used for maintained Bash +and AWK projects while adopting Python-native docstrings as the maintained source +of truth. It is intentionally compatible with Python documentation and linting +tools, including Pylint documentation checks, and with Doxygen reference +generation through the +[`python-doxygen`](https://github.com/wesley-dean/python-doxygen) input filter. + +Python has a different documentation model from Bash and AWK. Modules, classes, +functions, and methods expose runtime docstrings through `__doc__`; type +annotations carry machine-readable interface type information; exceptions form +part of the call contract; generators yield values; and decorators, descriptors, +context managers, asynchronous functions, protocols, and class inheritance +introduce Python-specific interface semantics. This standard therefore preserves +the documentation philosophy of the other language standards without mechanically +copying their syntax. + +Maintainers should not reduce source documentation merely to optimize package or +wheel size. If a project strips docstrings, generates optimized artifacts, or +otherwise transforms maintained Python source for distribution, that distribution +policy is separate from the maintained source-documentation standard. + +Prefer thorough, detailed, in-depth commentary over brevity. The goal is for the +work to be accessible, readable, and maintainable while targeting developers with +basic Python competence. Pay particular attention to assumptions and +preconditions. Consider that the reader may be a human new to the project or an +AI/LLM operating with focused context that may not retain the complete project +history or the consequences of prior decisions. + +## Precedence + +Repository-specific requirements, accepted Architecture Decision Records (ADRs), +documented public interfaces, compatibility requirements, security requirements, +and project-specific Python standards take precedence over this standard. + +Do not perform unrelated documentation rewrites or refactoring solely to bring +existing code into compliance unless that work is part of the requested scope. + +## Maintained Source of Truth + +Python docstrings are the maintained source of truth for generated API +reference documentation. + +Do not maintain a second Doxygen-specific documentation block beside a Python +docstring. Do not duplicate parameter, return, exception, or behavioral +contracts in separate comments merely to satisfy Doxygen. + +The maintained source should remain idiomatic Python and should be consumable by +Python-native tooling without first passing through `python-doxygen`. + +`python-doxygen` exists at the documentation-generation boundary. It translates +the governed maintained docstring structure into a Doxygen-friendly +representation without changing Python into another source language. + +Conceptually: + +```text +maintained Python source + | + | PEP 257 docstrings + | Sphinx/reStructuredText fields + v + python-doxygen + | + | Doxygen-compatible translated representation + v + Doxygen +``` + +The generated representation is derivative. It is not a maintained source of +truth and must not be edited as though it were authoritative documentation. + +## Docstring Syntax + +Maintained Python documentation must use Python docstrings rather than Doxygen +comment blocks as the primary source of API documentation. + +Use triple double quotes: + +```python +"""Describe the documented object.""" +``` + +For multi-line docstrings, use a concise summary line, a blank line, substantive +explanation, and a closing triple quote on its own line: + +```python +def load_configuration(path: Path) -> Configuration: + """Load and validate a configuration file. + + Explain why the operation exists, relevant preconditions, validation rules, + side effects, failure semantics, and assumptions callers must preserve. + """ +``` + +Use raw triple-double-quoted docstrings when backslashes are intended literally +and would otherwise be interpreted by Python. + +Docstrings should follow PEP 257 structural conventions unless repository-specific +policy establishes a stricter rule. + +Documentation lines should normally remain within the project's configured line +length. When no stricter project rule exists, prefer 80-character documentation +lines where practical. Long URLs, literal values, generated identifiers, and +other unbreakable content may exceed that limit. + +Do not use the Doxygen-specific `"""!` form in maintained source under this +standard. Structured Doxygen conversion belongs to `python-doxygen`, not to a +second source dialect embedded in the Python program. + +## Structured Documentation Fields + +This standard uses Sphinx/reStructuredText field syntax for structured function +and method contracts. + +Use: + +```text +:param name: description +:returns: description +:raises ExceptionType: description +:yields: description +``` + +When type annotations are present and authoritative, do not repeat the same type +information in `:type:` or `:rtype:` fields merely to satisfy documentation +formatting. + +Type hints and prose serve different purposes. Annotations express the +machine-readable type contract. Docstrings explain semantics, units, accepted +ranges, ownership, mutation, special values, ordering, failure behavior, +security interpretation, and other meaning that the type alone cannot express. + +When a maintained interface intentionally lacks type annotations and type +information is necessary for a linter or generated documentation, a project may +use fields such as: + +```text +:type name: str +:rtype: Configuration +``` + +Do not maintain duplicate type declarations when one authoritative annotation is +sufficient. + +## Relationship to Python Linters + +The documentation format must remain consumable by the project's configured +Python linters. + +At minimum, maintained public modules, classes, functions, and methods should have +docstrings. Projects that enable stricter documentation extensions may require +complete parameter, return, yield, and raised-exception documentation. + +When Pylint is used, projects adopting this standard should configure compatible +docstring checking, including `pylint.extensions.docparams` when parameter, +return, yield, and exception contract checking is desired. Projects may also +enable stricter docstring-style checks when those checks agree with this standard. + +Documentation must agree with the executable signature. Parameter names in +structured fields must match the actual parameter names. Do not document +parameters that do not exist, omit meaningful public parameters, or preserve +stale names after a signature change. + +A function that returns a meaningful value should document that value with +`:returns:`. A generator should document yielded values with `:yields:`. +Caller-visible exceptions that form part of the function's meaningful contract +should be documented with `:raises` fields. + +When a linter reports disagreement between code and documentation, treat the +mismatch as a defect to investigate. Do not automatically rewrite the docstring +to match the current implementation; the implementation may be the part that has +drifted from the intended contract. + +## Relationship to python-doxygen + +[`python-doxygen`](https://github.com/wesley-dean/python-doxygen) is the designated +Doxygen input filter for projects adopting this standard when structured Doxygen +reference output is required. + +The filter preserves Python as the filtered source language and translates only +the governed documentation forms at the Doxygen boundary. It remains a +documentation translator rather than a replacement Python parser, type checker, +or linter, and it does not infer behavior absent from maintained source. + +The implemented structured mappings are: + +```text +:param name: description + -> @param name description + +:returns: description + -> @return description + +:raises ExceptionType: description + -> @exception ExceptionType description + +:yields: description + -> dedicated Doxygen paragraph titled "Yields" + +:type name: value + -> dedicated Doxygen paragraph titled "Type of name" + +:rtype: value + -> dedicated Doxygen paragraph titled "Return type" +``` + +The `:type:` and `:rtype:` mappings preserve maintained type information for +intentionally unannotated interfaces. `python-doxygen` does not decide whether a +type field is redundant with an annotation, reconcile conflicting type +information, or infer types from executable source. Those responsibilities +remain with Python-native tooling and repository policy. + +The `:yields:` mapping is deliberately distinct from `:returns:` so generated +reference documentation does not describe generator output as an ordinary +function return. + +For example, maintained source such as: + +```python +def load_configuration(path: Path) -> Configuration: + """Load and validate configuration from ``path``. + + :param path: Configuration file to read. + :returns: A validated configuration object. + :raises ValueError: The configuration is invalid. + """ +``` + +is translated for Doxygen into a representation equivalent to: + +```text +@param path Configuration file to read. +@return A validated configuration object. +@exception ValueError The configuration is invalid. +``` + +The filter supports standards-conforming ordinary triple-double-quoted docstrings, +raw `r"""..."""` and `R"""..."""` docstrings where literal backslashes are +required, deterministic one-line prose docstrings in governed documentation +positions, conventional multi-line `def`, `async def`, and `class` declaration +headers, and representative property, async-function, generator, context-manager, +and decorated-function forms without inferring decorator semantics. + +Continuation prose following governed structured fields remains source-visible and +is preserved when Doxygen can retain the intended association. Ordinary prose, +examples, notes, warnings, unsupported markup, and ambiguous source remain visible +rather than being assigned speculative semantics. + +Most supported translations preserve physical line count. The dedicated titled +paragraph representations for `:yields:`, `:type name:`, and `:rtype:` add one +physical output line per translated field. This is a generated-representation +tradeoff and does not change the maintained-source contract. + +Doxygen integrations that rely on `python-doxygen` translating commands inside +ordinary Python docstrings must configure: + +```ini +PYTHON_DOCSTRING = NO +``` + +This causes Doxygen to interpret the translated commands structurally rather than +preserving the docstring body as preformatted text. + +`python-doxygen` must not require maintainers to duplicate the same contract in +both Sphinx-style and Doxygen-style forms. + +### Tooling Boundary + +Conformance with this standard is defined by the maintained Python source, not by +whether `python-doxygen` performs semantic program analysis. + +`python-doxygen` implements the Doxygen-facing structured documentation portion of +this standard. Semantic validation of Python signatures, annotations, return +behavior, exception behavior, documentation/signature agreement, type correctness, +and decorator semantics remains the responsibility of Python-native tooling such +as Pylint and of repository-specific tests and policy. + +The filter should continue to prefer visible pass-through or a false negative over +inventing source meaning it cannot establish safely. Parser-boundary details, +diagnostics, generated representation, and release behavior are governed by the +`python-doxygen` repository's ADRs and regression tests. + +## Module Docstrings + +Every maintained Python module should contain a module docstring near the start of +the file, after any required shebang or encoding declaration and before imports. + +For example: + +```python +"""Provide configuration loading and validation. + +This module owns the boundary between external configuration files and the +validated application configuration model. It documents accepted formats, +validation policy, security assumptions, and the errors callers should expect. +""" +``` + +A useful module docstring explains why the module exists, not merely which names +it exports. + +When applicable, describe: + +- the module's responsibility and architectural role; +- important public classes, functions, or protocols; +- global state owned by the module; +- initialization behavior and import-time side effects; +- persistence, filesystem, network, environment, or subprocess interactions; +- thread, process, or asynchronous concurrency assumptions; +- important compatibility or portability constraints; +- security boundaries; and +- relevant ADRs or governing specifications. + +Avoid import-time behavior that is surprising merely because it has been +documented. Documentation explains a contract; it does not justify unnecessary +side effects. + +## Function and Method Docstrings + +Maintained functions and methods must document their interface and non-obvious +behavior sufficiently for a caller to use them without reading the implementation. + +A complete function docstring should use the following structure as applicable: + +```python +def load_configuration(path: Path, *, strict: bool = True) -> Configuration: + """Load and validate configuration from ``path``. + + Explain the contract, important preconditions, validation policy, side + effects, external interactions, and why the function exists. + + :param path: Filesystem path containing the configuration document. + :param strict: Whether unknown configuration keys are rejected. + :returns: A validated configuration object owned by the caller. + :raises FileNotFoundError: The requested path does not exist. + :raises PermissionError: The configuration cannot be read. + :raises ValueError: The document is syntactically or semantically invalid. + """ +``` + +Document parameters in signature order when practical. Keyword-only parameters +must be documented as part of the public interface. Positional-only semantics, +variadic arguments, and meaningful default behavior must be explained when they +affect callers. + +### Parameters + +Use one `:param name:` field for each meaningful documented parameter. + +Do not document `self` or `cls` as ordinary caller-supplied parameters unless a +specific repository convention requires it. + +For `*args` and `**kwargs`, document the accepted contents and semantics rather +than merely saying "additional arguments": + +```text +:param args: Additional path fragments joined in order. +:param kwargs: Keyword options forwarded only to the configured transport. +``` + +If arbitrary keyword arguments are constrained to a known set, document that set +or link to the authoritative contract. + +A parameter description should explain semantics that the annotation does not, +including as applicable: + +- allowed values or ranges; +- units; +- sentinel meanings such as `None`; +- mutability and ownership; +- whether the object may be modified in place; +- whether iteration consumes the value; +- whether a callback may be retained; +- whether a path may be relative; +- encoding assumptions; +- ordering requirements; and +- security-sensitive interpretation. + +### Return Values + +Use `:returns:` when a function returns a meaningful value. + +```text +:returns: A normalized repository identifier suitable for cache lookup. +``` + +Do not repeat only the annotated type. Explain the meaning and ownership of the +returned value, relevant special cases, and whether the returned object aliases +input or internal state. + +A function that intentionally returns `None` and exists for side effects may omit +`:returns:` when project linter configuration permits it. When explicit return +documentation is required, state the contract clearly. + +If a function may return multiple semantic forms, document the conditions that +select them. Prefer precise return types in annotations and avoid prose that hides +an unnecessarily ambiguous interface. + +### Generators and Iterators + +Functions that use `yield` should document yielded values with `:yields:` rather +than describing them as ordinary return values. + +```python +def iter_records(path: Path) -> Iterator[Record]: + """Yield validated records from ``path``. + + :param path: Input file containing newline-delimited records. + :yields: Validated records in source order. + :raises OSError: The input cannot be read. + :raises ValueError: A record is malformed and strict parsing is enabled. + """ +``` + +Document whether iteration is lazy, whether the underlying resource remains open +between yields, whether iteration may produce side effects, whether partial +iteration is safe, and what cleanup occurs when iteration stops early. + +For asynchronous generators, document cancellation and resource cleanup when +those semantics matter. + +### Exceptions + +Use one `:raises ExceptionType:` field for each exception that forms part of the +function's meaningful caller-visible contract. + +```text +:raises ValueError: The supplied configuration violates validation rules. +:raises PermissionError: The requested file cannot be read. +``` + +Do not enumerate every implementation-level exception that could theoretically +escape. Document exceptions callers are expected to understand, handle, or treat +as part of the stable interface. + +If an exception from a dependency may intentionally propagate unchanged, describe +that behavior rather than inventing a new wrapper exception solely for +documentation consistency. + +When a function translates one exception into another, document the caller-visible +exception and explain relevant context preservation when useful. + +### Side Effects + +Material side effects must be documented in the descriptive prose or in an +explicit section when the side effects deserve prominence. + +Examples include: + +- modifying a caller-supplied mutable object; +- changing module or process-global state; +- changing environment variables; +- writing files or persistent storage; +- creating or removing directories; +- performing network operations; +- invoking subprocesses; +- emitting logs, metrics, or audit records; +- acquiring locks; +- registering callbacks; +- caching data with process-lifetime effects; and +- modifying external resources. + +A function that appears observational should not hide mutation merely because the +mutation is documented elsewhere. + +## Class Docstrings + +Every maintained public class must have a docstring that explains the abstraction +represented by the class, its responsibilities, important invariants, lifecycle, +and meaningful relationships with collaborators. + +For example: + +```python +class RepositoryCache: + """Cache validated repository metadata. + + Instances own an in-memory mapping for one synchronization run. The cache + does not persist data across processes and is not safe for concurrent mutation + without external synchronization. + """ +``` + +Class documentation should address as applicable: + +- what concept the class represents; +- ownership of resources and mutable state; +- construction preconditions; +- lifecycle and cleanup requirements; +- thread, process, and async safety; +- equality, hashing, ordering, or identity semantics; +- public attributes or properties whose meaning is not self-evident; +- subclassing expectations and extension points; and +- important invariants. + +Avoid documenting constructor parameters twice. A project should choose one +maintained location for constructor parameter documentation when its linter checks +for duplicate constructor documentation. Unless repository governance states +otherwise, document constructor-specific behavior in `__init__` and document the +class abstraction in the class docstring. + +If `__init__` contains no behavior or contract beyond what the class docstring +already establishes and the project's linter configuration permits omission, +avoid duplicating prose solely to satisfy an imagined requirement. + +## Properties and Descriptors + +A property docstring should describe the semantic attribute exposed to callers, +including mutation or validation behavior when a setter exists. + +```python +@property +def status(self) -> Status: + """Return the current lifecycle status.""" +``` + +Do not describe a property as a trivial getter when accessing it performs I/O, +expensive computation, caching, synchronization, or other meaningful side effects. + +Descriptors should document binding, caching, mutation, and exception semantics +when those behaviors are not obvious from normal attribute access. + +## Asynchronous Functions + +Async function docstrings should document behavior that is materially different +from synchronous calls. + +When applicable, identify: + +- when work begins; +- whether cancellation is supported or deferred; +- what state remains after cancellation; +- timeout behavior; +- concurrency limits; +- ordering guarantees; +- synchronization primitives used at the interface boundary; and +- whether returned objects or callbacks are safe across event loops. + +Do not describe an async function merely as "asynchronous" when the important +contract is resource ownership, cancellation, or concurrency behavior. + +## Context Managers + +Context managers should document resource acquisition, what becomes valid inside +the context, cleanup behavior, and exception handling. + +For example: + +```python +@contextmanager +def locked_repository(path: Path) -> Iterator[Repository]: + """Yield a repository while holding its process lock. + + :param path: Repository root whose lock is acquired. + :yields: Repository access valid while the lock is held. + :raises TimeoutError: The lock cannot be acquired within the configured time. + """ +``` + +Document whether cleanup occurs when the body raises, whether exceptions are +suppressed, and whether the yielded value remains valid after context exit. + +## Decorators + +A decorator should document how it changes the wrapped callable's behavior and +interface. + +Document as applicable: + +- whether the wrapper preserves the original signature and metadata; +- added retry, caching, authorization, logging, or synchronization behavior; +- newly raised exceptions; +- altered return values; +- ordering requirements relative to other decorators; and +- whether decoration occurs at import time with side effects. + +Use `functools.wraps` where appropriate, but do not rely on metadata preservation +to communicate semantic changes that callers need to know. + +## Variables, Constants, and Attributes + +Python type annotations and meaningful names often make local variables +self-documenting. Do not add docstrings or comments to every local value merely +to increase documentation volume. + +Document module-level constants, configuration values, registries, public class +attributes, security-sensitive state, caches, and other values whose meaning, +ownership, lifecycle, units, mutability, or compatibility role is not +self-evident. + +Attribute docstrings may be used when supported by the project's documentation +tooling. Ordinary comments are appropriate for local implementation intent that +is not part of generated API documentation. + +## Type Annotations and Documentation + +Type annotations are part of the interface but do not replace documentation. + +Prefer annotations for machine-readable structure: + +```python +def parse_manifest(path: Path) -> list[Dependency]: +``` + +and docstrings for semantic meaning: + +```text +:param path: Manifest file interpreted relative to the physical project root. +:returns: Dependencies in manifest order after complete validation. +``` + +Document behavior that types cannot express reliably, including ordering, +ownership, normalization, validation, aliasing, security interpretation, and +failure semantics. + +Do not contradict annotations in prose. If the type contract and documented +behavior disagree, resolve the inconsistency rather than choosing whichever form +is more convenient for a tool. + +## Examples + +Examples are strongly preferred for public, parsing, transformation, security, +serialization, persistence, network, configuration, or otherwise non-trivial +interfaces. + +Use reStructuredText-compatible examples that remain readable in the source: + +```python +def normalize_key(value: str) -> str: + """Normalize a lookup key. + + :param value: Untrusted key supplied by the caller. + :returns: Lowercase normalized key suitable for lookup. + + Example:: + + normalized = normalize_key("Demo") + """ +``` + +Examples should demonstrate intended use, not manufacture a second test suite +inside docstrings. + +If an example relies on omitted setup, make that omission obvious rather than +presenting incomplete code as directly executable. + +A fuller illustrative module is available at +[`standards/examples/python/documentation/example.py`](../examples/python/documentation/example.py). +The example is non-normative; this standard remains authoritative if the two ever +disagree. + +## Security-Sensitive Documentation + +For parsing, validation, authentication, authorization, redaction, +serialization, filesystem, subprocess, network, persistence, and output code, +docstrings should make it possible for a reviewer to answer questions such as: + +- what untrusted or sensitive state the callable receives or accesses; +- how input is interpreted; +- what validation occurs before use; +- whether values can reach logs, files, subprocesses, network services, or other + sinks; +- whether failure can expose original sensitive input; +- whether returned objects retain or alias sensitive state; +- whether temporary files or caches retain information after use; +- what concurrency assumptions affect protection; +- which exceptions distinguish validation failure from infrastructure failure; +- what platform or library assumptions affect the security promise; and +- which ADR establishes the relevant security boundary when applicable. + +Do not use documentation to imply stronger runtime protection than Python or the +implementation actually provides. + +Terms such as "private," "secure memory," "isolated," "sanitized," or "escaped" +must correspond to a real mechanism and an established contract. + +## Document Intent, Not Syntax + +Avoid comments or docstrings that merely restate executable syntax. + +Do not write prose equivalent to "increment the counter" above: + +```python +count += 1 +``` + +Prefer documentation that explains why the counter exists, what invariant it +represents, why the increment occurs at that stage, or why a seemingly unusual +implementation is necessary. + +If code and documentation disagree, treat the disagreement as a defect to +investigate. Do not automatically rewrite the documentation to match current +code; the code may be the part that drifted from the intended contract. + +## Relationship to ADRs + +Docstrings own implementation-level and caller-facing intent. ADRs own durable +architectural reasoning, promises, non-promises, compatibility decisions, +security boundaries, adversary and failure models, rejected alternatives, and +accepted tradeoffs. + +Source documentation may link to an ADR when a local implementation exists +specifically to satisfy an architectural constraint. + +Do not copy an entire ADR into a docstring. Do not invent historical rationale +when no source supports it. State uncertainty or add an ADR when a new +consequential decision is required. + +A project's `doc/decisions.md`, when present, provides concise ADR summaries and +does not replace either the full ADR or local source documentation. + +## Generated Reference Documentation + +Generated Doxygen output is derivative and is not a maintained source of truth. +The maintained Python source, type annotations, docstrings, and governing +repository documentation remain authoritative. + +`python-doxygen` preserves Python source while making only the governed +translations required for Doxygen indexing and rendering. + +The filter must not manufacture parameter types, exception guarantees, ownership +semantics, thread-safety promises, or other contracts absent from the maintained +source. + +Projects may build, package, optimize, or strip maintained Python source for +distribution. Those transformations must not become a reason to reduce the +quality of maintained source documentation. + +## Guidance for Automated Agents + +When generating, modifying, or reviewing Python source: + +1. Preserve Python docstrings as the maintained documentation authority. +2. Use triple-double-quoted PEP 257-style docstrings. +3. Use Sphinx/reStructuredText fields for structured contracts. +4. Keep parameter names synchronized with the executable signature. +5. Prefer type annotations for machine-readable type information. +6. Do not duplicate annotated types in docstring fields without a concrete need. +7. Document meaningful return values with `:returns:`. +8. Document generator output with `:yields:` rather than `:returns:`. +9. Document caller-visible contract exceptions with `:raises ExceptionType:`. +10. Document side effects, state ownership, lifecycle, and resource behavior when + they matter to callers or maintainers. +11. Document async cancellation, cleanup, and concurrency behavior when relevant. +12. Document security boundaries and untrusted-input interpretation explicitly. +13. Do not add Doxygen `@param`, `@return`, or `@exception` commands directly to + maintained docstrings merely for generated documentation. +14. Assume `python-doxygen` performs the Doxygen translation step. +15. Do not maintain parallel Python-native and Doxygen-native documentation for + the same callable. +16. Treat linter-reported documentation drift as a defect to investigate. +17. Respect accepted ADRs and repository-specific documentation rules. +18. Do not expand the requested scope merely to normalize unrelated docstrings. + +## General Module Structure Pattern + +A maintained Python module should generally follow this order where applicable: + +1. optional governed shebang; +2. optional encoding declaration when actually required; +3. module docstring; +4. future imports; +5. standard-library imports; +6. third-party imports; +7. project imports; +8. documented module constants and state; +9. classes; +10. functions; and +11. executable entry-point logic, when applicable. + +This is a documentation-oriented pattern, not a substitute for repository-specific +Python formatting or import-order standards. + +## General Function Docstring Structure Pattern + +A maintained public or non-trivial function or method should generally contain: + +1. a one-line summary; +2. a blank line; +3. substantive details describing intent, assumptions, side effects, and + non-obvious behavior; +4. a blank line; +5. zero or more `:param name:` fields in signature order; +6. one `:returns:` field when the callable returns meaningful data; +7. one `:yields:` field when the callable is a generator and yields meaningful + data; +8. zero or more `:raises ExceptionType:` fields for caller-visible contract + exceptions; +9. additional prose sections for side effects, lifecycle, concurrency, security, + or compatibility when useful; and +10. an example when it materially improves understanding. + +A callable should not document both `:returns:` and `:yields:` merely to satisfy a +pattern. Use the field that reflects the executable contract. + +## Review Standard + +Review documentation with the same seriousness as executable code. Ask whether +a maintainer unfamiliar with the current implementation could understand: + +- the responsibility of each module and class; +- the contract of each public or non-trivial callable; +- parameter semantics beyond their type annotations; +- meaningful return or yield behavior; +- caller-visible exceptions; +- state ownership and mutation; +- resource lifecycle and cleanup; +- async cancellation and concurrency behavior when applicable; +- meaningful edge cases and failure modes; +- security-sensitive state and output boundaries; +- why non-obvious implementation choices exist; +- which architectural decisions constrain future changes; +- whether the docstring remains consumable by configured Python linters; +- whether `python-doxygen` can translate the structured fields without requiring + a second maintained documentation dialect; and +- what the implementation explicitly does not guarantee. + +There is no target docstring-to-code ratio. The desired amount is "enough to +preserve the reasoning." In infrastructure, security, parsing, and integration +code, that may mean substantially more prose than teams accustomed to terse +Python docstrings expect, and that is intentional. + +## Structural Checklist + +Before considering a maintained Python file adequately documented, verify as +applicable: + +- the module contains a meaningful module docstring; +- public classes have docstrings describing their abstraction and lifecycle; +- public and non-trivial functions and methods have PEP 257-style docstrings; +- maintained docstrings use triple double quotes; +- structured contracts use Sphinx/reStructuredText fields; +- parameter names match the executable signature; +- meaningful parameters are documented in signature order where practical; +- meaningful return values use `:returns:`; +- generator output uses `:yields:`; +- caller-visible contract exceptions use `:raises ExceptionType:`; +- type annotations remain authoritative and are not duplicated without reason; +- side effects and external interactions are documented when material; +- resource ownership and cleanup are explicit where relevant; +- async cancellation and concurrency semantics are documented where relevant; +- security-sensitive code documents assumptions a future reviewer would otherwise + have to infer; +- examples are present where they materially improve understanding; +- documentation agrees with accepted ADRs and repository-specific contracts; +- maintained source does not contain a second Doxygen-specific documentation + block for the same object; and +- `python-doxygen` is treated as a translation boundary rather than a second + documentation authority.