Storage#

Native file-based storage layer for requirements documents and items.

Document DAG#

class jamb.storage.document_dag.DocumentDAG[source]#

Directed acyclic graph of document relationships.

Supports multiple parents per document (DAG structure).

documents#

Mapping of document prefix to its DocumentConfig.

Type:

dict[str, DocumentConfig]

document_paths#

Mapping of document prefix to the filesystem path of the document directory.

Type:

dict[str, Path]

get_parents(prefix)[source]#

Get parent document prefixes for a given document.

Parameters:

prefix (str) – The document prefix to look up.

Returns:

list[str] – List of parent document prefix strings. Empty if the document has no parents or is not found.

Return type:

list[str]

get_children(prefix)[source]#

Get child document prefixes for a given document.

Parameters:

prefix (str) – The document prefix to look up.

Returns:

list[str] – List of child document prefix strings.

Return type:

list[str]

get_root_documents()[source]#

Get documents with no parents.

Returns:

list[str] – List of document prefix strings that have no parent documents.

Return type:

list[str]

get_leaf_documents()[source]#

Get documents with no children.

Returns:

list[str] – List of document prefix strings that have no child documents.

Return type:

list[str]

topological_sort()[source]#

Return prefixes in topological order (parents before children).

Uses Kahn’s algorithm. If there are cycles, remaining nodes are appended at the end.

Raises:

ValueError – If any document references unknown parent documents.

Return type:

list[str]

validate_acyclic()[source]#

Check for cycles in the DAG.

Returns:

list[str] – List of error messages. Empty if no cycles.

Return type:

list[str]

__init__(documents=<factory>, document_paths=<factory>)#
Parameters:
Return type:

None

Document Configuration#

class jamb.storage.document_config.DocumentConfig[source]#

Configuration for a requirements document.

prefix#

Unique identifier prefix for items in this document (e.g. "REQ").

Type:

str

parents#

Prefixes of parent documents in the document DAG.

Type:

list[str]

digits#

Number of zero-padded digits in generated UIDs (e.g. 3 produces REQ001).

Type:

int

sep#

Separator between the prefix and numeric part of a UID (e.g. "-" produces REQ-001).

Type:

str

__init__(prefix, parents=<factory>, digits=3, sep='')#
Parameters:
Return type:

None

jamb.storage.document_config.load_document_config(path)[source]#

Load document config from a .jamb.yml file.

Parameters:

path (Path) – Path to the config file (.jamb.yml).

Returns:

DocumentConfig – DocumentConfig parsed from the file.

Raises:

ValueError – If the config file is missing required fields.

Return type:

DocumentConfig

jamb.storage.document_config.save_document_config(config, directory)[source]#

Save document config as .jamb.yml in the given directory.

Parameters:
  • config (DocumentConfig) – The document configuration to save.

  • directory (Path) – The directory to write .jamb.yml into.

Return type:

None

Discovery#

jamb.storage.discovery.discover_documents(root=None)[source]#

Walk filesystem for .jamb.yml files and build a DAG.

Parameters:

root (Path | None) – Root directory to search. Defaults to current working directory.

Returns:

DocumentDAG – DocumentDAG containing all discovered documents.

Raises:

FileNotFoundError – If root directory does not exist.

Return type:

DocumentDAG

Graph Builder#

jamb.storage.graph_builder.build_traceability_graph(dag, document_prefixes=None, include_inactive=False, exclude_patterns=None)[source]#

Build a TraceabilityGraph from the native storage layer.

Parameters:
  • dag (DocumentDAG) – The document DAG with discovered documents.

  • document_prefixes (list[str] | None) – Optional list of prefixes to include. If None, includes all documents.

  • include_inactive (bool) – Whether to include inactive items.

  • exclude_patterns (list[str] | None) – Optional glob patterns to exclude documents (by prefix) and items (by UID) from the graph.

Returns:

TraceabilityGraph – TraceabilityGraph populated with items and document relationships.

Return type:

TraceabilityGraph

Items#

jamb.storage.items.read_item(path, document_prefix)[source]#

Read an item YAML file and return a normalized dict.

Parameters:
  • path (Path) – Path to the item YAML file.

  • document_prefix (str) – The document prefix this item belongs to.

Returns:

uid, text, document_prefix, active, type, header, links, link_hashes, reviewed, derived, testable, custom_attributes.

Return type:

Dict with keys

Raises:
  • OSError – If the file cannot be read.

  • ValueError – If the file contains invalid YAML or has an empty UID.

jamb.storage.items.read_document_items(doc_path, prefix, include_inactive=False, sep='')[source]#

Read all item YAML files from a document directory.

Parameters:
  • doc_path (Path) – Path to the document directory.

  • prefix (str) – The document prefix.

  • include_inactive (bool) – Whether to include inactive items.

  • sep (str) – Separator between prefix and number.

Returns:

list[dict[str, Any]] – List of item dicts, sorted by UID.

Raises:

ValueError – If the prefix pattern is invalid.

Return type:

list[dict[str, Any]]

jamb.storage.items.compute_content_hash(item_data)[source]#

