Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions .rivet/agent-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Rivet Agent Context

Auto-generated by `rivet context` — do not edit.

## Project

- **Name:** kiln
- **Version:** 0.1.0
- **Schemas:** common, stpa, dev
- **Sources:** safety/stpa (stpa-yaml), safety/requirements (generic-yaml)
- **Docs:** docs

## Artifacts

| Type | Count | Example IDs |
|------|-------|-------------|
| control-action | 32 | CA-HOST-1, CA-HOST-2, CA-HOST-3 |
| controlled-process | 12 | PROC-INSTRUCTION, PROC-MEMORY, PROC-STACK |
| controller | 9 | CTRL-HOST, CTRL-ENGINE, CTRL-DECODER |
| controller-constraint | 29 | CC-E-1, CC-E-2, CC-E-3 |
| design-decision | 18 | SM-MEM-001, SM-MEM-002, SM-CFI-001 |
| feature | 16 | AC-RUNTIME, AC-MEMORY, AC-COMPONENT |
| hazard | 10 | H-1, H-2, H-3 |
| loss | 8 | L-1, L-2, L-3 |
| loss-scenario | 21 | LS-E-1, LS-E-2, LS-E-3 |
| requirement | 62 | SR-1, SR-2, SR-3 |
| sub-hazard | 5 | H-4.1, H-4.2, H-4.3 |
| system-constraint | 11 | SC-1, SC-2, SC-3 |
| uca | 29 | UCA-A-1, UCA-A-2, UCA-BZ-1 |
| **Total** | **262** | |

## Schema

- **`control-action`** — An action issued by a controller to a controlled process or another controller.

Required fields: action
- **`controlled-process`** — A process being controlled — the physical or data transformation acted upon by controllers.

Required fields: (none)
- **`controller`** — A system component (human or automated) responsible for issuing control actions. Each controller has a process model — its internal beliefs about the state of the controlled process.

Required fields: (none)
- **`controller-constraint`** — A constraint on a controller's behavior derived by inverting a UCA. Specifies what the controller must or must not do.

Required fields: constraint
- **`design-decision`** — An architectural or design decision with rationale
Required fields: rationale
- **`feature`** — A user-visible capability or feature
Required fields: (none)
- **`hazard`** — A system state or set of conditions that, together with worst-case environmental conditions, will lead to a loss.

Required fields: (none)
- **`loss`** — An undesired or unplanned event involving something of value to stakeholders. Losses define what the analysis aims to prevent.

Required fields: (none)
- **`loss-scenario`** — A causal pathway describing how a UCA could occur or how the control action could be improperly executed, leading to a hazard.

Required fields: (none)
- **`requirement`** — A functional or non-functional requirement
Required fields: (none)
- **`sub-hazard`** — A refinement of a hazard into a more specific unsafe condition.

Required fields: (none)
- **`system-constraint`** — A condition or behavior that must be satisfied to prevent a hazard. Each constraint is the inversion of a hazard.

Required fields: (none)
- **`uca`** — An Unsafe Control Action — a control action that, in a particular context and worst-case environment, leads to a hazard. Four types (provably complete):
1. Not providing the control action leads to a hazard
2. Providing the control action leads to a hazard
3. Providing too early, too late, or in the wrong order
4. Control action stopped too soon or applied too long

Required fields: uca-type

### Link Types

- `acts-on` (inverse: `acted-on-by`)
- `allocated-to` (inverse: `allocated-from`)
- `caused-by-uca` (inverse: `causes-scenario`)
- `constrained-by` (inverse: `constrains`)
- `constrains-controller` (inverse: `controller-constrained-by`)
- `depends-on` (inverse: `depended-on-by`)
- `derives-from` (inverse: `derived-into`)
- `implements` (inverse: `implemented-by`)
- `inverts-uca` (inverse: `inverted-by`)
- `issued-by` (inverse: `issues`)
- `leads-to-hazard` (inverse: `hazard-caused-by`)
- `leads-to-loss` (inverse: `loss-caused-by`)
- `mitigates` (inverse: `mitigated-by`)
- `prevents` (inverse: `prevented-by`)
- `refines` (inverse: `refined-by`)
- `satisfies` (inverse: `satisfied-by`)
- `traces-to` (inverse: `traced-from`)
- `verifies` (inverse: `verified-by`)

## Traceability Rules

