Docs
v1

Guide

Development guidelines

The engineering rules for contributions to Tenrai. Code style, comments, error handling, consensus code, performance, tests, dependencies and AI coding agents.

On this page

The Tenrai repositories carry this text as CONTRIBUTING.md.

1. Engineering Philosophy

Tenrai is a performance-oriented Layer 1 blockchain with security-critical consensus, cryptographic, networking, and state-management components.

All contributions must preserve the project's established engineering principles.

Core principles:

  • Correctness before convenience.
  • Simplicity before abstraction.
  • Deterministic behavior before implementation flexibility.
  • Explicit invariants before implicit assumptions.
  • Measured performance before speculative optimization.
  • Maintainability before unnecessary generalization.

Existing project conventions take precedence over personal preferences.

2. Preserve the Existing Codebase

Before implementing changes, developers must examine the surrounding code and understand its architecture, naming conventions, error handling, and testing patterns.

  • Follow established patterns rather than introducing competing implementations.
  • Do not restructure unrelated code.
  • Do not rename existing interfaces without a technical reason.
  • Do not introduce additional abstraction layers unless they solve an identifiable problem.
  • Avoid unnecessary dependencies.
  • Keep modifications focused on the requested functionality.
  • Prefer extending existing components over duplicating their responsibilities.

Do not rewrite working code merely to make it look cleaner or more modern.

3. Code Style

Tenrai favors concise, explicit, and technically focused Rust code.

  • Use descriptive names that reflect actual responsibilities.
  • Keep functions focused on well-defined operations.
  • Prefer strongly typed data structures over ambiguous representations.
  • Use Result and explicit error types for recoverable failures.
  • Avoid hidden state changes and unexpected side effects.
  • Avoid unnecessary allocation, copying, and cloning.
  • Follow Rust idioms without introducing abstractions for their own sake.
  • Respect existing module boundaries and visibility restrictions.

Code should be understandable through its structure rather than extensive commentary.

4. Comments and Documentation

Comments must provide meaningful technical information.

Write comments when they explain:

  • Non-obvious invariants.
  • Security-sensitive assumptions.
  • Protocol requirements.
  • Mathematical reasoning.
  • Hardware-specific behavior.
  • Intentional performance tradeoffs.
  • Behavior that cannot be understood from the implementation alone.

Avoid:

  • Comments that merely restate the code.
  • Narrating individual implementation steps.
  • Unnecessary explanations of standard Rust functionality.
  • Repetitive documentation.
  • Decorative section comments.
  • Speculative explanations without technical evidence.

Public APIs should be documented where their contracts are not otherwise clear.

Documentation must remain accurate when implementation details change.

Do not over-comment.

Somewhere along the way, commenting every single line became standard practice in crypto. It is not standard practice here. A comment that explains count += 1 adds nothing, goes stale with the next change, and is known to trigger allergic reactions in otherwise healthy developers. The same goes for documentation: a README is not a diary. If code needs an essay to be understood, fix the code.

5. Error Handling

Errors must be explicit, meaningful, and appropriately scoped.

  • Define specific error variants for distinct failure conditions.
  • Validate untrusted inputs before processing.
  • Check lengths, indices, bounds, and integer conversions.
  • Use checked arithmetic where overflow could affect correctness or security.
  • Reject malformed and non-canonical encodings.
  • Preserve useful error information across module boundaries.
  • Avoid silently ignoring failures.
  • Do not substitute fabricated or default values for invalid consensus data.

Use unwrap() and expect() only when their preconditions are established or when an unrecoverable failure is intentional.

6. Consensus and Cryptographic Code

Consensus-critical logic requires additional discipline.

  • Preserve deterministic behavior across supported platforms.
  • Never introduce floating-point dependence into consensus decisions.
  • Maintain canonical serialization and hashing.
  • Preserve domain separation in cryptographic operations.
  • Verify cryptographic bindings between related data structures.
  • Treat external network data as untrusted.
  • Do not weaken validation to improve performance.
  • Do not silently alter protocol constants or consensus rules.
  • Avoid changes that create different interpretations of the same state.

Consensus behavior must never depend on local timing, thread scheduling, or nondeterministic iteration order.

