1489 lines
45 KiB
Markdown
1489 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 Docusaurus doc site with tag-based ASPICE traceability, hosted on Cloudflare Pages with access control, served from a git submodule.
|
|
|
|
**Architecture:** The docs repo (`chanoraapp/docs`) is a standalone Docusaurus project added as a git submodule at `docs/` in the code repo. A custom Docusaurus plugin validates requirement ID traceability chains on every build. The code repo retains development-only docs in `dev-docs/`.
|
|
|
|
**Tech Stack:** Docusaurus 3.10 (Meta-maintained), Node.js 20, custom traceability plugin (~100 lines JavaScript), standalone CI validator (Node.js), GitHub Actions, Cloudflare Pages + Access, git submodules
|
|
|
|
**Spec:** `dev-docs/superpowers/specs/2026-06-13-documentation-site-design.md`
|
|
|
|
> **Note:** This plan was originally written for MkDocs Material. During implementation, MkDocs was replaced with Docusaurus due to MkDocs ecosystem instability (1.x unmaintained, 2.0 breaking). The task descriptions below reference MkDocs but the actual implementation uses Docusaurus 3.10. See the spec for the Docusaurus configuration details.
|
|
|
|
---
|
|
|
|
### 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"
|
|
```
|