Code Is Cheap. Proof Is Not. Objective-Driven Governance, in production.
I'm a product and engineering leader with 25 years in software delivery. I built HomesFlow to find out whether AI-assisted development can hold up to the same rigor I've always encouraged from teams. Short answer: it can, and the sprint that proved it took a few days, not months.
HomesFlow is a home management app for owners of multiple properties who need to coordinate maintenance and usage with family or a caretaking team. It was designed as a production-ready, well-crafted codebase for a user base of fewer than 12. The app was never the point. It's about the governance.
HomesFlow is also the live production evidence behind Dryfoos Consulting's Objective-Driven Governance experimentation. Generation was never the hard part; any developer can produce plausible code at near-zero cost now. Proving that code does what the strategy demands is the real constraint. In HomesFlow, every line of code (AI-assisted or not) traces to an authorized specification ID before it merges, checked by script on every build, not asserted after the fact.
If you have five minutes: look at the coverage matrix for scope and build state, read traceability.md for how the thread works, then HomesFlow.prd.md for the product itself.
Interested in the framework behind this repo? Visit dryfoos.com or start a conversation.
Every requirement in this repo is traceable end-to-end, from product intent to the named test that verifies it, and CI fails the build if that thread breaks anywhere.
How one thread runs, using a real example:
- Requirement: the PRD defines
AC-HOME-13: file preview must open in system Quick Look (HomesFlow.prd.md, authoritative ID registry). - Plan:
specs/001-mvp/tasks.mdtaskT065edeclaresTraces: AC-HOME-13; the implementation carries@covers AC-HOME-13inDocumentQuickLookPreview.swift. - Proof: the test suite names the criterion:
test_AC_HOME_13_streams_download_to_preview_directory. The gate script cross-references all four artifacts on every push.
No orphan code, no silent scope, no untracked debt: an acceptance criterion is either verified by a test that names it, or it appears in an unchecked task; anything else fails scripts/check-traceability.sh. The coverage matrix is a generated portfolio snapshot (regenerate with --matrix before hiring or release pushes); CI enforces integrity, not file freshness. Mechanics are documented in traceability.md.
Show the thread: the Thread Visualizer is a read-only descent view over the same Gate 2 data (one requirement → @covers → test_AC_*, plus a seeded break state). Regenerate with bash scripts/thread-visualizer-refresh.sh.
| Document | Role |
|---|---|
HomesFlow.prd.md |
Product requirements, user stories, acceptance criteria (authoritative scope) |
.specify/memory/constitution.md |
Non-negotiable process and architecture laws (not product scope) |
| Story map (StoriesOnBoard) | Human planning aid — releases and story slices; not Gate-2-enforced; promote changes into the PRD when they become product truth |
traceability.md |
How IDs flow from PRD → spec → tasks → code → tests |
specs/001-mvp/craft-conventions.md |
Swift, shell, lint, and Sonar policy (craft gates) |
specs/001-mvp/dev-notes.md |
Environments, deployment, feature breadcrumbs, platform backlog |
HomesFlow/
├── HomesFlow.prd.md ← product truth (you write / maintain)
├── traceability.md ← traceability mechanics
├── glossary.md ← domain terms
├── archive/
│ └── process.deprecated.rtf ← archived process narrative (superseded by markdown above)
├── .specify/ ← Spec Kit (templates, scripts, constitution)
│ └── memory/constitution.md ← non-negotiable laws
├── ios/ ← SwiftUI app (XcodeGen)
├── supabase/ ← migrations + local config
└── specs/
└── 001-mvp/ ← active feature (spec → plan → tasks → code)
├── spec.md
├── plan.md (after /speckit.plan)
└── tasks.md (after /speckit.tasks)
Active feature: 001-mvp
export SPECIFY_FEATURE=001-mvp
export SPECIFY_FEATURE_DIRECTORY=specs/001-mvp| Step | Command | Output |
|---|---|---|
| 1 | /speckit.specify |
Fills specs/001-mvp/spec.md from HomesFlow.prd.md |
| 2 | /speckit.clarify |
Resolves open questions |
| 3 | /speckit.plan |
plan.md, research.md, data-model.md |
| 4 | /speckit.tasks |
tasks.md with Traces: fields |
| 5 | /speckit.analyze |
Gate: must pass before coding |
| 6 | /speckit.implement |
ios/, supabase/ |
feature branch → pull request → craft-gate + SonarCloud green → merge to main
Do not push product or craft changes straight to main. Use a PR so Gate 2, craft checks, and Sonar run before merge. Branch protection setup: bash scripts/finish-phase-e.sh (admin). Details: specs/001-mvp/craft-conventions.md § Delivery workflow.
| Gate | What | CI |
|---|---|---|
| Gate 0 | Build + unit tests + SwiftLint + shellcheck | .github/workflows/ci.yml (craft-gate) |
| Gate 2 | Golden thread (check-traceability.sh) |
same workflow (traceability job) |
| SonarCloud | Static analysis (dashboard); policy in sonar-project.properties |
CI job sonar (SONAR_TOKEN) |
Local:
bash scripts/check-traceability.sh # Gate 2
bash scripts/check-traceability.sh --matrix # portfolio snapshot (coverage.md)
shellcheck scripts/*.sh
cd ios && swiftlint lint --config .swiftlint.ymlCraft conventions: specs/001-mvp/craft-conventions.md. Sonar suppressions: specs/001-mvp/sonar-disposition.md.
supabase start && supabase db reset
cp ios/HomesFlow/Resources/Secrets.xcconfig.example ios/HomesFlow/Resources/Secrets.xcconfig
# Paste SUPABASE_URL and SUPABASE_ANON_KEY from `supabase start` output
cd ios && xcodegen generate && open HomesFlow.xcodeprojUI reference (non-authoritative): https://haze-rabbit-58180688.figma.site
Before step 1: Add durable IDs to requirements and ACs in HomesFlow.prd.md per traceability.md §3.
- Do not maintain a separate root
spec.md/plan.md: Spec Kit usesspecs/<feature>/. - Do not rewrite the PRD into the feature spec by hand; let
/speckit.specifyderive the feature slice.