feat: SDD Compliance Dashboard — 7-layer spec scanner#87
Conversation
Implements a real feature using the SDD v11.0 workflow to validate the end-to-end specification-driven development pipeline. Server: - SpecComplianceService: evaluates specs against 7 information layers - GET /api/compliance/specs: scans specs/ directory, returns compliance report - Constitution v1.1.0 Specification Quality Gates enforced Dashboard: - SpecComplianceWidget: shows per-spec compliance scores (0-7 layers) - Integrated into DashboardPage - Real-time refresh, layer-level detail Tests: - 6/6 service tests passing (layer detection, scoring, reports) - 19/19 total tests passing (E2E + telegram + compliance) Type-check: 0 errors across all workspaces
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Kilo Code Review could not run — your account is out of credits. Add credits or switch to a free model to enable reviews on this change. |
| router.get('/specs', requirePermission('read:evidence'), (_req, res) => { | ||
| try { | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const specsDir = path.resolve(process.cwd(), 'specs'); | ||
| const archiveDir = path.resolve(process.cwd(), 'specs/archive'); | ||
|
|
||
| const specs: Array<{ name: string; path: string; content: string }> = []; | ||
|
|
||
| // Scan specs/ directory | ||
| for (const dir of [specsDir, archiveDir]) { | ||
| if (!fs.existsSync(dir)) continue; | ||
| const entries = fs.readdirSync(dir, { withFileTypes: true }); | ||
| for (const entry of entries) { | ||
| if (entry.isDirectory()) { | ||
| const specFile = path.join(dir, entry.name, 'spec.md'); | ||
| if (fs.existsSync(specFile)) { | ||
| const content = fs.readFileSync(specFile, 'utf-8'); | ||
| specs.push({ name: entry.name, path: specFile, content }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const report = generateComplianceReport(specs); | ||
| res.json(report); | ||
| } catch (error) { | ||
| res.status(500).json({ error: { message: 'Failed to scan specs', details: error instanceof Error ? error.message : String(error) } }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8dbeeae05
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| setLoading(true); | ||
| setError(null); | ||
| try { | ||
| const res = await fetch('/api/compliance/specs'); |
There was a problem hiding this comment.
Use the authenticated API client for compliance fetches
On the protected dashboard, this direct fetch does not attach the stored Bearer token, while /api/compliance/specs is mounted behind requireAuth and then requirePermission('read:evidence'); in a normal token-authenticated session the widget will receive 401 and only render Error: HTTP 401. Route this through the existing API client or otherwise add the Authorization header so the auth boundary is preserved. .github/copilot-instructions.mdL62-L62
Useful? React with 👍 / 👎.
| const specsDir = path.resolve(process.cwd(), 'specs'); | ||
| const archiveDir = path.resolve(process.cwd(), 'specs/archive'); |
There was a problem hiding this comment.
Resolve specs from the monorepo root
When the server is started through the documented workspace command (npm run dev:server), npm runs it with process.cwd() set to packages/server, so these paths resolve to packages/server/specs and packages/server/specs/archive; the repo's actual specs/ directory is then skipped and the endpoint reports zero specs. Resolve from the monorepo root/INIT_CWD (or a shared helper such as the existing root resolution used elsewhere) before appending specs. .github/copilot-instructions.mdL15-L15
Useful? React with 👍 / 👎.
| { id: 'L4', name: 'Hard Constraints', pattern: /## Hard Constraints/ }, | ||
| { id: 'L5', name: 'Codebase Anchoring', pattern: /## Codebase Anchoring/ }, | ||
| { id: 'L6', name: 'Edge Cases', pattern: /EC-\d{3}.*IF.*THEN/ }, | ||
| { id: 'L7', name: 'Verified Library Specs', pattern: /## Verified Library Specs/ }, |
There was a problem hiding this comment.
Validate L4-L7 contents instead of headings
For specs that contain the SDD headings but leave the required evidence empty, these regexes still set the layers to present; for example ## Codebase Anchoring passes without any FR-to-file mapping and ## Verified Library Specs passes without a library/version row. That can mark incomplete specs as fully compliant, so key these layers off the required contents (Allowed/Forbidden entries, FR path mappings, and library+version rows) rather than headings alone.
Useful? React with 👍 / 👎.
Summary
Implements a real feature using the SDD v1.1.0 (Spec-Driven Development) workflow to validate the end-to-end specification-driven development pipeline.
What's New
Server
packages/server/src/services/spec-compliance-service.ts): Evaluates feature specs against the 7 information layers from Constitution v1.1.0specs/directory, returns compliance report with per-spec scoresDashboard
packages/dashboard/src/components/SpecComplianceWidget.tsx):Tests
Constitution Compliance
All 7 information layers enforced:
Validation