@homericintelligence/athena-opencode 0.5.0 → 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 +93 -67
- package/skills/advise/scripts/list_retrievable_skills.py +3 -3
- package/skills/brainstorm/SKILL.md +160 -127
- package/skills/change-review/SKILL.md +91 -71
- package/skills/change-review/references/scope-resolution.md +69 -46
- package/skills/change-review/scripts/resolve_scope.py +119 -73
- package/skills/finalize-plan/SKILL.md +198 -139
- package/skills/git-worktrees/SKILL.md +100 -80
- package/skills/git-worktrees/scripts/prepare_worktree.py +16 -10
- package/skills/issue-review/SKILL.md +136 -79
- package/skills/learn/SKILL.md +276 -186
- package/skills/myrmidon-swarm/SKILL.md +126 -86
- package/skills/plan-issue/SKILL.md +122 -81
- package/skills/pr-review/SKILL.md +164 -114
- package/skills/pr-review/references/criteria.md +58 -37
- package/skills/pr-review/references/delivery.md +156 -98
- package/skills/pr-review/references/evidence.md +265 -148
- package/skills/pr-review/references/prevalidated.md +93 -61
- 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 +202 -131
- package/skills/systematic-debugging/SKILL.md +210 -192
- package/skills/systematic-debugging/scripts/repository_evidence.py +9 -4
- package/skills/test-driven-development/SKILL.md +126 -96
- package/skills/tidy/SKILL.md +92 -59
- package/skills/tidy/scripts/run_tidy.py +3 -3
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# P037 — Idempotency Before Retry
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
An operation that can occur more than one time must have one intended effect for equivalent
|
|
6
|
+
requests. An equivalent control can give this guarantee.
|
|
7
|
+
|
|
8
|
+
Such controls include an idempotency key, duplicate detection, a conditional write, or
|
|
9
|
+
reconciliation. After a timeout, the first try outcome is unknown. The try can change state.
|
|
10
|
+
|
|
11
|
+
**Aliases:** retry safety, idempotent operation, duplicate suppression
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Mathematics and protocol design have used idempotence for many years. Athena puts idempotency first.
|
|
18
|
+
Retry occurs after idempotency. Athena cannot identify one source for that phrase.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
If an operation has side effects and duplicate execution is safe, automatic retry can occur. A
|
|
23
|
+
different request identifier for each logical operation lets the system detect duplicate execution
|
|
24
|
+
and recover from it.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- Classify the operation effect. Record semantic equivalence for requests.
|
|
29
|
+
- If a requested-state operation satisfies domain rules, select that design.
|
|
30
|
+
- Accept an idempotency key for resource writes, charges, message sends, or publications. Connect the key to caller
|
|
31
|
+
identity and normalized request data.
|
|
32
|
+
- When possible, record the key and state change in one atomic operation. Record a stable duplicate
|
|
33
|
+
response.
|
|
34
|
+
- Record key scope, retention, conflict behavior, and treatment of late or concurrent duplicates.
|
|
35
|
+
- If results do not show that the operation is safe, do not retry. Give status queries or
|
|
36
|
+
reconciliation procedures.
|
|
37
|
+
- Do tests with duplicate requests, concurrent requests, timeouts, late requests, and key conflicts.
|
|
38
|
+
|
|
39
|
+
## Diagram
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
flowchart TD
|
|
43
|
+
A["Receive a request with a stable key"] --> B{"Is there a recorded key?"}
|
|
44
|
+
B -- Yes --> C{"Is the request equivalent?"}
|
|
45
|
+
C -- No --> D["Return a conflict"]
|
|
46
|
+
C -- Yes --> E["Return the recorded result"]
|
|
47
|
+
B -- No --> F["Commit the effect and key in one atomic operation"]
|
|
48
|
+
F --> E
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Language examples
|
|
52
|
+
|
|
53
|
+
Each example returns one job for each equivalent key and payload pair.
|
|
54
|
+
|
|
55
|
+
### Python
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
def create_job(store, key, payload):
|
|
59
|
+
outcome = store.atomic_get_or_create(key, payload)
|
|
60
|
+
if outcome.kind is CreateKind.CONFLICT:
|
|
61
|
+
raise Conflict(key)
|
|
62
|
+
return outcome.job_id
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Rust
|
|
66
|
+
|
|
67
|
+
```rust
|
|
68
|
+
fn create_job(store: &Store, key: Key, payload: Payload) -> Result<JobId, Error> {
|
|
69
|
+
match store.atomic_get_or_create(&key, &payload)? {
|
|
70
|
+
CreateResult::Created(job) | CreateResult::Replayed(job) => Ok(job.id),
|
|
71
|
+
CreateResult::Conflict => Err(Error::Conflict(key)),
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Boundaries and tensions
|
|
77
|
+
|
|
78
|
+
Idempotency decreases duplicate risk. A finite try count is also necessary. Apply
|
|
79
|
+
[P038](p038-bounded-retry.md) and [P039](p039-bounded-waiting.md). These controls have different
|
|
80
|
+
functions.
|
|
81
|
+
|
|
82
|
+
If the idempotency record and state change use different transactions, the state change can occur
|
|
83
|
+
only in part. If one transaction can contain the two effects, use [P044](p044-atomicity-where-possible.md).
|
|
84
|
+
|
|
85
|
+
If one transaction cannot contain the two effects, use reconciliation and
|
|
86
|
+
[P045](p045-compensation-where-atomicity-is-impossible.md). A key with a nonequivalent request is a conflict.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Positive application
|
|
91
|
+
|
|
92
|
+
A job API accepts a client request identifier. The server uses one atomic operation to record the
|
|
93
|
+
normalized payload, job identifier, and response. Equivalent requests return the same job.
|
|
94
|
+
|
|
95
|
+
A request with the same key and a different payload receives a conflict response.
|
|
96
|
+
|
|
97
|
+
### Misuse or counterexample
|
|
98
|
+
|
|
99
|
+
A client retries `charge-card` after each timeout without a request key. The first try can
|
|
100
|
+
succeed before the timeout. The retry can charge the customer two times.
|
|
101
|
+
|
|
102
|
+
### Athena or agent workflow
|
|
103
|
+
|
|
104
|
+
An Athena workflow does not receive the response from an issue creation request. Before a retry, it
|
|
105
|
+
examines issues for the specified title and marker. It can also use the host idempotency control.
|
|
106
|
+
|
|
107
|
+
The workflow has no results that show that the first request failed.
|
|
108
|
+
|
|
109
|
+
## Related principles
|
|
110
|
+
|
|
111
|
+
- [P033 — State-Safe Failure Semantics](p033-state-safe-failure-semantics.md)
|
|
112
|
+
- [P038 — Bounded Retry](p038-bounded-retry.md)
|
|
113
|
+
- [P039 — Bounded Waiting](p039-bounded-waiting.md)
|
|
114
|
+
- [P044 — Atomicity Where Possible](p044-atomicity-where-possible.md)
|
|
115
|
+
- [P045 — Compensation Where Atomicity Is Impossible](p045-compensation-where-atomicity-is-impossible.md)
|
|
116
|
+
|
|
117
|
+
## References
|
|
118
|
+
|
|
119
|
+
### Source information
|
|
120
|
+
|
|
121
|
+
- [RFC 2068, HTTP/1.1 section 9.1.2 (1997)](https://www.rfc-editor.org/rfc/rfc2068.html#section-9.1.2)
|
|
122
|
+
— a 1997 HTTP standards-track definition of idempotent methods and duplicate request effects.
|
|
123
|
+
HTTP is not the source of idempotence.
|
|
124
|
+
|
|
125
|
+
### Applicable information
|
|
126
|
+
|
|
127
|
+
- [RFC 9110 section 9.2.2, Idempotent Methods](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2)
|
|
128
|
+
— applicable HTTP semantics for requests that the client automatically sends again.
|
|
129
|
+
- [AWS Builders' Library, Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/)
|
|
130
|
+
— practitioner guidance for client request identifiers, semantic equivalence, late requests, and
|
|
131
|
+
atomic idempotency records.
|
|
132
|
+
|
|
133
|
+
### More information
|
|
134
|
+
|
|
135
|
+
- [Microsoft Azure, Retry pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/retry)
|
|
136
|
+
— shows why a response can fail after work succeeds. It also shows why retry policy must
|
|
137
|
+
include idempotency.
|
|
138
|
+
|
|
139
|
+
[Back to the engineering principles catalog](../README.md#p037)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# P038 — Bounded Retry
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Retry only a transient failure from a category in the dependency contract. If a specified try
|
|
6
|
+
limit, elapsed-time limit, or shared deadline expires, stop.
|
|
7
|
+
|
|
8
|
+
When callers can retry at the same time, put time between tries and wait for a random time. Obey
|
|
9
|
+
server guidance that controls retry. A retry policy must not cause an unlimited wait or load amplification.
|
|
10
|
+
|
|
11
|
+
**Aliases:** retry budget, limited retry, backoff and jitter
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Network and production systems have used finite retry and random backoff for many years. Athena
|
|
18
|
+
cannot identify one source for this rule.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
If the contract classifies the result as a transient failure and the operation is safe, retry. The caller
|
|
23
|
+
budget must also have capacity for a new try. If not, return the failure.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Use the dependency contract to select retryable error categories. Do not use a catch-all error
|
|
28
|
+
category.
|
|
29
|
+
- Give one layer ownership of one total retry budget for nested calls.
|
|
30
|
+
- Use a finite try count or deadline. When many callers can retry at the same time, use an
|
|
31
|
+
exponential wait and random variation.
|
|
32
|
+
- Before the caller deadline, obey protocol signals such as `Retry-After`.
|
|
33
|
+
- Apply [P037](p037-idempotency-before-retry.md) to operations with side effects.
|
|
34
|
+
- After cancellation, permanent failure, or budget exhaustion, stop. If the next try cannot complete
|
|
35
|
+
in the remaining time, stop.
|
|
36
|
+
- Record try count and last outcome as correlated telemetry. Do tests of the policy during
|
|
37
|
+
overload.
|
|
38
|
+
|
|
39
|
+
## Diagram
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
flowchart TD
|
|
43
|
+
A["Try the operation"] --> B{"Did the operation succeed?"}
|
|
44
|
+
B -- Yes --> C["Return success"]
|
|
45
|
+
B -- No --> D{"Is this a transient failure, and is the operation safe?"}
|
|
46
|
+
D -- No --> E["Return the failure"]
|
|
47
|
+
D -- Yes --> F{"Does the shared budget have capacity for a new try?"}
|
|
48
|
+
F -- No --> E
|
|
49
|
+
F -- Yes --> G["Wait for a bounded random time"]
|
|
50
|
+
G --> A
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Language examples
|
|
54
|
+
|
|
55
|
+
Each example limits a transient read failure to three tries.
|
|
56
|
+
|
|
57
|
+
### Python
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
def fetch(client):
|
|
61
|
+
for attempt in range(3):
|
|
62
|
+
result = client.fetch()
|
|
63
|
+
if result.ok or not result.transient:
|
|
64
|
+
return result
|
|
65
|
+
if attempt < 2:
|
|
66
|
+
sleep(jitter(2**attempt))
|
|
67
|
+
return result
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Rust
|
|
71
|
+
|
|
72
|
+
```rust
|
|
73
|
+
fn fetch(client: &Client) -> Result<Data, Error> {
|
|
74
|
+
for attempt in 0..3 {
|
|
75
|
+
match client.fetch() {
|
|
76
|
+
Err(error) if error.is_transient() && attempt < 2 => delay(jitter(2_u64.pow(attempt))),
|
|
77
|
+
result => return result,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
unreachable!()
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Boundaries and tensions
|
|
85
|
+
|
|
86
|
+
A circuit breaker from [P043](p043-circuit-breakers.md) prevents more calls during continuous
|
|
87
|
+
dependency failure. Use retry for an isolated transient failure. A clear sequence and one budget are necessary for
|
|
88
|
+
the combination.
|
|
89
|
+
|
|
90
|
+
Retries at each stack layer increase the number of tries and violate the single-owner error policy. The first
|
|
91
|
+
retry can occur immediately and correct a connection race. If more retries occur immediately, they
|
|
92
|
+
can add load at the same time.
|
|
93
|
+
|
|
94
|
+
Retry wait must obey [P039](p039-bounded-waiting.md). A retry queue stays subject to
|
|
95
|
+
[P040](p040-bounded-resources.md).
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
### Positive application
|
|
100
|
+
|
|
101
|
+
An idempotent read receives a specified transient status. The client makes at most three tries
|
|
102
|
+
before the request deadline. It uses a random exponential wait and obeys `Retry-After`.
|
|
103
|
+
|
|
104
|
+
The client returns the last failure after budget exhaustion.
|
|
105
|
+
|
|
106
|
+
### Misuse or counterexample
|
|
107
|
+
|
|
108
|
+
An SDK retries five times. Its service wrapper retries each SDK call five times. A job worker also
|
|
109
|
+
retries without a limit. One request causes a retry storm.
|
|
110
|
+
|
|
111
|
+
### Athena or agent workflow
|
|
112
|
+
|
|
113
|
+
A coordinator retries a transient transport failure from a subagent only while its iteration
|
|
114
|
+
budget and time budget permit the retry. It immediately gives a validation-failure or
|
|
115
|
+
permission-denial result.
|
|
116
|
+
|
|
117
|
+
## Related principles
|
|
118
|
+
|
|
119
|
+
- [P037 — Idempotency Before Retry](p037-idempotency-before-retry.md)
|
|
120
|
+
- [P039 — Bounded Waiting](p039-bounded-waiting.md)
|
|
121
|
+
- [P040 — Bounded Resources](p040-bounded-resources.md)
|
|
122
|
+
- [P043 — Circuit Breakers](p043-circuit-breakers.md)
|
|
123
|
+
|
|
124
|
+
## References
|
|
125
|
+
|
|
126
|
+
### Source information
|
|
127
|
+
|
|
128
|
+
- [Marc Brooker, “Exponential Backoff and Jitter” (2015)](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)
|
|
129
|
+
— practitioner analysis of contention from retries at the same time and random retry wait. Athena
|
|
130
|
+
is not the source of retry limits.
|
|
131
|
+
|
|
132
|
+
### Applicable information
|
|
133
|
+
|
|
134
|
+
- [AWS Builders' Library, Timeouts, retries, and backoff with jitter](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/)
|
|
135
|
+
— production guidance for timeouts, retry multiplication, token budgets, wait, and random
|
|
136
|
+
variation.
|
|
137
|
+
- [Microsoft Azure Well-Architected Framework, transient faults](https://learn.microsoft.com/en-us/azure/well-architected/design-guides/handle-transient-faults)
|
|
138
|
+
— applicable guidance that gives finite retries and random exponential wait.
|
|
139
|
+
|
|
140
|
+
### More information
|
|
141
|
+
|
|
142
|
+
- [Google SRE, Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/)
|
|
143
|
+
— shows how retries increase overload and cause cascade failure.
|
|
144
|
+
|
|
145
|
+
[Back to the engineering principles catalog](../README.md#p038)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# P039 — Bounded Waiting
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Each external wait must have termination behavior that satisfies its risk policy. This rule is for
|
|
6
|
+
operations, locks, queues, processes, asynchronous results, and delegated tasks.
|
|
7
|
+
|
|
8
|
+
Use a deadline, timeout, cancellation signal, or other bound from measurements. The caller must
|
|
9
|
+
show the difference between success, cancellation, timeout, and failure.
|
|
10
|
+
|
|
11
|
+
**Aliases:** deadlines, timeouts, finite blocking, wait budget
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Concurrent systems and distributed systems used timeouts and deadlines for many years. Athena
|
|
18
|
+
cannot identify one source for this rule.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
When a different actor controls the operation end or different actors use a resource, set the
|
|
23
|
+
maximum wait.
|
|
24
|
+
Specify the safe outcome for budget expiration.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- Use one end-to-end deadline that all downstream calls inherit. Do not use a different timeout
|
|
29
|
+
construction for each hop.
|
|
30
|
+
- Select budgets from service objectives, measured latency, operation value, and cleanup cost.
|
|
31
|
+
- Send cancellation and remaining time to child operations.
|
|
32
|
+
- After timeout, if an ownership contract gives permission, stop work or let it continue
|
|
33
|
+
independently. A timeout does not show that remote effects stopped.
|
|
34
|
+
- Release locks, slots, and temporary resources on each terminal path.
|
|
35
|
+
- Do tests of deadline expiration, cancellation races, slow dependencies, and success near each
|
|
36
|
+
side of the boundary.
|
|
37
|
+
|
|
38
|
+
## Diagram
|
|
39
|
+
|
|
40
|
+
```mermaid
|
|
41
|
+
flowchart TD
|
|
42
|
+
A["Get the cancellation signal before the wait"] --> B["Set the deadline"]
|
|
43
|
+
B --> C["Pass the signal to the operation"]
|
|
44
|
+
C --> D{"What occurs?"}
|
|
45
|
+
D -- Success --> E["Keep the completed result"]
|
|
46
|
+
D -- "Cancellation request" --> F["Send the cancellation signal"]
|
|
47
|
+
F --> G["Keep the cancellation result"]
|
|
48
|
+
D -- "Deadline expires" --> H["Send the cancellation signal"]
|
|
49
|
+
H --> I["Keep the timeout result"]
|
|
50
|
+
D -- Failure --> J["Keep the failure result"]
|
|
51
|
+
E --> K["Release the owned resources"]
|
|
52
|
+
G --> K
|
|
53
|
+
I --> K
|
|
54
|
+
J --> K
|
|
55
|
+
K --> L["Return the terminal result"]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Language examples
|
|
59
|
+
|
|
60
|
+
Each example uses a specified cancellation contract, limits the wait, and returns a different
|
|
61
|
+
result for each terminal result.
|
|
62
|
+
|
|
63
|
+
### Python
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
def await_result(future):
|
|
67
|
+
try:
|
|
68
|
+
return Completed(future.result(timeout=2.0))
|
|
69
|
+
except CancelledError:
|
|
70
|
+
return Cancelled()
|
|
71
|
+
except TimeoutError:
|
|
72
|
+
return TimedOut()
|
|
73
|
+
except OperationError as error:
|
|
74
|
+
return Failed(error)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Rust
|
|
78
|
+
|
|
79
|
+
```rust
|
|
80
|
+
fn await_result(rx: Receiver<WorkerEvent>) -> Outcome {
|
|
81
|
+
match rx.recv_timeout(Duration::from_secs(2)) {
|
|
82
|
+
Ok(WorkerEvent::Completed(value)) => Outcome::Completed(value),
|
|
83
|
+
Ok(WorkerEvent::Cancelled) => Outcome::Cancelled,
|
|
84
|
+
Ok(WorkerEvent::Failed(error)) => Outcome::Failed(error),
|
|
85
|
+
Err(RecvTimeoutError::Timeout) => Outcome::TimedOut,
|
|
86
|
+
Err(RecvTimeoutError::Disconnected) => Outcome::Unavailable,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Boundaries and tensions
|
|
92
|
+
|
|
93
|
+
A timeout limits the caller wait. Callee execution can continue without a bound. Before a retry of
|
|
94
|
+
work with side effects, use [P037](p037-idempotency-before-retry.md), status reconciliation, or
|
|
95
|
+
compensation.
|
|
96
|
+
|
|
97
|
+
Very short timeouts cause failure that is not necessary. Systems without timeouts can cause resource leaks and
|
|
98
|
+
failure cascades. Use measurements to set the budget.
|
|
99
|
+
|
|
100
|
+
Use the budget with [P040](p040-bounded-resources.md). Many finite waits must not use all system
|
|
101
|
+
capacity.
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### Positive application
|
|
106
|
+
|
|
107
|
+
A request has a two-second deadline. Each downstream call receives the remaining budget. After
|
|
108
|
+
cancellation, each call stops owned child work and returns a different deadline result.
|
|
109
|
+
|
|
110
|
+
### Misuse or counterexample
|
|
111
|
+
|
|
112
|
+
A worker calls an external process without a timeout. The stalled process holds a concurrency slot
|
|
113
|
+
without a limit. The finite queue cannot continue.
|
|
114
|
+
|
|
115
|
+
### Athena or agent workflow
|
|
116
|
+
|
|
117
|
+
A coordinator gives delegated research a specified deadline and examines the result status. After a
|
|
118
|
+
timeout, it records the missing results. It obeys the host contract for task termination or
|
|
119
|
+
release.
|
|
120
|
+
|
|
121
|
+
It does not wait without a limit or give a result that it did not receive.
|
|
122
|
+
|
|
123
|
+
## Related principles
|
|
124
|
+
|
|
125
|
+
- [P037 — Idempotency Before Retry](p037-idempotency-before-retry.md)
|
|
126
|
+
- [P038 — Bounded Retry](p038-bounded-retry.md)
|
|
127
|
+
- [P040 — Bounded Resources](p040-bounded-resources.md)
|
|
128
|
+
- [P043 — Circuit Breakers](p043-circuit-breakers.md)
|
|
129
|
+
|
|
130
|
+
## References
|
|
131
|
+
|
|
132
|
+
### Source information
|
|
133
|
+
|
|
134
|
+
- Athena does not identify one source. Deadline and timeout controls were in use before RPC
|
|
135
|
+
systems and occur in literature about operating systems, concurrency, and networks.
|
|
136
|
+
|
|
137
|
+
### Applicable information
|
|
138
|
+
|
|
139
|
+
- [gRPC, Deadlines](https://grpc.io/docs/guides/deadlines/) — official guidance for deadline
|
|
140
|
+
selection, deadline propagation, and server work termination after expiration.
|
|
141
|
+
- [gRPC, Cancellation](https://grpc.io/docs/guides/cancellation/) — official guidance for a client
|
|
142
|
+
that sends cancellation when it no longer wants an RPC result. It gives guidance for cancellation
|
|
143
|
+
propagation. Some language handlers must implement this propagation.
|
|
144
|
+
|
|
145
|
+
### More information
|
|
146
|
+
|
|
147
|
+
- [Google SRE, Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/)
|
|
148
|
+
— gives information about expired client deadlines, server work that cannot give a result to the
|
|
149
|
+
client, resource exhaustion, and failure cascades.
|
|
150
|
+
|
|
151
|
+
[Back to the engineering principles catalog](../README.md#p039)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# P040 — Bounded Resources
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Each resource with changing demand must have a specified limit or a physical bound from measurements.
|
|
6
|
+
Examples are queues, buffers, concurrency, recursion, batches, memory, disk, work that the system did not complete, agent
|
|
7
|
+
iterations, tokens, and tool calls.
|
|
8
|
+
|
|
9
|
+
The system must give a controlled response at the bound.
|
|
10
|
+
|
|
11
|
+
**Aliases:** resource limits, finite capacity, quotas
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Operating systems, queueing theory, and safe design use resource limits. Athena does not identify
|
|
18
|
+
one source for this language-neutral rule.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
For each work unit that can occur more than one time, find the capacity owner. Set a limit from
|
|
23
|
+
measurements. Set admission, rejection, cleanup, and recovery behavior at that limit.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Make a resource inventory for each request, tenant, process, and dependency.
|
|
28
|
+
- If item costs have large differences, limit the item count and total item cost.
|
|
29
|
+
- Use platform quotas, finite executors, and finite queues. If the platform has no applicable
|
|
30
|
+
control, use a custom counter.
|
|
31
|
+
- Reserve capacity or use different pools for very important work. Low-value demand must not use all
|
|
32
|
+
capacity.
|
|
33
|
+
- Make rejection cost less than admitted work. Give a clear overload signal.
|
|
34
|
+
- Monitor saturation, rejected work, queue age, and time at the limit. After workload changes,
|
|
35
|
+
change limits.
|
|
36
|
+
- Do tests of the system at each important limit and at values more than that limit. Make sure that
|
|
37
|
+
the system releases all temporary resources and operates correctly after the limit condition.
|
|
38
|
+
|
|
39
|
+
## Diagram
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
flowchart TD
|
|
43
|
+
A["A request uses a finite resource"] --> B{"Is capacity available?"}
|
|
44
|
+
B -- Yes --> C["Admit the request"]
|
|
45
|
+
C --> D["Use and release the resource"]
|
|
46
|
+
B -- No --> E["Reject with an overload result"]
|
|
47
|
+
E --> F["Keep capacity for admitted work"]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Language examples
|
|
51
|
+
|
|
52
|
+
The examples limit queue capacity and reject new work at capacity.
|
|
53
|
+
|
|
54
|
+
### Python
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
queue = Queue(maxsize=100)
|
|
58
|
+
|
|
59
|
+
def submit(task):
|
|
60
|
+
try:
|
|
61
|
+
queue.put_nowait(task)
|
|
62
|
+
return Accepted()
|
|
63
|
+
except Full:
|
|
64
|
+
return Overloaded()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Rust
|
|
68
|
+
|
|
69
|
+
```rust
|
|
70
|
+
fn task_queue() -> (SyncSender<Task>, Receiver<Task>) {
|
|
71
|
+
sync_channel(100)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn submit(tx: &SyncSender<Task>, task: Task) -> Outcome {
|
|
75
|
+
match tx.try_send(task) {
|
|
76
|
+
Ok(()) => Outcome::Accepted,
|
|
77
|
+
Err(TrySendError::Full(_)) => Outcome::Overloaded,
|
|
78
|
+
Err(TrySendError::Disconnected(_)) => Outcome::Unavailable,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Boundaries and tensions
|
|
84
|
+
|
|
85
|
+
A large finite limit does not help if available capacity is less than the limit. A small limit can
|
|
86
|
+
cause incorrect results or low availability when it does not admit bursts that satisfy the contract.
|
|
87
|
+
|
|
88
|
+
Use measurements and service objectives to select limits. Do not use constants without measurements.
|
|
89
|
+
|
|
90
|
+
[P041](p041-backpressure-and-load-shedding.md) gives the demand response at capacity.
|
|
91
|
+
[P042](p042-fault-isolation-bulkheads.md) prevents one consumer from exhaustion of capacity for a
|
|
92
|
+
different consumer. [P039](p039-bounded-waiting.md) limits resource retention time. Bounded
|
|
93
|
+
Resources limits resource count and capacity.
|
|
94
|
+
|
|
95
|
+
## Examples
|
|
96
|
+
|
|
97
|
+
### Positive application
|
|
98
|
+
|
|
99
|
+
A worker pool limits active tasks and queue depth. At capacity, it rejects new work with a retryable
|
|
100
|
+
overload response. It records queue age and reserves capacity for health operations.
|
|
101
|
+
|
|
102
|
+
### Misuse or counterexample
|
|
103
|
+
|
|
104
|
+
An API keeps each request in an unlimited memory queue during a downstream outage. The API uses more
|
|
105
|
+
memory until the process stops. The process then has no backlog data.
|
|
106
|
+
|
|
107
|
+
### Athena or agent workflow
|
|
108
|
+
|
|
109
|
+
A swarm workflow sets limits on concurrent specialists, iterations, tool calls, and tokens. At a
|
|
110
|
+
limit, it returns an accurate result for completed work or a failure. It does not make more work.
|
|
111
|
+
|
|
112
|
+
## Related principles
|
|
113
|
+
|
|
114
|
+
- [P039 — Bounded Waiting](p039-bounded-waiting.md)
|
|
115
|
+
- [P041 — Backpressure and Load Shedding](p041-backpressure-and-load-shedding.md)
|
|
116
|
+
- [P042 — Fault Isolation / Bulkheads](p042-fault-isolation-bulkheads.md)
|
|
117
|
+
- [P043 — Circuit Breakers](p043-circuit-breakers.md)
|
|
118
|
+
|
|
119
|
+
## References
|
|
120
|
+
|
|
121
|
+
### Source information
|
|
122
|
+
|
|
123
|
+
- Athena does not identify one primary source. Operating systems and network services used quotas
|
|
124
|
+
and capacity limits for many years. Athena applies the practice to software and agent resources.
|
|
125
|
+
|
|
126
|
+
### Applicable information
|
|
127
|
+
|
|
128
|
+
- [CWE List 4.20, CWE-770: Allocation of Resources Without Limits or Throttling](https://cwe.mitre.org/data/definitions/770.html)
|
|
129
|
+
— applicable weakness definition, effects, and controls for unlimited resource allocation.
|
|
130
|
+
- [Google SRE, Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/)
|
|
131
|
+
— production guidance for queue, memory, thread, CPU, and file-descriptor exhaustion.
|
|
132
|
+
|
|
133
|
+
### More information
|
|
134
|
+
|
|
135
|
+
- [Microsoft Azure, Throttling pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling)
|
|
136
|
+
— guidance for limits for the first saturated resource and for admission control.
|
|
137
|
+
|
|
138
|
+
[Back to the engineering principles catalog](../README.md#p040)
|