- Move ASPICE docs to chanoraapp/docs submodule at docs/ - Move development docs to dev-docs/ (superpowers, offline-knowledge, impl-mapping) - Add AGENTS.md with project conventions for AI agents - Add impl-mapping.md (SAD component → source file mapping) - Archive completed plans to dev-docs/superpowers/plans/_archived/ - Remove AGENTS.md from .gitignore (now tracked)
1487 lines
45 KiB
Markdown
1487 lines
45 KiB
Markdown
# Documentation Site & ASPICE Traceability Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Create a private MkDocs Material doc site with tag-based ASPICE traceability, hosted on Cloudflare Pages with access control, served from a git submodule.
|
|
|
|
**Architecture:** The docs repo (`chanora-docs`) is a standalone MkDocs Material project added as a git submodule at `docs/` in the code repo. A custom MkDocs plugin validates requirement ID traceability chains on every build. The code repo retains development-only docs in `dev-docs/`.
|
|
|
|
**Tech Stack:** MkDocs Material, Python 3.12, MkDocs tags/git-revision-date-localized plugins, custom traceability plugin (~200 lines Python), GitHub Actions, Cloudflare Pages + Access, git submodules
|
|
|
|
**Spec:** `dev-docs/superpowers/specs/2026-06-13-documentation-site-design.md`
|
|
|
|
---
|
|
|
|
### Task 1: Create Docs Repo and MkDocs Configuration
|
|
|
|
**Files:**
|
|
- Create: `mkdocs.yml`
|
|
- Create: `requirements.txt`
|
|
- Create: `pyproject.toml`
|
|
- Create: `docs/index.md`
|
|
- Create: `docs/.meta.yml`
|
|
- Create: `README.md`
|
|
|
|
Note: This task creates the `chanora-docs` GitHub repo. The `chanora-docs` repo must be created on GitHub first (private repo), then cloned locally for these steps.
|
|
|
|
- [ ] **Step 1: Create the private `chanora-docs` GitHub repo**
|
|
|
|
```bash
|
|
gh repo create chanora-docs --private --description "Chanora engineering documentation with ASPICE traceability"
|
|
```
|
|
|
|
- [ ] **Step 2: Clone and initialize**
|
|
|
|
```bash
|
|
git clone git@github.com:EdisonJwa/chanora-docs.git
|
|
cd chanora-docs
|
|
```
|
|
|
|
- [ ] **Step 3: Create `requirements.txt`**
|
|
|
|
```
|
|
mkdocs-material>=9.6.0
|
|
mkdocs-git-revision-date-localized-plugin>=1.5.0
|
|
```
|
|
|
|
- [ ] **Step 4: Create `pyproject.toml`**
|
|
|
|
```toml
|
|
[project]
|
|
name = "chanora-docs"
|
|
version = "0.1.0"
|
|
description = "Chanora engineering documentation with ASPICE traceability"
|
|
requires-python = ">=3.12"
|
|
```
|
|
|
|
- [ ] **Step 5: Create `mkdocs.yml` with full configuration**
|
|
|
|
```yaml
|
|
site_name: Chanora Engineering Docs
|
|
site_description: ASPICE-compliant engineering documentation with automated traceability
|
|
site_url: https://docs.chanora.dev
|
|
|
|
repo_name: EdisonJwa/chanora-docs
|
|
repo_url: https://github.com/EdisonJwa/chanora-docs
|
|
edit_uri: edit/main/docs/
|
|
|
|
theme:
|
|
name: material
|
|
language: en
|
|
features:
|
|
- navigation.instant
|
|
- navigation.tracking
|
|
- navigation.tabs
|
|
- navigation.sections
|
|
- navigation.expand
|
|
- navigation.footer
|
|
- search.highlight
|
|
- search.suggest
|
|
- content.code.copy
|
|
- content.tabs.link
|
|
palette:
|
|
- media: "(prefers-color-scheme)"
|
|
toggle:
|
|
icon: material/brightness-auto
|
|
name: Switch to light mode
|
|
- media: "(prefers-color-scheme: light)"
|
|
scheme: default
|
|
primary: deep purple
|
|
accent: purple
|
|
toggle:
|
|
icon: material/brightness-7
|
|
name: Switch to dark mode
|
|
- media: "(prefers-color-scheme: dark)"
|
|
scheme: slate
|
|
primary: deep purple
|
|
accent: purple
|
|
toggle:
|
|
icon: material/brightness-4
|
|
name: Switch to system preference
|
|
icon:
|
|
repo: fontawesome/brands/github
|
|
|
|
plugins:
|
|
- search
|
|
- tags:
|
|
tags_allowed:
|
|
- sysrs
|
|
- sysdes
|
|
- srs
|
|
- sad
|
|
- sdd
|
|
- swe.1
|
|
- swe.2
|
|
- swe.3
|
|
- swe.4
|
|
- swe.5
|
|
- swe.6
|
|
- sys.4
|
|
- requirements
|
|
- architecture
|
|
- verification
|
|
- governance
|
|
- security
|
|
- privacy
|
|
- legal
|
|
- release
|
|
- references
|
|
- ui-ux
|
|
- localization
|
|
- baseline
|
|
- draft
|
|
- candidate
|
|
- deferred
|
|
tags_file: tags.md
|
|
- git-revision-date-localized:
|
|
type: iso_date
|
|
enable_creation_date: true
|
|
- traceability:
|
|
strict: true
|
|
coverage_file: true
|
|
dashboard: true
|
|
|
|
nav:
|
|
- Home: index.md
|
|
- Requirements:
|
|
- System Requirements (SysRS): requirements/sysrs.md
|
|
- System Design (SysDes): requirements/sysdes.md
|
|
- Software Requirements (SRS): requirements/srs.md
|
|
- Architecture & Design:
|
|
- Software Architecture (SWE.2 / SAD): architecture/sad.md
|
|
- Detailed Design (SWE.3 / SDD): architecture/sdd.md
|
|
- File Transfer Design: architecture/file-transfer-design.md
|
|
- File Transfer Research: architecture/file-transfer-research.md
|
|
- File Transfer Implementation Plan: architecture/file-transfer-implementation-plan.md
|
|
- Desktop PTT Architecture: architecture/desktop-ptt-architecture.md
|
|
- Verification:
|
|
- System Level:
|
|
- SYS.4 System Integration: verification/sys4-system-integration-verification-plan.md
|
|
- Software Integration:
|
|
- SWE.5 Software Integration: verification/swe5-software-integration-verification-plan.md
|
|
- Unit Level:
|
|
- SWE.4 Unit Verification: verification/swe4-unit-verification-plan.md
|
|
- Software Qualification:
|
|
- SWE.6 Software Verification: verification/swe6-software-verification-plan.md
|
|
- Master Plan: verification/verification-master-plan.md
|
|
- Governance:
|
|
- Document Index: governance/document-index.md
|
|
- Traceability Matrix: governance/traceability-matrix.md
|
|
- Decision Register: governance/product-decision-register.md
|
|
- Baseline Approval Record: governance/baseline-approval-record.md
|
|
- Baseline Candidate Validation: governance/baseline-candidate-validation-report.md
|
|
- Document Review Report: governance/document-review-report.md
|
|
- Document Naming Convention: governance/document-naming-convention.md
|
|
- Decision Impact Assessment: governance/decision-impact-assessment.md
|
|
- Git Commit Message Convention: governance/git-commit-message-convention.md
|
|
- Repo Format Validation: governance/repo-format-validation-report.md
|
|
- Path Migration Map: governance/path-migration-map.md
|
|
- Maintainability Review: governance/maintainability-review-2026-06-08.md
|
|
- Security & Privacy:
|
|
- Security Guidelines: security/security-privacy-legal-guideline.md
|
|
- Threat Model: security/threat-model.md
|
|
- Secure Storage Audit: security/secure-storage-audit-report.md
|
|
- Diagnostic Redaction Audit: security/diagnostic-redaction-audit-report.md
|
|
- Dependency & Supply Chain: security/dependency-and-supply-chain-report.md
|
|
- License Inventory: security/license-inventory.md
|
|
- Flutter License Inventory: security/flutter-license-inventory.md
|
|
- Privacy Policy: privacy/privacy-policy.md
|
|
- Legal Review: legal/trademark-and-attribution-review.md
|
|
- Release:
|
|
- Platform Release Policy: release/platform-release-policy.md
|
|
- Release Readiness (Go/No-Go): release/release-readiness-go-nogo-record.md
|
|
- DV Waiver Register: release/dv-waiver-register.md
|
|
- References:
|
|
- External References: references/external-references.md
|
|
- ASPICE SWE.2/SWE.3 Note: references/aspice-swe2-swe3-integration-note.md
|
|
- TeamSpeak Protocol Reference (EN): references/yatqa-en.md
|
|
- TeamSpeak Protocol Reference (DE): references/yatqa-de.md
|
|
- TeaSpeak Overview: references/teaspeak-overview.md
|
|
- ReSpeak Overview: references/respeak-overview.md
|
|
- UI/UX:
|
|
- Material 3 Guideline: ui-ux/material3-guideline.md
|
|
- Design Tokens: ui-ux/material3-design-tokens.md
|
|
- Component Catalog: ui-ux/material3-component-catalog.md
|
|
- Adaptive Layout Guide: ui-ux/adaptive-layout-platform-guide.md
|
|
- Localization:
|
|
- Localization Architecture: i18n/localization-architecture.md
|
|
|
|
markdown_extensions:
|
|
- admonition
|
|
- pymdownx.details
|
|
- pymdownx.superfences
|
|
- pymdownx.tabbed:
|
|
alternate_style: true
|
|
- pymdownx.highlight:
|
|
anchor_linenums: true
|
|
- pymdownx.inlinehilite
|
|
- pymdownx.snippets
|
|
- attr_list
|
|
- md_in_html
|
|
- tables
|
|
- toc:
|
|
permalink: true
|
|
```
|
|
|
|
- [ ] **Step 6: Create `docs/.meta.yml` (global defaults)**
|
|
|
|
```yaml
|
|
status: draft
|
|
```
|
|
|
|
- [ ] **Step 7: Create `docs/index.md` (landing page)**
|
|
|
|
```markdown
|
|
# Chanora Engineering Documentation
|
|
|
|
**ASPICE-compliant engineering documentation with automated traceability**
|
|
|
|
---
|
|
|
|
## Lifecycle Chain
|
|
|
|
```text
|
|
SysRS → SysDes → SRS → SAD (SWE.2) → SDD (SWE.3) → Verification
|
|
↓ ↓
|
|
SWE.4 (unit) SWE.4/5/6/SYS.4
|
|
```
|
|
|
|
## Quick Navigation
|
|
|
|
- [System Requirements (SysRS)](requirements/sysrs.md)
|
|
- [System Design (SysDes)](requirements/sysdes.md)
|
|
- [Software Requirements (SRS)](requirements/srs.md)
|
|
- [Software Architecture (SAD)](architecture/sad.md)
|
|
- [Detailed Design (SDD)](architecture/sdd.md)
|
|
- [Verification Master Plan](verification/verification-master-plan.md)
|
|
- [Traceability Matrix](governance/traceability-matrix.md)
|
|
- [Document Index](governance/document-index.md)
|
|
|
|
## Baseline Status
|
|
|
|
| Document | Status |
|
|
|---|---|
|
|
| SysRS | Baseline |
|
|
| SysDes | Baseline |
|
|
| SRS | Baseline |
|
|
| SAD | Baseline candidate |
|
|
| SDD | Baseline candidate |
|
|
| Verification plans | Baseline candidate |
|
|
| Release readiness | No-Go |
|
|
|
|
---
|
|
|
|
[View all tags →](tags.md)
|
|
```
|
|
|
|
- [ ] **Step 8: Create `README.md`**
|
|
|
|
```markdown
|
|
# Chanora Engineering Docs
|
|
|
|
ASPICE-compliant engineering documentation site for Chanora.
|
|
|
|
## Local Development
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
mkdocs serve
|
|
```
|
|
|
|
## Build
|
|
|
|
```bash
|
|
mkdocs build --strict
|
|
```
|
|
|
|
## Traceability Validation
|
|
|
|
```bash
|
|
python scripts/validate_traceability.py docs/
|
|
```
|
|
|
|
## Deployment
|
|
|
|
Deploys automatically to Cloudflare Pages on push to `main`.
|
|
```
|
|
|
|
- [ ] **Step 9: Create directory structure for docs**
|
|
|
|
```bash
|
|
mkdir -p docs/{requirements,architecture,verification,governance,security,privacy,legal,release,references,ui-ux,i18n}
|
|
mkdir -p plugins/traceability
|
|
mkdir -p scripts
|
|
mkdir -p .github/workflows
|
|
```
|
|
|
|
- [ ] **Step 10: Commit**
|
|
|
|
```bash
|
|
git add -A
|
|
git commit -m "chore: initialize MkDocs Material project with configuration and landing page"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: Build Custom Traceability Plugin
|
|
|
|
**Files:**
|
|
- Create: `plugins/traceability/__init__.py`
|
|
- Create: `plugins/traceability/traceability.py`
|
|
- Create: `tests/test_traceability.py`
|
|
|
|
- [ ] **Step 1: Create plugin package init**
|
|
|
|
```python
|
|
# plugins/traceability/__init__.py
|
|
from .traceability import TraceabilityPlugin
|
|
|
|
def make_plugin(config, **kwargs):
|
|
return TraceabilityPlugin(config)
|
|
```
|
|
|
|
- [ ] **Step 2: Write the traceability plugin**
|
|
|
|
```python
|
|
# plugins/traceability/traceability.py
|
|
"""MkDocs plugin for ASPICE requirement traceability validation."""
|
|
|
|
import json
|
|
import re
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
from mkdocs.plugins import BasePlugin
|
|
from mkdocs.structure.pages import Page
|
|
|
|
REQUIREMENT_ID_PATTERNS = {
|
|
"sysrs": re.compile(r"SysRS-\d+"),
|
|
"sysdes": re.compile(r"SysDes-\d+"),
|
|
"srs": re.compile(r"SRS-\d+"),
|
|
"sdd_mod": re.compile(r"SDD-MOD-\d+"),
|
|
"dec": re.compile(r"DEC-\d+"),
|
|
}
|
|
|
|
CHAINS = [
|
|
("sysrs", "sysdes"),
|
|
("sysdes", "srs"),
|
|
("srs", "sad"),
|
|
("srs", "sdd"),
|
|
("sad", "swe5"),
|
|
("sdd", "swe4"),
|
|
("srs", "swe6"),
|
|
("sysdes", "sys4"),
|
|
]
|
|
|
|
|
|
class TraceabilityPlugin(BasePlugin):
|
|
config_scheme = (
|
|
("strict", {"type": bool, "default": True}),
|
|
("coverage_file", {"type": bool, "default": True}),
|
|
("dashboard", {"type": bool, "default": True}),
|
|
)
|
|
|
|
def __init__(self, config):
|
|
super().__init__(config)
|
|
self.defined_ids: dict[str, set[str]] = defaultdict(set)
|
|
self.referenced_ids: dict[str, set[str]] = defaultdict(set)
|
|
self.page_ids: dict[str, set[str]] = defaultdict(set)
|
|
self.page_src: dict[str, str] = {}
|
|
|
|
def on_page_markdown(self, markdown: str, page: Page, config, files):
|
|
src_path = page.file.src_path
|
|
self.page_src[src_path] = src_path
|
|
|
|
for pattern_name, pattern in REQUIREMENT_ID_PATTERNS.items():
|
|
found = set(pattern.findall(markdown))
|
|
if found:
|
|
self.page_ids[src_path].update(found)
|
|
|
|
tags = page.meta.get("tags", [])
|
|
for tag in tags:
|
|
if isinstance(tag, str) and any(
|
|
tag.startswith(prefix)
|
|
for prefix in ["SysRS-", "SysDes-", "SRS-", "SDD-MOD-", "DEC-"]
|
|
):
|
|
self.defined_ids[tag].add(src_path)
|
|
|
|
for pattern_name, pattern in REQUIREMENT_ID_PATTERNS.items():
|
|
for match in pattern.findall(markdown):
|
|
self.referenced_ids[match].add(src_path)
|
|
|
|
return markdown
|
|
|
|
def on_post_build(self, config):
|
|
orphans = []
|
|
for req_id, pages in self.referenced_ids.items():
|
|
if req_id not in self.defined_ids:
|
|
orphans.append((req_id, sorted(pages)))
|
|
|
|
coverage = {}
|
|
for upstream, downstream in CHAINS:
|
|
upstream_ids = set()
|
|
for req_id, pages in self.defined_ids.items():
|
|
if req_id.upper().startswith(upstream.upper()):
|
|
upstream_ids.add(req_id)
|
|
|
|
downstream_refs = set()
|
|
for req_id, pages in self.referenced_ids.items():
|
|
for page in pages:
|
|
if downstream in page.lower():
|
|
downstream_refs.add(req_id)
|
|
|
|
if upstream_ids:
|
|
covered = upstream_ids & downstream_refs
|
|
coverage[f"{upstream} -> {downstream}"] = {
|
|
"total": len(upstream_ids),
|
|
"covered": len(covered),
|
|
"percentage": round(100 * len(covered) / len(upstream_ids), 1)
|
|
if upstream_ids
|
|
else 0,
|
|
"orphaned": sorted(upstream_ids - covered),
|
|
}
|
|
|
|
report = {
|
|
"chains": coverage,
|
|
"orphaned_references": [
|
|
{"id": rid, "referenced_in": sorted(pages)}
|
|
for rid, pages in orphans
|
|
],
|
|
}
|
|
|
|
if self.config["coverage_file"]:
|
|
output_dir = Path(config["site_dir"])
|
|
with open(output_dir / "traceability-coverage.json", "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
|
|
self._print_summary(report)
|
|
|
|
if self.config["strict"] and (orphans or any(
|
|
c.get("orphaned") for c in coverage.values()
|
|
)):
|
|
import sys
|
|
print(
|
|
"\nERROR: Traceability validation failed. "
|
|
"Set strict: false to allow broken chains.",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
def _print_summary(self, report):
|
|
print("\n" + "=" * 60)
|
|
print("ASPICE Traceability Summary")
|
|
print("=" * 60)
|
|
for chain, data in report["chains"].items():
|
|
status = "PASS" if not data["orphaned"] else "WARN"
|
|
print(
|
|
f" [{status}] {chain}: "
|
|
f"{data['covered']}/{data['total']} "
|
|
f"({data['percentage']}%)"
|
|
)
|
|
if report["orphaned_references"]:
|
|
print(f"\n Orphaned references: {len(report['orphaned_references'])}")
|
|
for orphan in report["orphaned_references"][:10]:
|
|
print(f" - {orphan['id']} in {', '.join(orphan['referenced_in'])}")
|
|
if len(report["orphaned_references"]) > 10:
|
|
print(
|
|
f" ... and {len(report['orphaned_references']) - 10} more"
|
|
)
|
|
print("=" * 60 + "\n")
|
|
```
|
|
|
|
- [ ] **Step 3: Write plugin test**
|
|
|
|
```python
|
|
# tests/test_traceability.py
|
|
"""Tests for the traceability MkDocs plugin."""
|
|
|
|
import json
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from traceability import TraceabilityPlugin, REQUIREMENT_ID_PATTERNS
|
|
|
|
|
|
def test_pattern_matches_sysrs():
|
|
pattern = REQUIREMENT_ID_PATTERNS["sysrs"]
|
|
assert pattern.findall("This traces to SysRS-233 and SysRS-234") == [
|
|
"SysRS-233",
|
|
"SysRS-234",
|
|
]
|
|
|
|
|
|
def test_pattern_matches_srs():
|
|
pattern = REQUIREMENT_ID_PATTERNS["srs"]
|
|
assert pattern.findall("Covers SRS-045 through SRS-053") == [
|
|
"SRS-045",
|
|
"SRS-053",
|
|
]
|
|
|
|
|
|
def test_pattern_matches_sdd_mod():
|
|
pattern = REQUIREMENT_ID_PATTERNS["sdd_mod"]
|
|
assert pattern.findall("Module SDD-MOD-009 handles this") == ["SDD-MOD-009"]
|
|
|
|
|
|
def test_no_false_positives():
|
|
pattern = REQUIREMENT_ID_PATTERNS["sysrs"]
|
|
assert pattern.findall("No requirements here") == []
|
|
assert pattern.findall("sysrs-123 lowercase should not match") == []
|
|
|
|
|
|
def test_plugin_stores_defined_ids():
|
|
config = {"strict": False, "coverage_file": False, "dashboard": False}
|
|
plugin = TraceabilityPlugin(config)
|
|
|
|
page = MagicMock()
|
|
page.meta = {"tags": ["SysRS-233", "swe.1", "baseline"]}
|
|
page.file.src_path = "requirements/sysrs.md"
|
|
|
|
plugin.on_page_markdown("content", page, {}, None)
|
|
assert "SysRS-233" in plugin.defined_ids
|
|
|
|
|
|
def test_plugin_stores_referenced_ids():
|
|
config = {"strict": False, "coverage_file": False, "dashboard": False}
|
|
plugin = TraceabilityPlugin(config)
|
|
|
|
page = MagicMock()
|
|
page.meta = {"tags": ["swe.4"]}
|
|
page.file.src_path = "verification/swe4-unit-verification-plan.md"
|
|
|
|
plugin.on_page_markdown(
|
|
"Verifies SDD-MOD-001, SDD-MOD-002, and SDD-MOD-003",
|
|
page,
|
|
{},
|
|
None,
|
|
)
|
|
assert "SDD-MOD-001" in plugin.referenced_ids
|
|
assert "SDD-MOD-002" in plugin.referenced_ids
|
|
assert "SDD-MOD-003" in plugin.referenced_ids
|
|
```
|
|
|
|
- [ ] **Step 4: Create directory structure and run tests**
|
|
|
|
```bash
|
|
mkdir -p tests
|
|
pip install -r requirements.txt
|
|
cd plugins/traceability && python -m pytest ../../tests/test_traceability.py -v
|
|
```
|
|
|
|
Expected: 5 tests pass (some may fail if mkdocs is not installed in test environment — adjust imports as needed).
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
git add plugins/ tests/
|
|
git commit -m "feat: add traceability plugin with requirement ID scanning and validation"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: Build Standalone CI Validator
|
|
|
|
**Files:**
|
|
- Create: `scripts/validate_traceability.py`
|
|
|
|
- [ ] **Step 1: Write the standalone validator**
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""Standalone ASPICE traceability validator for CI.
|
|
|
|
Usage:
|
|
python scripts/validate_traceability.py docs/
|
|
|
|
Exit codes:
|
|
0 - All chains valid
|
|
1 - Broken chains found
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
REQUIREMENT_ID_PATTERNS = {
|
|
"sysrs": re.compile(r"SysRS-\d+"),
|
|
"sysdes": re.compile(r"SysDes-\d+"),
|
|
"srs": re.compile(r"SRS-\d+"),
|
|
"sdd_mod": re.compile(r"SDD-MOD-\d+"),
|
|
"dec": re.compile(r"DEC-\d+"),
|
|
}
|
|
|
|
CHAINS = [
|
|
("sysrs", "sysdes"),
|
|
("sysdes", "srs"),
|
|
("srs", "sad"),
|
|
("srs", "sdd"),
|
|
("sad", "swe5"),
|
|
("sdd", "swe4"),
|
|
("srs", "swe6"),
|
|
("sysdes", "sys4"),
|
|
]
|
|
|
|
|
|
def extract_front_matter(content: str) -> dict:
|
|
"""Extract YAML front matter from markdown content."""
|
|
if content.startswith("---"):
|
|
end = content.find("---", 3)
|
|
if end != -1:
|
|
return {"raw": content[3:end]}
|
|
return {}
|
|
|
|
|
|
def scan_docs(docs_dir: Path) -> dict:
|
|
"""Scan all markdown files for requirement IDs."""
|
|
defined_ids: dict[str, set[str]] = defaultdict(set)
|
|
referenced_ids: dict[str, set[str]] = defaultdict(set)
|
|
|
|
for md_file in docs_dir.rglob("*.md"):
|
|
content = md_file.read_text(encoding="utf-8")
|
|
rel_path = str(md_file.relative_to(docs_dir))
|
|
|
|
# Extract tags from front matter
|
|
fm = extract_front_matter(content)
|
|
if "raw" in fm:
|
|
for line in fm["raw"].split("\n"):
|
|
if "tags:" in line:
|
|
for tag in re.findall(r"\b(?:SysRS|SysDes|SRS|SDD-MOD|DEC)-\d+", line):
|
|
defined_ids[tag].add(rel_path)
|
|
|
|
# Find all requirement ID references in content
|
|
for pattern_name, pattern in REQUIREMENT_ID_PATTERNS.items():
|
|
for match in pattern.findall(content):
|
|
referenced_ids[match].add(rel_path)
|
|
|
|
return {"defined": defined_ids, "referenced": referenced_ids}
|
|
|
|
|
|
def validate(data: dict) -> list[dict]:
|
|
"""Validate traceability chains."""
|
|
issues = []
|
|
|
|
# Check for orphaned references
|
|
for req_id, pages in data["referenced"].items():
|
|
if req_id not in data["defined"]:
|
|
issues.append({
|
|
"type": "orphaned_reference",
|
|
"id": req_id,
|
|
"referenced_in": sorted(pages),
|
|
})
|
|
|
|
return issues
|
|
|
|
|
|
def print_report(issues: list[dict], data: dict) -> None:
|
|
"""Print validation report."""
|
|
print("=" * 60)
|
|
print("ASPICE Traceability Validation")
|
|
print("=" * 60)
|
|
|
|
if not issues:
|
|
print(" [PASS] All requirement references have definitions")
|
|
else:
|
|
orphaned = [i for i in issues if i["type"] == "orphaned_reference"]
|
|
if orphaned:
|
|
print(f"\n [FAIL] {len(orphaned)} orphaned reference(s):")
|
|
for issue in orphaned[:20]:
|
|
print(f" - {issue['id']} referenced in {', '.join(issue['referenced_in'])}")
|
|
if len(orphaned) > 20:
|
|
print(f" ... and {len(orphaned) - 20} more")
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print(f"Usage: {sys.argv[0]} <docs-directory>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
docs_dir = Path(sys.argv[1])
|
|
if not docs_dir.is_dir():
|
|
print(f"Error: {docs_dir} is not a directory", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
data = scan_docs(docs_dir)
|
|
issues = validate(data)
|
|
print_report(issues, data)
|
|
|
|
sys.exit(1 if issues else 0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
```
|
|
|
|
- [ ] **Step 2: Make script executable**
|
|
|
|
```bash
|
|
chmod +x scripts/validate_traceability.py
|
|
```
|
|
|
|
- [ ] **Step 3: Create `docs/.meta.yml` and a test file to validate the script**
|
|
|
|
```bash
|
|
mkdir -p docs/test
|
|
echo -e '---\ntags: [swe.1, SysRS-999]\n---\n\nTest doc referencing SysRS-999.' > docs/test/validation-test.md
|
|
python scripts/validate_traceability.py docs/
|
|
```
|
|
|
|
Expected: Exit code 0 (SysRS-999 is defined and referenced in the same file, no orphans).
|
|
|
|
- [ ] **Step 4: Remove test file and commit**
|
|
|
|
```bash
|
|
rm -rf docs/test
|
|
git add scripts/
|
|
git commit -m "feat: add standalone traceability validator for CI"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 4: Set Up CI/CD Pipeline
|
|
|
|
**Files:**
|
|
- Create: `.github/workflows/deploy.yml`
|
|
- Create: `wrangler.toml`
|
|
|
|
- [ ] **Step 1: Create GitHub Actions workflow**
|
|
|
|
```yaml
|
|
name: Build and Deploy Docs
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
cache: pip
|
|
|
|
- run: pip install -r requirements.txt
|
|
|
|
- name: Validate traceability chains
|
|
run: python scripts/validate_traceability.py docs/
|
|
|
|
- name: Build doc site
|
|
run: mkdocs build --strict
|
|
|
|
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
uses: cloudflare/wrangler-action@v3
|
|
with:
|
|
command: pages deploy site --project-name=chanora-docs
|
|
env:
|
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
```
|
|
|
|
- [ ] **Step 2: Create Wrangler configuration**
|
|
|
|
```toml
|
|
name = "chanora-docs"
|
|
compatibility_date = "2026-06-13"
|
|
|
|
[site]
|
|
bucket = "./site"
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add .github/ wrangler.toml
|
|
git commit -m "ci: add GitHub Actions workflow for build, validate, and Cloudflare Pages deploy"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 5: Migrate ASPICE Docs to Docs Repo
|
|
|
|
**Files:**
|
|
- Copy all ASPICE docs from `chanora/docs/` to `chanora-docs/docs/`
|
|
- Add YAML front matter to each migrated file
|
|
|
|
Note: This task runs in the `chanora-docs` repo. The source files are in the main `chanora` repo at `chanora/docs/`.
|
|
|
|
- [ ] **Step 1: Copy requirements docs**
|
|
|
|
```bash
|
|
# From chanora-docs repo root:
|
|
# Copy canonical files (these ARE the docs, not path records)
|
|
cp ../chanora/docs/sysrs.md docs/requirements/sysrs.md
|
|
cp ../chanora/docs/sysdes.md docs/requirements/sysdes.md
|
|
cp ../chanora/docs/srs.md docs/requirements/srs.md
|
|
# Note: The path records (docs/requirements/sysrs.md, docs/requirements/srs.md,
|
|
# docs/architecture/sysdes.md in the original repo) are stubs pointing to canonical
|
|
# files. We don't need them in the docs repo since the canonical files are now here.
|
|
```
|
|
|
|
- [ ] **Step 2: Copy architecture docs**
|
|
|
|
```bash
|
|
cp ../chanora/docs/architecture/sad.md docs/architecture/sad.md
|
|
cp ../chanora/docs/architecture/sdd.md docs/architecture/sdd.md
|
|
cp ../chanora/docs/architecture/file-transfer-design.md docs/architecture/
|
|
cp ../chanora/docs/architecture/file-transfer-research.md docs/architecture/
|
|
cp ../chanora/docs/architecture/file-transfer-implementation-plan.md docs/architecture/
|
|
cp ../chanora/docs/architecture/desktop-ptt-architecture.md docs/architecture/
|
|
# Note: docs/architecture/sysdes.md in the original repo is a path record
|
|
# pointing to docs/sysdes.md. Not needed — the canonical sysdes.md is in
|
|
# docs/requirements/sysdes.md in the docs repo.
|
|
```
|
|
|
|
- [ ] **Step 3: Copy verification docs**
|
|
|
|
```bash
|
|
cp ../chanora/docs/verification/*.md docs/verification/
|
|
```
|
|
|
|
- [ ] **Step 4: Copy governance docs**
|
|
|
|
```bash
|
|
cp ../chanora/docs/governance/*.md docs/governance/
|
|
```
|
|
|
|
- [ ] **Step 5: Copy security, privacy, legal docs**
|
|
|
|
```bash
|
|
cp ../chanora/docs/security/*.md docs/security/
|
|
cp ../chanora/docs/privacy/*.md docs/privacy/
|
|
cp ../chanora/docs/legal/*.md docs/legal/
|
|
```
|
|
|
|
- [ ] **Step 6: Copy release docs (policy, go-nogo, waiver only — NOT ios-build.md)**
|
|
|
|
```bash
|
|
cp ../chanora/docs/release/platform-release-policy.md docs/release/
|
|
cp ../chanora/docs/release/release-readiness-go-nogo-record.md docs/release/
|
|
cp ../chanora/docs/release/dv-waiver-register.md docs/release/
|
|
```
|
|
|
|
- [ ] **Step 7: Copy references + flatten external refs**
|
|
|
|
```bash
|
|
cp ../chanora/docs/references/*.md docs/references/
|
|
cp ../chanora/docs/offline-knowledge/external/yatqa-en.md docs/references/
|
|
cp ../chanora/docs/offline-knowledge/external/yatqa-de.md docs/references/
|
|
cp ../chanora/docs/offline-knowledge/external/teaspeak-overview.md docs/references/
|
|
cp ../chanora/docs/offline-knowledge/external/respeak-overview.md docs/references/
|
|
```
|
|
|
|
- [ ] **Step 8: Copy UI/UX, i18n, material3-guideline**
|
|
|
|
```bash
|
|
cp ../chanora/docs/ui-ux/*.md docs/ui-ux/
|
|
cp ../chanora/docs/i18n/*.md docs/i18n/
|
|
# Note: docs/material3-guideline.md in the original repo is a path record
|
|
# pointing to docs/ui-ux/material3-guideline.md. Not needed — the canonical
|
|
# file is already copied above.
|
|
```
|
|
|
|
- [ ] **Step 9: Create section `.meta.yml` files**
|
|
|
|
```bash
|
|
echo -e 'tags:\n - requirements\nstatus: baseline' > docs/requirements/.meta.yml
|
|
echo -e 'tags:\n - architecture\n - design\nstatus: candidate' > docs/architecture/.meta.yml
|
|
echo -e 'tags:\n - verification\nstatus: candidate' > docs/verification/.meta.yml
|
|
echo -e 'tags:\n - governance\nstatus: baseline' > docs/governance/.meta.yml
|
|
echo -e 'tags:\n - security\nstatus: candidate' > docs/security/.meta.yml
|
|
echo -e 'tags:\n - privacy\nstatus: candidate' > docs/privacy/.meta.yml
|
|
echo -e 'tags:\n - legal\nstatus: candidate' > docs/legal/.meta.yml
|
|
echo -e 'tags:\n - release\nstatus: candidate' > docs/release/.meta.yml
|
|
echo -e 'tags:\n - references\nstatus: baseline' > docs/references/.meta.yml
|
|
echo -e 'tags:\n - ui-ux\nstatus: candidate' > docs/ui-ux/.meta.yml
|
|
echo -e 'tags:\n - localization\nstatus: candidate' > docs/i18n/.meta.yml
|
|
```
|
|
|
|
- [ ] **Step 10: Commit all migrated files**
|
|
|
|
```bash
|
|
git add docs/
|
|
git commit -m "docs: migrate all ASPICE docs from chanora repo with section meta files"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 6: Add Front Matter to Key ASPICE Documents
|
|
|
|
**Files:**
|
|
- Modify: `docs/requirements/sysrs.md`
|
|
- Modify: `docs/requirements/sysdes.md`
|
|
- Modify: `docs/requirements/srs.md`
|
|
- Modify: `docs/architecture/sad.md`
|
|
- Modify: `docs/architecture/sdd.md`
|
|
- Modify: `docs/verification/*.md`
|
|
- Modify: `docs/governance/traceability-matrix.md`
|
|
|
|
- [ ] **Step 1: Add front matter to `docs/requirements/sysrs.md`**
|
|
|
|
Insert at the very top of the file (before the existing `# Chanora SysRS` heading):
|
|
|
|
```yaml
|
|
---
|
|
tags: [sysrs, requirements, swe.1, baseline]
|
|
upstream: []
|
|
downstream: [sysdes, srs]
|
|
lifecycle: SysRS
|
|
status: baseline
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 2: Add front matter to `docs/requirements/sysdes.md`**
|
|
|
|
```yaml
|
|
---
|
|
tags: [sysdes, requirements, swe.1, baseline]
|
|
upstream: [sysrs]
|
|
downstream: [srs, sys4]
|
|
lifecycle: SysDes
|
|
status: baseline
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 3: Add front matter to `docs/requirements/srs.md`**
|
|
|
|
```yaml
|
|
---
|
|
tags: [srs, requirements, swe.1, baseline]
|
|
upstream: [sysdes, sysrs]
|
|
downstream: [sad, sdd, swe6]
|
|
lifecycle: SRS
|
|
status: baseline
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 4: Add front matter to `docs/architecture/sad.md`**
|
|
|
|
```yaml
|
|
---
|
|
tags: [sad, architecture, swe.2, candidate]
|
|
upstream: [srs]
|
|
downstream: [sdd, swe5]
|
|
lifecycle: SWE.2
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 5: Add front matter to `docs/architecture/sdd.md`**
|
|
|
|
```yaml
|
|
---
|
|
tags: [sdd, architecture, swe.3, candidate]
|
|
upstream: [sad, srs]
|
|
downstream: [swe4]
|
|
lifecycle: SWE.3
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 6: Add front matter to each verification plan**
|
|
|
|
`docs/verification/verification-master-plan.md`:
|
|
```yaml
|
|
---
|
|
tags: [verification, baseline]
|
|
upstream: [sysrs, sysdes, srs, sad, sdd]
|
|
downstream: []
|
|
lifecycle: SWE.4-SWE.6
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
`docs/verification/swe4-unit-verification-plan.md`:
|
|
```yaml
|
|
---
|
|
tags: [swe.4, verification, candidate]
|
|
upstream: [sdd]
|
|
downstream: []
|
|
lifecycle: SWE.3 → SWE.4
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
`docs/verification/swe5-software-integration-verification-plan.md`:
|
|
```yaml
|
|
---
|
|
tags: [swe.5, verification, candidate]
|
|
upstream: [sad]
|
|
downstream: []
|
|
lifecycle: SWE.2 → SWE.5
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
`docs/verification/swe6-software-verification-plan.md`:
|
|
```yaml
|
|
---
|
|
tags: [swe.6, verification, candidate]
|
|
upstream: [srs]
|
|
downstream: []
|
|
lifecycle: SRS → SWE.6
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
`docs/verification/sys4-system-integration-verification-plan.md`:
|
|
```yaml
|
|
---
|
|
tags: [sys.4, verification, candidate]
|
|
upstream: [sysdes, sysrs]
|
|
downstream: []
|
|
lifecycle: SysDes → SYS.4
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 7: Add front matter to `docs/governance/traceability-matrix.md`**
|
|
|
|
```yaml
|
|
---
|
|
tags: [governance, baseline]
|
|
upstream: [sysrs, sysdes, srs, sad, sdd]
|
|
downstream: []
|
|
lifecycle: traceability
|
|
status: candidate
|
|
---
|
|
```
|
|
|
|
- [ ] **Step 8: Commit**
|
|
|
|
```bash
|
|
git add docs/
|
|
git commit -m "docs: add ASPICE lifecycle front matter to key documents"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 7: Create Tags Index Page and Validate Build
|
|
|
|
**Files:**
|
|
- Create: `docs/tags.md`
|
|
|
|
- [ ] **Step 1: Create `docs/tags.md`**
|
|
|
|
```markdown
|
|
# Tag Index
|
|
|
|
Browse all documentation by tag. Click any tag to see all pages that carry it.
|
|
|
|
<!-- material/tags -->
|
|
```
|
|
|
|
- [ ] **Step 2: Install dependencies and build locally**
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
mkdocs build --strict
|
|
```
|
|
|
|
Expected: Build succeeds, `site/` directory contains rendered HTML, `site/traceability-coverage.json` exists.
|
|
|
|
- [ ] **Step 3: Run standalone validator**
|
|
|
|
```bash
|
|
python scripts/validate_traceability.py docs/
|
|
```
|
|
|
|
Expected: Exit code 0 if all referenced IDs have definitions. Any broken chains will be reported.
|
|
|
|
- [ ] **Step 4: Check the generated coverage file**
|
|
|
|
```bash
|
|
cat site/traceability-coverage.json
|
|
```
|
|
|
|
Expected: JSON with chain coverage percentages and orphan list (if any).
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
git add docs/tags.md
|
|
git commit -m "docs: add tags index page for traceability browsing"
|
|
```
|
|
|
|
- [ ] **Step 6: Push to GitHub**
|
|
|
|
```bash
|
|
git push origin main
|
|
```
|
|
|
|
---
|
|
|
|
### Task 8: Restructure Code Repo — Create dev-docs/
|
|
|
|
**Files:**
|
|
- Create: `dev-docs/superpowers/specs/` (directory)
|
|
- Create: `dev-docs/superpowers/plans/_archived/` (directory)
|
|
- Create: `dev-docs/offline-knowledge/reviews/` (directory)
|
|
- Create: `dev-docs/release/` (directory)
|
|
|
|
Note: This task runs in the main `chanora` code repo.
|
|
|
|
- [ ] **Step 1: Create dev-docs directory structure**
|
|
|
|
```bash
|
|
mkdir -p dev-docs/superpowers/plans/_archived
|
|
mkdir -p dev-docs/superpowers/specs
|
|
mkdir -p dev-docs/offline-knowledge/reviews
|
|
mkdir -p dev-docs/release
|
|
```
|
|
|
|
- [ ] **Step 2: Move superpowers specs**
|
|
|
|
```bash
|
|
mv docs/superpowers/specs/* dev-docs/superpowers/specs/
|
|
```
|
|
|
|
- [ ] **Step 3: Move active plans**
|
|
|
|
```bash
|
|
mv docs/superpowers/plans/2026-05-28-server-resolution-prefetch.md dev-docs/superpowers/plans/
|
|
mv docs/superpowers/plans/2026-05-28-chanora-server-prefetch-crate.md dev-docs/superpowers/plans/
|
|
mv docs/superpowers/plans/2026-06-06-chat-panel-switching.md dev-docs/superpowers/plans/
|
|
mv docs/superpowers/plans/2026-06-08-core-internal-split.md dev-docs/superpowers/plans/
|
|
mv docs/superpowers/plans/2026-06-08-maintainability-continuation.md dev-docs/superpowers/plans/
|
|
```
|
|
|
|
- [ ] **Step 4: Move completed plans to archive**
|
|
|
|
```bash
|
|
mv docs/superpowers/plans/2026-05-29-finish-dv-document-tree.md dev-docs/superpowers/plans/_archived/
|
|
mv docs/superpowers/plans/2026-05-29-dv-evidence-pack.md dev-docs/superpowers/plans/_archived/
|
|
mv docs/superpowers/plans/2026-05-29-swe2-swe3-baselines.md dev-docs/superpowers/plans/_archived/
|
|
mv docs/superpowers/plans/2026-05-29-state-sync-ui-settings-validation.md dev-docs/superpowers/plans/_archived/
|
|
```
|
|
|
|
- [ ] **Step 5: Move offline-knowledge (minus external/)**
|
|
|
|
```bash
|
|
mv docs/offline-knowledge/coverage-analysis.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/doc-quality-analysis.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/link-coverage-report.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/docs-code-mismatch.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/docs-link-not-covered.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/docs-out-of-date.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/function-inventory.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/README.md dev-docs/offline-knowledge/
|
|
mv docs/offline-knowledge/reviews/* dev-docs/offline-knowledge/reviews/
|
|
```
|
|
|
|
- [ ] **Step 6: Move implementation status and ios-build**
|
|
|
|
```bash
|
|
mv docs/implementation-status-2026-05-28.md dev-docs/
|
|
mv docs/release/ios-build.md dev-docs/release/
|
|
```
|
|
|
|
- [ ] **Step 7: Remove now-empty directories**
|
|
|
|
```bash
|
|
rm -rf docs/superpowers
|
|
rm -rf docs/offline-knowledge
|
|
rm -f docs/implementation-status-2026-05-28.md
|
|
```
|
|
|
|
- [ ] **Step 8: Commit**
|
|
|
|
```bash
|
|
git add -A
|
|
git commit -m "refactor: move development docs to dev-docs/ directory"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 9: Add Git Submodule and Remove Original Docs
|
|
|
|
**Files:**
|
|
- Modify: `.gitmodules` (created by git submodule add)
|
|
- Remove: `docs/` directory contents (replaced by submodule)
|
|
|
|
Note: This task runs in the main `chanora` code repo.
|
|
|
|
- [ ] **Step 1: Remove original docs/ contents (keeping the directory)**
|
|
|
|
```bash
|
|
# Back up any remaining files first
|
|
ls docs/
|
|
# Remove everything except what was already moved
|
|
rm -rf docs/architecture docs/governance docs/i18n docs/implementation-status-2026-05-28.md docs/legal docs/material3-guideline.md docs/offline-knowledge docs/privacy docs/references docs/release docs/requirements docs/security docs/srs.md docs/superpowers docs/sysdes.md docs/sysrs.md docs/ui-ux docs/verification
|
|
```
|
|
|
|
- [ ] **Step 2: Verify docs/ is empty**
|
|
|
|
```bash
|
|
ls -la docs/
|
|
```
|
|
|
|
Expected: Empty directory (or only hidden files like `.gitkeep`).
|
|
|
|
- [ ] **Step 3: Add chanora-docs as submodule**
|
|
|
|
```bash
|
|
git submodule add git@github.com:EdisonJwa/chanora-docs.git docs
|
|
```
|
|
|
|
Expected: Creates `.gitmodules` file and `docs/` directory with submodule content.
|
|
|
|
- [ ] **Step 4: Verify submodule is working**
|
|
|
|
```bash
|
|
ls docs/
|
|
```
|
|
|
|
Expected: Contents of the chanora-docs repo (mkdocs.yml, docs/, plugins/, etc.).
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
git add .gitmodules docs
|
|
git commit -m "chore: add chanora-docs as git submodule at docs/"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 10: Write AGENTS.md and Update Cross-References
|
|
|
|
**Files:**
|
|
- Create: `AGENTS.md`
|
|
- Modify: `README.md` (update doc path references)
|
|
- Create: `dev-docs/impl-mapping.md`
|
|
|
|
Note: This task runs in the main `chanora` code repo.
|
|
|
|
- [ ] **Step 1: Write `AGENTS.md`**
|
|
|
|
```markdown
|
|
# AGENTS.md — Chanora Project Conventions
|
|
|
|
## Project Overview
|
|
|
|
Chanora is a cross-platform voice client (Flutter + Rust) targeting TeamSpeak-compatible servers. The project follows ASPICE engineering processes with full traceability from system requirements through verification.
|
|
|
|
## Repository Structure
|
|
|
|
```
|
|
chanora/ ← Code repo (this one)
|
|
├── docs/ → chanora-docs ← Git submodule: ASPICE docs, doc site source
|
|
├── dev-docs/ ← Local-only development docs
|
|
│ ├── superpowers/ ← AI agent specs and plans
|
|
│ │ ├── specs/ ← Feature/design specs (active)
|
|
│ │ └── plans/ ← Implementation plans (active)
|
|
│ │ └── _archived/ ← Completed plans
|
|
│ ├── offline-knowledge/ ← Doc maintenance tools, link coverage
|
|
│ ├── implementation-status-* ← Code state snapshots
|
|
│ └── release/ios-build.md ← Operational build instructions
|
|
├── apps/chanora_flutter/ ← Flutter application
|
|
├── core/chanora_core/ ← Rust core API + orchestration
|
|
├── crates/ ← Rust crates (protocol, audio, state, etc.)
|
|
└── dev-docs/impl-mapping.md ← SAD component → source file mapping
|
|
```
|
|
|
|
## Documentation Two-Repo Model
|
|
|
|
**`docs/` is a git submodule** pointing to the separate `chanora-docs` repository. It is NOT a local directory you can freely create files in.
|
|
|
|
### What lives where
|
|
|
|
| Content | Location | Reason |
|
|
|---|---|---|
|
|
| SysRS, SysDes, SRS, SAD, SDD | `docs/` (submodule) | ASPICE baselines, served on doc site |
|
|
| Verification plans (SWE.4/5/6, SYS.4) | `docs/` (submodule) | ASPICE verification evidence |
|
|
| Governance, traceability, decision register | `docs/` (submodule) | ASPICE governance |
|
|
| Security, privacy, legal | `docs/` (submodule) | Stakeholder-facing |
|
|
| UI/UX guidelines, i18n architecture | `docs/` (submodule) | Design references |
|
|
| Feature specs and implementation plans | `dev-docs/superpowers/` | Code-coupled, agent working files |
|
|
| Link coverage, doc quality analysis | `dev-docs/offline-knowledge/` | Maintenance tools |
|
|
| Implementation status snapshots | `dev-docs/` | Code state tracking |
|
|
| Source file path references | `dev-docs/impl-mapping.md` | Developer convenience, not ASPICE |
|
|
|
|
### Rules for agents
|
|
|
|
1. **Never create or edit files in `docs/`** without understanding it's a submodule. Changes there require committing in the `chanora-docs` repo first, then updating the submodule pointer in this repo.
|
|
|
|
2. **ASPICE documents do not contain code file paths.** ASPICE traces requirement IDs (e.g., `SysRS-233`, `SRS-045`, `SDD-MOD-009`), not source file paths. If you need to map a component to its source, use or update `dev-docs/impl-mapping.md`.
|
|
|
|
3. **Specs and plans go in `dev-docs/superpowers/`.** Follow the naming convention: `YYYY-MM-DD-<topic>-design.md` for specs, `YYYY-MM-DD-<topic>.md` for plans.
|
|
|
|
4. **Completed plans move to `_archived/`.** Once a plan is fully implemented and verified, move it to `dev-docs/superpowers/plans/_archived/`.
|
|
|
|
## ASPICE Traceability Chain
|
|
|
|
```text
|
|
SysRS → SysDes → SRS → SAD (SWE.2) → SDD (SWE.3) → Verification
|
|
↓ ↓
|
|
SWE.4 (unit) SWE.4/5/6/SYS.4
|
|
```
|
|
|
|
- Requirement IDs are the traceability mechanism, not file paths.
|
|
- Every downstream document must reference upstream IDs it traces from.
|
|
- Verification plans map to their upstream design/requirements level:
|
|
- SYS.4 ← SysDes, SysRS
|
|
- SWE.5 ← SAD (SWE.2)
|
|
- SWE.4 ← SDD (SWE.3)
|
|
- SWE.6 ← SRS
|
|
|
|
## Code Architecture
|
|
|
|
| Component | Location | Responsibility |
|
|
|---|---|---|
|
|
| Flutter app shell | `apps/chanora_flutter/` | UI, Material 3, navigation, localization |
|
|
| Rust core | `core/chanora_core/` | Session orchestration, bridge events |
|
|
| Protocol adapter | `crates/chanora_protocol/` | TeamSpeak protocol via tsclientlib |
|
|
| State sync | `crates/chanora_state/` | Snapshots, deltas, reducers |
|
|
| Audio subsystem | `crates/chanora_audio/` | Capture, DSP, Opus, PTT |
|
|
| Storage | `crates/chanora_storage/` | Bookmarks, identity, encryption |
|
|
| Diagnostics | `crates/chanora_diagnostics/` | Redaction, logs, export |
|
|
| Resolver | `crates/chanora_resolver/` | SRV/TSDNS/DNS resolution |
|
|
| Prefetch | `crates/chanora_prefetch/` | Resolution warming, TTL cache |
|
|
| Bridge | `crates/chanora_bridge/` | Flutter/Rust typed DTO boundary |
|
|
| Cache | `crates/chanora_cache/` | Avatar/icon blob cache |
|
|
|
|
## Coding Conventions
|
|
|
|
- **Rust:** Follow workspace `Cargo.toml` structure. Run `cargo check`, `cargo clippy`, `cargo test` before committing.
|
|
- **Flutter:** Run `flutter analyze`, `flutter test` before committing.
|
|
- **No code comments** unless explicitly requested.
|
|
- **Git commits:** Follow convention in `docs/governance/git-commit-message-convention.md` (accessible via submodule).
|
|
- **Bridge boundary:** Flutter must not directly depend on protocol-library internals. All cross-boundary communication goes through `chanora_bridge` typed DTOs.
|
|
|
|
## Verification Commands
|
|
|
|
```bash
|
|
cargo check && cargo clippy && cargo test
|
|
cd apps/chanora_flutter && flutter analyze && flutter test
|
|
```
|
|
|
|
## Important References
|
|
|
|
- Traceability matrix: `docs/governance/traceability-matrix.md`
|
|
- Decision register: `docs/governance/product-decision-register.md`
|
|
- Security guidelines: `docs/security/security-privacy-legal-guideline.md`
|
|
- Release readiness: `docs/release/release-readiness-go-nogo-record.md`
|
|
```
|
|
|
|
- [ ] **Step 2: Create `dev-docs/impl-mapping.md`**
|
|
|
|
```markdown
|
|
# SAD Component → Source File Mapping
|
|
|
|
**Purpose:** Developer convenience mapping from ASPICE architecture components to source file locations. This is NOT an ASPICE document — it's a lookup for developers.
|
|
|
|
## Component Mapping
|
|
|
|
| SAD Component | Source Location |
|
|
|---|---|
|
|
| Flutter app shell | `apps/chanora_flutter/lib/main.dart`, services, widgets |
|
|
| Flutter service layer | `apps/chanora_flutter/lib/services/` |
|
|
| Flutter widget layer | `apps/chanora_flutter/lib/widgets/` |
|
|
| Bridge layer | `crates/chanora_bridge/src/api.rs`, `apps/chanora_flutter/lib/src/rust/` |
|
|
| Rust core | `core/chanora_core/src/lib.rs`, `events.rs`, `network_diagnostics.rs`, `ptt.rs` |
|
|
| Protocol adapter | `crates/chanora_protocol/src/` |
|
|
| State sync | `crates/chanora_state/src/lib.rs`, `channel_join.rs` |
|
|
| Audio subsystem | `crates/chanora_audio/src/` |
|
|
| Storage | `crates/chanora_storage/src/lib.rs` |
|
|
| Diagnostics | `crates/chanora_diagnostics/src/lib.rs` |
|
|
| Resolution and prefetch | `crates/chanora_resolver/src/lib.rs`, `crates/chanora_prefetch/src/lib.rs`, `prefetch_debouncer.dart` |
|
|
| Build and release hooks | `.github/workflows/`, `tools/`, platform project files |
|
|
|
|
## SDD Module Mapping
|
|
|
|
| SDD Module | Source Location |
|
|
|---|---|
|
|
| SDD-MOD-001 Flutter app bootstrap | `apps/chanora_flutter/lib/services/app_bootstrap.dart`, `main.dart` |
|
|
| SDD-MOD-002 Connect UI | `apps/chanora_flutter/lib/widgets/connect_widgets.dart` |
|
|
| SDD-MOD-003 Snapshot and channel UI | `snapshot_view.dart`, `snapshot_state_mapper.dart`, `channel_spacer.dart` |
|
|
| SDD-MOD-004 Chat UI | `chat_views.dart`, `bbcode_text.dart` |
|
|
| SDD-MOD-005 Voice UI | `voice_bar.dart`, `voice_compact.dart`, `voice_settings*.dart`, `voice_level_meter.dart`, `ptt_capability_badge.dart` |
|
|
| SDD-MOD-006 Platform services | `android_permissions_service.dart`, `ios_permissions_service.dart`, `audio_lifecycle_service.dart`, `back_intent_*`, `link_trust_service.dart` |
|
|
| SDD-MOD-007 Bridge API | `crates/chanora_bridge/src/api.rs`, generated Dart/Rust bridge files |
|
|
| SDD-MOD-008 Rust core supervisor | `core/chanora_core/src/lib.rs`, `events.rs`, `network_diagnostics.rs`, `ptt.rs` |
|
|
| SDD-MOD-009 Protocol adapter | `crates/chanora_protocol/src/` |
|
|
| SDD-MOD-010 State sync | `crates/chanora_state/src/lib.rs`, `channel_join.rs` |
|
|
| SDD-MOD-011 Audio subsystem | `crates/chanora_audio/src/` |
|
|
| SDD-MOD-012 Storage | `crates/chanora_storage/src/lib.rs` |
|
|
| SDD-MOD-013 Diagnostics | `crates/chanora_diagnostics/src/lib.rs` |
|
|
| SDD-MOD-014 Resolution and prefetch | `crates/chanora_resolver/src/lib.rs`, `crates/chanora_prefetch/src/lib.rs`, `prefetch_debouncer.dart` |
|
|
| SDD-MOD-015 Build and release hooks | `.github/workflows/`, `tools/`, platform project files |
|
|
```
|
|
|
|
- [ ] **Step 3: Update README.md doc path references**
|
|
|
|
Replace any remaining references to old `docs/` paths (like `docs/superpowers/`) with `dev-docs/superpowers/`. Use grep to find all references:
|
|
|
|
```bash
|
|
grep -n "docs/superpowers\|docs/implementation-status\|docs/offline-knowledge" README.md
|
|
```
|
|
|
|
Update any found references to point to `dev-docs/`.
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add AGENTS.md dev-docs/impl-mapping.md README.md
|
|
git commit -m "docs: add AGENTS.md and impl-mapping.md, update README references"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 11: Update .gitignore and Verify Final State
|
|
|
|
**Files:**
|
|
- Modify: `.gitignore`
|
|
|
|
- [ ] **Step 1: Verify submodule status**
|
|
|
|
```bash
|
|
git submodule status
|
|
```
|
|
|
|
Expected: Shows chanora-docs commit hash.
|
|
|
|
- [ ] **Step 2: Verify docs/ contains submodule content**
|
|
|
|
```bash
|
|
ls docs/mkdocs.yml
|
|
```
|
|
|
|
Expected: File exists.
|
|
|
|
- [ ] **Step 3: Verify dev-docs/ structure**
|
|
|
|
```bash
|
|
find dev-docs -type f -name '*.md' | sort
|
|
```
|
|
|
|
Expected: All local-only docs present.
|
|
|
|
- [ ] **Step 4: Verify no stale docs/ files remain outside submodule**
|
|
|
|
```bash
|
|
git status
|
|
```
|
|
|
|
Expected: No untracked files in `docs/` outside the submodule pointer.
|
|
|
|
- [ ] **Step 5: Final commit if needed**
|
|
|
|
```bash
|
|
git add -A
|
|
git commit -m "chore: finalize documentation repo restructure"
|
|
```
|