219 lines
6.2 KiB
Python
219 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Doorstop configuration for UniversalisOS requirements management.
|
|
|
|
Defines document types, custom attributes, and YAML schema for the
|
|
traceability pipeline linking requirements → code → tests.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
@dataclass
|
|
class DoorstopAttribute:
|
|
"""A custom attribute definition for a Doorstop document type."""
|
|
name: str
|
|
type: str # "string", "integer", "list"
|
|
required: bool = False
|
|
default: str = ""
|
|
|
|
|
|
@dataclass
|
|
class DocumentType:
|
|
"""Configuration for a Doorstop document type."""
|
|
prefix: str
|
|
template: str = ""
|
|
attribute_defaults: dict = field(default_factory=dict)
|
|
|
|
|
|
# ─── Document type definitions ──────────────────────────────────────────────
|
|
|
|
DOCUMENT_TYPES = {
|
|
"req": DocumentType(
|
|
prefix="REQ",
|
|
template="requirement",
|
|
attribute_defaults={
|
|
"dal_level": "B",
|
|
"priority": "high",
|
|
"category": "functional",
|
|
},
|
|
),
|
|
"spec": DocumentType(
|
|
prefix="SPEC",
|
|
template="specification",
|
|
attribute_defaults={
|
|
"dal_level": "B",
|
|
"revision": "1.0",
|
|
},
|
|
),
|
|
"test": DocumentType(
|
|
prefix="TC",
|
|
template="test_case",
|
|
attribute_defaults={
|
|
"method": "unit",
|
|
"result": "pending",
|
|
},
|
|
),
|
|
}
|
|
|
|
|
|
# ─── Custom attributes ─────────────────────────────────────────────────────
|
|
|
|
CUSTOM_ATTRIBUTES = {
|
|
# Traceability links (lists of identifiers)
|
|
"linked_files": DoorstopAttribute(
|
|
name="linked_files",
|
|
type="list",
|
|
required=False,
|
|
),
|
|
"linked_functions": DoorstopAttribute(
|
|
name="linked_functions",
|
|
type="list",
|
|
required=False,
|
|
),
|
|
"linked_tests": DoorstopAttribute(
|
|
name="linked_tests",
|
|
type="list",
|
|
required=False,
|
|
),
|
|
# DO-178C / certification attributes
|
|
"dal_level": DoorstopAttribute(
|
|
name="dal_level",
|
|
type="string",
|
|
required=True,
|
|
default="B",
|
|
),
|
|
"priority": DoorstopAttribute(
|
|
name="priority",
|
|
type="string",
|
|
required=True,
|
|
default="high",
|
|
),
|
|
"category": DoorstopAttribute(
|
|
name="category",
|
|
type="string",
|
|
required=True,
|
|
default="functional",
|
|
),
|
|
"revision": DoorstopAttribute(
|
|
name="revision",
|
|
type="string",
|
|
required=False,
|
|
default="1.0",
|
|
),
|
|
"method": DoorstopAttribute(
|
|
name="method",
|
|
type="string",
|
|
required=False,
|
|
default="unit",
|
|
),
|
|
"result": DoorstopAttribute(
|
|
name="result",
|
|
type="string",
|
|
required=False,
|
|
default="pending",
|
|
),
|
|
}
|
|
|
|
|
|
# ─── YAML schema for requirements ──────────────────────────────────────────
|
|
|
|
YAML_SCHEMA = {
|
|
"type": "object",
|
|
"properties": {
|
|
"uid": {
|
|
"type": "string",
|
|
"description": "Unique requirement identifier (e.g. REQ-001)",
|
|
},
|
|
"level": {
|
|
"type": "integer",
|
|
"description": "Hierarchy level (0 = top-level)",
|
|
},
|
|
"active": {
|
|
"type": "boolean",
|
|
"description": "Whether this requirement is active",
|
|
},
|
|
"derived": {
|
|
"type": "boolean",
|
|
"description": "Whether this is derived from a parent",
|
|
},
|
|
"normative": {
|
|
"type": "boolean",
|
|
"description": "Whether this is normative (must be satisfied)",
|
|
},
|
|
"text": {
|
|
"type": "string",
|
|
"description": "Requirement description text",
|
|
},
|
|
"parent": {
|
|
"type": "string",
|
|
"description": "Parent requirement UID",
|
|
},
|
|
"ref": {
|
|
"type": "string",
|
|
"description": "External reference (e.g. DO-178C section)",
|
|
},
|
|
"attrs": {
|
|
"type": "object",
|
|
"properties": {
|
|
"dal_level": {"type": "string"},
|
|
"priority": {"type": "string"},
|
|
"category": {"type": "string"},
|
|
"linked_files": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
},
|
|
"linked_functions": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
},
|
|
"linked_tests": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"required": ["uid", "text"],
|
|
}
|
|
|
|
|
|
def get_document_type(prefix: str) -> DocumentType | None:
|
|
"""Look up a document type by its prefix."""
|
|
for doc_type in DOCUMENT_TYPES.values():
|
|
if doc_type.prefix == prefix:
|
|
return doc_type
|
|
return None
|
|
|
|
|
|
def validate_requirement(data: dict) -> list[str]:
|
|
"""Validate a requirement dict against the schema. Returns list of errors."""
|
|
errors = []
|
|
|
|
if "uid" not in data:
|
|
errors.append("Missing required field: uid")
|
|
if "text" not in data:
|
|
errors.append("Missing required field: text")
|
|
|
|
attrs = data.get("attrs", {})
|
|
for attr_name, attr_def in CUSTOM_ATTRIBUTES.items():
|
|
if attr_def.required and attr_name not in attrs:
|
|
if attr_def.default:
|
|
continue # has default, OK
|
|
errors.append(f"Missing required attribute: {attr_name}")
|
|
|
|
return errors
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import json
|
|
print("UniversalisOS Doorstop Configuration")
|
|
print("Document types:")
|
|
for name, dt in DOCUMENT_TYPES.items():
|
|
print(f" {name}: prefix={dt.prefix}, defaults={dt.attribute_defaults}")
|
|
print("Custom attributes:")
|
|
for name, attr in CUSTOM_ATTRIBUTES.items():
|
|
print(f" {name}: type={attr.type}, required={attr.required}")
|
|
print(f"\nYAML schema: {json.dumps(YAML_SCHEMA, indent=2)}")
|