Add JSON output format and a separate interpreter binary
deck-engine gains --format json (language-independent, slug-based) so a new dist/interpreter-cli can score how significant a day's transits are without linking the engine itself — it depends only on the JSON shape, via its own minimal parser. Also documents the full reading pipeline end to end (CLAUDE.md, README, docs/) and adds docs/reading.md, a non-technical explanation of what a daily reading contains and means.
This commit is contained in:
@@ -33,7 +33,7 @@ Two ways to run a reading:
|
||||
dist/deck-engine --seed "2026-07-03" \
|
||||
--birth-date 1990-05-14 --birth-time 14:32 --birth-utc-offset 2 \
|
||||
--birth-lat 52.5200 --birth-lon 13.4050 \
|
||||
[--date YYYY-MM-DDTHH:MM] [--format text|html] [--lang en|de] [--i18n-dir <path>]
|
||||
[--date YYYY-MM-DDTHH:MM] [--format text|html|json] [--lang en|de] [--i18n-dir <path>]
|
||||
|
||||
# 2. dist/run.sh [text|html] [lang] — wraps the binary for daily use: seed
|
||||
# and --date come from the OS clock (today's date / current UTC time),
|
||||
@@ -76,6 +76,7 @@ deck_in_a_dash/
|
||||
tests/smoke_test.c
|
||||
scripts/run.sh, scripts/user.properties.template
|
||||
Makefile
|
||||
interpreter/ Separate module + binary; see "Interpretation" below.
|
||||
dist/ Build output (gitignored-style; see Build & run).
|
||||
```
|
||||
|
||||
@@ -181,6 +182,73 @@ into the Pebble watchapp unchanged later. Only `reading_print_text`/
|
||||
`_html` (text formatting), `main.c` (CLI arg parsing), and `i18n_load`
|
||||
(reads a file from disk) are desktop-only and won't port as-is.
|
||||
|
||||
## Interpretation (`interpreter/`)
|
||||
|
||||
A second, separate top-level module and **its own binary**
|
||||
(`dist/interpreter-cli`, sibling to `dist/deck-engine`) that scores *how
|
||||
significant a day's transits are* — the first piece of a larger "turn the
|
||||
raw reading into an actual narrative" effort described in project chat
|
||||
history, not yet producing any narrative text. `deck-engine` itself is
|
||||
deliberately unchanged by this beyond gaining `--format json`; the two
|
||||
binaries compose over that JSON, never by linking together:
|
||||
|
||||
```bash
|
||||
cd engine && make # -> dist/deck-engine (unchanged; --format json is new)
|
||||
cd interpreter && make # -> dist/interpreter-cli
|
||||
cd interpreter && make test # builds and runs both interpreter/tests/*_test.c
|
||||
|
||||
dist/deck-engine ... --format json | dist/interpreter-cli
|
||||
# or: dist/deck-engine ... --format json > reading.json && dist/interpreter-cli reading.json
|
||||
```
|
||||
|
||||
- `interpret_daily_reading(reading, &out)` (`significance.h/.c`) scores
|
||||
every aspect in `reading->transits.aspects[]`, keeps the **top 5** by
|
||||
score in `DailyInterpretation.top_items[]` (descending, evicting the
|
||||
rest), and classifies the day into a `DaySignificance` enum (`DAY_QUIET`
|
||||
... `DAY_MAJOR`) from the single highest-scoring item.
|
||||
`interpretation_deserves_framing()` is true only at `DAY_MAJOR` — the
|
||||
intended hook for giving the Celtic Cross reading a "this matters"
|
||||
intro sentence naming `top_items[0]` on days that earn it; that
|
||||
rendering doesn't exist yet, `main.c`'s report is plain text only.
|
||||
- Score = `transiting-planet weight (slow/outer planets score higher) ×
|
||||
orb tightness (1.0 = exact, ~0 = at the edge) × natal-luminary bonus
|
||||
(transits to natal Sun/Moon score higher than to other planets)`. The
|
||||
weights and the `DAY_QUIET`/`DAY_NOTABLE`/`DAY_SIGNIFICANT`/`DAY_MAJOR`
|
||||
thresholds in `significance.c` are hand-tuned, not derived from
|
||||
anything physical — expect to retune them once real readings are
|
||||
compared against how "major" a day actually feels.
|
||||
- **`reading_print_json`** (`engine/src/reading.c`) is the wire format:
|
||||
the full `DailyReading` (natal, transits, spread), using the
|
||||
language-independent `astro_*_slug()`/`tarot_*_slug()` accessors
|
||||
(`astro.h`/`tarot.h`) rather than `astro_*_name()`/`tarot_*_name()` —
|
||||
the JSON must stay identical regardless of `--lang`, since it's a
|
||||
machine interchange format, not display text.
|
||||
- **`json.c`/`json.h`** is a small hand-rolled recursive-descent JSON
|
||||
parser (object/array/string/number/bool/null) - not a general-purpose
|
||||
validating library, just enough to parse `deck-engine`'s own output.
|
||||
Unlike the core engine, it uses `malloc`; `interpreter-cli` was never
|
||||
meant to run on the watch itself.
|
||||
- **`reading_io.c`** walks the parsed JSON down to `"transits"."aspects"`
|
||||
and fills a `DailyReading` with just that (everything else is left
|
||||
zeroed - `interpret_daily_reading` doesn't read `natal`/`spread`
|
||||
either). An aspect naming a planet/aspect-type slug it doesn't
|
||||
recognize, or a document missing `"transits"."aspects"` entirely (as
|
||||
opposed to a present-but-empty array, which is a valid "no aspects
|
||||
today"), makes the whole load fail rather than silently dropping data.
|
||||
- **Deliberately header-only dependency on the engine, throughout**:
|
||||
`significance.h`/`reading_io.h` `#include engine/src/reading.h` for the
|
||||
struct/enum *definitions*, but `interpreter/Makefile` never compiles or
|
||||
links any engine `.c` file (or the vendored Astronomy Engine) — every
|
||||
test in `interpreter/tests/` runs against hand-built JSON text or
|
||||
hand-built `DailyReading` values, with no real ephemeris/tarot-draw
|
||||
call involved anywhere. Consequently `reading_io.c` (planet/aspect
|
||||
slugs) and `main.c` (planet/aspect display names) each duplicate a
|
||||
small local table rather than linking `astro.c` to reuse its own -
|
||||
keep those in sync if the engine's slugs/names ever change.
|
||||
- Only `Aspect`s compete for the top 5 so far (`SignificantItemKind` is
|
||||
currently just `ITEM_ASPECT`); moon phase and house ingresses are
|
||||
candidate future item kinds but aren't scored yet.
|
||||
|
||||
## Licensing
|
||||
|
||||
- Engine code (`engine/src/`, `engine/scripts/`, `engine/Makefile`):
|
||||
|
||||
Reference in New Issue
Block a user