@keelcore/standards 0.9.7
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 +99 -0
- package/governance/ai/conduct.md +66 -0
- package/governance/api-management.md +185 -0
- package/governance/arb.md +110 -0
- package/governance/bash.md +147 -0
- package/governance/ci.md +496 -0
- package/governance/coding.md +156 -0
- package/governance/observability.md +158 -0
- package/governance/platform.md +167 -0
- package/governance/release-policy.md +171 -0
- package/governance/runtime.md +165 -0
- package/governance/security.md +149 -0
- package/governance/testing.md +100 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# keelcore/standards
|
|
2
|
+
|
|
3
|
+
Engineering standards for keelcore projects. Single source of truth for coding, CI, and bash.
|
|
4
|
+
Consumed by AI coding tools (Claude, Cursor, Copilot) and human contributors alike.
|
|
5
|
+
|
|
6
|
+
## Governance
|
|
7
|
+
|
|
8
|
+
| File | Scope |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| [governance/coding.md](governance/coding.md) | All code edits — scope control, reviewability, safety |
|
|
11
|
+
| [governance/ci.md](governance/ci.md) | CI workflows and scripts — supply chain, coverage, permissions |
|
|
12
|
+
| [governance/bash.md](governance/bash.md) | Bash scripts — portability, structure, logging |
|
|
13
|
+
| [governance/platform.md](governance/platform.md) | Platform architecture — governance process, DNS, TLS, WAF, networking |
|
|
14
|
+
| [governance/observability.md](governance/observability.md) | Metrics, logging, tracing, alerting |
|
|
15
|
+
| [governance/security.md](governance/security.md) | IAM, encryption, key management, data classification |
|
|
16
|
+
| [governance/runtime.md](governance/runtime.md) | Containers, orchestration, deployment, compliance |
|
|
17
|
+
| [governance/api-management.md](governance/api-management.md) | API design, versioning, rate limiting, quotas, gateway |
|
|
18
|
+
|
|
19
|
+
## Consumption
|
|
20
|
+
|
|
21
|
+
### Submodule (default, language-agnostic)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git submodule add git@github.com:keelcore/standards .standards
|
|
25
|
+
git submodule update --init --recursive
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Reference governance from your tool adapters via relative paths (`.standards/governance/coding.md`).
|
|
29
|
+
|
|
30
|
+
Update to latest:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git submodule update --remote .standards
|
|
34
|
+
git add .standards && git commit -m "chore: update standards"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Go
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
go get github.com/keelcore/standards/go
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Add to your repo:
|
|
44
|
+
|
|
45
|
+
```go
|
|
46
|
+
//go:generate go run github.com/keelcore/standards/go/cmd/materialize .standards
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then run `go generate ./...` to extract governance files to `.standards/` (gitignore this directory).
|
|
50
|
+
|
|
51
|
+
### Node
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install @keelcore/standards
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Governance files are available under `node_modules/@keelcore/standards/governance/`.
|
|
58
|
+
|
|
59
|
+
### Python
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install keelcore-standards
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Tool Adapters
|
|
66
|
+
|
|
67
|
+
Copy the relevant adapter to your repo and adjust paths if needed.
|
|
68
|
+
|
|
69
|
+
| Tool | Adapter |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Claude Code | [adapters/claude/CLAUDE.md](adapters/claude/CLAUDE.md) |
|
|
72
|
+
| Cursor | [adapters/cursor/](adapters/cursor/) |
|
|
73
|
+
| GitHub Copilot | [adapters/copilot/copilot-instructions.md](adapters/copilot/copilot-instructions.md) |
|
|
74
|
+
|
|
75
|
+
## Architecture Decision Records
|
|
76
|
+
|
|
77
|
+
ADRs documenting standards design decisions live in [docs/adr/](docs/adr/).
|
|
78
|
+
|
|
79
|
+
New ADRs use the template at [docs/adr/0000-template.md](docs/adr/0000-template.md).
|
|
80
|
+
|
|
81
|
+
| ADR | Decision |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| [0001](docs/adr/0001-standards-as-submodule-and-package.md) | Standards distributed as both submodule and language package |
|
|
84
|
+
| [0002](docs/adr/0002-coverage-baseline-in-repo.md) | Code coverage baseline stored in repository |
|
|
85
|
+
| [0003](docs/adr/0003-architecture-governance-process.md) | Architecture governance via DACI, RFC, and ARB |
|
|
86
|
+
| [0004](docs/adr/0004-workload-identity-spiffe-spire.md) | SPIFFE/SPIRE for workload identity |
|
|
87
|
+
| [0005](docs/adr/0005-observability-opentelemetry.md) | OpenTelemetry as the unified observability framework |
|
|
88
|
+
| [0006](docs/adr/0006-opa-centralized-policy-engine.md) | OPA as the centralized authorization policy engine |
|
|
89
|
+
| [0007](docs/adr/0007-zero-downtime-deployment.md) | Zero-downtime deployment via blue/green and canary |
|
|
90
|
+
| [0008](docs/adr/0008-rapid-key-rotation.md) | Rapid key rotation with a 5-minute platform SLA |
|
|
91
|
+
| [0009](docs/adr/0009-gitops-change-management.md) | GitOps as the declarative change management mechanism |
|
|
92
|
+
|
|
93
|
+
## Versioning
|
|
94
|
+
|
|
95
|
+
Semantic versioning. Tags trigger publication to all package ecosystems simultaneously.
|
|
96
|
+
|
|
97
|
+
- Breaking changes (governance removals, renamed files): major version bump.
|
|
98
|
+
- New governance or expanded rules: minor version bump.
|
|
99
|
+
- Corrections, clarifications: patch version bump.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# AI Model Conduct Standards
|
|
2
|
+
|
|
3
|
+
These rules govern the behavior of AI coding assistants (Claude, Copilot, Cursor, or equivalent)
|
|
4
|
+
when working in projects under this governance. They are non-negotiable and take precedence over
|
|
5
|
+
any model-default behavior.
|
|
6
|
+
|
|
7
|
+
**Maturity:** Required
|
|
8
|
+
**Version:** 1.0.0
|
|
9
|
+
**Last Reviewed:** 2026-03-14
|
|
10
|
+
|
|
11
|
+
## Commit Attribution
|
|
12
|
+
|
|
13
|
+
- Do NOT add `Co-Authored-By`, `Generated-by`, or any AI attribution trailer to commit messages.
|
|
14
|
+
- Commit messages contain only the subject, optional body, and the required DCO `Signed-off-by`
|
|
15
|
+
trailer. No AI branding.
|
|
16
|
+
|
|
17
|
+
## Test File Protection
|
|
18
|
+
|
|
19
|
+
- Do NOT modify test files without explicit prior authorization from the developer.
|
|
20
|
+
- When a test fails, find and fix the root cause in production code. Do not adjust the test to
|
|
21
|
+
make it pass.
|
|
22
|
+
- Exceptions (adding a new test, fixing a test bug, tracking an intentional contract change)
|
|
23
|
+
require explicit approval in the conversation before any edit is made.
|
|
24
|
+
|
|
25
|
+
## Test Suite Execution
|
|
26
|
+
|
|
27
|
+
- Run `make test` (or `make unit-test` at minimum) before declaring any code change complete.
|
|
28
|
+
- Do not hand off code without verifying the test suite passes.
|
|
29
|
+
- If tests cannot be run (environment constraint), state this explicitly and enumerate what was
|
|
30
|
+
not validated.
|
|
31
|
+
|
|
32
|
+
## Entry Point Files Are Pinned
|
|
33
|
+
|
|
34
|
+
- `main.go` (and any program entry point file) is pinned — do not edit it without explicit
|
|
35
|
+
developer consent in the current conversation.
|
|
36
|
+
- Entry points are considered high-blast-radius: a silent change to `main` can alter startup
|
|
37
|
+
behavior, flag defaults, or initialization order in ways that are hard to review.
|
|
38
|
+
|
|
39
|
+
## Bash Script Delivery
|
|
40
|
+
|
|
41
|
+
- When writing or editing a bash script, always deliver the complete script.
|
|
42
|
+
- Never deliver a diff, patch, or partial snippet of a bash script.
|
|
43
|
+
- Rationale: partial bash edits are error-prone; the complete script is reviewable as a unit.
|
|
44
|
+
|
|
45
|
+
## Governance Supremacy
|
|
46
|
+
|
|
47
|
+
- Project governance documents (this repo's `governance/` tree) override any model default or
|
|
48
|
+
prior training behavior.
|
|
49
|
+
- When a governance rule conflicts with a model default (e.g., adding attribution, adding
|
|
50
|
+
speculative features, cleaning up untouched code), governance wins without exception.
|
|
51
|
+
- If a governance rule is ambiguous, ask for clarification rather than applying a default.
|
|
52
|
+
|
|
53
|
+
## Scope Discipline
|
|
54
|
+
|
|
55
|
+
- Do not perform unrequested cleanup, refactoring, or improvements in files adjacent to the
|
|
56
|
+
current change.
|
|
57
|
+
- Do not add docstrings, comments, or type annotations to code not directly modified.
|
|
58
|
+
- Do not add error handling, fallbacks, or validation for scenarios that cannot occur.
|
|
59
|
+
- Surgical edits only: the smallest correct change that satisfies the request.
|
|
60
|
+
|
|
61
|
+
## Memory and Governance Relationship
|
|
62
|
+
|
|
63
|
+
- Model memory (session-local or persisted) is subordinate to governance.
|
|
64
|
+
- If a memory contradicts governance, flag the conflict to the developer; do not silently pick
|
|
65
|
+
one over the other.
|
|
66
|
+
- Governance is the source of truth; memory captures working context and in-flight decisions.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# API Management Standards
|
|
2
|
+
|
|
3
|
+
These rules govern API design, versioning, rate limiting, quotas, lifecycle management, and
|
|
4
|
+
developer experience. They are non-negotiable unless explicitly superseded by a signed ADR.
|
|
5
|
+
|
|
6
|
+
**Maturity:** Required
|
|
7
|
+
**Version:** 1.0.0
|
|
8
|
+
**Last Reviewed:** 2026-03-09
|
|
9
|
+
|
|
10
|
+
## API Design
|
|
11
|
+
|
|
12
|
+
### Interface Contracts
|
|
13
|
+
|
|
14
|
+
1. Every API exposes a machine-readable interface definition. REST APIs use OpenAPI 3.1+.
|
|
15
|
+
gRPC services use Protocol Buffers with buf schema registry publication. GraphQL schemas
|
|
16
|
+
are registered in the central schema registry.
|
|
17
|
+
2. Interface definitions are version-controlled in the owning service's repository and published
|
|
18
|
+
to the central API catalog on every release.
|
|
19
|
+
3. APIs follow a consistent resource-oriented design: nouns for resources, standard HTTP verbs
|
|
20
|
+
(GET, POST, PUT, PATCH, DELETE) for operations, and standard status codes.
|
|
21
|
+
|
|
22
|
+
### Versioning
|
|
23
|
+
|
|
24
|
+
4. All APIs are versioned. The version is embedded in the URL path for REST (`/v1/`, `/v2/`).
|
|
25
|
+
gRPC APIs encode the version in the package name (`keelcore.auth.v1`).
|
|
26
|
+
5. A version is considered stable once it is deployed to production. Stable versions must not
|
|
27
|
+
receive breaking changes. Add a new version instead.
|
|
28
|
+
6. Breaking changes are defined as: removing or renaming a field, changing a field's type,
|
|
29
|
+
removing an endpoint, changing required/optional status of a field, or changing error semantics.
|
|
30
|
+
7. Non-breaking additions (new optional fields, new endpoints, new enum values that do not affect
|
|
31
|
+
existing behavior) may be made to a stable version.
|
|
32
|
+
8. Deprecated versions remain available for a minimum of 6 months after the successor version
|
|
33
|
+
is available. Deprecation is communicated via the `Deprecation` and `Sunset` response headers
|
|
34
|
+
and in the API catalog.
|
|
35
|
+
|
|
36
|
+
### Error Responses
|
|
37
|
+
|
|
38
|
+
9. All error responses use a consistent envelope:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"error": {
|
|
43
|
+
"code": "RESOURCE_NOT_FOUND",
|
|
44
|
+
"message": "The requested resource was not found.",
|
|
45
|
+
"request_id": "<trace_id>",
|
|
46
|
+
"details": []
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
10. `code` is a machine-readable uppercase string constant. `message` is human-readable.
|
|
52
|
+
HTTP status codes and `code` values are documented in the API catalog.
|
|
53
|
+
11. Error messages must not include internal implementation details (stack traces, SQL queries,
|
|
54
|
+
internal service names) in production responses.
|
|
55
|
+
|
|
56
|
+
### Pagination
|
|
57
|
+
|
|
58
|
+
12. All list endpoints that may return more than 100 items support cursor-based pagination.
|
|
59
|
+
Offset pagination is acceptable only for internal tooling APIs.
|
|
60
|
+
13. Page size has a maximum (default 100, configurable per endpoint, maximum 1000). Requests
|
|
61
|
+
for unlimited results are rejected.
|
|
62
|
+
14. Pagination response includes: `next_cursor`, `prev_cursor` (where supported), `total_count`
|
|
63
|
+
(where computationally feasible), and `has_more`.
|
|
64
|
+
|
|
65
|
+
## Rate Limiting
|
|
66
|
+
|
|
67
|
+
### Global Limits
|
|
68
|
+
|
|
69
|
+
15. All API traffic passes through the centralized rate limiting layer before reaching service pods.
|
|
70
|
+
16. Global rate limits protect the platform from aggregate overload. These are set by the platform
|
|
71
|
+
team and documented in the API catalog.
|
|
72
|
+
17. Rate limit enforcement uses a token bucket algorithm. Burst capacity may be up to 2× the
|
|
73
|
+
sustained rate for a window of up to 5 seconds.
|
|
74
|
+
|
|
75
|
+
### Per-Service and Per-Client Limits
|
|
76
|
+
|
|
77
|
+
18. Every API defines explicit rate limits per endpoint. Rate limits are documented in the API
|
|
78
|
+
catalog alongside the endpoint specification.
|
|
79
|
+
19. Rate limits are enforced per API key, per client identity (OAuth client ID), or per
|
|
80
|
+
authenticated user, in that priority order. Unauthenticated traffic shares a shared
|
|
81
|
+
anonymous pool with a lower limit.
|
|
82
|
+
20. Services configure rate limits independently of the global limit; the effective limit is
|
|
83
|
+
the minimum of the global and per-service limits.
|
|
84
|
+
21. Rate limit state is stored in a shared, distributed backend (e.g., Redis). Per-replica
|
|
85
|
+
in-memory rate limiting that can be bypassed by round-robin routing is prohibited.
|
|
86
|
+
|
|
87
|
+
### Rate Limit Responses
|
|
88
|
+
|
|
89
|
+
22. Rate-limited requests receive HTTP 429 with:
|
|
90
|
+
- `Retry-After` header (seconds until the client may retry)
|
|
91
|
+
- `X-RateLimit-Limit` (requests allowed per window)
|
|
92
|
+
- `X-RateLimit-Remaining` (requests remaining in the current window)
|
|
93
|
+
- `X-RateLimit-Reset` (Unix timestamp of window reset)
|
|
94
|
+
- A JSON body following the standard error envelope (rule 9 above)
|
|
95
|
+
23. Rate limit headers (`X-RateLimit-*`) are included on every API response, not only on 429s.
|
|
96
|
+
|
|
97
|
+
### Quotas
|
|
98
|
+
|
|
99
|
+
24. Usage quotas (distinct from rate limits) enforce longer-window consumption caps (daily,
|
|
100
|
+
monthly) per API key or tenant. Quotas are configured in the API management platform.
|
|
101
|
+
25. Quota exhaustion returns HTTP 429 with `code: QUOTA_EXCEEDED` and a `Retry-After` pointing
|
|
102
|
+
to the quota reset time.
|
|
103
|
+
26. Quota alerts fire at 80% and 95% consumption to allow clients and operators to take action
|
|
104
|
+
before hard limits are hit.
|
|
105
|
+
|
|
106
|
+
## Authentication and Authorization
|
|
107
|
+
|
|
108
|
+
### API Key Management
|
|
109
|
+
|
|
110
|
+
27. API keys are issued by the central API management platform. Hand-crafted keys are prohibited.
|
|
111
|
+
28. API keys are associated with: an owner (human or service), a set of allowed scopes, an
|
|
112
|
+
expiry date, and an environment (keys do not cross environment boundaries).
|
|
113
|
+
29. API keys are rotated on a maximum 12-month cycle. Keys that have not been rotated are
|
|
114
|
+
automatically expired and flagged for the owner.
|
|
115
|
+
30. API key usage is logged per request with: key ID (never the key value), endpoint, response
|
|
116
|
+
code, and latency.
|
|
117
|
+
31. Compromised API keys are revoked within 5 minutes of detection. The platform supports
|
|
118
|
+
emergency bulk revocation for a compromised credential class.
|
|
119
|
+
|
|
120
|
+
### Scopes and Permissions
|
|
121
|
+
|
|
122
|
+
32. API scopes are defined at the resource level and follow the pattern `{resource}:{action}`
|
|
123
|
+
(e.g., `orders:read`, `orders:write`). Wildcard scopes are prohibited for non-admin APIs.
|
|
124
|
+
33. Clients are issued only the scopes they need. Over-provisioned scopes are flagged in the
|
|
125
|
+
quarterly access review.
|
|
126
|
+
34. Admin scopes require MFA-protected issuance and a shorter expiry (maximum 8 hours).
|
|
127
|
+
|
|
128
|
+
## API Gateway
|
|
129
|
+
|
|
130
|
+
### Gateway Responsibilities
|
|
131
|
+
|
|
132
|
+
35. The API gateway handles: routing, authentication verification, rate limiting, WAF enforcement,
|
|
133
|
+
request/response logging, and protocol translation (where needed).
|
|
134
|
+
36. Business logic must not reside in gateway configuration. Transformation rules that implement
|
|
135
|
+
business semantics belong in the upstream service.
|
|
136
|
+
37. Gateway configuration is version-controlled and deployed via the same GitOps pipeline as
|
|
137
|
+
application code. Manual console edits are prohibited in staging and production.
|
|
138
|
+
|
|
139
|
+
### Backend Health and Circuit Breaking
|
|
140
|
+
|
|
141
|
+
38. The gateway enforces circuit breakers for each upstream service. A service that exceeds the
|
|
142
|
+
error threshold (5xx rate > 50% for 10 seconds) is circuit-broken; traffic is rejected at
|
|
143
|
+
the gateway with HTTP 503 until the upstream recovers.
|
|
144
|
+
39. Upstream health checks are configured per route. The gateway does not route to unhealthy
|
|
145
|
+
upstreams.
|
|
146
|
+
|
|
147
|
+
### Observability at the Gateway
|
|
148
|
+
|
|
149
|
+
40. The gateway emits per-endpoint metrics: request rate, error rate, latency (p50/p95/p99),
|
|
150
|
+
and upstream latency. These are automatically included in each API's RED dashboard.
|
|
151
|
+
41. Every request is tagged with a `request_id` injected or verified by the gateway. The
|
|
152
|
+
`request_id` matches the `trace_id` in distributed traces.
|
|
153
|
+
|
|
154
|
+
## API Lifecycle
|
|
155
|
+
|
|
156
|
+
### Catalog and Discovery
|
|
157
|
+
|
|
158
|
+
42. Every API is registered in the central API catalog before its first production deployment.
|
|
159
|
+
Unregistered APIs are blocked by admission control.
|
|
160
|
+
43. The catalog entry includes: service owner, SLO, rate limits, authentication requirements,
|
|
161
|
+
versioning status, deprecation dates (if applicable), and a link to the OpenAPI/Protobuf spec.
|
|
162
|
+
44. The catalog is queryable by all engineers and is the single source of truth for API
|
|
163
|
+
discoverability.
|
|
164
|
+
|
|
165
|
+
### Deprecation and Retirement
|
|
166
|
+
|
|
167
|
+
45. API retirement follows a defined process: announce deprecation (Sunset header + catalog
|
|
168
|
+
update), monitor usage, notify active consumers, enforce sunset date.
|
|
169
|
+
46. An API version with active traffic cannot be retired without consumer migration or an
|
|
170
|
+
explicitly accepted exception.
|
|
171
|
+
47. The `Sunset` date is set in UTC and announced at least 6 months in advance for externally
|
|
172
|
+
consumed APIs, 30 days for internal-only APIs.
|
|
173
|
+
|
|
174
|
+
## Do Not
|
|
175
|
+
|
|
176
|
+
- Publish an API without an OpenAPI/Protobuf spec in the central catalog.
|
|
177
|
+
- Make breaking changes to a stable API version.
|
|
178
|
+
- Issue API keys outside the central API management platform.
|
|
179
|
+
- Cross environment boundaries with API keys.
|
|
180
|
+
- Return internal stack traces or SQL errors in production API responses.
|
|
181
|
+
- Implement rate limiting as per-replica in-memory state.
|
|
182
|
+
- Configure the gateway with business logic or inline transformations.
|
|
183
|
+
- Retire an API version with active consumers without an approved migration plan.
|
|
184
|
+
- Return list endpoints without pagination for collections that may grow beyond 100 items.
|
|
185
|
+
- Omit rate limit headers from API responses.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Architecture Review Board (ARB)
|
|
2
|
+
|
|
3
|
+
**Maturity:** Required
|
|
4
|
+
**Version:** 1.0.0
|
|
5
|
+
**Last Reviewed:** 2026-03-09
|
|
6
|
+
|
|
7
|
+
The ARB is the governing body for platform architecture decisions. It is the default Approver
|
|
8
|
+
for all architecture ADRs and the final escalation point for cross-domain technical disputes.
|
|
9
|
+
|
|
10
|
+
## Membership
|
|
11
|
+
|
|
12
|
+
### Composition
|
|
13
|
+
|
|
14
|
+
1. The ARB has a minimum of 5 members and a maximum of 9 members.
|
|
15
|
+
2. Members are nominated by the CTO and serve a minimum term of 12 months.
|
|
16
|
+
3. Required seats (one each): Infrastructure, Security, Observability, Data, Application Platform.
|
|
17
|
+
4. The CTO or a designated VP of Engineering holds the Chair seat. The Chair is a non-voting
|
|
18
|
+
member except to break ties (see Tie-Breaking below).
|
|
19
|
+
5. Membership is documented in the internal people directory and in this file's companion
|
|
20
|
+
`docs/arb-members.md` (maintained separately from this governance doc to avoid churn).
|
|
21
|
+
|
|
22
|
+
### Eligibility
|
|
23
|
+
|
|
24
|
+
6. Members must be active engineers or engineering managers with direct responsibility in their
|
|
25
|
+
domain. Advisory or external members are not permitted.
|
|
26
|
+
7. A member who misses three consecutive meetings without proxy is automatically suspended
|
|
27
|
+
pending review by the Chair.
|
|
28
|
+
|
|
29
|
+
## Meeting Cadence
|
|
30
|
+
|
|
31
|
+
8. The ARB meets on a defined monthly cadence. The meeting schedule is published at the start
|
|
32
|
+
of each quarter.
|
|
33
|
+
9. Emergency sessions may be called by the Chair or by any two members with a minimum 24-hour
|
|
34
|
+
notice. Emergency sessions are limited to the agenda item that triggered them.
|
|
35
|
+
10. Meeting notes and decisions are published to the engineering wiki within five business days.
|
|
36
|
+
11. Decisions made asynchronously (via PR approval or written vote) are recorded with the same
|
|
37
|
+
formality as decisions made in session.
|
|
38
|
+
|
|
39
|
+
## Decision-Making
|
|
40
|
+
|
|
41
|
+
### Quorum
|
|
42
|
+
|
|
43
|
+
12. Quorum is a simple majority of seated, non-suspended members (excluding the Chair):
|
|
44
|
+
- 5 members: quorum = 3
|
|
45
|
+
- 7 members: quorum = 4
|
|
46
|
+
- 9 members: quorum = 5
|
|
47
|
+
13. Decisions made without quorum are provisional. They must be ratified at the next session
|
|
48
|
+
where quorum is present, or they are void.
|
|
49
|
+
14. A member who has a conflict of interest in a decision must declare it and recuse. Recused
|
|
50
|
+
members do not count toward quorum for that item.
|
|
51
|
+
|
|
52
|
+
### Voting
|
|
53
|
+
|
|
54
|
+
15. Decisions are made by simple majority of present, non-recused members.
|
|
55
|
+
16. Votes are recorded (member, vote, rationale for dissent) in the meeting notes.
|
|
56
|
+
17. Abstentions are permitted but discourage without stated reason.
|
|
57
|
+
|
|
58
|
+
### Tie-Breaking
|
|
59
|
+
|
|
60
|
+
18. When a vote is tied, the Chair casts the deciding vote.
|
|
61
|
+
19. The Chair must state their rationale when casting a tie-breaking vote.
|
|
62
|
+
20. Tie-breaking decisions are flagged in meeting notes for CTO awareness.
|
|
63
|
+
|
|
64
|
+
## Scope of Authority
|
|
65
|
+
|
|
66
|
+
21. The ARB has authority over: platform architecture standards, vendor selection for
|
|
67
|
+
platform-level tooling, cross-domain API contracts, security architecture, and
|
|
68
|
+
data architecture patterns.
|
|
69
|
+
22. The ARB does not have authority over: team-internal implementation choices, product
|
|
70
|
+
roadmap prioritization, staffing decisions, or budget approval.
|
|
71
|
+
23. Any team may bring a decision to the ARB for guidance even if ARB approval is not strictly
|
|
72
|
+
required. The ARB may accept or decline to review.
|
|
73
|
+
|
|
74
|
+
## ADR and RFC Approval
|
|
75
|
+
|
|
76
|
+
24. The ARB is the default Approver for all ADRs tagged as architecture decisions.
|
|
77
|
+
25. The ARB reviews RFCs at the Under Discussion stage. Approval converts an RFC to Accepted
|
|
78
|
+
and triggers ADR creation.
|
|
79
|
+
26. The ARB may delegate Approver authority for a specific decision to a named individual or
|
|
80
|
+
sub-committee. Delegation is recorded in the relevant ADR/RFC.
|
|
81
|
+
27. The ARB chair may approve urgent security-related ADRs unilaterally with 24-hour notice
|
|
82
|
+
to the full board, subject to ratification at the next session.
|
|
83
|
+
|
|
84
|
+
## Escalation
|
|
85
|
+
|
|
86
|
+
28. Escalation path: Team → Domain Lead → ARB → CTO.
|
|
87
|
+
29. Any engineer may escalate a decision to the ARB by opening a GitHub issue in the
|
|
88
|
+
`keelcore/standards` repository labeled `arb-escalation`.
|
|
89
|
+
30. The ARB must acknowledge escalations within three business days and schedule review
|
|
90
|
+
within ten business days.
|
|
91
|
+
31. ARB decisions may be escalated to the CTO only on the grounds of: process violation,
|
|
92
|
+
conflict of interest, or organizational policy conflict. The CTO's decision is final.
|
|
93
|
+
32. Escalation outcomes are published (with appropriate confidentiality) in the engineering wiki.
|
|
94
|
+
|
|
95
|
+
## Standards Cadence
|
|
96
|
+
|
|
97
|
+
33. The ARB publishes a versioned Architecture Standards snapshot at least once per quarter.
|
|
98
|
+
The snapshot is tagged in this repository as `arb-standards-YYYY-QN`.
|
|
99
|
+
34. Each quarterly snapshot includes: new ADRs accepted since the last snapshot, standards
|
|
100
|
+
that changed maturity level, deprecated standards, and open RFCs in progress.
|
|
101
|
+
35. The ARB reviews all standards marked `Deprecated` at least once per year to confirm
|
|
102
|
+
retirement or rescind deprecation.
|
|
103
|
+
|
|
104
|
+
## Do Not
|
|
105
|
+
|
|
106
|
+
- Allow a decision with quorum impact to proceed if quorum is not met.
|
|
107
|
+
- Allow a member to vote on a decision where they have a declared conflict of interest.
|
|
108
|
+
- Publish meeting notes without removing information subject to legal hold or HR confidentiality.
|
|
109
|
+
- Allow the Chair to cast a non-tie-breaking vote.
|
|
110
|
+
- Make ARB decisions without recording them in the engineering wiki within five business days.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Bash Script Standards
|
|
2
|
+
|
|
3
|
+
These rules govern all bash scripts in this project. They are non-negotiable.
|
|
4
|
+
|
|
5
|
+
**Maturity:** Required
|
|
6
|
+
**Version:** 1.0.0
|
|
7
|
+
**Last Reviewed:** 2026-03-09
|
|
8
|
+
|
|
9
|
+
## Portability and Shell Baseline
|
|
10
|
+
|
|
11
|
+
1. Google Bash style unless overridden by rules below.
|
|
12
|
+
2. Darwin-compatible; Bash 3.x compatible — no `mapfile`, no `declare -A`.
|
|
13
|
+
3. Shebang: `#!/usr/bin/env bash` always.
|
|
14
|
+
4. Use the explicit shell options block (not `set -euo pipefail` shorthand).
|
|
15
|
+
|
|
16
|
+
## Required Shell Options Block
|
|
17
|
+
|
|
18
|
+
Every script begins with:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
#!/usr/bin/env bash
|
|
22
|
+
# <script name>
|
|
23
|
+
# <functional description, with arguments if needed>
|
|
24
|
+
|
|
25
|
+
# bash configuration:
|
|
26
|
+
# 1) Exit script if you try to use an uninitialized variable.
|
|
27
|
+
set -o nounset
|
|
28
|
+
|
|
29
|
+
# 2) Exit script if a statement returns a non-true return value.
|
|
30
|
+
set -o errexit
|
|
31
|
+
|
|
32
|
+
# 3) Use the error status of the first failure, rather than that of the last item in a pipeline.
|
|
33
|
+
set -o pipefail
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Script Structure
|
|
37
|
+
|
|
38
|
+
5. `main` is the FIRST function defined in the file.
|
|
39
|
+
6. `main "${@:-}"` is the LAST line of the file.
|
|
40
|
+
7. Always provide the complete script, never a patch or diff.
|
|
41
|
+
8. Never omit any referenced function.
|
|
42
|
+
|
|
43
|
+
## Functions
|
|
44
|
+
|
|
45
|
+
9. All function declarations preceded by keyword `function`.
|
|
46
|
+
10. No `function_` prefix on function names.
|
|
47
|
+
11. Function names: lowercase, simple, reflect intent.
|
|
48
|
+
12. One statement per line.
|
|
49
|
+
13. No function body > 10 lines unless reduction is genuinely impossible.
|
|
50
|
+
14. Prefer decomposition into small, reusable helpers.
|
|
51
|
+
15. Load-bearing functions: log intent first, then log result.
|
|
52
|
+
|
|
53
|
+
## Arguments and Validation
|
|
54
|
+
|
|
55
|
+
16. Validate argument count.
|
|
56
|
+
17. Validate required arguments are non-null.
|
|
57
|
+
18. Support empty argument lists under `set -u` using `"${@:-}"`.
|
|
58
|
+
19. `validate_args` must allow an empty first argument when zero arguments are valid:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
function validate_args() {
|
|
62
|
+
if [ "${#}" -gt 0 ] && [ -z "${1:-}" ]; then
|
|
63
|
+
log '❌ Error: Unexpected empty argument'
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Variables
|
|
70
|
+
|
|
71
|
+
20. Always `"${var}"` style for variable expansion.
|
|
72
|
+
21. Quote expansions unless unquoted behavior is explicitly required.
|
|
73
|
+
22. `local -r` for immutable locals NOT assigned from subshell.
|
|
74
|
+
23. Mutable locals or subshell-assigned: declare on one line, assign on next:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
local result
|
|
78
|
+
result="$(some_command)"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
24. Single quotes for literal strings with no expansion needed.
|
|
82
|
+
|
|
83
|
+
## Logging and Output
|
|
84
|
+
|
|
85
|
+
25. Route all messaging through a `log` function.
|
|
86
|
+
26. `log` must tee to a well-known log file.
|
|
87
|
+
27. Capture original stdout in `main` with `exec 5>&1`; `log` writes to FD 5.
|
|
88
|
+
28. Use emoji for key accomplishments.
|
|
89
|
+
29. Load-bearing functions log both intent and result.
|
|
90
|
+
|
|
91
|
+
## Printing
|
|
92
|
+
|
|
93
|
+
30. Prefer `printf` over `echo`.
|
|
94
|
+
31. `printf` format string must be single-quoted with explicit format specifiers.
|
|
95
|
+
32. Use `echo` only with no parameters and no formatting concerns.
|
|
96
|
+
|
|
97
|
+
## Standard `log` Function Pattern
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
function log() {
|
|
101
|
+
local msg
|
|
102
|
+
msg="${1:-}"
|
|
103
|
+
printf '%s\n' "${msg}" | tee -a '/tmp/SCRIPTNAME.log' >&5
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Standard `main` Pattern
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
function main() {
|
|
111
|
+
exec 5>&1
|
|
112
|
+
validate_args "${@:-}"
|
|
113
|
+
# ... work ...
|
|
114
|
+
}
|
|
115
|
+
# ... helper functions ...
|
|
116
|
+
main "${@:-}"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## GitHub Actions `validate_args` Quirk
|
|
120
|
+
|
|
121
|
+
In GitHub Actions, `shell: bash` expands an empty `$@` to a single empty-string argument when
|
|
122
|
+
using `"${@:-}"`. Unadjusted, this triggers the argument check spuriously. Apply the following
|
|
123
|
+
fixups based on script type:
|
|
124
|
+
|
|
125
|
+
**Zero-argument scripts** — tolerate the single-empty-string artifact; reject any real arg:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
function validate_args() {
|
|
129
|
+
if [ "${#}" -gt 1 ] || [ -n "${1:-}" ]; then
|
|
130
|
+
log '❌ Error: Unexpected argument'
|
|
131
|
+
exit 1
|
|
132
|
+
fi
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Argument-taking scripts** — tolerate the artifact; still catch multiple or non-empty extra args:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
function validate_args() {
|
|
140
|
+
if [ "${#}" -gt 1 ] && [ -n "${1:-}" ]; then
|
|
141
|
+
log '❌ Error: Too many arguments'
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Do NOT change the call site from `"${@:-}"` to `"$@"` — fix the body only.
|