# nenjim-journal-format Specification ## Purpose Defines the observable format-version-1 contract and immutable domain meaning of a complete, artifact-scoped Nenjim Journal snapshot. ## Requirements ### Requirement: Artifact-scoped complete snapshots The Journal format SHALL describe exactly one artifact identified by the coordinate `--`, SHALL contain no `JOURNAL_ID` or artifact `TYPE`, and SHALL represent a complete immutable worldview rather than a delta from its predecessor. #### Scenario: Valid artifact identity - **WHEN** metadata contains non-empty `GROUP=com_r35157_nenjim`, `MODULE=hubd`, and `ARTIFACT=api` - **THEN** the parsed coordinate is `com_r35157_nenjim-hubd-api` #### Scenario: Obsolete identity fields - **WHEN** a Journal contains `JOURNAL_ID` or `TYPE` - **THEN** parsing fails as an unknown or misplaced field without silently ignoring it #### Scenario: No-op semantic revision - **WHEN** a later valid snapshot differs from its predecessor only by `JOURNAL_VERSION` and `PREVIOUS_JOURNAL_DIGEST` - **THEN** the snapshot remains valid because revisions are complete worldviews and need not change their semantic content ### Requirement: Strict top-level structure and comments The parser SHALL require the logical order `FORMAT_VERSION=1`, `JOURNAL_VERSION`, optional `PREVIOUS_JOURNAL_DIGEST`, `[METADATA]`, optional `[POLICY]`, and one or more `[RELEASE ]` sections. Blank lines and full-line or trailing `#` comments SHALL be accepted, except that a `#` inside a quoted value is data. #### Scenario: Comments before format entry - **WHEN** blank lines and full-line comments precede `FORMAT_VERSION=1` - **THEN** the format entry is treated as the first actual configuration entry and parsing proceeds #### Scenario: Hash inside quoted text - **WHEN** `DESCRIPTION='Project #1' # trailing comment` is parsed - **THEN** the decoded description is `Project #1` and the trailing comment is discarded #### Scenario: Unsupported format - **WHEN** the first actual entry is `FORMAT_VERSION=2` - **THEN** parsing fails explicitly because the format version is unsupported #### Scenario: Misordered or duplicate structure - **WHEN** a required entry or section is missing, duplicated, malformed, unknown, or placed outside its defined order - **THEN** parsing fails and no unknown content is ignored ### Requirement: Journal and publication timestamps `JOURNAL_VERSION` and `PUBLISHED_AT` SHALL each use a strict UTC `uuuuMMddHHmmssSSS'Z'` timestamp with millisecond precision and SHALL retain distinct revision-time and release-time meanings. #### Scenario: Valid timestamp - **WHEN** `20260819121530842Z` is supplied as a Journal or publication timestamp - **THEN** it is represented as the corresponding immutable UTC instant/value #### Scenario: Invalid timestamp - **WHEN** a timestamp has missing milliseconds, a non-UTC suffix, an impossible calendar value, or trailing characters - **THEN** parsing fails ### Requirement: Quoted metadata values `[METADATA]` SHALL contain exactly one non-empty `GROUP`, `MODULE`, `ARTIFACT`, and single-quoted `DESCRIPTION`, and MAY contain at most one single-quoted `INFORMATION_URI`. The parser SHALL decode `\'` and `\\`, reject other malformed escaping and empty quoted values, and expose information URI as `Optional` only when the decoded value is a syntactically valid non-empty absolute URI, without restricting its scheme. #### Scenario: Valid quoted metadata - **WHEN** metadata contains `DESCRIPTION='Nenjim\'s reference hub'` and `INFORMATION_URI='ftp://ftp.domain.com/components/123.txt'` - **THEN** the model exposes description `Nenjim's reference hub` and the exact absolute FTP URI #### Scenario: Optional information URI absent - **WHEN** valid metadata omits `INFORMATION_URI` - **THEN** the model exposes an empty optional URI #### Scenario: Scheme-independent URI - **WHEN** a syntactically valid absolute `https:`, `ftp:`, or `ipfs:` URI is supplied - **THEN** parsing accepts it without fetching, opening, or scheme-specific interpretation #### Scenario: Invalid metadata text or URI - **WHEN** a required quoted value is unquoted, empty, unterminated, badly escaped, or the information URI is relative or syntactically invalid - **THEN** parsing fails at that field ### Requirement: Exact artifact releases and content Every release section SHALL identify a unique exact `major.minor.patch` stable semantic version and SHALL contain exactly one non-empty quoted `LICENSE`, exactly one valid `PUBLISHED_AT`, one or more supported unique `CONTENT_DIGEST` values, and exactly one non-negative long `CONTENT_SIZE`. #### Scenario: Valid release content - **WHEN** release `1.0.3` contains decoded license text, a valid publication timestamp, a SHA-256 digest, an optional CIDv1 digest, and a non-negative content size - **THEN** the immutable release model exposes all values without normalizing or interpreting the license #### Scenario: Invalid release version - **WHEN** a release heading uses `1`, `1.0`, `1.0.0-beta`, or `1.0.0+build.42` - **THEN** parsing fails rather than normalizing it to another exact release #### Scenario: Duplicate release - **WHEN** two release sections identify the same exact version - **THEN** parsing fails #### Scenario: Invalid license - **WHEN** a release omits `LICENSE`, repeats it, or supplies an unquoted, malformed, or empty value - **THEN** parsing fails #### Scenario: Digest validation - **WHEN** content digests use valid `sha256:<64 lowercase hexadecimal characters>` and/or `cid1:` values whose payload is the exact canonical unpadded lowercase Base32 encoding of a valid CIDv1 envelope, with at most one digest of each scheme - **THEN** all supplied content identities remain inspectable in the release model #### Scenario: Canonical CIDv1 envelope - **WHEN** a CIDv1 content digest is supplied - **THEN** its version, multicodec, multihash code, and digest-length fields use their shortest unsigned varint encoding within the supported `long` range, and the declared digest length matches the payload #### Scenario: Non-canonical CIDv1 - **WHEN** a CIDv1 spelling has non-zero unused Base32 padding bits, a non-minimal varint, or a varint that overflows the supported `long` range in any envelope field - **THEN** parsing fails even if a permissive decoder could produce the same CID bytes or a truncated numeric value #### Scenario: Invalid content identity - **WHEN** no content digest exists, a digest scheme is unknown, a digest syntax is invalid, a scheme repeats, or content size is negative or outside the long range - **THEN** parsing fails ### Requirement: Normalized version expressions The model SHALL distinguish exact artifact versions from partial version boundaries, normalize semantically equivalent selector syntax, support membership and set containment, and reject unsupported or empty expressions. #### Scenario: Equivalent exact forms - **WHEN** `1.0.3` and `[1.0.3]` are parsed - **THEN** both produce the same exact version-expression representation #### Scenario: Minor series - **WHEN** `[1.0]` is parsed - **THEN** it contains every stable `1.0.x` release from `1.0.0` through the release immediately before `1.1.0` and is not normalized to exact `1.0.0` #### Scenario: Inclusive and exclusive ranges - **WHEN** `[1.0.3-->1.0.7]` and `[1.0.3-->1.0.7)` are parsed - **THEN** the first contains both endpoints and the second excludes `1.0.7` #### Scenario: Partial range boundaries - **WHEN** `[1.0-->1.2]` or `[1.0-->1.2)` is parsed - **THEN** the inclusive form contains the entire `1.2.x` series and the exclusive form excludes the entire `1.2.x` series #### Scenario: Explicit cross-major range - **WHEN** `[1.0-->3.0)` is parsed - **THEN** it contains stable versions in major lines 1 and 2 but none in major line 3 #### Scenario: Open upper range - **WHEN** `[1.0-->`, `(1.0-->`, or `[1.0.3-->` is parsed - **THEN** its implicit exclusive upper boundary is `2.0.0`, while its lower boundary respectively starts at `1.0.0`, `1.1.0`, or `1.0.3` #### Scenario: Expression union - **WHEN** `[1.0.0-->1.0.3], [1.0.7], 1.1.1` is parsed for a repeatable/list-valued rule - **THEN** the model represents the normalized union and accepts whitespace around commas and `-->` #### Scenario: Invalid expression - **WHEN** an expression uses a major-only boundary, a bare incomplete exact version, prerelease/build syntax, mathematical comparison syntax, whitespace inside a numeric version, an empty list element, reversed boundaries, or an empty range - **THEN** parsing fails ### Requirement: Nenjim dependencies Each artifact release SHALL model each `nenjim:` dependency target with exactly one `DEPENDS_ON` base expression set, zero or more described `EXCLUDES` entries, and zero or more described `PREFERRED` entries. Unknown schemes SHALL fail explicitly, exclusions and preferences SHALL require a corresponding base dependency, and the complete preferred set SHALL be contained by `DEPENDS_ON - EXCLUDES`. #### Scenario: Valid dependency relationship - **WHEN** a release depends on `nenjim:com_r35157_nenjim-hubd-api=[1.0-->`, excludes `1.0.4` with a description, and prefers `1.0.3` - **THEN** the model preserves the target, base constraint, and individual described exclusion/preference rules #### Scenario: Repeated exclusion and preference rules - **WHEN** multiple `EXCLUDES` or `PREFERRED` lines refer to one declared target - **THEN** their expression sets form unions while every line and optional description remains individually inspectable #### Scenario: Duplicate base dependency - **WHEN** the same dependency target has two `DEPENDS_ON` entries - **THEN** parsing fails #### Scenario: Orphan relationship rule - **WHEN** an `EXCLUDES` or `PREFERRED` target has no corresponding `DEPENDS_ON` - **THEN** parsing fails #### Scenario: Invalid preferred subset - **WHEN** any preferred version lies outside the base dependency set or inside an exclusion - **THEN** parsing fails because preference cannot make an invalid version valid #### Scenario: Unsupported dependency scheme - **WHEN** a dependency uses `maven:` or another unsupported scheme in format version 1 - **THEN** parsing fails clearly rather than ignoring or resolving it ### Requirement: Artifact policy An optional `[POLICY]` section SHALL preserve individual `BLACKLIST`, `DISCOURAGED`, and `RECOMMENDED` rules and descriptions. Blacklist SHALL be a hard constraint, discouraged and recommended SHALL be hints, overlaps SHALL be valid, and each recommended rule SHALL identify exactly one exact release present in the same snapshot. These recommendation invariants SHALL be enforced both while parsing and when the public model types are constructed directly without the parser. #### Scenario: Valid overlapping policy - **WHEN** a broad discouraged range overlaps a blacklisted exact release and an existing exact release is recommended - **THEN** all individual rules and descriptions remain inspectable and the blacklist has the documented stronger meaning without flattening the rules #### Scenario: Repeated policy entries - **WHEN** policy contains several blacklist, discouraged, or recommended lines - **THEN** all lines are retained as immutable individual rules #### Scenario: Invalid recommendation - **WHEN** `RECOMMENDED` contains a non-exact range or identifies a release absent from the snapshot - **THEN** parsing fails #### Scenario: Direct policy construction rejects a non-exact recommendation - **WHEN** a caller constructs `JournalPolicy` directly with a recommended rule containing a range, a minor series, multiple versions, or any other non-exact `VersionExpressionSet` - **THEN** construction fails because one recommended rule must identify exactly one exact `major.minor.patch` version #### Scenario: Direct Journal construction rejects an absent recommendation - **WHEN** a caller constructs `Journal` directly with an exact recommended version that is absent from that Journal's release map - **THEN** construction fails because recommendations refer only to releases in the same snapshot #### Scenario: Direct construction preserves valid policy overlaps - **WHEN** a caller constructs a Journal with an existing exact release recommended while that version also belongs to discouraged or blacklist rules - **THEN** construction succeeds and all individual rules remain inspectable because overlaps are valid #### Scenario: Optional description decoding - **WHEN** a repeatable policy or dependency rule ends with `:'Known \'issue\' on C:\\tmp'` - **THEN** its decoded non-empty description is `Known 'issue' on C:\tmp` #### Scenario: Invalid optional description - **WHEN** an explicitly supplied description is empty, unquoted, unterminated, or has malformed escaping - **THEN** parsing fails ### Requirement: Complete diagnostics and immutable results Parsing SHALL validate the entire document before it is accepted, SHALL report the known logical source, one-based line number, and reason for every parse failure, and SHALL return immutable defensively copied objects and collections without using `null` for optional values. #### Scenario: Source-aware failure - **WHEN** line 12 of logical source `example.journal` contains an invalid field - **THEN** the parse exception identifies `example.journal`, line 12, and the validation reason #### Scenario: Immutable model - **WHEN** callers obtain metadata, releases, policies, dependencies, digests, or expression collections - **THEN** callers cannot mutate the Journal snapshot through those returned values