Changes affecting consensus rules, cryptographic constructions, or protocol compatibility require explicit technical justification and appropriate validation.

7. Performance Engineering

Tenrai is designed for high-throughput execution.

Performance-sensitive changes must be based on identifiable bottlenecks.

  • Avoid unnecessary memory allocations and copies.
  • Prefer bounded resource usage.
  • Preserve efficient data access patterns.
  • Consider CPU, memory, I/O, and network costs.
  • Measure performance before and after significant optimizations.
  • Do not introduce caching without a clear purpose and invalidation strategy.
  • Do not sacrifice protocol correctness for marginal performance improvements.

Optimizations must preserve the required semantic and cryptographic guarantees.

8. Testing Requirements

Tests should establish concrete behavioral properties, not merely exercise code paths.

Prioritize:

  • Deterministic test vectors.
  • Boundary conditions.
  • Invalid inputs and malformed encodings.
  • State-transition invariants.
  • Serialization round trips.
  • Cryptographic binding verification.
  • Consensus consistency.
  • Regression tests for known failures.
  • Cross-implementation consistency where applicable.

Use focused test fixtures and descriptive test names.

Do not be stingy with tests.

A function that works on its own can still cause the strangest failures in the functions that depend on it. Write thorough Rust tests together with the change, not afterwards.

Keep those tests in separate files so the source files stay short and readable:

Rust
#[cfg(test)]
#[path = "tests/engine.rs"]
mod tests;

Avoid tests that duplicate implementation logic so closely that both can share the same mistake.

Do not introduce meaningless assertions merely to increase test coverage.

A change is not complete when its relevant tests fail.

9. API and Module Design

Maintain clear boundaries between responsibilities.

  • Separate parsing from authentication and semantic validation where appropriate.
  • Separate protocol definitions from storage implementations.
  • Keep consensus rules independent of presentation and transport layers.
  • Use explicit interfaces where they provide genuine modularity.
  • Avoid exposing internal structures unnecessarily.
  • Keep public interfaces minimal and stable.
  • Do not create generic frameworks for a single concrete use case.

Abstraction must be justified by actual requirements.

10. Dependencies

External dependencies must have a clear technical purpose.

Before adding a dependency:

  • Check whether existing project components already provide the functionality.
  • Evaluate security and maintenance implications.
  • Consider binary size and runtime overhead where relevant.
  • Avoid replacing small, established project-specific implementations without justification.

Dependencies should support the architecture, not dictate it.

11. Working With AI Coding Agents

AI-assisted contributions are permitted, but they must follow the same engineering standards as human contributions.

Coding agents must:

  • Inspect relevant existing code before making changes.
  • Preserve established project conventions.
  • Implement only the requested changes and necessary supporting work.
  • Avoid unrelated refactoring.
  • Avoid unnecessary comments and abstractions.
  • Never invent protocol behavior or undocumented requirements.
  • Never claim tests or benchmarks passed unless actually executed.
  • Explicitly identify assumptions, unverified behavior, and remaining risks.
  • Preserve existing security and consensus invariants.
  • Request explicit decisions when requirements are ambiguous and cannot safely be inferred.

Every line of AI-generated code must be reviewed and validated by a human before it is merged.

AI agents frequently make serious mistakes that look correct at first glance. Reviewing their output requires a solid understanding of software development and of the code being changed.

Generated code must be reviewed according to its technical correctness, not its origin.

12. Change Discipline

Every change should have a clear purpose and limited scope.

Before considering work complete:

  1. Verify that the implementation meets the intended requirements.
  2. Check compatibility with surrounding modules.
  3. Run relevant tests and quality checks.
  4. Examine failure paths and boundary conditions.
  5. Review changes for unnecessary complexity.
  6. Confirm that existing behavior was not unintentionally modified.
  7. Report tests performed and any remaining limitations.

Do not claim successful validation without evidence.


Final Principle

Tenrai values engineering discipline over code volume.

Contributions should be correct, deterministic, secure, efficient, and consistent with the established architecture.

The goal is not to produce more code. The goal is to introduce the smallest well-justified change that completely and correctly solves the problem.

Type to search guides, concepts and reference pages.