Skip to content

Latest commit

 

History

History
1030 lines (797 loc) · 41.1 KB

File metadata and controls

1030 lines (797 loc) · 41.1 KB

Plexus — Code Standards & Style Guide

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

§1 Core Principles (Philosophy)

본 표준의 5 원칙. 충돌 시 우선순위:

  1. Stability over speed (ADR-0005 정합) — production-grade stability 가 속도보다 우선. TIGHT mode (3x 8GB → 24GB pool → 24GB LLM) 의 6 primitive 의무.
  2. One thing well per module — Linux Kernel "do just one thing" + Rust API Guidelines C-WORD-ORDER. 모듈/함수/struct 가 단일 책임.
  3. Tests as documentation — public API 의 doc test 는 실 동작 evidence. 변경 시 동시 update.
  4. Errors are valuesResult<T, E> 의무, panic 금지 (production). thiserror (lib) + anyhow (bin) 분리.
  5. Async cancellation safety — 모든 select! branch 가 cancel-safe. cleanup 의무.

본 5 원칙이 충돌 시 stability (R8) > simplicity > performance > convenience 순.


§2 Rust Code Standards

§2.1 Naming Conventions (MUST)

Rust API Guidelines C-CASE:

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 생태계 정합.

§2.2 Documentation (rustdoc) (MUST)

Rust API Guidelines + Effective Rust Item 27:

  • crate root: #![warn(missing_docs)] (또는 STYLE.md compliance 시 deny)
  • 모든 lib.rs / mod 최상단에 //! module doc
  • 모든 pub item (fn, struct, enum, trait, const) 에 /// doc 1문장 이상
  • 모든 pub fn -> Result<_, _># Errors 섹션
  • panic 가능 모든 함수에 # Panics 섹션
  • 모든 unsafe fn# Safety 섹션
  • 권장 모든 public function 에 # Examples runnable doc test
  • Cargo.tomldescription / 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())
}

§2.3 Error Handling (MUST)

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:?}"))
            }
        }
    }
}

§2.4 Async / Concurrency (tokio strict)

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 — clippy await_holding_lock deny
  • All channels bounded in production — mpsc::channel(N) not unbounded_channel()
  • CPU-bound work → tokio::task::spawn_blocking
  • Cancellation → tokio_util::sync::CancellationToken (hierarchical) not Arc<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)
  • JoinHandle from tokio::spawn MUST be tracked or detached explicitly
  • Shutdown: listen for both tokio::signal::ctrl_c() AND signal::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).

§2.5 Module Organization (edition 2024)

MUST:

  • modern foo.rs + foo/ directory pattern (NOT foo/mod.rs — edition 2018+ style)
  • lib.rs 구조: //! crate doc → #![lints] attrs → pub use re-exports → pub mod declarations
  • 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 정의

§2.6 Type Safety (MUST)

Rust API Guidelines + Effective Rust:

  • Newtype 도메인 ID (C-NEWTYPE, Item 6): struct UserId(u64); not raw u64
  • No bool parameters in public API (C-CUSTOM-TYPE): enum Verbose { Yes, No } not fn 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)
  • bitflags crate flag set (C-BITFLAG)

SHOULD: typestate via PhantomData<T> (e.g., Conn<Idle>Conn<Active>).

§2.7 Performance

MUST:

  • Vec::with_capacity(n) size known ahead
  • String::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" parameter
  • Box<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 binary

SHOULD: type > 128 bytes triggers memcpycargo +nightly rustc -- -Zprint-type-sizes 로 audit.

§2.8 Edition 2024 Specifics (MUST adopt)

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 자동.


§3 Workspace Lints (Cargo.toml strict config)

본 표준의 lint config 는 Cargo.toml[workspace.lints] 에 codify. 각 crate Cargo.toml[lints] workspace = true.

§3.1 Rust lints

