Commuted-Telegraphy 0.4.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/PKG-INFO +747 -0
  2. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/SOURCES.txt +44 -0
  3. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/dependency_links.txt +1 -0
  4. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/entry_points.txt +3 -0
  5. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/requires.txt +8 -0
  6. commuted_telegraphy-0.4.3/Commuted_Telegraphy.egg-info/top_level.txt +1 -0
  7. commuted_telegraphy-0.4.3/LICENSE +21 -0
  8. commuted_telegraphy-0.4.3/MANIFEST.in +1 -0
  9. commuted_telegraphy-0.4.3/PKG-INFO +747 -0
  10. commuted_telegraphy-0.4.3/README.md +706 -0
  11. commuted_telegraphy-0.4.3/pyproject.toml +94 -0
  12. commuted_telegraphy-0.4.3/sbom.cdx.json +45 -0
  13. commuted_telegraphy-0.4.3/setup.cfg +4 -0
  14. commuted_telegraphy-0.4.3/telegraphy/__init__.py +1 -0
  15. commuted_telegraphy-0.4.3/telegraphy/gui/__init__.py +1 -0
  16. commuted_telegraphy-0.4.3/telegraphy/gui/tablet_app.py +505 -0
  17. commuted_telegraphy-0.4.3/telegraphy/scripts/__init__.py +1 -0
  18. commuted_telegraphy-0.4.3/telegraphy/scripts/generate_sbom.py +85 -0
  19. commuted_telegraphy-0.4.3/telegraphy/scripts/run_coverage_workflow.py +95 -0
  20. commuted_telegraphy-0.4.3/telegraphy/story_brief/__init__.py +1 -0
  21. commuted_telegraphy-0.4.3/telegraphy/story_brief/__main__.py +14 -0
  22. commuted_telegraphy-0.4.3/telegraphy/story_brief/_constants.py +15 -0
  23. commuted_telegraphy-0.4.3/telegraphy/story_brief/_range_utils.py +21 -0
  24. commuted_telegraphy-0.4.3/telegraphy/story_brief/availability_validation.py +65 -0
  25. commuted_telegraphy-0.4.3/telegraphy/story_brief/cli.py +183 -0
  26. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/__init__.py +1 -0
  27. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/config.json +109 -0
  28. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/entities.json +1246 -0
  29. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/partner_distributions.json +712 -0
  30. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/prompts.json +274 -0
  31. commuted_telegraphy-0.4.3/telegraphy/story_brief/data/titles.json +82 -0
  32. commuted_telegraphy-0.4.3/telegraphy/story_brief/data_io.py +270 -0
  33. commuted_telegraphy-0.4.3/telegraphy/story_brief/filenames.py +260 -0
  34. commuted_telegraphy-0.4.3/telegraphy/story_brief/generate_story_brief.py +157 -0
  35. commuted_telegraphy-0.4.3/telegraphy/story_brief/generation.py +350 -0
  36. commuted_telegraphy-0.4.3/telegraphy/story_brief/generation_invariants.py +42 -0
  37. commuted_telegraphy-0.4.3/telegraphy/story_brief/linting.py +410 -0
  38. commuted_telegraphy-0.4.3/telegraphy/story_brief/normalization.py +79 -0
  39. commuted_telegraphy-0.4.3/telegraphy/story_brief/partner_models.py +331 -0
  40. commuted_telegraphy-0.4.3/telegraphy/story_brief/rendering.py +97 -0
  41. commuted_telegraphy-0.4.3/telegraphy/story_brief/schema_validation.py +345 -0
  42. commuted_telegraphy-0.4.3/telegraphy/story_brief/validation.py +23 -0
  43. commuted_telegraphy-0.4.3/tests/test_generate_sbom.py +88 -0
  44. commuted_telegraphy-0.4.3/tests/test_project_metadata.py +38 -0
  45. commuted_telegraphy-0.4.3/tests/test_run_coverage_workflow.py +69 -0
  46. commuted_telegraphy-0.4.3/tests/test_tablet_app_coverage.py +471 -0
