Files
dnshelper/.specify/memory/constitution.md
T

209 lines
9.6 KiB
Markdown
Raw Normal View History

<!--
Sync Impact Report
Version change: 1.1.0 → 1.1.1
Modified principles: None
Added sections: N/A
Modified sections:
- Dependency Governance — Removed `github.com/miekg/dns` from
Currently Approved External Dependencies (replaced by
`golang.org/x/net/dns/dnsmessage` in feature 001)
Removed sections: N/A
Templates requiring updates:
- .specify/templates/plan-template.md — ⚠ pending (Constitution Check
section references "[Gates determined based on constitution file]";
will be populated when /speckit.plan runs against this constitution)
- .specify/templates/spec-template.md — ✅ no updates required
- .specify/templates/tasks-template.md — ✅ no updates required
Follow-up TODOs: None
-->
# 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.mod` file MUST specify `go 1.20` as 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 `error` value.
- Callers MUST inspect returned errors and either handle them, wrap them
with additional context, or propagate them upward.
- The `main` function is the only location permitted to call `os.Exit`
or 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.go` in 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 vet` MUST 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