Skip to main content

golded-ftn-jam

Repository: golded-ftn-jam-python. The distribution remains golded-ftn-jam; imports use golded_ftn_jam. The source is public on GitHub. Version 1.3.0 is available on PyPI.

Install with Python 3.12 or newer:

python -m pip install golded-ftn-jam==1.3.0

Read and edit JAM revision 1 areas through the golded-ftn models. Python 3.12+.

For development, clone core and the format package:

git clone https://github.com/golded-dev/golded-ftn-python.git
git clone https://github.com/golded-dev/golded-ftn-jam-python.git
cd golded-ftn-jam-python
uv sync --locked
from pathlib import Path
from tempfile import TemporaryDirectory

from golded_ftn import MessageBaseReader, ReaderOptions
from golded_ftn_jam import JamReader

# A minimal empty area. Real callers pass the area basename, without an extension.
with TemporaryDirectory() as directory:
    base = Path(directory) / "example"
    header = bytearray(1024)
    header[:4] = b"JAM\0"
    header[20:24] = (1).to_bytes(4, "little")
    base.with_suffix(".JHR").write_bytes(header)
    base.with_suffix(".JDT").write_bytes(b"")
    base.with_suffix(".JDX").write_bytes(b"")
    reader: MessageBaseReader = JamReader()
    messages = list(reader.read(base, ReaderOptions(fallback_charset="CP850")))
    assert messages == []

The basename is exact; .JHR, .JDT and .JDX extensions are matched without regard to case. Each must identify one regular file; symlinks and ambiguous extension variants are rejected. The standalone reader ignores .JLR; editing preserves it and creation initializes an empty file.

The index determines message numbers and which headers are live. Index holes and deleted messages are skipped. Old unindexed headers are ignored. The reader validates signatures, revision, record boundaries, offsets, subfield lengths, message numbers and reused header offsets. By default it streams indexed messages; pass ReaderOptions(eager=True) to load and validate the whole area before returning a tuple. In eager mode a malformed later record cannot leave a caller with a partial result. Filesystem errors remain filesystem errors; damaged data and decoding errors raise ParserException with source path, byte offset and a chained cause.

The standalone JamReader requires a stable area with no concurrent writes. It does not lock the area or produce a snapshot across the three files. Stop the writer or use a consistent copy before reading.

Decoding is strict, with core charset detection and CP850 fallback. Header FTSKLUDGE declarations are considered before body declarations. Conflicting charset declarations and IDs fail. Unknown charset names use the configured fallback. Mojibake repair is the caller's choice.

body_text contains only normalized .JDT text. Header control and routing subfields go into control_lines, ahead of body metadata. Repeated controls and routing entries keep their order within the core model's kludges, seen_by and path sequences. Unknown subfields and nonzero HiID fields are bounds-checked and skipped. The first originating/destination address is preserved as decoded text, including node 0, point and domain. Other single-value subfields must agree when repeated. Header MSGID/REPLYID take precedence over matching body IDs; missing MSGID uses the core synthetic ID over decoded, normalized fields.

Dates are naive 1970-01-01 + DateWritten seconds, independent of the machine's timezone; zero means None. TZUTC is retained as a control line. Writer and recovery sessions invert that epoch to local wall time when a valid TZUTC offset is present, so aware timestamps round-trip without an hour shift. The naive DateWritten mapping is unchanged when TZUTC is absent. Raw attributes, all three reply links and .JHR provenance are retained; zero reply links become None. Unknown area metadata stays None.

Compressed, encrypted and escaped active messages are unsupported. Area discovery, databases, packing and repair are outside this package.

Development