@@ -0,0 +1,747 @@
1
+ Metadata-Version: 2.4
2
+ Name: Commuted_Telegraphy
3
+ Version: 0.4.3
4
+ Summary: A data-driven story brief generator for the Commuted fiction universe.
5
+ Author-email: Commuted <jeffrey.w.evans@gmail.com>
6
+ Maintainer-email: Commuted <commuted.convicted@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/jeffreywevans/Telegraphy
9
+ Project-URL: Repository, https://github.com/jeffreywevans/Telegraphy.git
10
+ Project-URL: Issues, https://github.com/jeffreywevans/Telegraphy/issues
11
+ Project-URL: Changelog, https://github.com/jeffreywevans/Telegraphy/blob/HEAD/CHANGELOG.md
12
+ Project-URL: Documentation, https://github.com/jeffreywevans/Telegraphy#readme
13
+ Project-URL: Security, https://github.com/jeffreywevans/Telegraphy/blob/HEAD/SECURITY.md
14
+ Keywords: commuted,creative-writing,fiction,story-brief,writing-tools
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Environment :: Console
17
+ Classifier: Environment :: X11 Applications
18
+ Classifier: Intended Audience :: End Users/Desktop
19
+ Classifier: Intended Audience :: Developers
20
+ Classifier: Natural Language :: English
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3 :: Only
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Topic :: Artistic Software
27
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
28
+ Classifier: Topic :: Utilities
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.12
31
+ Description-Content-Type: text/markdown
32
+ License-File: LICENSE
33
+ Requires-Dist: PyYAML>=6.0.3
34
+ Provides-Extra: dev
35
+ Requires-Dist: mypy>=1.18.0; extra == "dev"
36
+ Requires-Dist: pytest>=9.0.3; extra == "dev"
37
+ Requires-Dist: pytest-cov>=7.1.0; extra == "dev"
38
+ Requires-Dist: ruff>=0.15.12; extra == "dev"
39
+ Requires-Dist: types-PyYAML>=6.0.12.20260408; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # Telegraphy
43
+
44
+ [![Build](https://github.com/jeffreywevans/Telegraphy/actions/workflows/build.yml/badge.svg)](https://github.com/jeffreywevans/Telegraphy/actions/workflows/build.yml)
45
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
46
+ [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=bugs)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
47
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
48
+ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=coverage)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
49
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
50
+ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
51
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
52
+ [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
53
+ [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
54
+ [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
55
+ [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jeffreywevans_Telegraphy&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jeffreywevans_Telegraphy)
56
+
57
+
58
+
59
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/jeffreywevans/Telegraphy/license)
60
+
61
+ Telegraphy is a Python package and command-line tool for generating structured story briefs from a versioned, data-driven canon dataset.
62
+
63
+ It exposes two user-facing entry points:
64
+
65
+ - `story-brief` (CLI)
66
+ - `telegraphy-gui` (desktop GUI)
67
+
68
+ Telegraphy does not write prose. It generates the feedstock: YAML front matter, scenario constraints, style guidance, date-aware character and setting selections, optional sexual-content metadata, and a Markdown drafting scaffold. The result is a repeatable prompt artifact that can be copied into a writing workflow or saved as a Markdown seed file.
69
+
70
+ ## Contents
71
+
72
+ - [What is this?](#what-is-this)
73
+ - [Install](#install)
74
+ - [Quickstart](#quickstart)
75
+ - [GUI quickstart](#gui-quickstart)
76
+ - [Using the GUI](#using-the-gui)
77
+ - [CLI examples](#cli-examples)
78
+ - [Data override](#data-override)
79
+ - [Validation and linting](#validation-and-linting)
80
+ - [Software bill of materials (SBOM)](#software-bill-of-materials-sbom)
81
+ - [How the generator works](#how-the-generator-works)
82
+ - [Output files and safety](#output-files-and-safety)
83
+ - [Development](#development)
84
+ - [Release notes and status](#release-notes-and-status)
85
+ - [Maintainer docs](#maintainer-docs)
86
+ - [Troubleshooting](#troubleshooting)
87
+ - [License](#license)
88
+
89
+ ## What is this?
90
+
91
+ Telegraphy is the focused story-brief generator for the Commuted fiction universe.
92
+
93
+ At a practical level, it is:
94
+
95
+ - a Python package named `telegraphy`;
96
+ - a CLI named `story-brief`;
97
+ - a packaged JSON dataset under `telegraphy/story_brief/data/`;
98
+ - validation and linting tools for keeping that dataset usable;
99
+ - tests and CI for preserving deterministic generation behavior.
100
+
101
+ A generated brief includes:
102
+
103
+ - title;
104
+ - protagonist and secondary character;
105
+ - date;
106
+ - setting;
107
+ - weather;
108
+ - central conflict;
109
+ - inciting pressure;
110
+ - ending type;
111
+ - style guidance;
112
+ - sexual content level;
113
+ - sexual partner metadata when applicable;
114
+ - sexual scene tags when applicable;
115
+ - word-count target;
116
+ - a Markdown story-draft heading.
117
+
118
+ The generator is date-aware. Character availability, setting availability, and partner distributions are constrained by configured date ranges. That is the point of the tool: it lets the fiction machine throw sparks without setting the continuity barn on fire.
119
+
120
+ ## Install
121
+
122
+ Telegraphy requires Python 3.12 or newer.
123
+
124
+ For normal local use from a clone:
125
+
126
+ ```bash
127
+ git clone https://github.com/jeffreywevans/Telegraphy.git
128
+ cd Telegraphy
129
+ python -m pip install -e .
130
+ ```
131
+
132
+ For development:
133
+
134
+ ```bash
135
+ python -m pip install -e ".[dev]"
136
+ ```
137
+
138
+ The development extra installs the tools used by the repository:
139
+
140
+ - `pytest`
141
+ - `pytest-cov`
142
+ - `ruff`
143
+ - `mypy`
144
+ - `types-PyYAML`
145
+
146
+ You can verify that the CLI is available with:
147
+
148
+ ```bash
149
+ story-brief --help
150
+ ```
151
+
152
+ You can also run it as a module:
153
+
154
+ ```bash
155
+ python -m telegraphy.story_brief --help
156
+ ```
157
+
158
+ You can verify that the GUI launcher is available with:
159
+
160
+ ```bash
161
+ telegraphy-gui --help
162
+ ```
163
+
164
+ If you prefer module execution:
165
+
166
+ ```bash
167
+ python -m telegraphy.gui.tablet_app
168
+ ```
169
+
170
+ ## Quickstart
171
+
172
+ Print a generated brief to the terminal:
173
+
174
+ ```bash
175
+ story-brief --print-only
176
+ ```
177
+
178
+ Generate a reproducible brief for a specific date:
179
+
180
+ ```bash
181
+ story-brief --seed 42 --date 2000-01-01 --print-only
182
+ ```
183
+
184
+ Write a brief to the default output directory:
185
+
186
+ ```bash
187
+ story-brief
188
+ ```
189
+
190
+ By default, Telegraphy writes Markdown files under:
191
+
192
+ ```text
193
+ output/story-seeds/
194
+ ```
195
+
196
+ Use an explicit filename:
197
+
198
+ ```bash
199
+ story-brief --filename brief.md
200
+ ```
201
+
202
+ Overwrite an existing file only when you mean it:
203
+
204
+ ```bash
205
+ story-brief --filename brief.md --force
206
+ ```
207
+
208
+ Run dataset linting without generating a brief:
209
+
210
+ ```bash
211
+ story-brief --lint-dataset
212
+ ```
213
+
214
+ Example clean report:
215
+
216
+ ```text
217
+ Dataset lint: no blocking coverage gaps found.
218
+ Dataset lint: no warnings.
219
+ ```
220
+
221
+ Run strict validation before generation:
222
+
223
+ ```bash
224
+ story-brief --validate-strict --print-only
225
+ ```
226
+
227
+ ## GUI quickstart
228
+
229
+ Start the GUI:
230
+
231
+ ```bash
232
+ telegraphy-gui
233
+ ```
234
+
235
+ Press **GENERATE!** to run the same generator used by the CLI (`python -m telegraphy.story_brief --print-only`).
236
+
237
+ Use the **Seed** and **Date** fields to forward `--seed` and `--date` to the CLI for reproducible GUI runs.
238
+
239
+ Press **COPY!** to copy the most recent successful brief to your clipboard.
240
+
241
+ ## Using the GUI
242
+
243
+ The 0.4.3 GUI is intentionally focused: it is a tablet-shaped desktop wrapper around the existing `story-brief` engine.
244
+
245
+ ### What happens when you click GENERATE!
246
+
247
+ 1. The GUI disables both buttons to avoid overlapping runs.
248
+ 2. It starts a background worker thread so the window stays responsive.
249
+ 3. The worker executes: `python -m telegraphy.story_brief --print-only`.
250
+ 4. On success, the generated Markdown is displayed in the output pane and cached as the latest output.
251
+ 5. On failure, stderr/stdout diagnostics are shown in the output pane and copy is disabled for empty output.
252
+
253
+ ### GUI layout
254
+
255
+ - **Header**: app title and subtitle.
256
+ - **Toolbar**:
257
+ - **GENERATE!**: run generation.
258
+ - **COPY!**: copy last successful output.
259
+ - **Status**: live state (Ready, Generating, Generated, Failed, Copied).
260
+ - **Output pane**: read-only text area with scrollbar showing Markdown output or errors.
261
+
262
+ ### GUI behavior details
263
+
264
+ - Uses your local Python interpreter (`sys.executable`) and inherited environment (`os.environ`) by design; this is convenient for virtualenv workflows, but also means local environment changes can alter behavior.
265
+ - GUI CLI worker has a default 30-second timeout (override with `telegraphy-gui --timeout <seconds>`).
266
+ - `telegraphy-gui --help` is supported without launching a window.
267
+ - In headless environments, startup fails cleanly with a user-facing error instead of a tkinter traceback.
268
+ - Decodes CLI output using your preferred locale encoding, then falls back to UTF-8 with replacement for robust display.
269
+ - Never writes files directly; it always requests `--print-only` output from the CLI.
270
+ - Clipboard copy only works after a successful generation.
271
+
272
+ ### GUI troubleshooting
273
+
274
+ - If `telegraphy-gui` fails to launch, ensure `tkinter` is available in your Python build.
275
+ - If generation fails, read the output pane: the GUI surfaces the underlying CLI error message.
276
+ - For reproducible debugging, run the CLI directly with explicit flags (for example `story-brief --seed 42 --date 2000-01-01 --print-only`).
277
+
278
+ ## CLI examples
279
+
280
+ ### CLI reference
281
+
282
+ | Option | Purpose |
283
+ | --- | --- |
284
+ | `--print-only` | Print Markdown to the terminal and skip file writing. |
285
+ | `--seed <int>` | Use deterministic randomness for reproducible briefs; omit it to use OS-backed entropy. |
286
+ | `--date YYYY-MM-DD` | Force the story date for scenario testing. |
287
+ | `-o, --output-dir <path>` | Choose the output directory. Defaults to `output/story-seeds`. |
288
+ | `--filename <name.md>` | Choose the output filename. |
289
+ | `--force` | Allow overwriting an existing output file. |
290
+ | `--validate-strict` | Validate date-range generation preconditions before generating. |
291
+ | `--lint-dataset` | Run dataset lint diagnostics and exit. |
292
+ | `-h, --help` | Show command help. |
293
+
294
+ ### Print only
295
+
296
+ Use this when you want to copy the generated prompt directly from the terminal.
297
+
298
+ ```bash
299
+ story-brief --print-only
300
+ ```
301
+
302
+ ### Reproducible generation
303
+
304
+ Seeded output is intended for debugging, tests, reviews, and repeatable creative workflows.
305
+
306
+ ```bash
307
+ story-brief --seed 8675309 --print-only
308
+ ```
309
+
310
+ Lock both the random seed and the story date:
311
+
312
+ ```bash
313
+ story-brief --seed 42 --date 2000-01-01 --print-only
314
+ ```
315
+
316
+ That command produces Markdown shaped like this:
317
+
318
+ ```markdown
319
+ ---
320
+ title: It's Only Profound if You're Not Stoned
321
+ protagonist: Cremeans
322
+ secondary_character: Bill Davenport
323
+ time_period: '2000-01-01'
324
+ setting: Lenovo Center - Raleigh, NC, USA
325
+ weather: lousy
326
+ sexual_content_level: none
327
+ sexual_partner: null
328
+ sexual_scene_tags: []
329
+ word_count_target: 6000
330
+ ---
331
+
332
+ # It's Only Profound if You're Not Stoned
333
+
334
+ ## Story Draft
335
+
336
+ *Write a story of approximately 6000 words using the YAML brief above.*
337
+ ```
338
+
339
+ ### Write to a specific directory
340
+
341
+ ```bash
342
+ story-brief --output-dir output/story-seeds
343
+ ```
344
+
345
+ The output directory is resolved under the current working directory. Telegraphy intentionally refuses output paths that escape that tree.
346
+
347
+ ### Pick the filename
348
+
349
+ ```bash
350
+ story-brief --filename "first-pass.md"
351
+ ```
352
+
353
+ Filenames are sanitized and checked for cross-platform safety. Telegraphy rejects path separators, dot-segments, leading or trailing spaces, Windows device names, and other file-system traps.
354
+
355
+ ### Validate before generating
356
+
357
+ ```bash
358
+ story-brief --validate-strict --seed 42 --date 2000-01-01 --print-only
359
+ ```
360
+
361
+ Strict validation checks generation preconditions across the configured date range before creating output.
362
+
363
+ ### Lint the dataset
364
+
365
+ ```bash
366
+ story-brief --lint-dataset
367
+ ```
368
+
369
+ Linting emits a concise report and exits without generating a brief.
370
+
371
+ A clean dataset reports:
372
+
373
+ ```text
374
+ Dataset lint: no blocking coverage gaps found.
375
+ Dataset lint: no warnings.
376
+ ```
377
+
378
+ ## Data override
379
+
380
+ Telegraphy ships with its canonical dataset inside the package:
381
+
382
+ ```text
383
+ telegraphy/story_brief/data/
384
+ ```
385
+
386
+ The packaged dataset contains five required JSON files:
387
+
388
+ ```text
389
+ config.json
390
+ entities.json
391
+ partner_distributions.json
392
+ prompts.json
393
+ titles.json
394
+ ```
395
+
396
+ For experiments, alternate timelines, review fixtures, or private datasets, point Telegraphy at another directory:
397
+
398
+ ```bash
399
+ TELEGRAPHY_DATA_DIR=/absolute/path/to/story-data story-brief --print-only
400
+ ```
401
+
402
+ `TELEGRAPHY_DATA_DIR` is the only supported environment variable override. The legacy `COMMUTED_STORY_BRIEF_DATA_DIR` override was removed and is intentionally ignored.
403
+
404
+ Override directories must:
405
+
406
+ - be absolute paths after optional current-user `~` expansion;
407
+ - already exist;
408
+ - contain all five required JSON files;
409
+ - avoid parent-directory traversal;
410
+ - avoid `~user` expansion;
411
+ - avoid NUL bytes.
412
+
413
+ Only the known dataset filenames are loaded. Telegraphy refuses unknown data-file requests and checks that resolved files remain inside the configured data directory.
414
+
415
+ ### Data-file responsibilities
416
+
417
+ `titles.json` contains title templates. Supported title tokens are:
418
+
419
+ ```text
420
+ @protagonist
421
+ @setting
422
+ @time_period
423
+ ```
424
+
425
+ `entities.json` contains date-bounded character and setting availability.
426
+
427
+ `prompts.json` contains narrative prompt pools such as conflicts, pressures, endings, style guidance, and weather.
428
+
429
+ `config.json` contains schema metadata, dataset version, date range, output key order, word-count targets, sexual-content options and weights, tag groups, and the writing preamble.
430
+
431
+ `partner_distributions.json` contains date-aware weighted partner pools by protagonist. An empty partner list means intentional celibacy for that era. A missing era means absent data and should be treated as a dataset problem.
432
+
433
+ ## Validation and linting
434
+
435
+ Telegraphy has two related safety nets: validation and linting.
436
+
437
+ Validation checks whether the dataset can be loaded and normalized. It rejects malformed schema, missing keys, unsupported title tokens, overlapping availability windows for the same entity, invalid dates, broken weight tables, bad ordered keys, invalid partner distributions, and other hard failures.
438
+
439
+ Strict validation goes farther:
440
+
441
+ ```bash
442
+ story-brief --validate-strict --print-only
443
+ ```
444
+
445
+ It checks date-range generation preconditions at availability checkpoints, including:
446
+
447
+ - at least two distinct available characters for each checked date;
448
+ - at least one available setting for each checked date.
449
+
450
+ Linting looks for dataset coverage gaps and fragile areas:
451
+
452
+ ```bash
453
+ story-brief --lint-dataset
454
+ ```
455
+
456
+ Lint exits with code `0` when no blocking issues are found and code `1` when the report contains errors. Strict validation also exits nonzero on hard failures.
457
+
458
+ Use linting before committing dataset edits. Use strict validation before trusting a new or heavily edited dataset.
459
+
460
+ A good minimum review loop for data changes is:
461
+
462
+ ```bash
463
+ story-brief --lint-dataset
464
+ story-brief --validate-strict --seed 42 --date 2000-01-01 --print-only
465
+ pytest -q tests/story_brief
466
+ ```
467
+
468
+ ## Software bill of materials (SBOM)
469
+
470
+ Telegraphy ships a CycloneDX SBOM at:
471
+
472
+ ```text
473
+ sbom.cdx.json
474
+ ```
475
+
476
+ You can use this file for dependency transparency, supply-chain review, and security tooling that ingests CycloneDX JSON.
477
+
478
+ To regenerate the SBOM after dependency or version changes:
479
+
480
+ ```bash
481
+ python -m telegraphy.scripts.generate_sbom
482
+ ```
483
+
484
+ The repository includes `sbom.cdx.json` in source distributions via `MANIFEST.in`.
485
+
486
+ ## How the generator works
487
+
488
+ Telegraphy follows a small, deliberate pipeline:
489
+
490
+ ```text
491
+ JSON dataset
492
+ -> data_io.load_data()
493
+ -> validation.validate_story_data()
494
+ -> normalized StoryData
495
+ -> generation.pick_story_fields()
496
+ -> rendering.to_markdown()
497
+ -> terminal output or safe Markdown write
498
+ ```
499
+
500
+ The main modules are:
501
+
502
+ | Module | Responsibility |
503
+ | --- | --- |
504
+ | `telegraphy.story_brief.cli` | Argument parsing and CLI orchestration. |
505
+ | `telegraphy.story_brief.data_io` | Dataset discovery, package resources, environment overrides, JSON loading, cache management. |
506
+ | `telegraphy.story_brief.validation` | Schema validation, semantic validation, strict date-range preconditions. |
507
+ | `telegraphy.story_brief.linting` | Dataset coverage diagnostics and human-facing lint reports. |
508
+ | `telegraphy.story_brief.generation` | Date selection, availability filtering, weighted choices, field selection. |
509
+ | `telegraphy.story_brief.partner_models` | Partner-distribution parsing and date-aware weighted partner pools. |
510
+ | `telegraphy.story_brief.rendering` | YAML front matter and Markdown output. |
511
+ | `telegraphy.story_brief.filenames` | Slugging, filename sanitization, output-path safety, write protection. |
512
+ | `telegraphy.story_brief.generate_story_brief` | Compatibility facade over the refactored implementation. |
513
+
514
+ Seeded generation is designed to be stable. When you supply `--seed`, Telegraphy uses a deterministic random source and sorted selection pools so that the same inputs produce the same brief.
515
+
516
+ When no seed is supplied, Telegraphy uses `secrets.SystemRandom`, so unseeded runs draw OS-backed entropy instead of using a deterministic PRNG.
517
+
518
+ ## Output files and safety
519
+
520
+ Telegraphy is conservative about writes.
521
+
522
+ By default it writes into:
523
+
524
+ ```text
525
+ output/story-seeds/
526
+ ```
527
+
528
+ It refuses to overwrite existing files unless `--force` is provided.
529
+
530
+ It confines output to the current working directory tree. This is intentional: generated files should not be able to wander out of the project and bite the furniture.
531
+
532
+ It also performs filename checks and sanitization, including:
533
+
534
+ - cross-platform unsafe characters;
535
+ - path separators;
536
+ - dot-segments;
537
+ - leading or trailing spaces;
538
+ - Windows reserved device names;
539
+ - UTF-8 byte-length limits;
540
+ - optional `O_NOFOLLOW` protection on platforms that provide it.
541
+
542
+ ## Development
543
+
544
+ Create and activate a virtual environment, then install the development extra:
545
+
546
+ ```bash
547
+ python -m pip install -e ".[dev]"
548
+ ```
549
+
550
+ Run the local quality checks:
551
+
552
+ ```bash
553
+ ruff check .
554
+ ruff format .
555
+ mypy telegraphy
556
+ pytest
557
+ ```
558
+
559
+ Install tox if it is not already available:
560
+
561
+ ```bash
562
+ python -m pip install tox
563
+ ```
564
+
565
+ Run the full tox workflow:
566
+
567
+ ```bash
568
+ tox -e py312
569
+ ```
570
+
571
+ Run fast tests only:
572
+
573
+ ```bash
574
+ tox -e py312-fast
575
+ ```
576
+
577
+ Run slow or integration tests:
578
+
579
+ ```bash
580
+ tox -e py312-slow
581
+ ```
582
+
583
+ The repository uses:
584
+
585
+ - Ruff for linting and formatting;
586
+ - mypy in strict mode for the package;
587
+ - pytest for the test suite;
588
+ - pytest-cov and coverage settings for branch coverage;
589
+ - tox for repeatable local test environments;
590
+ - GitHub Actions for CI;
591
+ - SonarQube Cloud for quality reporting.
592
+
593
+ ### GitHub Actions pinning policy
594
+
595
+ This repository has a strong preference for pinning GitHub Actions to immutable commit SHAs.
596
+ Pinned SHAs reduce supply-chain risk from mutable tags and make CI behavior easier to reproduce.
597
+
598
+ Where practical, workflow `uses:` references should follow this style:
599
+
600
+ ```yaml
601
+ - uses: owner/action@<40-character-commit-sha> # v1.2.3
602
+ ```
603
+
604
+ In a small number of cases, we intentionally keep a trusted GitHub-maintained action (for example,
605
+ from the `actions/` or `github/` organizations) on a major tag (for example `@v4`) instead of a SHA.
606
+ When we do this, the trade-off is explicit: the repository chooses to trust GitHub's managed release
607
+ process for that core toolchain, and to accept the small reduction in strict immutability in exchange
608
+ for simpler maintenance.
609
+
610
+ ### Project metadata
611
+
612
+ The package metadata lives in `pyproject.toml`.
613
+
614
+ Current package facts:
615
+
616
+ | Field | Value |
617
+ | --- | --- |
618
+ | Package | `telegraphy` |
619
+ | Current version | `0.4.3` |
620
+ | Python | `>=3.12` |
621
+ | Runtime dependency | `PyYAML>=6.0.3` |
622
+ | Console script | `story-brief = telegraphy.story_brief.cli:main` |
623
+ | License | MIT |
624
+
625
+ ### Contribution expectations
626
+
627
+ Before opening a pull request, run the relevant checks and include the commands you ran in the PR notes.
628
+
629
+ For code changes, include tests that cover success and failure behavior.
630
+
631
+ For dataset changes, keep diffs focused and run:
632
+
633
+ ```bash
634
+ story-brief --lint-dataset
635
+ story-brief --validate-strict --print-only
636
+ ```
637
+
638
+ For generation changes, preserve deterministic seeded behavior unless the PR explicitly and intentionally changes it.
639
+
640
+ ## Release notes and status
641
+
642
+ Current status: `0.4.3`.
643
+
644
+ This release establishes the 0.4.3 line, preparing for PyPI Trusted Publishing plus follow-up build consistency updates across metadata, docs, and SBOM artifacts.
645
+
646
+ Highlights:
647
+
648
+ - launched the desktop `telegraphy-gui` command with a tablet-style interface backed by the existing CLI engine;
649
+ - strengthened GUI reliability with threaded generation flow, robust subprocess decode fallback, and expanded GUI unit coverage;
650
+ - kept package metadata, changelog references, README status text, and SBOM artifact versioning aligned for build consistency.
651
+
652
+ See [CHANGELOG.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/CHANGELOG.md) for release notes.
653
+
654
+ ### Stability note
655
+
656
+ Telegraphy is usable as a local CLI and developer tool. The command-line interface and data schema are still young enough that maintainers should treat changes carefully and document migration impact in PRs.
657
+
658
+ No published package distribution is assumed by this README. Install from the repository unless and until a release workflow says otherwise.
659
+
660
+ ## Maintainer docs
661
+
662
+ Start here:
663
+
664
+ - [CONTRIBUTING.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/CONTRIBUTING.md): development setup, local checks, pull-request expectations.
665
+ - [CHANGELOG.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/CHANGELOG.md): release notes.
666
+ - [GREETINGS.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/GREETINGS.md): lightweight project-facing documentation artifact.
667
+ - [SECURITY.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/SECURITY.md): vulnerability reporting.
668
+ - [docs/STORY-BRIEF-MAINTAINER.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/STORY-BRIEF-MAINTAINER.md): data strategy, regression coverage, dataset versioning, and maintenance rules.
669
+ - [docs/Story Brief Generator Evaluation.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/Story%20Brief%20Generator%20Evaluation.md): current evaluation and constructive criticism.
670
+ - [docs/requirements.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/requirements.md): runtime dependency policy.
671
+ - [docs/requirements-dev.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/requirements-dev.md): development dependency policy.
672
+ - [docs/dependabot_setup.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/dependabot_setup.md): dependency update automation.
673
+ - [docs/review_2026-04-27.md](https://github.com/jeffreywevans/Telegraphy/blob/HEAD/docs/review_2026-04-27.md): code review notes and known follow-up items.
674
+
675
+ ## Troubleshooting
676
+
677
+ ### `story-brief` is not found
678
+
679
+ Install the package in the current environment:
680
+
681
+ ```bash
682
+ python -m pip install -e .
683
+ ```
684
+
685
+ For development:
686
+
687
+ ```bash
688
+ python -m pip install -e ".[dev]"
689
+ ```
690
+
691
+ Then retry:
692
+
693
+ ```bash
694
+ story-brief --help
695
+ ```
696
+
697
+ ### The selected date is rejected
698
+
699
+ The date must be inside the configured dataset range. Use ISO format:
700
+
701
+ ```bash
702
+ story-brief --date 2000-01-01 --print-only
703
+ ```
704
+
705
+ ### The data override is rejected
706
+
707
+ Check that the override is absolute and contains the required JSON files:
708
+
709
+ ```bash
710
+ ls /absolute/path/to/story-data
711
+ ```
712
+
713
+ Expected files:
714
+
715
+ ```text
716
+ config.json
717
+ entities.json
718
+ partner_distributions.json
719
+ prompts.json
720
+ titles.json
721
+ ```
722
+
723
+ ### An output file already exists
724
+
725
+ Telegraphy will not overwrite files by accident. Use another filename or pass `--force`:
726
+
727
+ ```bash
728
+ story-brief --filename brief.md --force
729
+ ```
730
+
731
+ ### Output path is rejected
732
+
733
+ Keep `--output-dir` inside the current working directory tree. Absolute paths are allowed only when they resolve inside that tree.
734
+
735
+ ### Linting passes but generation still fails
736
+
737
+ Run strict validation:
738
+
739
+ ```bash
740
+ story-brief --validate-strict --print-only
741
+ ```
742
+
743
+ Linting reports dataset health. Strict validation checks generation preconditions across key date boundaries.
744
+
745
+ ## License
746
+
747
+ Telegraphy is released under the [MIT License](https://github.com/jeffreywevans/Telegraphy/license).