[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"

§3.2 Clippy lints (strict)

[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"

§3.3 Per-crate root attrs

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.

§3.4 Lint exception (escape hatch)

특정 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 (별도 추적).


§4 Distributed Systems Code (Plexus-specific)

§4.1 gRPC + tonic

MUST:

  • .proto 위치 = proto/<package>/v1/<service>.proto (version prefix v1)
  • Package: lower_snake_case 또는 dot-delimited (plexus.worker.v1) — Java-style com.x.y 금지
  • Message = TitleCase, field = snake_case, enum = TitleCase type + UPPER_SNAKE_CASE values
  • 첫 enum value = _UNSPECIFIED = 0
  • required field 금지 (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 raw String
  • grpc.health.v1.Health 서비스 의무 (K8s probe)
  • Tower layer 순서: tracing → auth → rate-limit → timeout → retry → load-shed
  • Single Channel per 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 차단

§4.2 HTTP + axum (gateway client API)

MUST:

  • Handler signature: async fn h(extractors...) -> impl IntoResponse
  • Extractor 순서: State / Path / Query / headers/auth / Json (body LAST)
  • 커스텀 error enum + IntoResponse impl (status + JSON body) — raw anyhow::Error 금지
  • Middleware via tower::Layer + ServiceBuilder (route-specific 만 .route_layer)
  • Request ID: tower-http::request_id middleware + tracing span propagation
  • Graceful shutdown: axum::serve(...).with_graceful_shutdown(signal_fut)
  • Signal future: tokio::select! over ctrl_c() + SignalKind::terminate()
  • Compression: tower-http::compression::CompressionLayer (gzip + br)
  • CORS: explicit allow-list, NEVER Any in production
  • Fallback handler: 명시적 404 JSON
  • Body limit: RequestBodyLimitLayer (default 2MB)

§4.3 Structured Logging (tracing)

MUST:

  • tracing macros 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_id span field at entry — child span 자동 propagate

SHOULD: log sampling for debug/trace high-throughput (DynFilter rate limit).

§4.4 Metrics (Prometheus)

MUST:

  • Naming: <namespace>_<subsystem>_<name>_<unit> snake_case
  • Counter _total suffix 의무 (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 (NOT user_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.

§4.5 Distributed Tracing (OpenTelemetry)

MUST:

  • W3C Trace Context (traceparent header) 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/client on RPC boundary

SHOULD: head-based sampler (1-10% prod, 100% staging).

§4.6 Resilience Patterns (ADR-0005 TIGHT mode 정합)

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

§4.7 K8s Operator / Workload Patterns

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: true only if in-cluster controller (global CLAUDE.md §10)
  • PDB minAvailable: N-1 for 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 정합)

§4.8 Security (Distributed)

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 sub claim, NOT IP only
  • DoS protection: body limit + request timeout + max-headers + max-concurrent-streams
  • Audit logging: 별 audit! macro at info level with audit=true field
  • TLS terminate in Rust binary (tonic native rustls), NOT sidecar unless service-mesh

SHOULD: rate limit per identity + circuit breaker per downstream (DoS amplification 차단).


§5 Testing Standards

§5.1 Test Layout

crates/plexus-core/
├── src/
│   ├── lib.rs            # #[cfg(test)] mod tests { ... } — unit
│   └── foo.rs            # 동일
├── tests/                # integration (각 file = 별 binary)
│   └── e2e.rs
└── benches/              # criterion benchmarks (optional)

§5.2 Test Levels

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

§5.3 Test Rules (MUST)

  • 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::sleep for sync — tokio::time::pause() + advance() deterministic
  • Snapshot via insta for serialization assertion
  • Property via proptest for parsers / encoders / hash
  • Coverage via cargo-llvm-cov — 80%+ on changed code (Plexus standards/testing.md §5 정합)

SHOULD: doc test every public function example.

§5.4 Plexus-specific Test Patterns (TIGHT mode 검증)

  • libp2p Kademlia 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)

§6 OSS Contribution Standards

§6.1 Commit Standards (MUST)

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, not FEAT)
  • subject 마지막 마침표 금지
  • BREAKING CHANGE: <desc> footer (대문자 강제, footer 형식)

SHOULD:

  • Closes #N / Refs ADR-0005 footer
  • body 에 why (what 은 diff 가 보임)

§6.2 PR / MR Standards

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)

§6.3 Code Review Checklist (Reviewer 의무)

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 warnings PASS (자동)
  • rustfmt edition 2024 PASS (자동)
  • 모든 unsafe block 인접 // SAFETY: 주석 의무
  • 모든 pub fn rustdoc 의무
  • #[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 금지)

§6.4 Code Review Checklist (Author 의무)

  • 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 정합)

§6.5 Documentation Standards (OSS-specific)

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).

§6.6 Issue Templates (MUST)

.github/ISSUE_TEMPLATE/ 디렉토리:

  • bug_report.yml — reproduction + expected/actual + environment + version
  • feature_request.yml — problem + solution + alternatives + use case
  • security_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.

§6.7 Maintainer Responsibilities (MUST)

  • 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 양성.

§6.8 Versioning + Release (SemVer 2.0.0 strict)

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)

§6.9 Governance / Decision Making

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

§6.10 Contributor Onboarding

  • good first issue labeling (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+)

§7 Enforcement Layers (6-hop)

§7.1 L0 — IDE (real-time)

  • rustfmt format on save
  • rust-analyzer LSP
  • clippy diagnostics
  • recommended VSCode/Helix/Zed config (.editorconfig 의무)

§7.2 L1 — pre-commit (lefthook)

.lefthook.ymlpre-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"

§7.3 L2 — pre-push (lefthook)

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"

§7.4 L3 — CI (GitLab CI L5, RFC-0043 정합)

.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 check

§7.5 L4 — PR Review (human)

Reviewer 의무 (§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 인용

§7.6 L5 — Release

  • 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)

§8 OpenSSF + CNCF Maturity Path (long-term)

§8.1 OpenSSF Best Practices Badge

OpenSSF Best Practices:

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)

§8.2 CNCF Sandbox → Incubating → Graduated (선택)

CNCF Project Lifecycle:

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 정합.


§9 ADR-0007 Reference

본 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.


§10 References (28+ authoritative sources)

Rust Language + Tooling

Async + Distributed Systems

OSS Contribution + Governance


§11 변경 이력

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.