| Rule | Source Type | Severity | Description |
|------|------------|----------|-------------|
| hazard-has-loss | hazard | error | Every hazard must link to at least one loss |
| constraint-has-hazard | system-constraint | error | Every system constraint must link to at least one hazard |
| uca-has-hazard | uca | error | Every UCA must link to at least one hazard |
| uca-has-controller | uca | error | Every UCA must link to a controller |
| controller-constraint-has-uca | controller-constraint | error | Every controller constraint must link to at least one UCA |
| hazard-has-constraint | hazard | warning | Every hazard should be addressed by at least one system constraint |
| uca-has-controller-constraint | uca | warning | Every UCA should be addressed by at least one controller constraint |
| requirement-coverage | requirement | warning | Every requirement should be satisfied by at least one design decision or feature |
| decision-justification | design-decision | error | Every design decision must link to at least one requirement |

## Coverage

**Overall: 93.0%**

| Rule | Source Type | Covered | Total | % |
|------|------------|---------|-------|---|
| hazard-has-loss | hazard | 10 | 10 | 100.0% |
| constraint-has-hazard | system-constraint | 11 | 11 | 100.0% |
| uca-has-hazard | uca | 29 | 29 | 100.0% |
| uca-has-controller | uca | 29 | 29 | 100.0% |
| controller-constraint-has-uca | controller-constraint | 29 | 29 | 100.0% |
| hazard-has-constraint | hazard | 10 | 10 | 100.0% |
| uca-has-controller-constraint | uca | 29 | 29 | 100.0% |
| requirement-coverage | requirement | 46 | 62 | 74.2% |
| decision-justification | design-decision | 18 | 18 | 100.0% |

## Validation

0 errors, 16 warnings

## Commands

```bash
rivet validate # validate all artifacts
rivet list # list all artifacts
rivet list -t <type> # filter by type
rivet stats # artifact counts + orphans
rivet coverage # traceability coverage report
rivet matrix --from X --to Y # traceability matrix
rivet diff --base A --head B # compare artifact sets
rivet schema list # list schema types
rivet schema show <type> # show type details
rivet schema rules # list traceability rules
rivet export -f generic-yaml # export as YAML
rivet serve # start dashboard on :3000
rivet context # regenerate this file
```
1 change: 0 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
sphinx>=7.1.2
sphinx-needs>=1.2.1
sphinx-book-theme>=0.0.1
myst-parser>=2.0.0
sphinxcontrib-plantuml>=0.25.0
Expand Down
147 changes: 2 additions & 145 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,12 @@ def patched_process_doc(self, env, docname, document):
# Add our custom JavaScript for code copy
app.add_js_file('js/code-copy.js')

# Register the dynamic function for extracting requirements
from sphinx_needs.api.configuration import add_dynamic_function
add_dynamic_function(app, extract_reqs)

return {'version': '0.1', 'parallel_read_safe': True}

extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
'sphinx_needs',
'myst_parser',
'sphinxcontrib.plantuml',
"sphinxcontrib_rust",
Expand Down Expand Up @@ -188,103 +183,9 @@ def patched_process_doc(self, env, docname, document):
# Allow customization through environment variables
plantuml_output_format = os.environ.get('PLANTUML_FORMAT', 'svg')

# Sphinx-needs configuration
needs_types = [
dict(directive="req", title="Requirement", prefix="REQ_", color="#BFD8D2", style="node"),
dict(directive="spec", title="Specification", prefix="SPEC_", color="#FEDCD2", style="node"),
dict(directive="impl", title="Implementation", prefix="IMPL_", color="#DF744A", style="node"),
dict(directive="test", title="Test Case", prefix="T_", color="#DCB239", style="node"),
dict(directive="safety", title="Safety", prefix="SAFETY_", color="#FF5D73", style="node"),
dict(directive="qual", title="Qualification", prefix="QUAL_", color="#9370DB", style="node"),
dict(directive="constraint", title="Constraint", prefix="CNST_", color="#4682B4", style="node"),
dict(directive="panic", title="Panic", prefix="KILNQ_", color="#E74C3C", style="node"),
dict(directive="src", title="Source file", prefix="SRC_", color="#C6C6FF", style="node"),
# Architecture-specific types
dict(directive="arch_component", title="Architectural Component", prefix="ARCH_COMP_", color="#FF6B6B", style="node"),
dict(directive="arch_interface", title="Interface", prefix="ARCH_IF_", color="#4ECDC4", style="node"),
dict(directive="arch_decision", title="Design Decision", prefix="ARCH_DEC_", color="#45B7D1", style="node"),
dict(directive="arch_constraint", title="Design Constraint", prefix="ARCH_CON_", color="#96CEB4", style="node"),
dict(directive="arch_pattern", title="Design Pattern", prefix="ARCH_PAT_", color="#FECA57", style="node"),
]

# Add ID regex pattern for sphinx-needs
needs_id_regex = '^[A-Z0-9_]{5,}$'

# Add option specs to register additional options for directives
needs_extra_options = [
'rationale',
'verification',
'mitigation',
'implementation',
'safety_impact',
'item_status',
'handling_strategy',
'last_updated',
'file',
'implements',
# Architecture-specific options
'crate',
'provides',
'requires',
'allocated_requirements',
'environment',
'variant_of',
'impacts',
'deciders',
'alternatives',
'stability',
'protocol',
]

