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
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
tag:
description: Reviewed GitHub release tag
required: true
default: v1.1.0
default: v1.1.1
type: string
permissions:
contents: read
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.1.1 — 2026-10-25

- Remap numeric reply links when importing export envelopes, including forward links and existing destinations. Drop links to messages outside the batch and return revisions after link updates.

## 1.1.0 — 2026-10-25

- Add SQLite message-base support and an optional network extra for packet, nodelist and node commands. Operational failures use closed codes, including legacy commands; broken stdout exits 141. Base operations remain available without network dependencies.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
Command-line tools for FTN message bases, JSON fixtures, packets, nodelists
and node operations. Python 3.12+. MIT licensed.

Version **1.1.0** adds SQLite and network operations. Packet, nodelist and node commands require the
Version **1.1.1** fixes numeric reply links during conversion. SQLite and network
operations were added in 1.1.0. Packet, nodelist and node commands require the
optional `[network]` extra.

```sh
Expand All @@ -30,6 +31,10 @@ validation finishes before opening a writer. Each append commits separately;
a later failure keeps earlier appends. A broken pipe can hide the receipt of
an already committed message. Rerunning may create duplicates.

Export envelopes remap numeric reply links within the input batch and drop
links to omitted messages. Their receipts follow link updates. Flat write
objects keep destination-local reply numbers unchanged.

`read --body` emits the reader's `body_text` exactly, including any controls
present there, without adding a newline. `read --revision` adds the writer's
identity and revision. `export --archive` reports reader issues as JSONL on
Expand Down
4 changes: 2 additions & 2 deletions RELEASE-SHA256.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
28380c1c5df4adc571f06690d3bf30937ef790aa45e9f1f23845f7101e4b3738 dist/golded_ftn_tools-1.1.0-py3-none-any.whl
55361fb9c86080e74b018db91c67f9c98eae5f5694d3001c493848ce36d67339 dist/golded_ftn_tools-1.1.0.tar.gz
ac2c066032df9b8414d1ba63ce3033fd9f3139b786b70c64eb9171d7a2c630c7 dist/golded_ftn_tools-1.1.1-py3-none-any.whl
c340e02df4c60a963e767c6f13ec909c0ef0f5f0ff3e560e5e4a1f8d89e62867 dist/golded_ftn_tools-1.1.1.tar.gz
4 changes: 2 additions & 2 deletions catalog.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div><span>FTNT💥</span><a href="https://golded-dev.github.io/golded-ftn-python-docs/">Library docs ↗</a></div>
</header>
<div class="shell">
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.0.2 · PYTHON 3.12+</span></div>
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.1.1 · PYTHON 3.12+</span></div>
<div class="layout">
<aside><div class="sidebar">
<nav class="page-nav" aria-label="Manual"><a href="index.html">Home</a><a href="create.html">create</a><a href="write.html">write</a><a href="read.html">read</a><a href="export.html">export</a><a href="decode.html">decode</a><a href="repair.html">repair</a><a href="heads.html">heads</a><a href="catalog.html" aria-current="page">catalog</a></nav>
Expand All @@ -27,7 +27,7 @@
<main><p class="eyebrow">Read the tool. Not the base.</p><p class="command">ftnt catalog</p><h1>Describe this binary.</h1><p class="hero-lead">Commands, fields, date rules and error codes for the version you are running.</p><section class="guide-section" id="usage"><div class="section-title"><span>00</span><h2>Usage</h2></div><p><code>ftnt catalog</code></p><p>Prints one JSON document that describes this binary: commands, flags, write fields, date rules, exit codes and error codes. It is built from the parser and the tables the commands use. Proposals are not included.</p><div class="code-pane" id="catalog-example"><div class="code-head"><span>describe the binary</span><button type="button" data-copy="catalog-example-text" hidden>Copy code</button></div><pre><code id="catalog-example-text">ftnt catalog
</code></pre></div><p><code>--json-errors</code> prints a failure as one JSON object on stderr. A stderr that is not a terminal does the same. On a terminal, the sentence stays unless you pass the flag. The object carries <code>code</code>, <code>exit_status</code> and <code>message</code>. A write also carries <code>input_record</code> and <code>committed</code>.</p></section></main>
</div></div>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.0.2 · MIT LICENSE</span></footer>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.1.1 · MIT LICENSE</span></footer>
</div>

<script>
Expand Down
4 changes: 2 additions & 2 deletions create.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div><span>FTNT💥</span><a href="https://golded-dev.github.io/golded-ftn-python-docs/">Library docs ↗</a></div>
</header>
<div class="shell">
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.0.2 · PYTHON 3.12+</span></div>
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.1.1 · PYTHON 3.12+</span></div>
<div class="layout">
<aside><div class="sidebar">
<nav class="page-nav" aria-label="Manual"><a href="index.html">Home</a><a href="create.html" aria-current="page">create</a><a href="write.html">write</a><a href="read.html">read</a><a href="export.html">export</a><a href="decode.html">decode</a><a href="repair.html">repair</a><a href="heads.html">heads</a><a href="catalog.html">catalog</a></nav>
Expand All @@ -28,7 +28,7 @@
</code></pre></div><p>Stdout is one JSON object. <code>base</code> is the resolved path.</p><div class="code-pane" id="create-result"><div class="code-head"><span>create_result</span><button type="button" data-copy="create-result-text" hidden>Copy code</button></div><pre><code id="create-result-text">{&quot;schema_version&quot;:1,&quot;type&quot;:&quot;create_result&quot;,&quot;format&quot;:&quot;jam&quot;,&quot;base&quot;:&quot;/resolved/fixtures/general&quot;}
</code></pre></div></section><section class="guide-section" id="failures"><div class="section-title"><span>01</span><h2>Failures</h2></div><p>An existing base fails with exit 3. An unknown path problem from the filesystem fails with exit 6. <code>--format</code> is required and must be one of <code>msg</code>, <code>opus</code>, <code>jam</code>, <code>squish</code> or <code>hudson</code>.</p></section></main>
</div></div>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.0.2 · MIT LICENSE</span></footer>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.1.1 · MIT LICENSE</span></footer>
</div>

<script>
Expand Down
4 changes: 2 additions & 2 deletions decode.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div><span>FTNT💥</span><a href="https://golded-dev.github.io/golded-ftn-python-docs/">Library docs ↗</a></div>
</header>
<div class="shell">
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.0.2 · PYTHON 3.12+</span></div>
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.1.1 · PYTHON 3.12+</span></div>
<div class="layout">
<aside><div class="sidebar">
<nav class="page-nav" aria-label="Manual"><a href="index.html">Home</a><a href="create.html">create</a><a href="write.html">write</a><a href="read.html">read</a><a href="export.html">export</a><a href="decode.html" aria-current="page">decode</a><a href="repair.html">repair</a><a href="heads.html">heads</a><a href="catalog.html">catalog</a></nav>
Expand All @@ -27,7 +27,7 @@
<main><p class="eyebrow">Old bytes. No substitutions.</p><p class="command">ftnt decode</p><h1>Decode a charset to UTF-8.</h1><p class="hero-lead">A strict text filter. The whole input is read before any output.</p><section class="guide-section" id="usage"><div class="section-title"><span>00</span><h2>Usage</h2></div><p><code>ftnt decode --charset CHARSET</code></p><p>Reads all of stdin into memory and writes UTF-8 text to stdout. Decoding is strict. Line endings and trailing nulls are preserved. <code>CHARSET</code> is a core charset alias, for example <code>IBMPC</code>, <code>CP850</code> or <code>LATIN-1</code>.</p><div class="code-pane" id="decode-example"><div class="code-head"><span>decode a legacy file</span><button type="button" data-copy="decode-example-text" hidden>Copy code</button></div><pre><code id="decode-example-text">ftnt decode --charset IBMPC &lt; old-text.txt
</code></pre></div></section><section class="guide-section" id="failures"><div class="section-title"><span>01</span><h2>Failures</h2></div><p>An unknown alias or a byte that is illegal in that charset fails the command. The filter does not guess a replacement character and does not run the mojibake repair.</p></section></main>
</div></div>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.0.2 · MIT LICENSE</span></footer>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.1.1 · MIT LICENSE</span></footer>
</div>

<script>
Expand Down
24 changes: 21 additions & 3 deletions docs/JSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ base number. Do not conceal contradictory controls, MSGID or charset declaration
Reject unknown top-level/control keys, duplicate keys, NaN/Infinity, incorrect
nested types, BOM and invalid UTF-8 with a record number. `provenance`, `msgno`,
`identity`, `revision` and other non-write fields inside an export envelope are
dropped when unwrapping. Flat write objects must not include those fields.
dropped when unwrapping. Source identity and area metadata are used to remap
reply links before being discarded. Flat write objects must not include those fields.
Provenance comes from the source/read operation, not an imported claim about the
new record.

Expand All @@ -70,8 +71,25 @@ format. The CLI maps nested `control_lines.kludges` to `control_lines` and neste
stripped to match the write date grammar.

No arbitrary binary header import or requested message number. Append assigns
the format's number. Fixture authors manage forward reply links; there is no
automatic link resolver.
the format's number.

For export envelopes, `write` translates `reply_to_msgno`, `reply1st_msgno`,
`reply_next_msgno` and `reply_list` into the destination numbering. Links resolve
only within the same source format, base, board and area, and only to messages
in the same input batch. Missing targets are dropped. Forward links work, as do
imports into an existing base. Duplicate source identities or missing source
format/base/message number are rejected during preflight.

Conversion appends messages without numeric links, then updates the links using
the actual write results. Conversion receipts follow link updates and contain
the resulting revisions. If an append fails, the committed prefix is linked
using only that prefix before its receipts and the error are emitted. A link
update failure can leave committed messages without all their links; the error
reports the input record and total committed append count. Conversion is not a
batch transaction. Interrupted conversion can leave incomplete links.

Flat write objects retain destination-local reply numbers unchanged. Fixture
authors manage their forward links. MSGID/REPLY control lines are unchanged.

## Export and read

Expand Down
16 changes: 13 additions & 3 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ reject `--area` for other formats and reject `--board` with sqlite. V1 does not
expose Hudson's separate `scan_path`; use the writer package's documented default.
Investigate external scan directories before adding an option.

Export envelopes and flat write objects are both accepted. Envelope unwrapping
drops provenance, source msgno, area metadata, identity and revision; the
destination writer assigns new numbers.
Export envelopes and flat write objects are both accepted. The destination
writer assigns new numbers. Envelope source identities and area metadata scope
reply-link remapping within the input batch; they are not imported as target
metadata. Missing link targets are dropped. Flat objects retain target-local
reply numbers. See JSON.md for the source identity and conversion contract.

Read, parse and structurally validate the entire input before opening a writer
session. Spool normalized, validated JSONL records to a temporary file instead
Expand All @@ -106,6 +108,14 @@ receipts only for committed messages. stderr gives the failed record number and
the committed count. No automatic retry or rollback of earlier successes. No
guarantee against process death, power loss or an interrupted pipe.

For batches containing export envelopes, append without the envelopes' numeric
links first, then update those links using actual destination identities.
Emit each receipt after its link update with the resulting revision. On append
failure, finalize links within the committed prefix before reporting the error.
An update failure reports the failing record and committed append count; it
does not roll back the batch. Keep message payloads in the spool; retain only
source identities and write results in memory for link resolution.

A broken pipe can occur after append commits but before its receipt reaches the
consumer. Help and docs must explain this: rerunning can create duplicates.

Expand Down
2 changes: 1 addition & 1 deletion docs/release.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release preparation

Version 1.1.0 targets Linux and macOS, Python 3.12–3.14.
Version 1.1.1 targets Linux and macOS, Python 3.12–3.14.
Windows is outside this release's test and compatibility promises.

1. Run pytest, Ruff lint/format and strict mypy against the published dependency wheels.
Expand Down
44 changes: 44 additions & 0 deletions evidence/release-1.1.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"schema_version": 1,
"package": "golded-ftn-tools",
"version": "1.1.1",
"tag": "v1.1.1",
"source_commit": "5edbfbd83a1374fd946fd0d222d05665071978cb",
"status": "verified_release_candidate",
"platforms": [
"Linux",
"macOS"
],
"python_versions": [
"3.12",
"3.13",
"3.14"
],
"artifacts": [
{
"file": "golded_ftn_tools-1.1.1-py3-none-any.whl",
"sha256": "ac2c066032df9b8414d1ba63ce3033fd9f3139b786b70c64eb9171d7a2c630c7"
},
{
"file": "golded_ftn_tools-1.1.1.tar.gz",
"sha256": "c340e02df4c60a963e767c6f13ec909c0ef0f5f0ff3e560e5e4a1f8d89e62867"
}
],
"ci": {
"run_id": 40217572261,
"url": "https://github.com/golded-dev/golded-ftn-tools-python/actions/runs/40217572261",
"result": "six matrix jobs passed"
},
"local_checks": {
"environment": "macOS, CPython 3.14.8; installed wheel with public dependency wheels",
"pytest": "171 passed",
"ruff_lint": "passed",
"ruff_format": "passed",
"strict_mypy": "passed",
"stubtest": "passed",
"twine": "wheel and sdist passed",
"distribution_verification": "metadata, contents, identical sdist wheel rebuild and two clean consumer installs passed",
"manual_pages": "nine pages passed structural checks; no browser visual check",
"whitespace": "git diff --check passed"
}
}
4 changes: 2 additions & 2 deletions export.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div><span>FTNT💥</span><a href="https://golded-dev.github.io/golded-ftn-python-docs/">Library docs ↗</a></div>
</header>
<div class="shell">
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.0.2 · PYTHON 3.12+</span></div>
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.1.1 · PYTHON 3.12+</span></div>
<div class="layout">
<aside><div class="sidebar">
<nav class="page-nav" aria-label="Manual"><a href="index.html">Home</a><a href="create.html">create</a><a href="write.html">write</a><a href="read.html">read</a><a href="export.html" aria-current="page">export</a><a href="decode.html">decode</a><a href="repair.html">repair</a><a href="heads.html">heads</a><a href="catalog.html">catalog</a></nav>
Expand All @@ -29,7 +29,7 @@
</code></pre></div><div class="table-wrap"><table><thead><tr><th>Option</th><th>Meaning</th></tr></thead><tbody><tr><td><code>--archive</code></td><td>Keep going after reader issues. Each issue is a JSON object on stderr. Exit 7 when any issue was reported, otherwise 0.</td></tr><tr><td><code>--board</code></td><td>Optional Hudson filter, 1..200. Other formats reject it.</td></tr><tr><td><code>--fallback-charset</code></td><td>Default <code>CP850</code>.</td></tr></tbody></table></div></section><section class="guide-section" id="partial"><div class="section-title"><span>01</span><h2>Partial output</h2></div><p>Readers may buffer the base. If the command fails, stdout can already contain earlier messages. Check the exit status before treating the stream as complete. Without <code>--archive</code>, a reader problem stops the command instead of being collected as an issue.</p><div class="code-pane" id="export-issue"><div class="code-head"><span>reader_issue on stderr</span><button type="button" data-copy="export-issue-text" hidden>Copy code</button></div><pre><code id="export-issue-text">{&quot;schema_version&quot;:1,&quot;type&quot;:&quot;reader_issue&quot;,&quot;issue&quot;:{}}
</code></pre></div><p>The <code>issue</code> object is the reader’s own report.</p></section></main>
</div></div>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.0.2 · MIT LICENSE</span></footer>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.1.1 · MIT LICENSE</span></footer>
</div>

<script>
Expand Down
4 changes: 2 additions & 2 deletions heads.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div><span>FTNT💥</span><a href="https://golded-dev.github.io/golded-ftn-python-docs/">Library docs ↗</a></div>
</header>
<div class="shell">
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.0.2 · PYTHON 3.12+</span></div>
<div class="bar"><span>GOLDED / FTN TOOLS</span><span>RELEASED 1.1.1 · PYTHON 3.12+</span></div>
<div class="layout">
<aside><div class="sidebar">
<nav class="page-nav" aria-label="Manual"><a href="index.html">Home</a><a href="create.html">create</a><a href="write.html">write</a><a href="read.html">read</a><a href="export.html">export</a><a href="decode.html">decode</a><a href="repair.html">repair</a><a href="heads.html" aria-current="page">heads</a><a href="catalog.html">catalog</a></nav>
Expand All @@ -27,7 +27,7 @@
<main><p class="eyebrow">Subjects first. Bodies later.</p><p class="command">ftnt heads</p><h1>Index a base without bodies.</h1><p class="hero-lead">A short list for choosing one message. Not an archive.</p><section class="guide-section" id="usage"><div class="section-title"><span>00</span><h2>Usage</h2></div><p><code>ftnt heads BASE --format FORMAT [options]</code></p><p>Prints one JSON object per message and leaves out <code>body_text</code>. Use <a href="read.html"><code>read</code></a> for the message you actually need. The default <code>--limit</code> is 100. <code>--limit 0</code> reads the whole base. <code>--after MSGNO</code> skips that number and everything before it.</p><div class="code-pane" id="heads-example"><div class="code-head"><span>first hundred subjects</span><button type="button" data-copy="heads-example-text" hidden>Copy code</button></div><pre><code id="heads-example-text">ftnt heads ./fixtures/general --format jam --limit 100
</code></pre></div><p><code>body_bytes</code> is the UTF-8 length of the body the reader returned. <code>msgid</code> is present only when the reader parsed one. Exit 0, or 7 with <code>--archive</code> when a reader issue was reported.</p></section></main>
</div></div>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.0.2 · MIT LICENSE</span></footer>
<footer><span>GoldED FTN tools / GoldED.dev</span><span>RELEASED 1.1.1 · MIT LICENSE</span></footer>
</div>

<script>
Expand Down
Loading
Loading