uv sync --locked --python 3.14
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run python -m mypy.stubtest golded_ftn_jam
uv build
uv run twine check dist/*
uv run python scripts/verify_distribution.py

Development and distribution use public dependency constraints; no local source overrides are configured. Install unpublished dependencies from the reviewed candidate wheelhouse. See CONTRIBUTING.md and release checks.

Format references and credits

JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, Mats Wallin. ALL RIGHTS RESERVED.

The package code is MIT licensed; the JAM specification has its own terms.

Archive mode

Strict reading remains the default. Archive mode requires a report callback:

from golded_ftn import ReaderIssue, ReaderOptions

issues: list[ReaderIssue] = []
options = ReaderOptions(archive_mode=True, on_issue=issues.append)
# Pass options to JamReader().read(source, options).

Issues carry recovered, skipped or stopped, the actual filename, record identity and physical offset. Their detail contains no message contents. A stop means the traversal is incomplete; a validated prefix may still be returned. Multiple issues can describe one record, including recovery followed by a skip. Filesystem errors and callback exceptions propagate. Files must remain stable.

Bounded fields exceeding JAM's specification limits are retained and reported. Malformed TZUTC metadata is retained without interpretation. Distinct PID, FLAGS and TZUTC subfields stay in source order. Conflicting names, subjects, IDs or charset declarations are skipped rather than guessed. Failed records are skipped using the next fixed index slot; reused header offsets stop traversal.

If declared ASCII cannot decode a payload, the configured fallback is tried strictly and reported. The original charset control stays unchanged. Other decoding failures are skipped; there is no lossy decoding or mojibake repair.

Writing

JamWriter.create(base) creates .JHR, .JDT, .JDX and an empty .JLR. Pass JamWriterOptions(extension_case="lower") to create .jhr and friends instead. Open and read already use the casing that is on disk; both casings of the same sidecar at once are still rejected. Existing files are refused. The initial message number is 1.

from golded_ftn import MessagePatch, OutgoingMessage
from golded_ftn_jam import JamWriter

writer = JamWriter()
writer.create("new-area")
with writer.open("new-area") as session:
    result = session.append(
        OutgoingMessage(
            from_name="Alice",
            to_name="Bob",
            subject="Hello",
            body_text="Hello Bob",
        )
    )
    result = session.update(
        result.identity, MessagePatch(subject="Changed"), result.revision
    )
    session.delete(result.identity, result.revision)

Every operation rereads and validates the index, referenced headers, text ranges and active-message count under the byte-0 .JHR record lock. A session read returns SessionMessage with a raw-byte SHA-256 revision. Changes to other messages do not invalidate it. The revision includes identity, physical index/header/text locations and SHA-256 over raw header, subfield and text bytes. An omitted patch field retains its raw metadata; explicit None clears optional metadata. Names, subject, text and attributes reject None.

control_lines replaces general controls in both header subfields and inline text. MSGID, address controls and routing retain their separate fields when omitted; conflicting explicit controls are rejected. external_id and routing patches remove obsolete inline copies as well as replacing their header metadata. Body-only changes retain existing inline controls and routing. Unknown subfields and nonzero HiID values survive unless their supported field is explicitly changed.

Content updates append a header, subfields and text, then redirect the index. Header-only changes retain the text bytes and record position. Unknown subfields, reserved words, timestamps and reply links remain intact. Delete marks the header, sets the recipient index CRC to FFFFFFFF, and decrements the active count. Message numbers and lastread data remain unchanged.

CP850 is the default. Encoding is strict; conflicting charset declarations, truncation, unsupported compression flags and arbitrary reply lists are refused. No MSGID, routing or duplicate detection is generated. Full-file snapshots support in-place rollback during ordinary I/O failures; rollback failure poisons the session. This provides no process-kill or power-loss transaction guarantee.

JamWriter.recovery_session(path, recovery_root=...) holds the .JHR byte-0 lock across prepare/apply/settle and reuses that descriptor for header I/O. Recovery covers .JHR, .JDT and .JDX only; .JLR is never touched. Torn header or index bytes are restored from durable artifacts before ordinary validation. concurrent=True is accepted.

GoldED compatibility profile

Candidate interoperability is bounded to GoldED source commit d7449053bd674df54c4a442c92dce8c06ad7b586, version 3.1.0, native macOS arm64/GCC 16 and Ubuntu 24.04 aarch64/GCC 13. The suite release manifest pins the resulting binaries and records actual checks. Other GoldED versions, Windows and network filesystems are not qualified.

Writers default to offline operation. Explicit concurrent=True opts into the tested read/write/refresh/lastread/stale-save profile, not a general multiwriter guarantee. Standalone readers still need a stable base; a session read uses its format lock. MSG/Opus and Goldbase have no shared GoldED writer lock: stale-save detection cannot close a race between comparison and a foreign write. Keep same-message edits serialized. Goldbase is outside the Python C1 profile.

Use format-specific WriterOptions extension_case="lower" for newly created Unix bases used by GoldED; preserve existing casing and reject ambiguous twins. Hudson scan queues belong in the configured system directory. Recovery sessions have a durable journal protocol; ordinary open() sessions only roll back handled I/O failures. UNKNOWN outcomes retain artifacts for operator reconciliation.

Original-source evidence

The reference checkout is golded-open-source, commit 600266252b73174ff5116cee697ef9a97aeb1859. It contains goldlib/gmb3/gmojamm.h (JamHdrInfo, JamHdr, JamIndex, subfield IDs), gmojamm2.cpp (open_area initialization, scan indexing), and gmojamm4.cpp (lock, unlock, save_message). lock takes byte 0 length 1 in .JHR; save_message maintains recipient/MSGID/ REPLY CRCs, active count and modification counter. Its CRC seed and missing final complement are confirmed by goldlib/gall/gcrcs32.cpp::strCrc32. These source checks establish layout and write semantics. They do not establish that a running GoldED reader refreshes safely after external changes.

Candidate 1.3.0

Add recoverable sessions and explicit extension_case. Retain the JHR lock descriptor across reads and mutations; preserve raw metadata and revisions.

Linux and macOS, Python 3.12–3.14, are the release targets. Windows is outside this candidate's test and compatibility promises. See release preparation.

Metadata

Release files for golded-ftn-jam 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for golded-ftn-jam 1.3.0
File Size Uploaded Provenance
golded_ftn_jam-1.3.0.tar.gz 38.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for golded-ftn-jam 1.3.0
File Interpreter ABI Platform
golded_ftn_jam-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 62.4 kB

Release files / golded_ftn_jam-1.3.0.tar.gz

Download URL golded_ftn_jam-1.3.0.tar.gz
Size 38.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0e075f5c49c104ff62d3686cd6ae64d2340c63d3aef6b0302867572d17835a3f
BLAKE2b-256 checksum
How to use checksums
8e078ff864e86de04157b99eae1ed1802f0087b988e3f329739622e460357843
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / golded_ftn_jam-1.3.0-py3-none-any.whl

Download URL golded_ftn_jam-1.3.0-py3-none-any.whl
Size 23.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4739f8357d75059e1871222b58fa4b02fc1a90e85a70d02e56bb91f53a669e00
BLAKE2b-256 checksum
How to use checksums
364a5bf76d8d6b58432d6207abd0d0ee3ec00f68da18a6753e66bb785ba48d0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for golded-ftn-jam 1.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for golded_ftn_jam-1.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page