# Allow all sphinx-needs options for all directives
needs_allow_unsafe_options = True

# Disable warnings for unknown link targets to avoid the many outgoing link warnings
needs_warnings_always_warn = False

# Custom sphinx-needs templates for qualification and safety
needs_templates = {
'safety_template': '**Hazard**: {{content}}\n\n**Mitigation**: {{mitigation}}',
'qualification_template': '**Status**: {{item_status}}\n\n**Implementation**: {{implementation}}',
'constraint_template': '**Constraint**: {{content}}\n\n**Rationale**: {{rationale}}\n\n**Verification**: {{verification}}',
'panic_template': '**Panic Condition**: {{content}}\n\n**Safety Impact**: {{safety_impact}}\n\n**Status**: {{item_status}}\n\n**Handling Strategy**: {{handling_strategy}}',
}

# Tags for filtering and displaying panic entries
needs_tags = [
dict(name="panic", description="Panic documentation entry", bgcolor="#E74C3C"),
dict(name="low", description="Low safety impact", bgcolor="#2ECC71"),
dict(name="medium", description="Medium safety impact", bgcolor="#F39C12"),
dict(name="high", description="High safety impact", bgcolor="#E74C3C"),
dict(name="unknown", description="Unknown safety impact", bgcolor="#95A5A6"),
# Architecture tags
dict(name="core", description="Core architecture component", bgcolor="#FF6B6B"),
dict(name="portability", description="Multi-platform portability", bgcolor="#4ECDC4"),
dict(name="safety", description="Safety-critical component", bgcolor="#FF5D73"),
dict(name="performance", description="Performance-critical component", bgcolor="#FECA57"),
dict(name="testing", description="Testing and verification", bgcolor="#96CEB4"),
]

# Configure needs roles for referencing
needs_role_need_template = "{title} ({id})"
needs_role_need_max_title_length = 30

needs_id_length = 7
needs_title_optional = True
needs_file_pattern = '**/*.rst'

# New extra links configuration
needs_extra_links = [
dict(
option = "realizes",
incoming = "is realized by",
outgoing = "realizes",
style = "solid,#006A6A",
),
]

# Regular expression for finding requirement IDs
REQ_RE = re.compile(r"SW-REQ-ID\\s*:\\s*(REQ_\\w+)", re.I)
# Requirement/safety traceability has been migrated to rivet (safety/ directory).
# See: rivet validate, rivet coverage, rivet serve

# Initialize source_suffix before attempting to modify it
source_suffix = {
Expand All @@ -308,50 +209,6 @@ def patched_process_doc(self, env, docname, document):
'.md': 'markdown',
}

# Dynamic function to extract requirement IDs from a file
def extract_reqs(app, need, needs, *args, **kwargs):
"""
Return all REQ_xxx IDs that occur in the file given via :file:.
Called as a *dynamic function* during the build.
"""
relative_file_path_from_doc_source = need.get("file")
if not relative_file_path_from_doc_source:
return ""

# Construct the absolute path to the source file.
# app.confdir is the directory of conf.py (e.g., /path/to/workspace/docs/source)
# relative_file_path_from_doc_source is like '../../kiln/src/some_file.rs'
# So, Path(app.confdir) / relative_file_path_from_doc_source gives the absolute path.
absolute_src_file_path = (pathlib.Path(app.confdir) / relative_file_path_from_doc_source).resolve()

try:
text = absolute_src_file_path.read_text(errors="ignore")
ids = REQ_RE.findall(text)
return ";".join(sorted(set(ids))) # needs wants ';' as separator
except FileNotFoundError:
print(f"WARNING: [extract_reqs] File not found: {absolute_src_file_path} (original path in need: {relative_file_path_from_doc_source})")
return ""
except Exception as e:
print(f"ERROR: [extract_reqs] Could not read file {absolute_src_file_path}: {e}")
return ""

# Configuration to make specific strings in RST linkable
needs_string_links = {
# Link REQ_XXX to its definition
"req_inline": {
"regex": r"(?P<value>REQ_\w+)",
"link_url": "#{{value}}",
"link_name": "{{value}}",
"options": [],
},
# Link file paths in :file: option to GitHub
"source_file_link": {
"regex": r"^(?P<value>(?:\.\.\/)*[a-zA-Z0-9_\-\/]+\.rs)$",
"link_url": "https://github.com/pulseengine/kiln/blob/main/{{value.replace('../../', '')}}",
"link_name": "{{value}}",
"options": ["file"],
}
}

# Rust documentation configuration
# Start with core working crates first
Expand Down
Loading
Loading