Compute a SHA-256 hash of item content for review/suspect detection.

Hashes: text, header, links, type. All strings are normalized to NFC Unicode form for consistent hashing across platforms.

Parameters:

item_data (dict[str, Any]) – Dict with item fields.

Returns:

str – URL-safe base64-encoded SHA-256 hash.

Return type:

str

jamb.storage.items.write_item(item_data, path, extra_fields=None)[source]#

Write an item as a YAML file.

Parameters:
  • item_data (dict[str, Any]) – Dict with item fields (uid, text, etc.).

  • path (Path) – Path to write the YAML file.

  • extra_fields (dict[str, Any] | None) – Additional fields to include in the YAML output.

Return type:

None

jamb.storage.items.next_uid(prefix, digits, existing_uids, sep='')[source]#

Generate the next available UID for a document.

Parameters:
  • prefix (str) – Document prefix (e.g. “SRS”).

  • digits (int) – Number of digits in the UID (must be >= 1).

  • existing_uids (list[str]) – List of existing UIDs.

  • sep (str) – Separator between prefix and number.

Returns:

str – Next available UID string.

Raises:

ValueError – If digits < 1 or if the prefix pattern is invalid.

Return type:

str

jamb.storage.items.dump_yaml(data, stream, **kwargs)[source]#

Dump YAML using block scalar style for multiline strings.

Parameters:
  • data (dict[str, Any]) – The dictionary to serialize as YAML.

  • stream (IO[str]) – A writable file-like object for the YAML output.

  • **kwargs (Any) – Additional keyword arguments passed to yaml.dump.

Return type:

None

Validation#

class jamb.storage.validation.ValidationIssue[source]#

A single validation issue.

level#

Severity — "error", "warning", or "info".

Type:

str

uid#

UID of the item involved, or None for document-level issues.

Type:

str | None

prefix#

Document prefix involved, or None when not applicable.

Type:

str | None

message#

Human-readable description of the issue.

Type:

str

__init__(level, uid, prefix, message)#
Parameters:
  • level (Literal['error', 'warning', 'info'])

  • uid (str | None)

  • prefix (str | None)

  • message (str)

Return type:

None

jamb.storage.validation.validate(dag, graph, *, check_links=True, check_suspect=True, check_review=True, check_children=True, check_empty_docs=True, check_empty_text=True, check_self_links=True, check_item_cycles=True, check_unlinked=True, skip_prefixes=None)[source]#

Run validation checks on the document tree.

Parameters:
  • dag (DocumentDAG) – The document DAG.

  • graph (TraceabilityGraph) – The traceability graph with items.

  • check_links (bool) – Check link validity and conformance.

  • check_suspect (bool) – Check for suspect links (hash mismatch).

  • check_review (bool) – Check review status.

  • check_children (bool) – Check that non-leaf docs have children linking to them.

  • check_empty_docs (bool) – Check for documents with no items.

  • check_empty_text (bool) – Check for items with empty text.

  • check_self_links (bool) – Check for items linking to themselves.

  • check_item_cycles (bool) – Check for cycles in item-to-item links.

  • check_unlinked (bool) – Check for unlinked normative items in child documents.

  • skip_prefixes (list[str] | None) – Document prefixes to skip during validation.

Returns:

list[ValidationIssue] – List of ValidationIssue objects.

Return type:

list[ValidationIssue]

Reorder#

jamb.storage.reorder.reorder_document(doc_path, prefix, digits, sep, all_doc_paths)[source]#

Renumber items sequentially and update all cross-document links.

Items are sorted by current UID and assigned new sequential UIDs (e.g. PREFIX001, PREFIX002, …). Files are renamed on disk and every link reference across all documents is updated.

Note: This operation is not atomic. If an error occurs during link updates after files have been renamed, the document may be left in an inconsistent state. Consider committing to version control before reordering.

Returns {“renamed”: int, “unchanged”: int, “rename_map”: dict[str, str]}.

Raises:

ValueError – If digits < 1.

Return type:

dict[str, int | dict[str, str]]

Parameters:
jamb.storage.reorder.insert_items(doc_path, prefix, digits, sep, position, count, all_doc_paths)[source]#

Insert count new item slots at position, shifting existing items forward.

Items with number >= position are renamed to number + count. Links across all documents are updated to reflect the new UIDs.

Parameters:
  • doc_path (Path) – Path to the document directory.

  • prefix (str) – Document prefix (e.g. “SRS”).

  • digits (int) – Number of digits in item UIDs.

  • sep (str) – Separator between prefix and number.

  • position (int) – Position to insert at (must be >= 1).

  • count (int) – Number of items to insert.

  • all_doc_paths (dict[str, Path]) – Mapping of all document prefixes to their paths.

Returns:

  • new_uids: List of new UIDs that were freed (e.g. ["SRS005"]). The caller is responsible for writing the actual item files at those paths.

  • rename_map: Dict mapping old UIDs to new UIDs for items that were shifted.

Return type:

A tuple of (new_uids, rename_map) where

Raises:

ValueError – If position < 1 or count < 1.