Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# dns-helper Development Guidelines
|
||||
|
||||
Auto-generated from all feature plans. Last updated: 2026-03-03
|
||||
|
||||
## Active Technologies
|
||||
|
||||
- Go 1.20 (maximum; currently go.mod says 1.18, must be updated to 1.20) + Go standard library, `golang.org/x/net/dns/dnsmessage` (replacing `github.com/miekg/dns`) (001-safety-reliability-refactor)
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
src/
|
||||
tests/
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
# Add commands for Go 1.20 (maximum; currently go.mod says 1.18, must be updated to 1.20)
|
||||
|
||||
## Code Style
|
||||
|
||||
Go 1.20 (maximum; currently go.mod says 1.18, must be updated to 1.20): Follow standard conventions
|
||||
|
||||
## Recent Changes
|
||||
|
||||
- 001-safety-reliability-refactor: Added Go 1.20 (maximum; currently go.mod says 1.18, must be updated to 1.20) + Go standard library, `golang.org/x/net/dns/dnsmessage` (replacing `github.com/miekg/dns`)
|
||||
|
||||
<!-- MANUAL ADDITIONS START -->
|
||||
<!-- MANUAL ADDITIONS END -->
|
||||
@@ -59,6 +59,8 @@ Load only the minimal necessary context from each artifact:
|
||||
- Phase grouping
|
||||
- Parallel markers [P]
|
||||
- Referenced file paths
|
||||
- Context blocks (per-task): code signatures, implementation patterns, gotchas, acceptance signals
|
||||
- Phase Context summaries: files modified, key types/interfaces, codebase conventions
|
||||
|
||||
**From constitution:**
|
||||
|
||||
@@ -111,14 +113,26 @@ Focus on high-signal findings. Limit to 50 findings total; aggregate remainder i
|
||||
- Task ordering contradictions (e.g., integration tasks before foundational setup tasks without dependency note)
|
||||
- Conflicting requirements (e.g., one requires Next.js while other specifies Vue)
|
||||
|
||||
#### G. Implementation Self-Containment
|
||||
|
||||
**Why this matters**: Tasks will be executed by a less-capable implementing model (e.g., Sonnet) that cannot reliably infer implementation details from sparse descriptions. Every non-trivial task must be a standalone implementation brief.
|
||||
|
||||
- **Missing Context blocks**: Flag any non-trivial task (anything beyond adding a simple field or creating an empty file) that lacks an indented **Context** block beneath the checkbox line. Severity: HIGH.
|
||||
- **Missing code signatures**: Context blocks that describe interfaces, structs, or functions the task depends on but do NOT quote the actual signatures with fenced code blocks. Severity: HIGH.
|
||||
- **Missing implementation pattern**: Context blocks that say *what* to build but not *how* — no code skeleton, no pseudocode, no reference to an analogous pattern elsewhere in the codebase. Severity: MEDIUM.
|
||||
- **Missing acceptance signal**: Tasks without a concrete, verifiable "done" statement (e.g., a specific test command, a build command, or observable output). Severity: MEDIUM.
|
||||
- **Missing gotchas/constraints**: Tasks that touch complex logic (edge cases, platform constraints, performance-sensitive code) but whose Context block omits known pitfalls from the spec or research documents. Severity: MEDIUM.
|
||||
- **Missing Phase Context summary**: Phases that lack the opening block listing files modified, key types, and codebase conventions. Severity: LOW.
|
||||
- **Placeholder signatures**: Context blocks that contain generic or assumed code signatures not verified against the actual codebase (e.g., `func DoSomething()` when the real signature has different parameters). Severity: HIGH.
|
||||
|
||||
### 5. Severity Assignment
|
||||
|
||||
Use this heuristic to prioritize findings:
|
||||
|
||||
- **CRITICAL**: Violates constitution MUST, missing core spec artifact, or requirement with zero coverage that blocks baseline functionality
|
||||
- **HIGH**: Duplicate or conflicting requirement, ambiguous security/performance attribute, untestable acceptance criterion
|
||||
- **MEDIUM**: Terminology drift, missing non-functional task coverage, underspecified edge case
|
||||
- **LOW**: Style/wording improvements, minor redundancy not affecting execution order
|
||||
- **HIGH**: Duplicate or conflicting requirement, ambiguous security/performance attribute, untestable acceptance criterion, non-trivial task missing Context block or code signatures (blocks implementation by less-capable model)
|
||||
- **MEDIUM**: Terminology drift, missing non-functional task coverage, underspecified edge case, Context block missing implementation pattern or acceptance signal
|
||||
- **LOW**: Style/wording improvements, minor redundancy not affecting execution order, missing Phase Context summary
|
||||
|
||||
### 6. Produce Compact Analysis Report
|
||||
|
||||
@@ -145,9 +159,12 @@ Output a Markdown report (no file writes) with the following structure:
|
||||
|
||||
- Total Requirements
|
||||
- Total Tasks
|
||||
- Non-Trivial Tasks (tasks requiring Context blocks)
|
||||
- Coverage % (requirements with >=1 task)
|
||||
- Context Completeness % (non-trivial tasks with a complete Context block containing: code signatures, implementation pattern, and acceptance signal)
|
||||
- Ambiguity Count
|
||||
- Duplication Count
|
||||
- Self-Containment Issues Count (from Detection Pass G)
|
||||
- Critical Issues Count
|
||||
|
||||
### 7. Provide Next Actions
|
||||
|
||||
@@ -25,14 +25,14 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
2. **Load design documents**: Read from FEATURE_DIR:
|
||||
- **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities)
|
||||
- **Optional**: data-model.md (entities), contracts/ (interface contracts), research.md (decisions), quickstart.md (test scenarios)
|
||||
- **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios)
|
||||
- Note: Not all projects have all documents. Generate tasks based on what's available.
|
||||
|
||||
3. **Execute task generation workflow**:
|
||||
- Load plan.md and extract tech stack, libraries, project structure
|
||||
- Load spec.md and extract user stories with their priorities (P1, P2, P3, etc.)
|
||||
- If data-model.md exists: Extract entities and map to user stories
|
||||
- If contracts/ exists: Map interface contracts to user stories
|
||||
- If contracts/ exists: Map endpoints to user stories
|
||||
- If research.md exists: Extract decisions for setup tasks
|
||||
- Generate tasks organized by user story (see Task Generation Rules below)
|
||||
- Generate dependency graph showing user story completion order
|
||||
@@ -64,6 +64,101 @@ Context for task generation: $ARGUMENTS
|
||||
|
||||
The tasks.md should be immediately executable - each task must be specific enough that an LLM can complete it without additional context.
|
||||
|
||||
## Implementation Context Requirements
|
||||
|
||||
**CRITICAL**: The tasks.md will be executed by a DIFFERENT model than the one generating it. The generating model (you) has deep reasoning capability and can infer implementation details from sparse descriptions. The implementing model does NOT — it needs explicit, self-contained context embedded directly in each task. Every task must be a standalone implementation brief, not a summary that requires the reader to independently analyze the codebase.
|
||||
|
||||
### Per-Task Context Blocks
|
||||
|
||||
For every non-trivial task (anything beyond creating an empty file or adding a simple field), include an indented **Context** block immediately below the task checkbox line. This block MUST contain:
|
||||
|
||||
1. **Existing code references**: Quote the exact current function signatures, struct definitions, or interface methods that the task modifies or depends on. Use fenced code blocks with the language identifier.
|
||||
|
||||
2. **Target file state**: Describe what already exists in the target file that the implementer needs to know about (imports, adjacent functions, package conventions).
|
||||
|
||||
3. **Expected implementation pattern**: Show a concrete code skeleton or pseudocode of what the implementation should look like. Reference similar patterns already in the codebase by quoting them. For example: "Follow the same pattern as `computeDatasetAnalytics()` in `engine.go` lines 245-310, which iterates entries and accumulates stats."
|
||||
|
||||
4. **Key decisions and gotchas**: Non-obvious constraints, edge cases, or design decisions from the spec/research that affect this task. Example: "Must use `int64` not `int` for file sizes to handle >2GB files on 32-bit systems" or "The profile may have RecursiveAnalysis disabled — check `opts.Profile.RecursiveAnalysis` before accumulating subdirectory maps."
|
||||
|
||||
5. **Acceptance signal**: A concrete, verifiable statement of what "done" looks like. Example: "`go test ./internal/engine/... -run TestRegistryResolve` passes with all 6 subcases green."
|
||||
|
||||
### Example Task WITH Context (REQUIRED format for all non-trivial tasks)
|
||||
|
||||
```markdown
|
||||
- [ ] T009 [US1] Create template analysis module in `internal/engine/module_template.go`
|
||||
|
||||
**Context**:
|
||||
- **Implements**: `AnalysisModule` interface from `internal/engine/module.go`:
|
||||
```go
|
||||
type AnalysisModule interface {
|
||||
Name() string
|
||||
Description() string
|
||||
ProcessEntry(entry *types.ManifestEntry)
|
||||
Finalize(ctx *FinalizationContext) (*ModuleResult, error)
|
||||
}
|
||||
```
|
||||
- **Depends on**: `ContainerMatcher` from `internal/discovery/matcher.go` — call `matcher.Match(entry.Path)` to identify containers. The matcher is initialized from `profile.ContainerPatterns` (see `engine.go:initContainerMatcher()`).
|
||||
- **Accumulation pattern**: Follow the same accumulator pattern as `DatasetAnalyticsAccumulator` in `pipeline.go` — use maps keyed by container path to accumulate file counts, total sizes, and date ranges incrementally during `ProcessEntry()`.
|
||||
- **Key struct fields to accumulate**:
|
||||
```go
|
||||
type templateModule struct {
|
||||
matcher *discovery.ContainerMatcher
|
||||
profile *config.Profile
|
||||
accumulators map[string]*containerAccumulator // keyed by container path
|
||||
seen map[string]bool // for nesting exclusion
|
||||
subdirs map[string]map[string]bool // container -> subdirs (only if recursive enabled)
|
||||
filesByPath map[string]map[string]int // container -> subdir -> file count
|
||||
sizeByPath map[string]map[string]int64 // container -> subdir -> total size
|
||||
}
|
||||
```
|
||||
- **Gotcha**: Nesting exclusion — if `/projects/foo` is a container, `/projects/foo/bar` should NOT also be identified as a separate container even if it matches. Use the `seen` set: before adding a new container, check if any prefix of its path is already in `seen`.
|
||||
- **Acceptance**: Module registers successfully, `ProcessEntry()` populates accumulators for test entries, `Name()` returns `"template"`.
|
||||
```
|
||||
|
||||
### Example Task WITHOUT Context (WRONG — never do this)
|
||||
|
||||
```markdown
|
||||
- [ ] T009 [US1] Create template analysis module in `internal/engine/module_template.go` — implement AnalysisModule interface, accumulate container stats during ProcessEntry(), handle nesting exclusion
|
||||
```
|
||||
|
||||
The second example forces the implementing model to independently figure out what `AnalysisModule` looks like, how `ContainerMatcher` works, what fields to accumulate, and how nesting exclusion works. This results in incorrect or incomplete implementations.
|
||||
|
||||
### Per-Phase Context Summary
|
||||
|
||||
At the start of each phase (after the **Goal** line), include a **Phase Context** block listing:
|
||||
|
||||
- **Files modified in this phase**: Full paths with a one-line description of each file's current purpose
|
||||
- **Key types/interfaces used**: Quoted signatures of types that tasks in this phase depend on
|
||||
- **Codebase conventions to follow**: Naming patterns, error handling style, import grouping, or test patterns observed in the project (reference specific files as examples)
|
||||
|
||||
### Context Sourcing Strategy — Plan Artifacts First
|
||||
|
||||
The design documents produced by `/speckit.plan` (contracts, data-model, research, quickstart) already contain most of the information that Context blocks need: interface signatures, struct definitions, design decisions, gotchas, error messages, and acceptance scenarios. **Use these artifacts as your primary source for Context blocks instead of re-reading source files.**
|
||||
|
||||
**For tasks that CREATE new files** (new modules, new types, new test files):
|
||||
- Pull interface signatures, struct definitions, and method contracts from **contracts/** and **data-model.md** — these already contain the exact code the implementer needs
|
||||
- Pull design decisions, accumulation patterns, and gotchas from **research.md** — cite the specific research item (e.g., "See R3: Container Identification During Streaming")
|
||||
- Pull acceptance scenarios from **quickstart.md** — map CLI examples to verifiable acceptance signals
|
||||
- **Do NOT read source files** unless the plan artifacts reference an existing pattern that needs to be matched (e.g., "follows the existing `plugin.Registry` pattern") — in that case, read only the referenced file to quote the specific pattern
|
||||
|
||||
**For tasks that MODIFY existing files** (adding fields, rewiring functions, updating existing logic):
|
||||
- Still use plan artifacts for the **target design** (what the code should become)
|
||||
- Read the **specific function/struct being modified** from the source file to quote its **current state** — the implementer needs to see both "what exists now" and "what it should become"
|
||||
- Do NOT read the entire file — read only the function/struct being changed plus its immediate dependencies
|
||||
|
||||
**For test tasks**:
|
||||
- Read **one existing test file** in the same package to capture test conventions (table-driven patterns, setup/teardown helpers, assertion style). Quote a representative test function as a pattern to follow.
|
||||
- Pull test scenarios from contracts and quickstart — these define expected inputs/outputs
|
||||
|
||||
**Always**:
|
||||
- Read **copilot-instructions.md** or equivalent project guidelines (once, at the start of task generation) for language version constraints, banned patterns, build requirements, and protected code paths
|
||||
- If the project has a design system or style guide referenced in the plan, read it (once)
|
||||
|
||||
**Do NOT**:
|
||||
- Read full source files for every task — the plan artifacts already distill the relevant information
|
||||
- Re-derive information that exists in contracts or research — reference those documents directly
|
||||
- Generate tasks with placeholder signatures — every code reference must come from either plan artifacts or a targeted source file read
|
||||
|
||||
## Task Generation Rules
|
||||
|
||||
**CRITICAL**: Tasks MUST be organized by user story to enable independent implementation and testing.
|
||||
@@ -109,13 +204,13 @@ Every task MUST strictly follow this format:
|
||||
- Map all related components to their story:
|
||||
- Models needed for that story
|
||||
- Services needed for that story
|
||||
- Interfaces/UI needed for that story
|
||||
- Endpoints/UI needed for that story
|
||||
- If tests requested: Tests specific to that story
|
||||
- Mark story dependencies (most stories should be independent)
|
||||
|
||||
2. **From Contracts**:
|
||||
- Map each interface contract → to the user story it serves
|
||||
- If tests requested: Each interface contract → contract test task [P] before implementation in that story's phase
|
||||
- Map each contract/endpoint → to the user story it serves
|
||||
- If tests requested: Each contract → contract test task [P] before implementation in that story's phase
|
||||
|
||||
3. **From Data Model**:
|
||||
- Map each entity to the user story(ies) that need it
|
||||
|
||||
Reference in New Issue
Block a user