9.6 KiB
ekdns Constitution
Core Principles
I. System File Safety
The hosts file is a critical operating system resource. Corruption or data loss in this file disables all local name resolution and can render a machine unusable without manual intervention.
- The tool MUST NOT truncate, zero-out, or partially overwrite the hosts file at any point during its operation.
- All writes to the hosts file MUST use an atomic pattern: write complete content to a temporary file in the same directory, then rename over the original.
- A backup of the current hosts file MUST be created before any modification is committed.
- If any step in the write pipeline fails, the original hosts file MUST remain unmodified.
Rationale: This tool exists to solve DNS reliability problems. If it introduces a new failure mode — destroying the hosts file — it is worse than the problem it solves.
II. Standard Library First
The Go standard library MUST be the first choice for all functionality. External dependencies introduce supply-chain risk, version conflicts, and maintenance burden that are disproportionate for a small, single-purpose utility.
- All functionality MUST be implemented using the Go standard library unless a documented technical justification proves it insufficient.
- When an external dependency is genuinely required, it MUST come from
one of the following approved sources:
golang.org/x/*(official Go extended libraries)dev.emberkom.com/*(Emberkom internal libraries)
- Any other external dependency MUST have a written justification in the code review or commit message explaining: (a) what standard library alternative was considered, (b) why it was insufficient, and (c) what the external dependency provides that the stdlib does not.
- Dependencies MUST be audited when upgraded to ensure no new transitive dependencies from unapproved sources are introduced.
Rationale: A single-binary CLI tool that modifies a system file must have a minimal and auditable dependency tree. Every external package is an attack surface and a maintenance liability.
III. Go 1.20 Compatibility
This tool MUST compile and run correctly with Go 1.20. This version ceiling exists to maintain compatibility with legacy systems that cannot run newer Go runtimes.
- The
go.modfile MUST specifygo 1.20as the language version. - No language features, standard library APIs, or dependency versions exclusive to Go 1.21 or later are permitted.
- Build and test pipelines MUST use Go 1.20 as the primary toolchain version to catch compatibility issues early.
- If a dependency releases a version that requires Go 1.21+, the tool MUST pin to the last Go 1.20-compatible release of that dependency.
Rationale: The target deployment environments include older systems where upgrading the Go toolchain or OS is not feasible. Pinning the version ensures the tool remains deployable everywhere it is needed.
IV. Idiomatic Error Handling
Errors MUST flow upward through return values. Functions MUST NOT
terminate the process, call os.Exit, or invoke global exit helpers
except at the top-level main function.
- Every function that can fail MUST return an
errorvalue. - Callers MUST inspect returned errors and either handle them, wrap them with additional context, or propagate them upward.
- The
mainfunction is the only location permitted to callos.Exitor print a fatal error and terminate. - Platform-specific code (build-tagged files) MUST return errors to the caller rather than terminating directly.
- Errors presented to the user MUST include enough context to understand what operation failed and why (e.g., file path, hostname, DNS server).
Rationale: Internal os.Exit calls make code untestable, prevent
cleanup logic from running, and cause execution to continue past error
points when deferred. Centralizing exit decisions in main produces
predictable, debuggable control flow.
V. Simplicity and Single Purpose
This tool does one thing: update the local hosts file with DNS entries resolved from a specified DNS server. Every design decision MUST favor the simplest approach that satisfies the requirement.
- The tool MUST remain a single-binary CLI with no external configuration files, services, or daemons.
- Features MUST be justified by a concrete user need, not speculative future use. YAGNI (You Aren't Gonna Need It) applies.
- Dead code, unused exports, and speculative abstractions MUST be removed. If code is not called, it does not belong in the repository.
- The CLI interface MUST remain straightforward: subcommand + flags. No interactive prompts, no TUI, no config file parsing.
Rationale: Complexity is the enemy of reliability. A tool that modifies a critical system file must be small enough to reason about completely and audit quickly.
VI. Test-Driven Development
All new and refactored code MUST be developed using a test-driven development (TDD) approach. Tests are not an afterthought — they are the specification that drives implementation.
- Tests MUST be written before the implementation code they verify. The Red-Green-Refactor cycle is mandatory: write a failing test, write the minimum code to make it pass, then refactor.
- Every exported function and every function with non-trivial logic MUST have corresponding test coverage.
- Functions that interact with external resources (filesystem, DNS, network) MUST be designed to accept interfaces or parameters that enable testing with fakes, stubs, or in-memory implementations. Direct calls to OS-level I/O from business logic are prohibited.
- Platform-specific code MUST have tests that verify the function contract (correct return values, correct error conditions) on each supported platform.
- Test files MUST follow Go conventions:
*_test.goin the same package as the code under test. go test ./...MUST pass with zero failures before code is merged.
Rationale: This tool modifies a critical system file. Untested code is untrustworthy code. TDD ensures that every behavior is verified, every error path is exercised, and regressions are caught immediately. It also enforces the interface-based design required by Principle IV (idiomatic error handling) and makes the codebase safe to refactor.
Dependency Governance
This section codifies the external dependency policy from Principle II into an auditable process.
| Source | Status | Condition |
|---|---|---|
| Go standard library | Always permitted | N/A |
golang.org/x/* |
Permitted | Must solve a problem stdlib cannot |
dev.emberkom.com/* |
Permitted | Must solve a problem stdlib cannot |
| All other sources | Prohibited by default | Requires written justification, code review approval, and an entry in this table |
Currently Approved External Dependencies
None. All external functionality is provided by golang.org/x/net/dns/dnsmessage (covered by the golang.org/x/* blanket approval above).
Development Standards
- Formatting: All Go source files MUST be formatted with
gofmt. No exceptions. - Vet/Lint:
go vetMUST pass with zero findings before code is merged. Additional linting (e.g.,staticcheck) is encouraged. - Testing: All new and refactored code MUST have test coverage
written before the implementation (TDD). Functions that interact with
the filesystem or DNS MUST be designed to accept interfaces or
parameters that allow testing with fakes/stubs.
go test ./...MUST pass with zero failures before merge. See Principle VI for the full TDD policy. - Build tags: Platform-specific code MUST use Go build tags
(
//go:build windows, etc.) and MUST implement identical function signatures across all supported platforms. - Commit messages: Follow conventional commit format
(e.g.,
fix:,feat:,refactor:,docs:).
Governance
This constitution is the authoritative source of project standards for ekdns. It supersedes informal conventions, ad-hoc decisions, and prior practices that conflict with its contents.
- Amendment process: Any change to this constitution MUST be documented with a version bump, a rationale for the change, and an update to the Sync Impact Report at the top of this file.
- Versioning policy: This constitution follows semantic versioning. MAJOR for principle removals or redefinitions, MINOR for new principles or materially expanded guidance, PATCH for clarifications and non-semantic refinements.
- Compliance review: All pull requests and code reviews MUST verify that changes comply with the principles defined here. Violations MUST be resolved before merge, or the constitution MUST be amended first.
- Dependency audits: When dependencies are added or upgraded, the reviewer MUST verify compliance with Principle II and the Dependency Governance table above.
Version: 1.1.1 | Ratified: 2026-03-03 | Last Amended: 2026-03-04