Strong clean code rules for Plexus contributors. This is the single source of truth for code quality, style, and OSS contribution standards. All PRs MUST comply.
Plexus context: 10-crate Rust workspace · Rust 1.95.0 · edition 2024 · tokio + tonic + axum + libp2p + sqlx · Apache 2.0 · DCO sign-off · K8s-native distributed inference.
Authority hierarchy: This document combines 28+ authoritative sources (Rust API Guidelines · Linux Kernel · Apache · CNCF · Kubernetes · Google Eng Practices · OpenSSF · Effective Rust · Embark Studios · Tokio · Tonic · Protobuf · Prometheus · OpenTelemetry · Operator SDK) into Plexus-specific rules.
Rule levels (RFC 2119 정합):
- MUST — 위반 시 PR reject (자동 차단 또는 reviewer reject)
- SHOULD — 강력 권장. 예외 시 PR body 또는 commit body 에 justification 의무
- MAY — context 별 판단
Enforcement matrix (6-layer):
| Layer | Tool | Trigger |
|---|---|---|
| L0 IDE | rustfmt + rust-analyzer + clippy auto | save / type |
| L1 pre-commit | lefthook cargo fmt --check + clippy -D warnings + gitleaks |
git commit |
| L2 pre-push | lefthook cargo test --workspace + cargo audit |
git push |
| L3 CI (GitLab L5) | .gitlab-ci.yml (RFC-0043, shadow → enforcing) |
MR pipeline |
| L4 PR review | reviewer manual + LGTM | PR open |
| L5 release | SBOM + signed release + CHANGELOG | git tag |
본 표준의 5 원칙. 충돌 시 우선순위:
- Stability over speed (ADR-0005 정합) — production-grade stability 가 속도보다 우선. TIGHT mode (3x 8GB → 24GB pool → 24GB LLM) 의 6 primitive 의무.
- One thing well per module — Linux Kernel "do just one thing" + Rust API Guidelines C-WORD-ORDER. 모듈/함수/struct 가 단일 책임.
- Tests as documentation — public API 의 doc test 는 실 동작 evidence. 변경 시 동시 update.
- Errors are values —
Result<T, E>의무, panic 금지 (production). thiserror (lib) + anyhow (bin) 분리. - Async cancellation safety — 모든
select!branch 가 cancel-safe. cleanup 의무.
본 5 원칙이 충돌 시 stability (R8) > simplicity > performance > convenience 순.
| Element | Convention | Example |
|---|---|---|
| Crate / module | snake_case 단복수 명사 1개 |
plexus_core, worker |
| Type / trait / enum variant | UpperCamelCase |
RequestContext, CircuitState::Open |
| Function / method / variable | snake_case |
send_tensor, cache_invalidate |
| Constant / static | SCREAMING_SNAKE_CASE |
PER_HOP_TIMEOUT, MAX_BATCH_SIZE |
| Lifetime | short lowercase | 'a, 'src, 'de |
| Type parameter | uppercase 1 letter 또는 UpperCamelCase |
T, E, K, V, Backend |
| Macro | snake_case! |
tracing::info! |
Conversion method prefixes (C-CONV):
| Prefix | Cost | Ownership | Example |
|---|---|---|---|
as_ |
Free | Borrowed → borrowed | str::as_bytes |
to_ |
Expensive | Borrowed → owned (non-Copy) |
Path::to_owned |
into_ |
Variable | Owned → owned | String::into_bytes |
from_ |
— | Constructor | String::from_utf8 |
try_from_ / try_into_ |
Variable | Fallible | i32::try_from(u64) |
new |
— | Default constructor | Vec::new |
with_* |
— | Constructor with arg | Vec::with_capacity |
Getters (C-GETTER): 단일 필드 접근자는 field() 가 아닌 get_field() 금지. Indexed/keyed 접근만 get_*.
Word order (C-WORD-ORDER): Vec::new not Vec::create_new; HashMap::insert not HashMap::put. Stable 생태계 정합.
Rust API Guidelines + Effective Rust Item 27:
- crate root:
# - 모든
lib.rs/mod최상단에//!module doc - 모든
pubitem (fn,struct,enum,trait,const) 에///doc 1문장 이상 - 모든
pub fn -> Result<_, _>에# Errors섹션 - panic 가능 모든 함수에
# Panics섹션 - 모든
unsafe fn에# Safety섹션 - 권장 모든 public function 에
# Examplesrunnable doc test Cargo.toml에description/license/repository/documentation/keywords/categories(C-METADATA)- private 함수도 SHOULD: complex algorithm 또는 비명확한 invariant 시 doc
Doc test 패턴:
/// Computes the BLAKE3 hash of the input bytes.
///
/// # Examples
///
/// ```
/// use plexus_core::hash::blake3_hex;
///
/// let h = blake3_hex(b"hello");
/// assert_eq!(h.len(), 64);
/// ```
///
/// # Errors
///
/// Never returns `Err` — function is infallible. Type kept for trait compat.
///
/// # Panics
///
/// Never panics.
pub fn blake3_hex(input: &[u8]) -> Result<String, std::convert::Infallible> {
Ok(blake3::hash(input).to_hex().to_string())
}Library crates (모든 plexus-* crate) — thiserror:
use thiserror::Error;
#[derive(Debug, Error)]
pub enum NetError {
#[error("connection refused to {peer}")]
Refused { peer: PeerId },
#[error("transport error")]
Transport(#[source] std::io::Error),
#[error("deadline exceeded after {elapsed:?}")]
DeadlineExceeded { elapsed: std::time::Duration },
}
pub type Result<T> = std::result::Result<T, NetError>;Binary crates (plexus-cli 의 main / integration) — anyhow:
use anyhow::{Context, Result};
fn main() -> Result<()> {
let config = load_config("config.toml")
.context("loading config from config.toml")?;
// ...
Ok(())
}MUST rules:
- 모든 recoverable error 는
Result<T, E>— library code 에 panic 금지 ?operator 우선 (C-QUESTION-MARK)- Error type 이
std::error::Error구현 +source()chain 유지 (C-GOOD-ERR) Display+Debug의무 (C-COMMON-TRAITS)#[non_exhaustive]모든 public error enum (future-proofing)- production code 에서
unwrap()/expect()금지. test 또는#[cfg(test)]만 허용 expect()사용 시"BUG: <invariant>"형식 message 의무todo!()/unimplemented!()non-test code 금지 (clippy deny)- domain-specific error variants — generic
Other(String)회피
RPC boundary 에러 매핑 (gRPC + axum):
impl From<NetError> for tonic::Status {
fn from(e: NetError) -> Self {
use tonic::{Code, Status};
match e {
NetError::Refused { peer } => Status::new(Code::Unavailable, format!("refused {peer}")),
NetError::Transport(io) => Status::new(Code::Internal, io.to_string()),
NetError::DeadlineExceeded { elapsed } => {
Status::new(Code::DeadlineExceeded, format!("after {elapsed:?}"))
}
}
}
}Runtime selection:
| Workload | Runtime | Pattern |
|---|---|---|
| Server (tonic / axum) | #[tokio::main(flavor = "multi_thread")] |
worker threads = num_cpus |
| CLI / single-task | #[tokio::main(flavor = "current_thread")] |
smaller binary |
| Test | #[tokio::test] |
per-test runtime |
Locks vs channels decision (MUST 정합):
| Need | Use | Rationale |
|---|---|---|
Sync state, never crosses .await |
parking_lot::Mutex |
sync, fast, no poisoning |
Sync state held across .await |
tokio::sync::Mutex |
sync mutex blocks runtime |
| Read-heavy state | tokio::sync::RwLock |
fair write-preferring |
| Single-producer broadcast | tokio::sync::broadcast |
bounded, lossy on lag |
| Multi-producer / single-consumer pipeline | tokio::sync::mpsc (bounded) |
backpressure |
| One-shot reply / cancellation | tokio::sync::oneshot |
|
| Notify single waiter | tokio::sync::Notify |
MUST rules:
- Never hold sync mutex across
.await— clippyawait_holding_lockdeny - All channels bounded in production —
mpsc::channel(N)notunbounded_channel() - CPU-bound work →
tokio::task::spawn_blocking - Cancellation →
tokio_util::sync::CancellationToken(hierarchical) notArc<AtomicBool> tokio::select!branches MUST be cancel-safe — document cancel-safety in doc comment if non-obvious- Always set timeout on outbound network call:
tokio::time::timeout(deadline, fut) JoinHandlefromtokio::spawnMUST be tracked or detached explicitly- Shutdown: listen for both
tokio::signal::ctrl_c()ANDsignal::unix::SignalKind::terminate()(K8s SIGTERM) - Shutdown drain timeout = 30s default (K8s
terminationGracePeriodSeconds: 120s의 1/4 — gateway drain reserve)
SHOULD: structured concurrency via JoinSet (homogeneous tasks) or TaskTracker (graceful drain).
MUST:
- modern
foo.rs+foo/directory pattern (NOTfoo/mod.rs— edition 2018+ style) - 각
lib.rs구조://!crate doc →#![lints]attrs →pub usere-exports →pub moddeclarations pub use로 crate facade pattern — 사용자가 crate root 에서 import- Visibility:
pub(crate)우선,pub최소화 (Effective Rust Item 22) - 세밀한 visibility:
pub(in crate::module)적절히 사용
SHOULD:
- 파일 크기 ~500 lines 한계 — 초과 시 split
crate::절대 경로 (sub-module 에서),super::만 sibling 접근- wildcard
use foo::*금지 (prelude 모듈 외)
Plexus workspace layout:
plexus/
├── Cargo.toml # [workspace] + [workspace.dependencies] + [workspace.lints]
├── crates/
│ ├── plexus-core/ # 도메인 타입, no I/O
│ ├── plexus-kernel/ # GPU kernel backend
│ ├── plexus-tensor/ # Tensor primitive + sharding
│ ├── plexus-graph/ # Compute graph + partition
│ ├── plexus-runtime/ # Native LLM 아키텍처
│ ├── plexus-gateway/ # axum + tonic API
│ ├── plexus-worker/ # tonic gRPC worker
│ ├── plexus-verifier/ # 검증 layer
│ ├── plexus-telemetry/ # tracing + Prometheus
│ └── plexus-cli/ # bin: CLI entry
└── proto/ # tonic-build .proto 정의
Rust API Guidelines + Effective Rust:
- Newtype 도메인 ID (C-NEWTYPE, Item 6):
struct UserId(u64);not rawu64 - No
boolparameters in public API (C-CUSTOM-TYPE):enum Verbose { Yes, No }notfn build(verbose: bool) #[non_exhaustive]public struct/enum 생장 가능 (C-STRUCT-PRIVATE)- Sealed traits trait extension 통제 (C-SEALED): private supertrait
Sealed - Private struct fields + accessor (C-STRUCT-PRIVATE)
- Builder pattern struct with 4+ fields (C-BUILDER)
bitflagscrate flag set (C-BITFLAG)
SHOULD: typestate via PhantomData<T> (e.g., Conn<Idle> → Conn<Active>).
MUST:
Vec::with_capacity(n)size known aheadString::with_capacity(n)accumulating strings- iterator combinator over manual loop (equally fast, more idiomatic)
clone()회피 —&T,&str,&[T](C-CALLER-CONTROL)Cow<'_, T>"maybe owned" parameterBox<LargeVariant>enum 의 one variant >> others#[inline]만 small cross-crate hot-path#[cold]error path (branch prediction)
Release profile (Cargo.toml):
[profile.release]
lto = "thin" # link-time optimization
codegen-units = 1
strip = "symbols"
opt-level = 3
panic = "abort" # smaller binarySHOULD: type > 128 bytes triggers memcpy — cargo +nightly rustc -- -Zprint-type-sizes 로 audit.
| Feature | Action |
|---|---|
| Temporary scope of tail expressions | refactor c.borrow().len() pattern |
if let temporary scope |
review long if let chains |
Never type fallback (! → !) |
명시적 type annotation 필요 시 |
| Match ergonomics 2024 | no mut on inferred ref, no redundant ref, no & on inferred-ref pattern |
| RPIT lifetime capture | impl Trait capture all generics; restrict via + use<'a, T> |
| Unsafe extern blocks | unsafe extern "C" { ... } 의무, items 에 safe fn / unsafe fn |
| Unsafe attributes | #[unsafe(no_mangle)], #[unsafe(export_name = "…")] |
gen keyword reserved |
identifier gen 회피, r#gen if needed |
| Prelude additions | Future, IntoFuture 추가 — trait method 충돌 disambiguate |
expr fragment matches const + _ |
macros — expr_2021 if 2021-behavior 필요 |
| Cargo resolver v3 | 자동, package.rust-version = "1.95" 명시 |
Migration: cargo fix --edition 자동.
본 표준의 lint config 는 Cargo.toml 의 [workspace.lints] 에 codify. 각 crate Cargo.toml 에 [lints] workspace = true.
[workspace.lints.rust]
# Safety
unsafe_code = "forbid" # MUST — Plexus has no FFI requirement
unsafe_op_in_unsafe_fn = "deny"
# API hygiene
missing_docs = "warn" # SHOULD — gradually enable as deny
missing_debug_implementations = "warn"
unreachable_pub = "warn"
# Style
rust_2018_idioms = "warn"
unused_lifetimes = "warn"
unused_macro_rules = "warn"
elided_lifetimes_in_paths = "warn"
single_use_lifetimes = "warn"
# Future
unstable_features = "deny"[workspace.lints.clippy]
# Default + pedantic + nursery + cargo all warned
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
cargo = { level = "warn", priority = -1 }
# Hard denies (CI fail — production code 안전성)
await_holding_lock = "deny" # async mutex 위 sync mutex
await_holding_refcell_ref = "deny"
dbg_macro = "deny" # forgotten dbg!()
exit = "deny" # std::process::exit not allowed in lib
mem_forget = "deny"
todo = "deny" # production code in todo
unimplemented = "deny"
unwrap_used = "deny" # production unwrap
expect_used = "deny" # production expect (test allowed)
panic = "deny" # production panic
indexing_slicing = "deny" # use .get() / .first() / etc
integer_arithmetic = "warn" # overflow audit
float_arithmetic = "warn"
unwrap_in_result = "deny"
manual_assert = "deny"
unnecessary_wraps = "warn"
unneeded_field_pattern = "warn"
# Allow pedantic noise (signal-to-noise 균형)
module_name_repetitions = "allow" # plexus_core::core_module 같이 자연스러움
missing_errors_doc = "allow" # 점진적 활성
missing_panics_doc = "allow"
must_use_candidate = "allow"
similar_names = "allow"
type_complexity = "allow"
too_many_lines = "allow"
# Cargo lints
multiple_crate_versions = "warn"
wildcard_dependencies = "deny"각 lib.rs / main.rs 최상단:
#![forbid(unsafe_code)]
#![warn(missing_docs)] // gradually 'deny' 로
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
//! Crate-level doc comment.
특정 lint 가 정당화 가능한 violation 시 ADR 또는 inline #[allow(...)] + 인접 주석 의무:
// SAFETY: K8s gRPC health probe requires unwrap on well-known port parse.
// Port 7878 is hard-coded in StatefulSet manifest (see deploy/k8s/).
#[allow(clippy::unwrap_used)]
let addr: SocketAddr = "0.0.0.0:7878".parse().unwrap();Exception 통계 → governance-report clippy_allow_count rule (별도 추적).
MUST:
.proto위치 =proto/<package>/v1/<service>.proto(version prefix v1)- Package:
lower_snake_case또는 dot-delimited (plexus.worker.v1) — Java-stylecom.x.y금지 - Message =
TitleCase, field =snake_case, enum =TitleCasetype +UPPER_SNAKE_CASEvalues - 첫 enum value =
_UNSPECIFIED = 0 requiredfield 금지 (proto3 표준)- Reserved tags:
reserved 5, 7 to 10; - 표준 CRUD:
Get/List/Create/Update/Delete(AIP-131/132/133/134/135) - 모든 client RPC 에 deadline 설정 — 기본 tonic = infinite
- Deadline propagation: 다운스트림 호출 시 incoming deadline - 50-200ms reserve
tonic::Status+ 적절한 code (UNAVAILABLE/DEADLINE_EXCEEDED/INVALID_ARGUMENT/NOT_FOUND/FAILED_PRECONDITION/INTERNAL) — never rawStringgrpc.health.v1.Health서비스 의무 (K8s probe)- Tower layer 순서:
tracing → auth → rate-limit → timeout → retry → load-shed - Single
Channelper target (HTTP/2 multiplex) - mTLS between services in K8s (tonic + rustls)
SHOULD:
grpc.reflection.v1.ServerReflection(debug + dev), feature flag 로 prod gate- async interceptor (Tonic 0.5.7+) — sync interceptor 는 executor 차단
MUST:
- Handler signature:
async fn h(extractors...) -> impl IntoResponse - Extractor 순서:
State/Path/Query/ headers/auth /Json(body LAST) - 커스텀 error enum +
IntoResponseimpl (status + JSON body) — rawanyhow::Error금지 - Middleware via
tower::Layer+ServiceBuilder(route-specific 만.route_layer) - Request ID:
tower-http::request_idmiddleware +tracingspan propagation - Graceful shutdown:
axum::serve(...).with_graceful_shutdown(signal_fut) - Signal future:
tokio::select!overctrl_c()+SignalKind::terminate() - Compression:
tower-http::compression::CompressionLayer(gzip + br) - CORS: explicit allow-list, NEVER
Anyin production - Fallback handler: 명시적 404 JSON
- Body limit:
RequestBodyLimitLayer(default 2MB)
MUST:
tracingmacros only —println!/log::*금지- Level 정책:
error!(alarm-worthy) /warn!(degraded recoverable) /info!(lifecycle: startup/shutdown/config) /debug!(per-request dev) /trace!(per-iteration off in prod) #[tracing::instrument]async function 경계 + RPC entry- Skip large fields:
#[instrument(skip(self, big_buffer))] - Structured fields:
%value(Display) for user IDs,?value(Debug) for complex types - Production formatter: JSON via
tracing_subscriber::fmt().json() EnvFilter(e.g.,RUST_LOG=plexus_worker=debug,info)request_idspan field at entry — child span 자동 propagate
SHOULD: log sampling for debug/trace high-throughput (DynFilter rate limit).
MUST:
- Naming:
<namespace>_<subsystem>_<name>_<unit>snake_case - Counter
_totalsuffix 의무 (plexus_grpc_requests_total) - Base units:
_seconds(not ms/μs),_bytes(not KB/MB) - App prefix:
plexus_on every metric - Label cardinality: max 10 unique values per label
- Required labels for RPC counter:
method,code(NOTuser_id,request_id— high cardinality) /metrics별 internal port (e.g.,:9090), NOT exposed via Ingress
SHOULD: histogram bucket [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0] seconds for latency.
MUST:
- W3C Trace Context (
traceparentheader) propagation tracing-opentelemetry::OpenTelemetryLayer(tracing span → OTel span)- OTLP exporter to in-cluster collector (NOT direct to Jaeger/Tempo)
- Span naming:
<verb>.<resource>(e.g.,worker.execute_task) otel.kind=server/clienton RPC boundary
SHOULD: head-based sampler (1-10% prod, 100% staging).
| Pattern | MUST/SHOULD | Specifics |
|---|---|---|
| Timeout per outbound RPC | MUST | tokio::time::timeout(deadline, rpc) — never infinite. Deadline propagation |
| Retry transient only | MUST | UNAVAILABLE, DEADLINE_EXCEEDED, network reset. NEVER INVALID_ARGUMENT, NOT_FOUND, FAILED_PRECONDITION |
| Exponential backoff + jitter | MUST | delay = min(max, base * 2^attempt) * (0.5 + rand(0..0.5)) |
| Retry budget | MUST | max 10-20% of normal traffic |
| Max attempts | SHOULD | 3-5 (exp 5 attempts = 16s+) |
| Circuit breaker | MUST | closed → (N failures in window) → open (reject T) → half-open (1 trial) → closed |
| Circuit thresholds | SHOULD | failure rate > 50% / 10s, open 30s, half-open 1 request |
| Bulkhead | SHOULD | per-downstream Semaphore cap |
| Rate limit | MUST | per-client identity (NOT per-IP only) |
| Idempotency | MUST | client request_id (UUIDv4) on mutating RPC, server dedupe over T |
| Graceful degradation | SHOULD | fallback (cache / default) when open-circuit |
Plexus TIGHT mode (ADR-0005) 6 primitive 매핑:
| TIGHT primitive | STYLE §4.6 항목 |
|---|---|
| Context length cap ≤1024 | (input validation, §2.6 newtype ContextLength) |
| Batch size = 1 strict | bulkhead Semaphore(1) + queue overflow → 429 |
| KV cache pre-allocation | (memory budget — not §4.6 directly) |
| Per-pod memory probe | (startup health probe — §4.1 health service) |
| MoE expert-aware partition | (Plexus-specific routing) |
| OOM circuit breaker priority | §4.6 circuit breaker — TerminalOom = no retry |
MUST:
- Stateful worker → StatefulSet + Headless Service
- Stateless gateway → Deployment
- CRD: OpenAPI structural schema, NO
x-kubernetes-preserve-unknown-fields - CRD version migration: conversion webhook for v1→v2
- Operator: 단일 application type (Unix principle)
- ServiceAccount: dedicated, NEVER
default - RBAC: Role + RoleBinding (NOT ClusterRole unless cluster-wide)
runAsUser: 65534+(non-root);automountServiceAccountToken: trueonly if in-cluster controller (global CLAUDE.md §10)- PDB
minAvailable: N-1for N-replica StatefulSet (Plexus: 2 of 3) - NetworkPolicy default-deny + explicit allows
- podAntiAffinity
requiredDuringSchedulingIgnoredDuringExecution(단일 node 장애 격리) - Resource requests + limits (
priorityClassName의무) lifecycle.preStop+terminationGracePeriodSeconds: 120(LB drain — Plexus model inference 완료 reserve)- Liveness probe via gRPC health (
grpc-health-probe또는 native K8s gRPC probe v1.24+) - Readiness probe stricter than liveness (downstream connectivity verify)
- ConfigMap for non-secret, Secret from Infisical via ESO
- Helm chart
{{- if ne .Values.enabled false }}(RFC-0027 정합)
MUST:
- mTLS between services (rustls + SPIFFE/SPIRE 또는 cert-manager)
- Client auth: JWT/OIDC (Keycloak per global §2.6)
- Secret: Infisical via ESO
ExternalSecret→ K8s Secret → env var - Input validation at RPC boundary
- Rate limit keyed on JWT
subclaim, NOT IP only - DoS protection: body limit + request timeout + max-headers + max-concurrent-streams
- Audit logging: 별
audit!macro at info level withaudit=truefield - TLS terminate in Rust binary (tonic native rustls), NOT sidecar unless service-mesh
SHOULD: rate limit per identity + circuit breaker per downstream (DoS amplification 차단).
crates/plexus-core/
├── src/
│ ├── lib.rs # #[cfg(test)] mod tests { ... } — unit
│ └── foo.rs # 동일
├── tests/ # integration (각 file = 별 binary)
│ └── e2e.rs
└── benches/ # criterion benchmarks (optional)
| Layer | Tool | Frequency | Notes |
|---|---|---|---|
| Unit | cargo test |
every commit | no external deps |
| Integration | cargo test --workspace --tests |
every commit | in-process tonic channel |
| Property | proptest |
every commit | invariant code (state machines, parsers) |
| Stateful property | proptest-state-machine |
every commit | consensus / distributed protocol |
| Contract | gRPC service stub | every commit | proto schema |
| E2E | tokio::test + kind cluster |
PR | real TCP/K8s |
| Snapshot | insta |
every commit | serialization shape regression |
| Load | k6 / vegeta / ghz |
pre-release | p50/p95/p99/p999 |
| Soak | sustained 24h+ | pre-release | memory leak / creep detection |
| Chaos | chaos-mesh (preferred) / litmus |
staging | TimeChaos + NetworkChaos |
- Unit tests
#[cfg(test)] mod tests { ... }at bottom of source file - Integration tests in
tests/— black-box public API only #[tokio::test(flavor = "multi_thread")]tokio-based when 다중 task;#[tokio::test]default- No
std::thread::sleepfor sync —tokio::time::pause()+advance()deterministic - Snapshot via
instafor serialization assertion - Property via
proptestfor parsers / encoders / hash - Coverage via
cargo-llvm-cov— 80%+ on changed code (Plexus standards/testing.md §5 정합)
SHOULD: doc test every public function example.
libp2pKademlia partition tolerance (split → reconverge)- tonic streaming backpressure (slow consumer + fast producer)
tokio::select!cancellation safety (proptest random drop)- TIGHT mode OOM probe (forced model > pool → 503 graceful)
- Mixtral 8x7B int4 MoE expert routing (Phase 1C)
- 3-pod ring forward verification (Phase 1A acceptance)
Conventional Commits v1.0.0 + Linux Foundation DCO:
Format:
<type>(<scope>)<!>: <subject>
<body — 한국어 허용>
<trailers>
| Element | Level | Rule |
|---|---|---|
| Type | MUST | feat / fix / docs / style / refactor / perf / test / build / chore / ci |
Breaking ! |
MUST | type!: ... → SemVer MAJOR |
| Scope | SHOULD | crate / module name (예: feat(worker), fix(gateway)) |
| Subject | MUST | ≤72자 (hard limit 100자), imperative mood ("Add x" not "Added x"), no period |
| Body | SHOULD | blank line after subject, free-form 한국어 허용, 72-char wrap 권장 |
| Footer | MUST | DCO Signed-off-by: (git commit -s 자동) + Co-Authored-By (AI 협업 시) |
MUST:
- atomic commit (1 logical change per commit)
- DCO sign-off (
git commit -s) — CLA 없음, DCO 의무 - type 소문자 (
feat, notFEAT) - subject 마지막 마침표 금지
BREAKING CHANGE: <desc>footer (대문자 강제, footer 형식)
SHOULD:
Closes #N/Refs ADR-0005footer- body 에 why (what 은 diff 가 보임)
| Aspect | Level | Rule |
|---|---|---|
| PR title | MUST | Conventional Commits 형식 (feat(scope): summary) |
| PR body sections | MUST | Why / What / Testing / Refs (+ How / Screenshots / Breaking SHOULD) |
| AI disclosure | MUST | AI tool 사용 시 PR body 에 명시 (Kubernetes 정합) |
| PR size | SHOULD | ≤400 lines ideal, ≤1000 lines acceptable, >1000 = block + split request |
| Target branch | MUST | dev (RFC-0046 — feat/* / fix/* / docs/* / refactor/* / chore/* → dev); hotfix/* → main SEV-1 only |
| Linked issues | MUST | Closes #N 또는 Refs #N |
| Review SLA | MUST | 24h response (Google 정합) — LGTM 또는 substantive comment |
| Reviewer count | MUST | 1 maintainer LGTM (초기) / 2-stage LGTM + approve (성숙) |
| Merge strategy | MUST | dev squash merge, stable fast-forward only, hotfix squash + cherry-pick |
| Post-merge cleanup | MUST | git push origin --delete <feat> + git branch -D <feat> (자동: lefthook post-merge) |
Google Eng Practices "Looking For" 10 영역 + Linux Kernel strict:
| 영역 | 검사 |
|---|---|
| Design | architecture 적합? library 위치? |
| Functionality | 의도대로 동작? user 에게 좋음? |
| Complexity | 과한 abstraction? deadlock/race? |
| Tests | unit + integration + e2e 추가? assertion 의미? |
| Naming | clear / accurate / not too verbose? |
| Comments | why not what? |
| Style | clippy + rustfmt PASS? (자동화) |
| Consistency | style guide 권위? 기존 코드 정합? |
| Documentation | public API + module + examples 갱신? |
| Every Line | 모든 line 이해하고 review? |
Plexus 추가 (Rust-specific):
clippy -D warningsPASS (자동)- rustfmt edition 2024 PASS (자동)
- 모든
unsafeblock 인접// SAFETY:주석 의무 - 모든
pub fnrustdoc 의무 #[must_use]적절 부착
Linux Kernel strict 추가:
- Function complexity: short + do one thing (5-10 local vars max)
- Nesting max 3 levels
- Function length 1-2 screenfuls (80x24)
- Comments NEVER explain HOW
- Global function naming: descriptive 의무 (single-letter 금지)
- Self-review — git diff 본인 한번 더 읽기 (MUST)
- Draft PR 우선 — 큰 변경 early feedback 권장
- Failing test first (TDD) — bug fix 는 실패 재현 test 1건 의무
- Documentation 동시 갱신 — public API → rustdoc, 사용자 가시 → CHANGELOG, 아키텍처 → ADR/RFC
- Response to comments — 모든 reviewer comment 응답 의무 (inline)
- PR changelog v2 patch 시 v1 와 차이 명시 (Linux Kernel 정합)
Repository root file 의무:
| File | Level | Rationale |
|---|---|---|
| README.md | MUST | OpenSSF Passing |
| LICENSE | MUST | MIT (Plexus 영구, ADR-0002) |
| CONTRIBUTING.md | MUST | onboarding |
| CODE_OF_CONDUCT.md | MUST | Contributor Covenant 2.1 (Plexus 채택) |
| SECURITY.md | MUST | vulnerability disclosure 14-day SLA |
| CHANGELOG.md | MUST | Keep a Changelog 1.1.0 6 categories |
| MAINTAINERS.md | SHOULD | subsystem owner |
| CODEOWNERS | SHOULD | GitHub native (Plexus 가 채택 검토) |
| AUTHORS | MAY | contributor recognition |
| STYLE.md | MUST | 본 문서 |
README 의무 sections:
- What it is (1-2 sentences)
- Why use it (target use case)
- Quick start (minimal install + first command)
- Architecture link
- License (MIT + DCO mention)
- CONTRIBUTING link
- Security policy link
CHANGELOG (Keep a Changelog 1.1.0):
- 6 categories:
Added/Changed/Deprecated/Removed/Fixed/Security - ISO 8601 date (
2026-05-22) [Unreleased]section top- SemVer 명시적
자동화: git-cliff (Plexus standards/enforcement.md §2.3).
.github/ISSUE_TEMPLATE/ 디렉토리:
bug_report.yml— reproduction + expected/actual + environment + versionfeature_request.yml— problem + solution + alternatives + use casesecurity_advisory— 별 channel (GitHub Security Advisory 또는 SECURITY.md email)
Labels (SHOULD): bug/feature/docs/refactor/chore + priority/critical|high|normal|low + severity/sev-1|2|3 + area/* + status/triage|in-progress|blocked + good first issue + help wanted.
- Responsive review (24h SLA)
- Mentor new contributors
- Protect main/dev branch (GitHub protected rules)
- Release management (SemVer + Keep a Changelog)
- Security incident response (14-day SLA)
- CoC enforcement (CNCF 정합)
- 표준 fairly + consistently 적용
Saying No gracefully (GitHub OSS guide):
"No is temporary, yes is forever."
- Thank → explain → link docs → close
- Silence = future participation 차단 신호 (회피)
Sustainable pace: 2-5h weekly baseline + co-maintainer 양성.
| Increment | Trigger |
|---|---|
| MAJOR (X.y.z, X > 0) | API breaking change |
| MINOR | backward-compatible feature add |
| PATCH | backward-compatible bug fix |
| 0.y.z | initial dev — anything MAY change |
Pre-release: 1.0.0-alpha / -beta / -rc.1 (lower precedence).
Build metadata: 1.0.0+20260522 (precedence 무관).
Plexus release artifacts (SHOULD):
- Binary multi-arch (musl static — global standards/checklist.md "멀티아키텍처 빌드")
- Docker image
linux/amd64(GOVERNANCE.md §2.3) - SBOM (Software Bill of Materials — OpenSSF supply-chain)
- Signed release (cosign 또는 GPG)
- Checksums (sha256sums.txt)
| Scope | Approval rule |
|---|---|
| Tactical (single PR) | maintainer LGTM (1 reviewer) |
| Strategic (architecture) | RFC (PIP) + multi-reviewer consensus |
| Constitutional (license / governance) | TSC 또는 Foundation 결정 |
Apache voting (Apache Voting):
- Code modification: 3 +1 votes + 0 -1 votes consensus
- Release: 3 binding +1 + more positive (vetoes 금지 on release)
- Lazy consensus: 3 day silence (procedural only, not code)
- Veto: -1 on code = absolute (technical justification 의무)
Voting period min 72h (global participation).
RFC process (Plexus PIP — Plexus Improvement Proposal):
docs/rfcs/NNNN-slug.md(다음 free number)- Draft → Proposed (30-day comment) → Accepted (TSC consensus) → Implemented → Superseded
good first issuelabeling (MUST)- CLA 없음 / DCO 의무 (per-commit
Signed-off-by:) - Recognition: AUTHORS file + CHANGELOG contributors section + Hall of Fame
- Async first: GitHub Issues + Discussions
- Optional real-time: Matrix
#plexus:matrix.org(Phase 5+)
- rustfmt format on save
- rust-analyzer LSP
- clippy diagnostics
- recommended VSCode/Helix/Zed config (
.editorconfig의무)
.lefthook.yml 의 pre-commit 섹션:
pre-commit:
parallel: true
commands:
fmt-check:
glob: "*.rs"
run: cargo fmt --check
clippy-strict:
glob: "*.rs"
run: |
cargo clippy --workspace --all-targets --all-features -- \
-D warnings \
-D clippy::unwrap_used \
-D clippy::expect_used \
-D clippy::panic \
-D clippy::todo \
-D clippy::unimplemented \
-D clippy::dbg_macro \
-D clippy::await_holding_lock
secrets:
run: |
command -v gitleaks >/dev/null 2>&1 && \
gitleaks protect --staged --redact --no-banner || \
echo "gitleaks not installed — skipped"
cargo-deny:
glob: "{Cargo.toml,Cargo.lock,deny.toml}"
run: |
command -v cargo-deny >/dev/null 2>&1 && \
cargo deny check || \
echo "cargo-deny not installed — skipped"pre-push:
parallel: false
commands:
test:
run: cargo test --workspace --no-fail-fast
audit:
run: |
command -v cargo-audit >/dev/null 2>&1 && \
cargo audit --deny warnings || \
echo "cargo-audit not installed"
proto-lint:
glob: "*.proto"
run: |
command -v buf >/dev/null 2>&1 && \
buf lint || \
echo "buf not installed — skipped".gitlab-ci.yml (Phase 6+ activate):
stages: [lint, typecheck, test, validate, audit, governance]
lint:
script:
- cargo fmt --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
test:
script:
- cargo test --workspace --no-fail-fast
audit:
script:
- cargo audit --deny warnings
- cargo deny checkReviewer 의무 (§6.3 정합):
- §2-§5 STYLE.md rules MUST PASS check
- 24h response SLA
- LGTM 또는 substantive comment
clippy: PASS,cargo test: PASS,cargo audit: 0 high+PR body 인용
git tag -a vX.Y.Z- GitHub Release with CHANGELOG section
- Binary multi-arch (musl static) — global standards/checklist.md
- Docker image
linux/amd64(GOVERNANCE.md §2.3) - SBOM via
cargo-cyclonedx또는syft - Signed via
cosign - Checksums (sha256sums.txt)
| Level | Criteria count | Plexus 목표 |
|---|---|---|
| Passing | 67 criteria | MUST (v1.0 launch 의무) |
| Silver | 55 criteria | SHOULD (1년 내) |
| Gold | 23 criteria | MAY (2년 후, supply-chain hardening) |
Passing 핵심 (모든 MUST 충족):
- HTTPS 사이트 ✓ (github.com/keiailab/plexus)
- FLOSS license posted ✓ (MIT)
- public version control + unique version (SemVer)
- 14-day vulnerability response (SECURITY.md SLA)
- automated test suite (cargo test 자동화)
- secure design knowledge (STYLE.md §4.8)
- HTTPS/SSH delivery
- no leaked credentials (gitleaks)
- static analysis pre-release (clippy + cargo deny + cargo audit)
| Stage | Criteria |
|---|---|
| Sandbox | proof-of-concept + CNCF CoC + neutral home 의지 |
| Incubating | sandbox + 3 production adopters + healthy committers + ongoing commits |
| Graduated | incubating + 2+ organizations committers + 3rd-party security audit + OpenSSF Passing badge |
Plexus 가 CNCF 또는 Apache donation 목표 시 본 path 정합.
본 STYLE.md 의 decision trace = ADR-0007 ("Code Standards adoption — 28+ sources synthesis").
향후 STYLE.md 의 substantive 변경 (NEW MUST rule / lint deny 추가) 은 RFC (PIP) 의무. trivial (typo / new SHOULD / clarification) 은 직접 PR.
- Rust API Guidelines Checklist
- Rust Style Guide (nightly)
- Rust 2024 Edition Guide
- Rust 1.95.0 Release Notes
- Effective Rust by David Drysdale
- Embark Studios Rust Guidelines
- Embark Studios Rust Lints
- Clippy Lints Documentation
- Cargo Workspaces Reference
- Rust Performance Book
- Rust Cookbook
- Async Rust Book
- Tokio Tutorial
- Tonic Examples
- Axum Examples
- tracing crate docs
- OpenTelemetry Rust
- Prometheus naming best practices
- gRPC Deadlines
- Protobuf Style Guide
- Operator SDK Best Practices
- Linux Kernel Coding Style
- Linux Kernel Submitting Patches
- Apache Code of Conduct
- Apache Voting Process
- CNCF Project Lifecycle
- Kubernetes Contributor Guide
- Google Engineering Practices — Reviewer
- Google Engineering Practices — Speed
- Google Engineering Practices — Small CLs
- GitHub OSS Best Practices
- Conventional Commits v1.0.0
- Semantic Versioning 2.0.0
- Keep a Changelog 1.1.0
- Linux Foundation DCO
- OpenSSF Best Practices Badge
- Rust RFC Process
| Date | Change |
|---|---|
| 2026-05-22 | 초안 작성 — 3 parallel research agent (28+ sources) 종합. 11 sections / ~1500 lines / strong MUST rules / 6 enforcement layer / OpenSSF Passing 목표 codify |
본 문서의 변경은 PIP RFC 의무 (substantive) 또는 직접 PR (trivial).
End of STYLE.md. 모든 PR 의 의무 reference.