# nenjim-journal-management Specification ## Purpose Defines the public Journal query service, its lifecycle manager, internal atomic chain ingestion, historical query behavior, and explicit filesystem loading of immutable Journal revisions. ## Requirements ### Requirement: Strict Journal API package boundary The public Journal API SHALL begin at `com.r35157.nenjim.service.journal`, where the only directly contained Java types SHALL be the public interfaces `JournalService` and `JournalServiceManager`. Public composed domain objects SHALL be under `.model`, public value types SHALL be under `.valuetypes`, public Journal-specific exceptions SHALL be under `.exception`, and the reference implementation and its parser, ingestion, chain-state, and filesystem helpers SHALL be under `.impl.ref` or its subpackages without leaking implementation types through public signatures. #### Scenario: Public package contents - **WHEN** the compiled Journal API packages are inspected - **THEN** only `JournalService` and `JournalServiceManager` are directly in `com.r35157.nenjim.service.journal`, while composed models, value types, and exceptions are in their respective public subpackages #### Scenario: Reference implementation boundary - **WHEN** the public service and model signatures are inspected - **THEN** they expose no parser, mutable ingestion API, filesystem loader, chain store, or reference-implementation type #### Scenario: Superseded API removed - **WHEN** the source and compiled Journal API are inspected - **THEN** no public `JournalManager`, deprecated alias, forwarding wrapper, or compatibility type remains under `com.r35157.nenjim.journal` or another superseded package ### Requirement: Filesystem-independent read-only Journal service `JournalService` SHALL be the ordinary application-facing, filesystem-independent, read-only API. It SHALL list known artifact coordinates and chronological revisions; obtain latest, exact, and newest-at-or-before revisions; obtain an exact artifact release from a selected revision; return immutable results without `null`; and expose no lifecycle, path, refresh, parser, configuration, or mutation operation. #### Scenario: Chronological and latest queries - **WHEN** an artifact has several accepted revisions - **THEN** the service lists all complete snapshots in ascending Journal-version order and returns the chain head as latest #### Scenario: Exact and as-of historical queries - **WHEN** a caller requests an exact revision or the newest revision at or before a Journal version - **THEN** the service returns the complete worldview from that chain position rather than filtering a newer snapshot by release publication time #### Scenario: Release query from selected worldview - **WHEN** a caller requests an exact artifact version from a selected revision - **THEN** the release, including license, content, dependencies, and policy context in that snapshot, is returned only if that revision knows it #### Scenario: Missing query result - **WHEN** a coordinate, revision, as-of revision, or artifact release is unknown - **THEN** the service returns an empty optional or immutable empty collection rather than `null` #### Scenario: Read-only boundary - **WHEN** an ordinary consumer receives `JournalService` - **THEN** the interface provides no start, stop, filesystem root, refresh, parsing, update, ingestion, or other mutation operation ### Requirement: Internal atomic text ingestion and chain identity The reference service implementation SHALL keep mutable ingestion non-public and filesystem-independent. One ingestion SHALL reject null, empty, or blank input; parse and validate the complete text; compute SHA-256 over its exact UTF-8 bytes including whitespace and line endings; validate its chain relationship; and atomically expose the immutable Journal through `JournalService`. A failed ingestion SHALL leave every previously accepted revision unchanged for that operation. #### Scenario: Valid internal ingestion - **WHEN** a complete valid genesis Journal is supplied internally - **THEN** it becomes immediately queryable through the read-only service under its metadata-derived coordinate #### Scenario: Exact text digest - **WHEN** a Journal text is accepted - **THEN** its revision digest is calculated from exactly the supplied UTF-8 text, including whitespace and line endings #### Scenario: Failed ingestion is atomic - **WHEN** an ingestion is null, empty, blank, structurally invalid, semantically invalid, or chain-invalid - **THEN** the operation fails and every previously accepted chain and revision remains unchanged ### Requirement: Linear per-artifact Journal chains Each artifact coordinate SHALL have exactly one genesis revision and one linear head. A non-genesis revision SHALL reference the current predecessor's exact SHA-256 digest and have a strictly greater Journal version. Missing, cross-artifact, stale-head, duplicate-genesis, or fork relationships SHALL fail. #### Scenario: Valid successor - **WHEN** a later revision for the same coordinate references the current head's exact text digest and has a strictly greater Journal version - **THEN** it becomes the new head while the predecessor remains historically queryable #### Scenario: Missing or cross-artifact predecessor - **WHEN** a non-genesis revision references an unknown digest or a digest owned by another artifact coordinate - **THEN** ingestion fails without changing either chain #### Scenario: Fork or stale predecessor - **WHEN** a revision references a known non-head predecessor or attempts another genesis for an existing coordinate - **THEN** ingestion fails rather than creating multiple heads #### Scenario: Non-increasing revision time - **WHEN** a successor Journal version is equal to or earlier than its predecessor's version - **THEN** ingestion fails ### Requirement: Idempotency and conflicts Supplying the same coordinate, Journal version, and exact complete text more than once SHALL be idempotent. Supplying different text for an existing coordinate and Journal version SHALL fail as a conflict even if the semantic model would be equal. #### Scenario: Repeated identical text - **WHEN** an already accepted complete text is supplied again - **THEN** the existing immutable revision is returned without changing the chain #### Scenario: Conflicting text - **WHEN** different text is supplied for an already stored coordinate and Journal version - **THEN** ingestion reports a conflict and does not mutate state ### Requirement: Journal service lifecycle manager `JournalServiceManager` SHALL be the lifecycle and administrative API. It SHALL start and stop the service, report the normalized configured Journal data root, perform explicit refresh, and expose the corresponding `JournalService` only after successful initialization. It SHALL not duplicate the Journal query API. #### Scenario: Successful initial start - **WHEN** the configured root and all runtime Journal data are valid - **THEN** start performs the complete initial chronological load before the manager reports success and exposes its read-only service #### Scenario: Failed initial start - **WHEN** the root, placement, filename, text, or chain is invalid during initial loading - **THEN** start fails clearly and the manager does not report a started service or expose a partially loaded service #### Scenario: Service access follows lifecycle - **WHEN** service access or refresh is requested before successful start or after stop - **THEN** the manager rejects the operation as unavailable in the current lifecycle state #### Scenario: Stop is non-destructive - **WHEN** the manager is stopped - **THEN** service-owned maintenance stops cleanly without creating, rewriting, or deleting Journal files #### Scenario: Administrative API does not duplicate queries - **WHEN** `JournalServiceManager` is inspected - **THEN** artifact and revision query operations are available only through its associated `JournalService` ### Requirement: Filesystem-backed lifecycle loading The reference service manager SHALL own a configured existing readable root, discover runtime files only at `//.journal`, ignore `.journal.example`, validate directory and filename placement against parsed content, sort each artifact's files chronologically, read complete UTF-8 text, and supply it to the internal ingestion operation. It SHALL not create, overwrite, delete, publish, download, synchronize, or watch files. #### Scenario: Valid filesystem load - **WHEN** an artifact directory contains chronologically named valid genesis and successor `.journal` files whose content identity matches their placement - **THEN** initial start or refresh ingests both complete UTF-8 texts in chronological order and exposes their chain through the service #### Scenario: Example files are ignored - **WHEN** a directory contains `.journal.example` - **THEN** loading does not ingest it as a runtime Journal #### Scenario: Invalid directory placement - **WHEN** a runtime Journal's metadata-derived coordinate differs from its parent directory name - **THEN** loading fails clearly #### Scenario: Invalid filename placement - **WHEN** a runtime filename does not use the strict timestamp syntax or differs from the parsed `JOURNAL_VERSION` - **THEN** loading fails clearly #### Scenario: Invalid root - **WHEN** the configured Journal root is missing, not a directory, or unreadable - **THEN** start or refresh fails clearly without creating it #### Scenario: Unexpected filesystem entry - **WHEN** the configured root contains a runtime entry outside the artifact-directory/revision-file structure - **THEN** loading fails rather than silently treating it as a Journal ### Requirement: Explicit idempotent refresh The service manager SHALL support explicit refresh. Repeating refresh for unchanged files SHALL be idempotent, and a later refresh SHALL discover valid newly added successors while preserving existing historical revisions. #### Scenario: Unchanged refresh - **WHEN** refresh runs twice without filesystem changes - **THEN** the second run leaves all chains unchanged and succeeds through ingestion idempotency #### Scenario: New revision discovered - **WHEN** a valid successor file is added after an earlier successful refresh - **THEN** the next refresh ingests it and the read-only service exposes it as the new head ### Requirement: Version-controlled examples and migration Version-controlled examples SHALL use `.journal.example` beneath an artifact-coordinate directory and collectively demonstrate quoted description, a scheme-independent information URI, per-release license, dependencies, exclusions, preferences, policy, exact/range syntax, and optional descriptions. Any multi-revision example chain SHALL use the predecessor file's real exact-text SHA-256 digest. #### Scenario: Example placement - **WHEN** repository Journal examples are inspected - **THEN** each is placed under `data/nenjim/journals//` with a strict Journal-version filename ending in `.journal.example` #### Scenario: Example chain integrity - **WHEN** examples include a successor revision - **THEN** its predecessor digest equals the SHA-256 of the predecessor example file's exact UTF-8 bytes