Skip Evaluation Logic
Skip Evaluation System
Overview
The skip evaluation system prevents unnecessary full rebuilds when nothing has changed. It uses a rule-based validation approach to determine if a build can be safely skipped, comparing current state against previous build artifacts and persisted metadata.
When Builds Are Skipped
A build will be skipped (reusing previous public/ output) when all of the following are true:
- No repository changes: All repository commits match the previous build
- No configuration changes: Hugo config hash is identical to previous build
- No version changes: DocBuilder and Hugo versions match previous build
- Previous build exists: Valid
build-report.jsonandpublic/directory exist - Content integrity: All content files and their hashes match previous build
When Builds Are Forced
A full rebuild will occur when any of these conditions are detected:
| Condition | Why Rebuild? |
|---|---|
| Repository added/removed | Content structure changed |
| Repository updated (new commits) | Documentation content changed |
| DocBuilder version changed | New features, bug fixes, compatibility |
| Hugo version changed | Rendering engine updates |
| Configuration changed | Parameters, theme settings, URLs, etc. |
| Previous build missing/corrupt | Cannot validate skip safety |
| Content file modified outside git | Integrity violation |
Architecture
Components
Validation Rules
Rules are executed in order, with early exit on first failure:
Rule Validation Pattern
Each rule implements this interface:
Rules have access to:
- Context.State: Persisted commit/config metadata
- Context.Generator: Current Hugo configuration
- Context.Repos: Current repository list
- Context.OutDir: Output directory path
- Context.PrevReport: Previous build report (loaded by PreviousReportRule)
Configuration
Enabling Skip Evaluation
Daemon Mode (enabled by default):
CLI Mode (opt-in):
Configuration Hash
The config hash is computed from:
- Hugo configuration (title, base_url, theme, params, etc.)
- Build configuration (render mode, skip settings, etc.)
- Repository list (URLs, branches, paths, auth)
Changes to any of these trigger a rebuild.
State Persistence
The skip evaluator relies on the StateManager to track:
State is persisted in /data/state/daemon-state.json and survives daemon restarts.
Build Report
When a build is skipped, the evaluator returns the previous build report unmodified:
The caller cannot distinguish a skipped build from a successful build - this is intentional for idempotency.
Integration with Daemon
Factory Pattern
The daemon uses a factory to create the skip evaluator with late binding:
This allows:
- Lazy creation: Evaluator created only when needed during build
- Late binding: State manager initialized after build service creation
- Type adaptation: Bridge typed daemon.SkipEvaluator to generic build.SkipEvaluator
Type Adapter
The skipEvaluatorAdapter bridges the type gap:
The adapter performs runtime type checking and conversion.
Testing
Unit Tests
Validation rules are tested in isolation:
Integration Tests
End-to-end skip behavior is tested in daemon integration tests:
Performance Impact
Skip evaluation adds minimal overhead:
- Config hash computation: ~5ms (YAML marshaling + SHA256)
- File tree scan: ~10-50ms (depends on content size)
- State manager lookups: ~1ms (in-memory with disk cache)
- Rule validation: ~20-100ms total
Total overhead: ~50-200ms vs. full rebuild: 5-30 seconds
The cost of skip validation is negligible compared to git operations and Hugo rendering.
Logging
Skip decisions are logged at INFO level:
Troubleshooting
Skip Not Working
Symptom: Builds always run fully even when nothing changed
Diagnosis:
- Check
skip_if_unchangedis enabled in config - Verify state manager is initialized (
/data/state/daemon-state.jsonexists) - Check logs for skip validation failures
- Ensure
public/directory andbuild-report.jsonexist from previous build
Common Causes:
- Configuration changes not reflected in config hash
- Timestamps in config (use static values)
- File system changes outside git (edited files directly)
- State file corruption or deletion
False Skips
Symptom: Build skipped but content appears outdated
Diagnosis:
- Check repository commits match:
git log -1 --format=%H - Verify content file integrity (no manual edits)
- Compare config hashes (previous vs. current)
Common Causes:
- Files edited outside git (breaks content integrity)
- Force-pushed branches (commit SHA same but content differs)
- Symlinked content (changes not tracked)
Future Enhancements
Potential improvements to the skip system:
- Partial rebuilds: Skip unchanged repos, rebuild only changed ones
- Content diffing: Detect file-level changes without full tree scan
- Incremental Hugo: Use Hugo’s
--gcand caching for faster builds - Parallel validation: Run rules concurrently for large repositories
- Skip hints: Allow repos to declare “always rebuild” vs. “safe to skip”