@homericintelligence/athena-opencode 0.4.4 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -17
- package/package.json +2 -2
- package/plugin.js +20 -5
- package/skills/TECHNICAL_ENGLISH.md +78 -0
- package/skills/_cli.py +26 -18
- package/skills/_support/docs/dependency-resolution.md +192 -0
- package/skills/_support/docs/policies/development.md +117 -0
- package/skills/_support/docs/policies/evidence-integrity.md +40 -0
- package/skills/_support/docs/principles/README.md +542 -0
- package/skills/_support/docs/principles/details/p001-kiss.md +114 -0
- package/skills/_support/docs/principles/details/p002-yagni.md +109 -0
- package/skills/_support/docs/principles/details/p003-dry.md +126 -0
- package/skills/_support/docs/principles/details/p004-solid.md +165 -0
- package/skills/_support/docs/principles/details/p005-modularity.md +123 -0
- package/skills/_support/docs/principles/details/p006-principle-of-least-astonishment.md +115 -0
- package/skills/_support/docs/principles/details/p007-subtraction-over-addition.md +113 -0
- package/skills/_support/docs/principles/details/p008-understand-before-subtracting.md +115 -0
- package/skills/_support/docs/principles/details/p009-general-mechanisms-over-special-cases.md +108 -0
- package/skills/_support/docs/principles/details/p010-scope-fidelity.md +117 -0
- package/skills/_support/docs/principles/details/p011-minimal-coherent-change.md +128 -0
- package/skills/_support/docs/principles/details/p012-evidence-before-modification.md +115 -0
- package/skills/_support/docs/principles/details/p013-avoid-hasty-abstractions.md +112 -0
- package/skills/_support/docs/principles/details/p014-preserve-unrequested-behavior.md +110 -0
- package/skills/_support/docs/principles/details/p015-architecture-conformance.md +124 -0
- package/skills/_support/docs/principles/details/p016-separation-of-concerns.md +125 -0
- package/skills/_support/docs/principles/details/p017-high-cohesion-low-coupling.md +130 -0
- package/skills/_support/docs/principles/details/p018-information-hiding.md +128 -0
- package/skills/_support/docs/principles/details/p019-explicit-contracts.md +134 -0
- package/skills/_support/docs/principles/details/p020-executable-architecture.md +130 -0
- package/skills/_support/docs/principles/details/p021-evolutionary-and-reversible-design.md +126 -0
- package/skills/_support/docs/principles/details/p022-test-behavior-not-implementation.md +129 -0
- package/skills/_support/docs/principles/details/p023-parameterized-table-driven-testing.md +129 -0
- package/skills/_support/docs/principles/details/p024-boundary-value-testing.md +128 -0
- package/skills/_support/docs/principles/details/p025-property-based-testing-for-invariants.md +133 -0
- package/skills/_support/docs/principles/details/p026-regression-before-repair.md +134 -0
- package/skills/_support/docs/principles/details/p027-deterministic-and-hermetic-tests.md +128 -0
- package/skills/_support/docs/principles/details/p028-test-failure-paths.md +133 -0
- package/skills/_support/docs/principles/details/p029-generalize-error-policy-preserve-specific-cause.md +131 -0
- package/skills/_support/docs/principles/details/p030-nearest-responsible-error-boundary.md +133 -0
- package/skills/_support/docs/principles/details/p031-propagate-rather-than-swallow.md +131 -0
- package/skills/_support/docs/principles/details/p032-handle-once-preserve-causality.md +137 -0
- package/skills/_support/docs/principles/details/p033-state-safe-failure-semantics.md +140 -0
- package/skills/_support/docs/principles/details/p034-fail-fast.md +132 -0
- package/skills/_support/docs/principles/details/p035-fail-secure-fail-closed.md +137 -0
- package/skills/_support/docs/principles/details/p036-graceful-degradation.md +137 -0
- package/skills/_support/docs/principles/details/p037-idempotency-before-retry.md +139 -0
- package/skills/_support/docs/principles/details/p038-bounded-retry.md +145 -0
- package/skills/_support/docs/principles/details/p039-bounded-waiting.md +151 -0
- package/skills/_support/docs/principles/details/p040-bounded-resources.md +138 -0
- package/skills/_support/docs/principles/details/p041-backpressure-and-load-shedding.md +141 -0
- package/skills/_support/docs/principles/details/p042-fault-isolation-bulkheads.md +140 -0
- package/skills/_support/docs/principles/details/p043-circuit-breakers.md +148 -0
- package/skills/_support/docs/principles/details/p044-atomicity-where-possible.md +141 -0
- package/skills/_support/docs/principles/details/p045-compensation-where-atomicity-is-impossible.md +163 -0
- package/skills/_support/docs/principles/details/p046-resumability.md +138 -0
- package/skills/_support/docs/principles/details/p047-observability-is-part-of-correctness.md +134 -0
- package/skills/_support/docs/principles/details/p048-secure-by-design.md +132 -0
- package/skills/_support/docs/principles/details/p049-secure-by-default.md +126 -0
- package/skills/_support/docs/principles/details/p050-least-privilege.md +123 -0
- package/skills/_support/docs/principles/details/p051-complete-mediation.md +124 -0
- package/skills/_support/docs/principles/details/p052-separation-of-duties.md +129 -0
- package/skills/_support/docs/principles/details/p053-validate-at-trust-boundaries.md +126 -0
- package/skills/_support/docs/principles/details/p054-defense-in-depth.md +135 -0
- package/skills/_support/docs/principles/details/p055-minimize-attack-surface.md +133 -0
- package/skills/_support/docs/principles/details/p056-secrets-stay-out-of-code-and-context.md +137 -0
- package/skills/_support/docs/principles/details/p057-supply-chain-integrity.md +135 -0
- package/skills/_support/docs/principles/details/p058-bounded-agent-authority.md +137 -0
- package/skills/_support/docs/principles/details/p059-data-is-not-instruction.md +130 -0
- package/skills/_support/docs/principles/details/p060-constrain-sub-agents.md +136 -0
- package/skills/_support/docs/principles/details/p061-separate-decision-from-high-impact-execution.md +131 -0
- package/skills/_support/docs/principles/details/p062-human-approval-for-irreversible-or-high-risk-actions.md +129 -0
- package/skills/_support/docs/principles/details/p063-requirement-to-code-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p064-requirement-to-test-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p065-verify-before-claiming-completion.md +129 -0
- package/skills/_support/docs/principles/details/p066-preserve-existing-work.md +114 -0
- package/skills/_support/docs/principles/details/p067-no-test-cheating.md +126 -0
- package/skills/_support/docs/principles/details/p068-no-validation-bypass.md +119 -0
- package/skills/_support/docs/principles/details/p069-independent-review-for-high-risk-changes.md +129 -0
- package/skills/_support/docs/principles/details/p070-code-health-must-not-regress.md +116 -0
- package/skills/_support/docs/principles/details/p071-consistency-over-personal-preference.md +117 -0
- package/skills/_support/docs/principles/details/p072-technical-evidence-over-preference.md +122 -0
- package/skills/_support/docs/principles/details/p073-optimize-only-with-evidence.md +123 -0
- package/skills/_support/docs/principles/details/p074-prefer-existing-mechanisms.md +121 -0
- package/skills/_support/docs/principles/details/p075-make-invalid-states-hard-to-represent.md +128 -0
- package/skills/_support/docs/principles/details/p076-parse-then-validate-then-operate.md +133 -0
- package/skills/_support/docs/principles/details/p077-separate-policy-from-mechanism.md +112 -0
- package/skills/_support/docs/principles/details/p078-single-source-of-truth.md +131 -0
- package/skills/_support/docs/principles/details/p079-explicit-ownership-and-lifetimes.md +124 -0
- package/skills/_support/docs/principles/details/p080-make-concurrency-deliberate.md +122 -0
- package/skills/_support/docs/principles/details/p081-forward-progress-with-safety.md +125 -0
- package/skills/_support/docs/principles/details/p082-design-for-cancellation.md +133 -0
- package/skills/_support/docs/principles/details/p083-irreversible-actions-last.md +124 -0
- package/skills/_support/docs/principles/details/p084-prefer-local-reasoning.md +131 -0
- package/skills/_support/docs/principles/details/p085-explicit-is-better-than-implicit.md +123 -0
- package/skills/_support/docs/principles/details/p086-readability-counts.md +113 -0
- package/skills/_support/docs/principles/details/p087-comments-explain-why-code-explains-what.md +120 -0
- package/skills/_support/docs/principles/details/p088-delete-dead-code.md +125 -0
- package/skills/_support/docs/principles/details/p089-delete-obsolete-configuration-and-dependencies.md +125 -0
- package/skills/_support/docs/principles/details/p090-prefer-negative-code.md +134 -0
- package/skills/_support/docs/principles/details/p091-test-driven-development.md +149 -0
- package/skills/_support/docs/review/README.md +59 -0
- package/skills/_support/docs/review/behavior-first-testing.md +73 -0
- package/skills/_support/docs/review/common.md +365 -0
- package/skills/_support/docs/review/design-docs.md +74 -0
- package/skills/_support/docs/review/issue-planning.md +220 -0
- package/skills/_support/docs/review/language-routing.md +141 -0
- package/skills/_support/docs/review/repository-scorecard.md +170 -0
- package/skills/advise/SKILL.md +102 -40
- package/skills/advise/scripts/list_retrievable_skills.py +3 -3
- package/skills/brainstorm/SKILL.md +167 -76
- package/skills/change-review/SKILL.md +99 -43
- package/skills/change-review/references/scope-resolution.md +70 -41
- package/skills/change-review/scripts/resolve_scope.py +119 -73
- package/skills/finalize-plan/SKILL.md +208 -100
- package/skills/git-worktrees/SKILL.md +108 -59
- package/skills/git-worktrees/scripts/prepare_worktree.py +16 -10
- package/skills/issue-review/SKILL.md +143 -47
- package/skills/learn/SKILL.md +284 -162
- package/skills/myrmidon-swarm/SKILL.md +136 -61
- package/skills/plan-issue/SKILL.md +129 -47
- package/skills/pr-review/SKILL.md +170 -71
- package/skills/pr-review/references/criteria.md +61 -14
- package/skills/pr-review/references/delivery.md +159 -80
- package/skills/pr-review/references/evidence.md +268 -139
- package/skills/pr-review/references/prevalidated.md +91 -48
- package/skills/pr-review/scripts/collect_evidence.py +211 -140
- package/skills/pr-review/scripts/diff_context.py +6 -4
- package/skills/pr-review/scripts/materialize_snapshot.py +112 -120
- package/skills/pr-review/scripts/pr_identity.py +27 -15
- package/skills/pr-review/scripts/resolve_pr.py +53 -31
- package/skills/repo-review/SKILL.md +209 -87
- package/skills/systematic-debugging/SKILL.md +195 -131
- package/skills/systematic-debugging/scripts/repository_evidence.py +9 -4
- package/skills/test-driven-development/SKILL.md +134 -53
- package/skills/tidy/SKILL.md +97 -33
- package/skills/tidy/scripts/run_tidy.py +3 -3
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# P075 — Make Invalid States Hard to Represent
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Use types, schemas, constructors, validation, encapsulation, and state machines to prevent invalid
|
|
6
|
+
data combinations. Reject invalid data at the constructor boundary. As an alternative, make its
|
|
7
|
+
representation unavailable to standard program paths. Core logic must receive values that satisfy
|
|
8
|
+
important structural invariants.
|
|
9
|
+
|
|
10
|
+
**Aliases:** make illegal states unrepresentable, encode invariants in the model.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** practitioner heuristic.
|
|
15
|
+
|
|
16
|
+
This rule has provenance in typed functional programs and domain models. This page does not name one
|
|
17
|
+
author. Algebraic data types, abstract data types, design by contract, and schema
|
|
18
|
+
validation supply established technical foundations.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
When a state combination is always invalid, use a construction that does not let standard callers
|
|
23
|
+
make that combination. Only when the boundary or representation cannot enforce the invariant more
|
|
24
|
+
clearly, use runtime checks at more than one location.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- When states are exclusive, replace correlated booleans and nullable fields with specified
|
|
29
|
+
variants.
|
|
30
|
+
- Use validated constructors or factories that return a value that satisfies the invariant or a
|
|
31
|
+
specified error.
|
|
32
|
+
- When unrestricted mutation can violate invariants, give field access only with operations that
|
|
33
|
+
enforce invariants.
|
|
34
|
+
- Express units, identifiers, necessary fields, and legal transitions in types or schemas.
|
|
35
|
+
- Revalidate facts from external mutable state at the responsible boundary.
|
|
36
|
+
|
|
37
|
+
## Diagram
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart LR
|
|
41
|
+
A["Receive boundary data"] --> B["Parse specified state variant"]
|
|
42
|
+
B --> C["Apply constructor invariants"]
|
|
43
|
+
C --> D{"State valid?"}
|
|
44
|
+
D -- "No" --> E["Return specific error"]
|
|
45
|
+
D -- "Yes" --> F["Give valid value to core logic"]
|
|
46
|
+
F --> G["Use only legal transition"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Language examples
|
|
50
|
+
|
|
51
|
+
The two examples represent exclusive payment states as variants with state-specific data.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from dataclasses import dataclass
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class Pending:
|
|
58
|
+
request_id: str
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True)
|
|
61
|
+
class Settled:
|
|
62
|
+
receipt_id: str
|
|
63
|
+
|
|
64
|
+
Payment = Pending | Settled
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```rust
|
|
68
|
+
enum Payment {
|
|
69
|
+
Pending { request_id: String },
|
|
70
|
+
Settled { receipt_id: String },
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Boundaries and tensions
|
|
75
|
+
|
|
76
|
+
No type system can prove all temporal, distributed, authorization, or business invariants. External
|
|
77
|
+
data is untrusted. Also use
|
|
78
|
+
[P053 boundary validation](p053-validate-at-trust-boundaries.md) and
|
|
79
|
+
[P076 parse-validate-operate](p076-parse-then-validate-then-operate.md). When the complexity of
|
|
80
|
+
wrappers, generics, or type-level mechanisms is more than the risk reduction, do not use these
|
|
81
|
+
mechanisms.
|
|
82
|
+
Representations must be clear, easy to change, and compatible with necessary serialization
|
|
83
|
+
contracts.
|
|
84
|
+
|
|
85
|
+
## Examples
|
|
86
|
+
|
|
87
|
+
**Positive:** One enum represents a payment state with variant-specific data.
|
|
88
|
+
The payment cannot have the `settled` and `failed` states at the same time. The interface contains
|
|
89
|
+
only legal transitions.
|
|
90
|
+
|
|
91
|
+
**Misuse:** Three booleans and two nullable time stamps represent workflow state. Each caller must
|
|
92
|
+
identify the invalid combinations. Each caller must reject them again.
|
|
93
|
+
|
|
94
|
+
**Athena/agent workflow:** A constructor for a review contract must contain a revision, scope, and
|
|
95
|
+
active principle content. Thus, the restricted reviewer cannot receive a contract with missing
|
|
96
|
+
necessary data.
|
|
97
|
+
|
|
98
|
+
## Related principles
|
|
99
|
+
|
|
100
|
+
- [P019 Explicit Contracts](p019-explicit-contracts.md)
|
|
101
|
+
- [P053 Validate at Trust Boundaries](p053-validate-at-trust-boundaries.md)
|
|
102
|
+
- [P076 Parse, Then Validate, Then Operate](p076-parse-then-validate-then-operate.md)
|
|
103
|
+
- [P079 Explicit Ownership and Lifetimes](p079-explicit-ownership-and-lifetimes.md)
|
|
104
|
+
- [P084 Prefer Local Reasoning](p084-prefer-local-reasoning.md)
|
|
105
|
+
|
|
106
|
+
## References
|
|
107
|
+
|
|
108
|
+
### Source information
|
|
109
|
+
|
|
110
|
+
- [Liskov and Zilles, "Programming with Abstract Data Types" (1974)](https://doi.org/10.1145/800233.807045)
|
|
111
|
+
is a primary source for abstract types that control representation and operations.
|
|
112
|
+
The rule has no verified initial source.
|
|
113
|
+
|
|
114
|
+
### Applicable information
|
|
115
|
+
|
|
116
|
+
- [The Rust Programming Language: Defining an Enum](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html)
|
|
117
|
+
shows how variants and exhaustive matches let a compiler distinguish cases. The compiler can
|
|
118
|
+
verify that code handles all variants.
|
|
119
|
+
- [Microsoft C#: Nullable reference types](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/null-safety/nullable-reference-types)
|
|
120
|
+
documents type annotations and flow analysis that find states that do not agree with declared null
|
|
121
|
+
contracts.
|
|
122
|
+
|
|
123
|
+
### More information
|
|
124
|
+
|
|
125
|
+
- [Meyer, "Applying Design by Contract"](https://www.kth.se/social/files/59526bfb56be5b4f17000807/meyer-92-contracts.pdf)
|
|
126
|
+
gives preconditions, postconditions, and invariants as runtime tools that enforce one contract.
|
|
127
|
+
|
|
128
|
+
[Back to the engineering principles catalog](../README.md#p075)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# P076 — Parse, Then Validate, Then Operate
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
**Parse, Then Validate, Then Operate** is a boundary sequence. First, change an external
|
|
6
|
+
representation into a specified internal structure. Then, validate the internal structure for syntax, meaning, security, and task
|
|
7
|
+
limits. Operate only on the validated value. Core logic receives structured values and does not
|
|
8
|
+
interpret the raw input again.
|
|
9
|
+
|
|
10
|
+
**Aliases:** none. *Parse, Don't Validate* is a different rule.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** Athena synthesis.
|
|
15
|
+
|
|
16
|
+
This sequence uses the *Parse, Don't Validate* type guidance. The two rules are not the same. The
|
|
17
|
+
*Parse, Don't Validate* guidance uses types that cannot contain incorrect values. Athena
|
|
18
|
+
includes validation because a parsed value can be incorrect for a domain rule, authority rule,
|
|
19
|
+
invariant, or state precondition.
|
|
20
|
+
|
|
21
|
+
## Decision rule
|
|
22
|
+
|
|
23
|
+
Change boundary data to one canonical structure. Validate that structure fully. After the validator
|
|
24
|
+
completes all input validation, the system can start a side effect.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- Find the trust boundary and the internal type for accepted data.
|
|
29
|
+
- Parse the input. Reject it if it does not match a specified grammar or if its meaning is not clear.
|
|
30
|
+
- Normalize only transformations with one specified meaning.
|
|
31
|
+
- Validate ranges, relationships, invariants, authority, and state preconditions at operation time.
|
|
32
|
+
- Make the operation accept only the validated structure.
|
|
33
|
+
- Keep safe diagnostic context. Do not keep secrets or raw input that is not necessary.
|
|
34
|
+
|
|
35
|
+
## Diagram
|
|
36
|
+
|
|
37
|
+
The diagram shows one safe transition from raw data to an operation.
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart LR
|
|
41
|
+
A["Raw input"] --> B["One parse"]
|
|
42
|
+
B --> C["Structured value"]
|
|
43
|
+
C --> D["Validate all rules"]
|
|
44
|
+
D --> E{"Correct?"}
|
|
45
|
+
E -->|Yes| F["Operate"]
|
|
46
|
+
E -->|No| G["Reject before side effects"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Language examples
|
|
50
|
+
|
|
51
|
+
Before the operation starts, each example validates the port.
|
|
52
|
+
|
|
53
|
+
### Python
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
def parse_port(text: str) -> int:
|
|
57
|
+
if not text.isascii() or not text.isdecimal():
|
|
58
|
+
raise ValueError("invalid port")
|
|
59
|
+
port = int(text)
|
|
60
|
+
if not 1 <= port <= 65_535:
|
|
61
|
+
raise ValueError("invalid port")
|
|
62
|
+
return port
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
server.bind(parse_port(raw_port))
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Rust
|
|
69
|
+
|
|
70
|
+
```rust
|
|
71
|
+
fn parse_port(text: &str) -> Result<u16, String> {
|
|
72
|
+
if text.is_empty() || !text.bytes().all(|byte| byte.is_ascii_digit()) {
|
|
73
|
+
return Err("invalid port".into());
|
|
74
|
+
}
|
|
75
|
+
let port = text.parse::<u16>().map_err(|_| "invalid port")?;
|
|
76
|
+
if port == 0 {
|
|
77
|
+
return Err("invalid port".into());
|
|
78
|
+
}
|
|
79
|
+
Ok(port)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let port = parse_port(raw_port)?;
|
|
83
|
+
server.bind(port)?;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Boundaries and tensions
|
|
87
|
+
|
|
88
|
+
Parsing is not sanitization. Validation is not authorization. Examine mutable facts again immediately
|
|
89
|
+
before the operation. This check prevents time-of-check and time-of-use defects.
|
|
90
|
+
|
|
91
|
+
Keep validation at the boundary. Validate a boundary value for each context after the boundary. Use types
|
|
92
|
+
for stable invariants. Keep policy checks explicit.
|
|
93
|
+
|
|
94
|
+
## Examples
|
|
95
|
+
|
|
96
|
+
**Positive:** A boundary parser changes a deployment request into a typed target and version. A
|
|
97
|
+
validator examines the permitted environment and the release state at validation time. The deployer receives only the
|
|
98
|
+
validated request.
|
|
99
|
+
|
|
100
|
+
**Misuse:** A parser returns an object with missing fields. The executor creates external resources.
|
|
101
|
+
After the side effect, a check finds an incorrect field.
|
|
102
|
+
|
|
103
|
+
**Athena/agent workflow:** An agent parses issue fields and file paths. The agent validates the
|
|
104
|
+
fields and paths for compliance with the task and repository scope. The agent uses tools only with
|
|
105
|
+
validated targets.
|
|
106
|
+
|
|
107
|
+
## Related principles
|
|
108
|
+
|
|
109
|
+
- [P053 Validate at Trust Boundaries](p053-validate-at-trust-boundaries.md)
|
|
110
|
+
- [P059 Data Is Not Instruction](p059-data-is-not-instruction.md)
|
|
111
|
+
- [P075 Make Invalid States Hard to Represent](p075-make-invalid-states-hard-to-represent.md)
|
|
112
|
+
- [P083 Irreversible Actions Last](p083-irreversible-actions-last.md)
|
|
113
|
+
|
|
114
|
+
## References
|
|
115
|
+
|
|
116
|
+
### Source information
|
|
117
|
+
|
|
118
|
+
- [Parse, Don't Validate](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/)
|
|
119
|
+
gives the type-oriented formulation. Types that cannot contain incorrect values give more information than Boolean checks.
|
|
120
|
+
|
|
121
|
+
### Applicable information
|
|
122
|
+
|
|
123
|
+
- [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
|
|
124
|
+
gives the difference between syntactic and semantic validation. Before operation, the guidance tells
|
|
125
|
+
authors to validate untrusted data.
|
|
126
|
+
|
|
127
|
+
### More information
|
|
128
|
+
|
|
129
|
+
- [OWASP REST Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html)
|
|
130
|
+
gives guidance about secure parsers, strong input types, and content constraints. It tells
|
|
131
|
+
authors to reject input that is not in the API contract.
|
|
132
|
+
|
|
133
|
+
[Back to the engineering principles catalog](../README.md#p076)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# P077 — Separate Policy from Mechanism
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
**Separate Policy from Mechanism** puts decisions about necessary behavior in policy. The principle
|
|
6
|
+
puts execution capabilities in mechanisms. A mechanism supplies stable capabilities. A policy selects
|
|
7
|
+
and controls those capabilities for a specified context.
|
|
8
|
+
|
|
9
|
+
**Aliases:** policy-mechanism separation and separation of policy and mechanism.
|
|
10
|
+
|
|
11
|
+
## Provenance
|
|
12
|
+
|
|
13
|
+
**Classification:** principle with source evidence.
|
|
14
|
+
|
|
15
|
+
Operating-system research used this distinction. The Hydra system put policy and mechanism in
|
|
16
|
+
different components for schedules, memory pages, and protection. The Hydra mechanisms let external
|
|
17
|
+
policies change. The principle is also applicable to applications, security, work control, storage, and
|
|
18
|
+
infrastructure.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
Give a policy boundary with a name to a rule that can change. Keep a neutral mechanism that uses each
|
|
23
|
+
selected policy correctly.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Find decisions that can change. Put these decisions in policy interfaces.
|
|
28
|
+
- Give policy inputs, outputs, defaults, and failure behavior an explicit contract.
|
|
29
|
+
- Use a narrow interface to supply the policy. Do not put copies of policy branches in the mechanism.
|
|
30
|
+
- Do policy-selection tests and mechanism-correctness tests independently.
|
|
31
|
+
- If a policy is a security or integrity control, keep enforcement mandatory.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
The policy selects an operation. The mechanism does only the selected operation.
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
A["Context"] --> B["Policy decision"]
|
|
40
|
+
B --> C["Selected operation"]
|
|
41
|
+
C --> D["Neutral mechanism"]
|
|
42
|
+
D --> E["Result"]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Language examples
|
|
46
|
+
|
|
47
|
+
The two examples supply a policy to a stable queue mechanism.
|
|
48
|
+
|
|
49
|
+
### Python
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
def dispatch(job, priority_policy, queue) -> None:
|
|
53
|
+
priority = priority_policy(job)
|
|
54
|
+
entry = QueueEntry(job, priority)
|
|
55
|
+
queue.push(entry)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Rust
|
|
59
|
+
|
|
60
|
+
```rust
|
|
61
|
+
fn dispatch<P: PriorityPolicy>(job: Job, policy: &P, queue: &mut Queue) {
|
|
62
|
+
let priority = policy.priority(&job);
|
|
63
|
+
let entry = QueueEntry::new(job, priority);
|
|
64
|
+
queue.push(entry);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Boundaries and tensions
|
|
69
|
+
|
|
70
|
+
An abstraction is not necessary for each condition. Until two components use a stable policy, the
|
|
71
|
+
policy can stay local. A neutral mechanism must use the policy.
|
|
72
|
+
|
|
73
|
+
Some low-level policy is necessary for fairness, safety, or resource limits. Record that decision.
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
**Positive:** A scheduler supplies queueing and dispatch primitives while a different strategy
|
|
78
|
+
selects priority and fairness rules.
|
|
79
|
+
|
|
80
|
+
**Misuse:** Authorization rules occur in transport handlers, database helpers, and user interfaces.
|
|
81
|
+
One role change causes edits to all three, and the edits do not agree.
|
|
82
|
+
|
|
83
|
+
**Athena/agent workflow:** A coordinator selects tasks that can operate independently in parallel. The
|
|
84
|
+
delegation mechanism starts, monitors, and collects workers without new scope policy.
|
|
85
|
+
|
|
86
|
+
## Related principles
|
|
87
|
+
|
|
88
|
+
- [P016 Separation of Concerns](p016-separation-of-concerns.md)
|
|
89
|
+
- [P018 Information Hiding](p018-information-hiding.md)
|
|
90
|
+
- [P019 Explicit Contracts](p019-explicit-contracts.md)
|
|
91
|
+
- [P078 Single Source of Truth](p078-single-source-of-truth.md)
|
|
92
|
+
- [P084 Prefer Local Reasoning](p084-prefer-local-reasoning.md)
|
|
93
|
+
|
|
94
|
+
## References
|
|
95
|
+
|
|
96
|
+
### Source information
|
|
97
|
+
|
|
98
|
+
- [Policy/mechanism separation in Hydra](https://doi.org/10.1145/1067629.806531)
|
|
99
|
+
is the 1975 primary paper that gives the principle for schedules, memory pages, and protection.
|
|
100
|
+
|
|
101
|
+
### Applicable information
|
|
102
|
+
|
|
103
|
+
- [Linux Integrity Policy Enforcement](https://www.kernel.org/doc/html/latest/security/ipe.html)
|
|
104
|
+
gives a kernel design with integrity measurement and local enforcement policies in different
|
|
105
|
+
components.
|
|
106
|
+
|
|
107
|
+
### More information
|
|
108
|
+
|
|
109
|
+
- [The Protection of Information in Computer Systems](https://www.cs.virginia.edu/~evans/cs551/saltzer/)
|
|
110
|
+
gives guidance on Complete Mediation, least privilege, and simple security mechanisms.
|
|
111
|
+
|
|
112
|
+
[Back to the engineering principles catalog](../README.md#p077)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# P078 — Single Source of Truth
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
**Single Source of Truth** (SSOT) gives each authoritative mutable fact or policy one declared owner
|
|
6
|
+
and one write path. Other representations are derived views, caches, replicas, or exports. The
|
|
7
|
+
source and synchronization rules for each representation are explicit.
|
|
8
|
+
|
|
9
|
+
**Aliases:** SSOT, authoritative source, canonical owner.
|
|
10
|
+
|
|
11
|
+
## Provenance
|
|
12
|
+
|
|
13
|
+
**Classification:** practitioner heuristic.
|
|
14
|
+
|
|
15
|
+
The phrase occurs in data, configuration, and software design. No source records where the phrase
|
|
16
|
+
first occurred. The rule uses concepts from database normalization and DRY. The rule is only about
|
|
17
|
+
authority and divergence, not all duplication.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
For each mutable fact, record the authoritative representation and the permitted writers. Record how
|
|
22
|
+
all other representations receive the same data from the authoritative representation.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Give each domain fact an authoritative owner and specified write interface.
|
|
27
|
+
- If policy accepts the cost, make secondary representations from authoritative data.
|
|
28
|
+
- Give caches and replicas a non-authoritative status. Record freshness limits.
|
|
29
|
+
- Record the source, version, and reconciliation rules for asynchronous boundaries.
|
|
30
|
+
- Use an explicit operation to move authority. Do not let two writers give different values without a signal.
|
|
31
|
+
- When authors can change copies independently, find differences.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
The authoritative source supplies each derived representation.
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
A["Permitted writer"] --> B["Authoritative source"]
|
|
40
|
+
B --> C["Read-only derived view"]
|
|
41
|
+
B --> D["Cache"]
|
|
42
|
+
B --> E["Replica"]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Language examples
|
|
46
|
+
|
|
47
|
+
The two examples derive one timeout from the authoritative configuration and reject values that are
|
|
48
|
+
not in the `u64` domain.
|
|
49
|
+
|
|
50
|
+
### Python
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class Config:
|
|
55
|
+
timeout_seconds: str
|
|
56
|
+
|
|
57
|
+
def client_timeout(config: Config) -> int:
|
|
58
|
+
text = config.timeout_seconds
|
|
59
|
+
if not text.isascii() or not text.isdecimal():
|
|
60
|
+
raise ValueError("timeout must be a u64")
|
|
61
|
+
seconds = int(text)
|
|
62
|
+
if seconds > 2**64 - 1:
|
|
63
|
+
raise ValueError("timeout must be a u64")
|
|
64
|
+
return seconds
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Rust
|
|
68
|
+
|
|
69
|
+
```rust
|
|
70
|
+
struct Config {
|
|
71
|
+
timeout_seconds: String,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn client_timeout(config: &Config) -> Result<u64, &'static str> {
|
|
75
|
+
let text = &config.timeout_seconds;
|
|
76
|
+
if text.is_empty() || !text.bytes().all(|byte| byte.is_ascii_digit()) {
|
|
77
|
+
return Err("timeout must be a u64");
|
|
78
|
+
}
|
|
79
|
+
text.parse::<u64>().map_err(|_| "timeout must be a u64")
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Boundaries and tensions
|
|
84
|
+
|
|
85
|
+
SSOT is not a rule for one database, one service, or one global system owner. Different bounded contexts
|
|
86
|
+
can own different facts. Distributed replicas can increase availability. When the authority and
|
|
87
|
+
consistency model of each copy are clear, derived copies are permitted in the specified model.
|
|
88
|
+
When control causes a bottleneck or incorrect agreement, central control is incorrect.
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
**Positive:** One schema owns an API shape. Generated clients and documentation show the schema
|
|
93
|
+
version. Authors do not change derived artifacts independently.
|
|
94
|
+
|
|
95
|
+
**Misuse:** Code, deployment configuration, and a runbook give timeout defaults that authors can
|
|
96
|
+
change independently. No precedence rule selects one of the different values.
|
|
97
|
+
|
|
98
|
+
**Athena/agent workflow:** The principles catalog owns IDs and decision rules. Detail pages give more
|
|
99
|
+
information. Skills refer to the catalog and do not keep duplicate definitions.
|
|
100
|
+
|
|
101
|
+
## Related principles
|
|
102
|
+
|
|
103
|
+
- [P018 Information Hiding](p018-information-hiding.md)
|
|
104
|
+
- [P020 Executable Architecture](p020-executable-architecture.md)
|
|
105
|
+
- [P077 Separate Policy from Mechanism](p077-separate-policy-from-mechanism.md)
|
|
106
|
+
- [P084 Prefer Local Reasoning](p084-prefer-local-reasoning.md)
|
|
107
|
+
- [P089 Delete Obsolete Configuration and Dependencies](p089-delete-obsolete-configuration-and-dependencies.md)
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
### Source information
|
|
112
|
+
|
|
113
|
+
- No primary source records the first occurrence of the phrase. Use the phrase as a practitioner term without
|
|
114
|
+
attribution to one author.
|
|
115
|
+
- [On the Criteria To Be Used in Decomposing Systems into Modules](https://doi.org/10.1145/361598.361623)
|
|
116
|
+
gives a historical foundation for authoritative module boundaries.
|
|
117
|
+
|
|
118
|
+
### Applicable information
|
|
119
|
+
|
|
120
|
+
- [Microsoft Azure Architecture Center: Data considerations for microservices](https://learn.microsoft.com/en-us/azure/architecture/microservices/design/data-considerations)
|
|
121
|
+
tells architects to use one authoritative service for necessary strong consistency. The guidance
|
|
122
|
+
lets a system use non-authoritative copies with explicit eventual consistency.
|
|
123
|
+
|
|
124
|
+
### More information
|
|
125
|
+
|
|
126
|
+
- [NASA: A PPE Use Case on Configuration Management Approach for MBSE](https://ntrs.nasa.gov/citations/20230000079)
|
|
127
|
+
gives a model that is the controlled source for derived engineering artifacts.
|
|
128
|
+
- [USENIX SREcon: There Is No Single Source of Truth](https://www.usenix.org/conference/srecon24emea/presentation/burke)
|
|
129
|
+
gives information about ambiguity and authority for each domain in production systems.
|
|
130
|
+
|
|
131
|
+
[Back to the engineering principles catalog](../README.md#p078)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# P079 — Explicit Ownership and Lifetimes
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
**Explicit Ownership and Lifetimes** gives each resource and work unit a clear owner and a specified
|
|
6
|
+
lifetime. The principle also gives transfer, cleanup, and termination rules. Resources include memory,
|
|
7
|
+
files, locks, transactions, connections, callbacks, processes, tasks, and temporary artifacts.
|
|
8
|
+
|
|
9
|
+
**Aliases:** none. Resource Acquisition Is Initialization (RAII) and ownership types are
|
|
10
|
+
implementation families for this principle.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** principle with source evidence.
|
|
15
|
+
|
|
16
|
+
No source records an initial author of the general rule. Structured programs, C++ RAII, ownership
|
|
17
|
+
types, scope cleanup, and structured concurrency use this rule. These mechanisms are different.
|
|
18
|
+
Each mechanism makes responsibility and lifetime clear.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
Before resource acquisition, record the resource owner and lifetime. Record each ownership
|
|
23
|
+
transfer. Give cleanup rules for success, failure, timeout, and cancellation.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Use scope-bound resource handles, context managers, or equivalent cleanup constructs.
|
|
28
|
+
- Make ownership transfer clear in types, names, or interface contracts.
|
|
29
|
+
- If no durable owner accepts ownership, connect child tasks to a parent scope.
|
|
30
|
+
- Give the shutdown order and wait behavior for concurrent work.
|
|
31
|
+
- Until the owner records the terminal disposition of each item, record temporary artifacts and state.
|
|
32
|
+
- Do tests of failure exits and the standard release path.
|
|
33
|
+
|
|
34
|
+
## Diagram
|
|
35
|
+
|
|
36
|
+
The owner controls the resource for the full resource lifetime.
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart LR
|
|
40
|
+
A["Acquire resource"] --> B["Owner with a name"]
|
|
41
|
+
B --> C{"Transfer?"}
|
|
42
|
+
C -->|Yes| D["Specified new owner"]
|
|
43
|
+
C -->|No| E["Owner does not change"]
|
|
44
|
+
D --> F["Cleanup on all exits"]
|
|
45
|
+
E --> F
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Language examples
|
|
49
|
+
|
|
50
|
+
The two examples connect file cleanup to a clear scope, accept line-feed (LF) and
|
|
51
|
+
carriage-return/line-feed (CRLF) endings, and give an error for an empty file.
|
|
52
|
+
|
|
53
|
+
### Python
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
def first_line(path: Path) -> str:
|
|
57
|
+
with path.open("rb") as stream:
|
|
58
|
+
line = stream.readline()
|
|
59
|
+
if line == b"":
|
|
60
|
+
raise EOFError("empty file")
|
|
61
|
+
if line.endswith(b"\r\n"):
|
|
62
|
+
line = line[:-2]
|
|
63
|
+
elif line.endswith(b"\n"):
|
|
64
|
+
line = line[:-1]
|
|
65
|
+
return line.decode("utf-8")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Rust
|
|
69
|
+
|
|
70
|
+
```rust
|
|
71
|
+
fn first_line(path: &Path) -> io::Result<String> {
|
|
72
|
+
let file = File::open(path)?;
|
|
73
|
+
let mut lines = BufReader::new(file).lines();
|
|
74
|
+
lines.next().transpose()?.ok_or_else(|| io::ErrorKind::UnexpectedEof.into())
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Boundaries and tensions
|
|
79
|
+
|
|
80
|
+
Garbage collection does not close files, release locks, cancel requests, or complete transactions.
|
|
81
|
+
Shared ownership and long work can follow the principle. The last owner of each resource and the
|
|
82
|
+
shutdown protocol must stay explicit. A lifetime does not have to be the same as a lexical scope.
|
|
83
|
+
Leases and durable workflows can have longer lifetimes.
|
|
84
|
+
|
|
85
|
+
## Examples
|
|
86
|
+
|
|
87
|
+
**Positive:** A transaction object owns the lock and connection. The object does one commit or rollback
|
|
88
|
+
and releases each resource on all exit paths.
|
|
89
|
+
|
|
90
|
+
**Misuse:** A helper starts a detached task. After the request stops, the task uses a request-scoped
|
|
91
|
+
credential. The task has no cancellation contract or supervisor.
|
|
92
|
+
|
|
93
|
+
**Athena/agent workflow:** A coordinator records each subagent, the subagent deadline, the specified
|
|
94
|
+
output, and the terminal disposition. The coordinator collects or cancels all children. The
|
|
95
|
+
coordinator then records completion.
|
|
96
|
+
|
|
97
|
+
## Related principles
|
|
98
|
+
|
|
99
|
+
- [P039 Bounded Waiting](p039-bounded-waiting.md)
|
|
100
|
+
- [P046 Resumability](p046-resumability.md)
|
|
101
|
+
- [P080 Make Concurrency Deliberate](p080-make-concurrency-deliberate.md)
|
|
102
|
+
- [P082 Design for Cancellation](p082-design-for-cancellation.md)
|
|
103
|
+
- [P083 Irreversible Actions Last](p083-irreversible-actions-last.md)
|
|
104
|
+
|
|
105
|
+
## References
|
|
106
|
+
|
|
107
|
+
### Source information
|
|
108
|
+
|
|
109
|
+
- [Bjarne Stroustrup's C++ glossary](https://stroustrup.com/glossary.html) records RAII as a
|
|
110
|
+
method that binds resource management to object construction and destruction.
|
|
111
|
+
|
|
112
|
+
### Applicable information
|
|
113
|
+
|
|
114
|
+
- [The Rust Programming Language: What Is Ownership?](https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html)
|
|
115
|
+
gives compiler-enforced ownership and scope rules.
|
|
116
|
+
- [Go: Contexts and structs](https://go.dev/blog/context-and-structs) gives information about a clear
|
|
117
|
+
request lifetime at each call. This per-call lifetime makes cancellation and deadlines clear.
|
|
118
|
+
|
|
119
|
+
### More information
|
|
120
|
+
|
|
121
|
+
- [Standard C++ FAQ: Exceptions and RAII](https://isocpp.org/wiki/faq/exceptions/1000) gives
|
|
122
|
+
information about deterministic cleanup for success and exception paths.
|
|
123
|
+
|
|
124
|
+
[Back to the engineering principles catalog](../README.md#p079)
|