@@ -143,28 +143,43 @@ graph TD
143143
144144``` mermaid
145145graph LR
146- subgraph "commands/validate.py "
146+ subgraph "commands/"
147147 VC[validate_cmd]
148+ DIS[get_latest_spec_dir]
149+ RPT[report_validation_result]
150+ end
151+
152+ subgraph "validation/"
148153 VP[validate_plan]
149154 VB[validate_build]
150155 VT[validate_task]
151156 MP[MarkdownParser]
152157 CB[ContractBlock]
158+ SC[CodeScanner]
159+ SI[ScanResult]
160+ RD[run_rumdl_format]
153161 end
154162
155- subgraph "validation/scanner.py"
156- CS[CodeScanner]
157- SI[ScanIssue]
163+ subgraph "support/"
164+ CFG[config.py]
165+ EXC[exceptions.py]
166+ GIT[git_utils.py]
167+ OUT[output.py]
158168 end
159169
160170 VC --> VP
161171 VC --> VB
162172 VC --> VT
173+ VC --> DIS
174+ VC --> RPT
163175 VP --> MP
164176 VP --> CB
165- VT --> CS
166- VB --> CS
167- CS --> SI
177+ VB --> SC
178+ VB --> MP
179+ VT --> SC
180+ SC --> GIT
181+ SC --> CFG
182+ RD --> CFG
168183```
169184
170185### 4.4 Key Design Principles
@@ -179,9 +194,14 @@ graph LR
179194| Component | Location | How to Reuse |
180195| :--- | :--- | :--- |
181196| Click CLI framework | ` src/pb_spec/cli.py ` | Extend with new subcommands |
182- | MarkdownParser | ` src/pb_spec/commands/validate .py ` | Reuse for parsing any spec markdown |
183- | ContractBlock | ` src/pb_spec/commands/validate .py ` | Reuse for structured block validation |
197+ | MarkdownParser | ` src/pb_spec/validation/parser .py ` | Reuse for parsing any spec markdown |
198+ | ContractBlock | ` src/pb_spec/validation/parser .py ` | Reuse for structured block validation |
184199| CodeScanner | ` src/pb_spec/validation/scanner.py ` | Reuse for code quality scanning |
200+ | get_latest_spec_dir | ` src/pb_spec/commands/discovery.py ` | Discover latest spec directory |
201+ | report_validation_result | ` src/pb_spec/commands/report.py ` | Format and display validation results |
202+ | get_timeout_config | ` src/pb_spec/config.py ` | Shared timeout configuration |
203+ | get_git_modified_files | ` src/pb_spec/git_utils.py ` | Git-aware file discovery |
204+ | Colors / print_ * helpers | ` src/pb_spec/output.py ` | Terminal output formatting |
185205
186206---
187207
@@ -306,62 +326,77 @@ class ValidationMode(Enum):
306326 TASK = " task"
307327
308328
329+ class ErrorSeverity (Enum ):
330+ CRITICAL = " critical"
331+ HIGH = " high"
332+ MEDIUM = " medium"
333+ LOW = " low"
334+
335+
309336@dataclass (frozen = True )
310337class ValidationError :
311- file : str
312- line: int | None = None
338+ """ A single structured validation error. """
339+ severity: ErrorSeverity
313340 message: str
314- severity: str = " error" # 'error', 'warning', 'info'
341+ file_path: str | None = None
342+ line_number: int | None = None
343+ field_name: str | None = None
315344
316345
317- @dataclass ( frozen = True )
346+ @dataclass
318347class ValidationResult :
319- mode: ValidationMode
320- spec_dir: str | None
348+ """ Result of a validation operation."""
321349 is_valid: bool
322- errors: tuple[ValidationError, ... ] = ()
323- warnings: tuple[ValidationError, ... ] = ()
324-
350+ errors: list[ValidationError] = field(default_factory = list )
351+ warnings: list[str ] = field(default_factory = list )
325352
326- class DesignParser :
327- def parse (self , content : str , mode : str = " full" ) -> list[ValidationError]:
328- """ Parse design.md and return validation errors."""
329- ...
330-
331-
332- class TasksParser :
333- def parse (self , content : str ) -> list[ValidationError]:
334- """ Parse tasks.md and return validation errors."""
335- ...
353+ def errors_by_severity (self , severity : ErrorSeverity) -> list[ValidationError]: ...
354+ def errors_by_file (self , file_path : str ) -> list[ValidationError]: ...
355+ def has_critical (self ) -> bool : ...
336356
337357
338358class CodeScanner :
339- def scan (self , files : list[str ]) -> list[ScanIssue]:
340- """ Scan files for code quality issues."""
341- ...
359+ def scan (self ) -> ScanResult: ...
342360```
343361
344362### 7.2 Exception Hierarchy
345363
346364``` python
347365class ValidationError (Exception ):
348366 """ Base exception for all validation errors."""
349- pass
350367
351368
352369class SpecNotFoundError (ValidationError ):
353370 """ Raised when spec directory is missing."""
354- pass
355371
356372
357373class FileReadError (ValidationError ):
358374 """ Raised when spec files cannot be read."""
359- pass
360375
361376
362- class ContractViolationError (ValidationError ):
363- """ Raised when markdown contract is violated."""
364- pass
377+ class ConfigError (ValidationError ):
378+ """ Raised when configuration parsing fails."""
379+ ```
380+
381+ ### 7.3 Configuration Types
382+
383+ ``` python
384+ from dataclasses import dataclass
385+
386+
387+ @dataclass (frozen = True )
388+ class TimeoutConfig :
389+ """ Structured timeout configuration with type-safe attribute access."""
390+ git_ls_files: int = 60
391+ rumdl_check: int = 10
392+ rumdl_format: int = 30
393+ ```
394+
395+ ### 7.4 Markdown Parsing
396+
397+ ``` python
398+ def parse_task_blocks (content : str ) -> list[TaskBlock]:
399+ """ Module-level function for extracting task blocks from markdown."""
365400```
366401
367402---
@@ -374,12 +409,24 @@ class ContractViolationError(ValidationError):
374409src/pb_spec/
375410├── __init__.py # Version from metadata
376411├── cli.py # Click CLI entry point
412+ ├── config.py # Shared configuration (timeouts from env vars)
413+ ├── exceptions.py # Exception hierarchy
414+ ├── git_utils.py # Git interaction utilities
415+ ├── output.py # Terminal output helpers (colors, formatting)
377416├── commands/
378417│ ├── __init__.py
379- │ └── validate.py # Validate command implementation
418+ │ ├── validate.py # Validate command implementation
419+ │ ├── discovery.py # Spec directory discovery
420+ │ └── report.py # Terminal output formatting for results
380421└── validation/
381- ├── __init__.py
382- └── scanner.py # Code quality scanner
422+ ├── __init__.py # Public API re-exports
423+ ├── contract_sections.toml # Contract rules (single source of truth)
424+ ├── result.py # Structured validation result types
425+ ├── parser.py # Markdown parser for task/contract blocks
426+ ├── plan.py # Plan validation logic (design.md, tasks.md)
427+ ├── build.py # Build validation logic (task completion, code quality)
428+ ├── scanner.py # Code quality scanner
429+ └── rumdl.py # rumdl markdown formatting integration
383430```
384431
385432### 8.2 Logic Flow
@@ -448,32 +495,56 @@ sequenceDiagram
448495
449496### 10.1 Exception Hierarchy
450497
451- - ` ValidationError ` : Base exception for all validation errors
498+ - ` PbSpecError ` : Base exception for all pb-spec errors
452499- ` SpecNotFoundError ` : When spec directory is missing
453500- ` FileReadError ` : When spec files cannot be read
454- - ` ContractViolationError ` : When markdown contract is violated
501+ - ` ConfigError ` : When configuration parsing fails
502+
503+ ### 10.2 Structured Validation Results
455504
456- ### 10.2 Safety Mechanisms
505+ - ` ValidationResult ` : Collection of errors and warnings with severity levels
506+ - ` ValidationError ` : Single validation issue with file, line, field context
507+ - ` ErrorSeverity ` : Severity enum — ` CRITICAL ` , ` HIGH ` , ` MEDIUM ` , ` LOW `
457508
458- 1 . ** Git-aware scanning:** Respects .gitignore, excludes irrelevant directories
459- 2 . ** Timeout protection:** All external commands have 60-second timeouts
460- 3 . ** Graceful degradation:** Optional tools (rumdl) fail safely without breaking validation
461- 4 . ** Idempotent operations:** Validation is read-only, never modifies files
509+ ### 10.3 Safety Mechanisms (RFC 2119)
510+
511+ - The validator ** MUST NOT** modify source files — all operations are read-only.
512+ - The validator ** MUST** exit with non-zero status when CRITICAL or HIGH errors are found.
513+ - The validator ** SHOULD** exit with non-zero status when MEDIUM errors are found.
514+ - The validator ** MAY** continue past LOW severity issues without failing.
515+ - ` rumdl ` formatting checks ** SHOULD** run when available, but the validator ** MUST NOT** fail when ` rumdl ` is not installed.
516+ - All external commands ** MUST** have configurable timeouts (default 60s for git, 10-30s for rumdl).
517+ - The validator ** MUST** respect ` .gitignore ` rules via ` git ls-files ` .
518+
519+ ---
520+
521+ ## 11. Contract-Driven Configuration
522+
523+ Validation rules are loaded from ` contract_sections.toml ` — the single source of truth
524+ that stays synchronized with ` docs/contract.md ` . This eliminates hardcoded section lists
525+ and enables per-project customization.
526+
527+ | Config Key | Purpose | Location |
528+ | :--- | :--- | :--- |
529+ | ` full_mode.required_sections ` | Required design.md sections for full mode | ` contract_sections.toml ` |
530+ | ` lightweight_mode.required_sections ` | Required design.md sections for lightweight mode | ` contract_sections.toml ` |
531+ | ` tasks.required_fields ` | Required fields per task block | ` contract_sections.toml ` |
532+ | ` tasks.na_reason_fields ` | Fields where N/A requires a reason | ` contract_sections.toml ` |
462533
463534---
464535
465- ## 11 . Implementation Plan
536+ ## 12 . Implementation Plan
466537
467538- [x] ** Phase 1: Foundation** — CLI entry point, Click group, basic validate command
468539- [x] ** Phase 2: Core Logic** — Markdown parser, contract block parser, validation rules
469540- [x] ** Phase 3: Scanner** — Code quality scanner with multi-language support
470541- [x] ** Phase 4: Integration** — Wire validation modes, add rumdl integration
471- - [ ] ** Phase 5: Polish ** — Additional validation rules, performance optimization
542+ - [x ] ** Phase 5: Contract-Driven Config ** — TOML-based rule loading, RFC 2119 constraints
472543
473544---
474545
475- ## 12 . Cross-Functional Concerns
546+ ## 13 . Cross-Functional Concerns
476547
477548- ** Performance:** For very large codebases, consider implementing parallel scanning or incremental validation
478549- ** Extensibility:** Additional programming languages can be added by extending scanner patterns
479- - ** Configuration:** Currently hardcoded patterns; future versions may support configurable rule sets
550+ - ** Configuration:** Rules loaded from ` contract_sections.toml ` ; projects may override with local config
0 commit comments