Skip to content

worldgen: -format text|json, dice-consumption invariant across formats - #372

Merged
philoserf merged 2 commits into
mainfrom
issue-360-json-output
Aug 5, 2026
Merged

worldgen: -format text|json, dice-consumption invariant across formats#372
philoserf merged 2 commits into
mainfrom
issue-360-json-output

Conversation

@philoserf

Copy link
Copy Markdown
Owner

Summary

  • -format json on cmd/worldgen emits one record per line: raw UWP characteristics plus the rendered uwp convenience string and trade codes.
  • Scope note: the issue's source (../traveller-worldgen) suggested worldgen.World.MarshalJSON, but cmd/worldgen only ever builds a bare uwp.Profile (worldgen.Generate), never a full WorldGenerateWorld needs system context (gas giants, belts, capital status) this command doesn't have and would have to fabricate. So the JSON shape here is CLI-local (jsonWorld); a World-level shape waits for a consumer that actually builds one (systemgen, survey), matching the issue's own "extend as consumers appear." pbg isn't renderable at World granularity either way (belts/giants are system-level, per SecondSurvey's own doc comment), and ru (from the issue's key list) maps to nothing in this repo's model.
  • The one thing that mattered most: -format must not change what gets generated or how many dice get drawn — -seed 42 -format json and -seed 42 -format text must describe the same worlds. TestFormatIsDiceInvariant checks the JSON records' UWPs equal the text lines' UWPs, in order; verified adversarially (simulated an extra roll on the JSON-only path, confirmed the test fails, reverted).
  • Golden fixture for the JSON output via clitest — golden stdout fixtures with -update for the formatting-heavy CLIs #361's clitest harness.
  • README documents -format in prose only, not a new fenced sample — ReadmeBlock's marker matching is substring-based and takes the first hit, so adding a JSON sample risked colliding with the existing text sample's marker.
  • Fixed a now-stale CLAUDE.md claim ("no test pins CLI output") that clitest — golden stdout fixtures with -update for the formatting-heavy CLIs #361 had already made false.

Closes #360.

Test plan

  • task check (lint + full test suite) green
  • Manually compared -format text and -format json output for the same seed
  • Adversarially confirmed TestFormatIsDiceInvariant fails on a real dice-consumption regression

Adapted from ../traveller-worldgen's cmd/worldgen (#360), scoped down to
what this command actually generates. t5 emits no machine-readable format
anywhere, so anything downstream of the record stream must re-parse
fixed-width text.

- -format json emits one record per line: raw UWP characteristics
  (starport, size, atmosphere, hydrographics, population, government, law,
  techLevel) plus the rendered "uwp" convenience string and trade codes.
- The shape is CLI-local (jsonWorld in cmd/worldgen), not
  worldgen.World.MarshalJSON: this command only ever builds a bare
  uwp.Profile (worldgen.Generate), never a full World — GenerateWorld needs
  system context (gas giants, belts, capital status) this command doesn't
  have and would have to fabricate to call it. A World-level JSON shape
  waits for a consumer that actually builds one (systemgen, survey), per
  the issue's own "extend as consumers appear." pbg isn't renderable at
  World granularity either way (belts/giants are system-level, per
  SecondSurvey's own doc comment).
- -format never changes what is generated or how many dice a world draws —
  only how the same records render, so the same -seed names the same
  worlds under either format. TestFormatIsDiceInvariant is the one test
  that would catch a regression to a roll-hungrier JSON path; verified
  adversarially (a simulated extra roll on the json-only path made it fail
  before being reverted).
- Golden fixture for -format json output, via #361's clitest harness.
- README's flag list documents -format in prose only (no new fenced
  sample): ReadmeBlock's marker matching is substring-based and takes the
  first hit, so a JSON sample line risks colliding with the existing text
  sample's marker.
- Updated CLAUDE.md's now-stale claim that "no test pins CLI output" —
  #361 already closed that.

Co-Authored-By: Claude
Copilot AI lite review requested due to automatic review settings August 5, 2026 20:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a machine-readable JSON output mode to the cmd/worldgen CLI while explicitly preserving the repo’s reproducibility contract: output format must not affect generation or dice consumption. This fits the broader CLI ecosystem that treats stdout as a stream of records and stderr as diagnostics/seed reporting.

Changes:

  • Add -format text|json to cmd/worldgen, emitting one JSON record per generated world (one per line) when json is selected.
  • Add golden fixture coverage for JSON output and a regression test ensuring -format does not change generated UWPs (dice-consumption invariance).
  • Update README and CLAUDE.md documentation to reflect the new format option and existing golden/README-parity testing guarantees.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Documents worldgen -format text|json and the dice-invariance guarantee.
cmd/worldgen/main.go Implements -format flag and JSON streaming output for generated worlds.
cmd/worldgen/main_test.go Extends CLI rejection tests to include invalid -format values.
cmd/worldgen/golden_test.go Adds JSON golden fixture and format/dice-invariance test.
cmd/worldgen/testdata/n3seed42-json.txt Golden fixture for -format json output.
CLAUDE.md Updates repo documentation to reflect current test coverage and new worldgen format behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/worldgen/main.go
Correct — verified. uwp.Profile.String() already guards an invalid/zero
Starport byte down to '?' (formatStarport's own doc comment: "the zero
value, whose unset Starport would otherwise emit a NUL into a piped
record stream"), but the JSON path read p.Starport directly, bypassing
that guard. Fixed by deriving Starport from the already-guarded p.String()
output instead of the raw byte. No fixture change: a valid Starport
renders identically either way.

Co-Authored-By: Claude
@philoserf
philoserf merged commit ddf56e4 into main Aug 5, 2026
1 check passed
@philoserf
philoserf deleted the issue-360-json-output branch August 5, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli — JSON output format for generator CLIs

2 participants