Add narrative text and a day-significance rank to the interpreter

Each of the day's top significant transits now gets a short sentence
describing what it classically means and which area of life its house
governs, condensed from Sepharial's Transits and Planetary Periods
(1920, public domain) plus a small table of traditional house
significations. The day-level line also shows its rank out of the 4
defined levels, e.g. "Notable (2/4)". Docs (CLAUDE.md, README,
docs/input-output-format.md, docs/reading.md) updated to match,
including a full worked example in docs/reading.md.
This commit is contained in:
ml
2026-07-05 21:05:53 +02:00
parent 1136e3257a
commit 41422adf98
11 changed files with 476 additions and 41 deletions
+53 -15
View File
@@ -71,7 +71,10 @@ deck_in_a_dash/
res/ Tarot card art (22 RWS Major Arcana JPEGs),
Waite's "Pictorial Key to the Tarot" (PDF,
public domain — source of all card/spread
text), logo, research notes.
text), Sepharial's "Transits and Planetary
Periods" (PDF, public domain — source of
interpreter/src/narrative.c's text), logo,
research notes.
engine/
third_party/astronomy/ Vendored cosinekitty/astronomy C library
(MIT, pinned commit — see VENDORED.md).
@@ -199,11 +202,14 @@ into the Pebble watchapp unchanged later. Only `reading_print_text`/
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:
significant a day's transits are* and, for each of the top items, prints
a short narrative sentence about what that transit classically means —
the first piece of a larger "turn the raw reading into an actual
narrative" effort described in project chat history; the Celtic Cross
spread itself isn't woven into that narrative yet (see
`docs/reading.md`). `deck-engine` itself is deliberately unchanged by
this beyond gaining `--format json`; the two binaries compose over that
JSON, never by linking together:
```bash
make # -> dist/deck-engine (unchanged; --format json is new) and dist/interpreter-cli
@@ -223,11 +229,15 @@ between the two binaries (see the next bullet).
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.
... `DAY_MAJOR`) from the single highest-scoring item. The enum also
carries a trailing `DAY_SIGNIFICANCE_COUNT` sentinel (not a real level)
purely so callers can print the level as a rank, e.g. `main.c`'s
`"%s (%d/%d)"``"Notable (2/4)"``interp.day_level + 1` out of
`DAY_SIGNIFICANCE_COUNT`. `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
@@ -235,6 +245,29 @@ between the two binaries (see the next bullet).
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.
- **`narrative.c`/`narrative.h`** supplies `main.c`'s one-sentence
description printed under each top item, condensed from Sepharial's
*Transits and Planetary Periods* (1920, public domain —
`res/Transits_and_Planetary_Periods.pdf`), Chapter VIII "Effects of
Transits". Per transiting planet it holds a `base` description plus a
`harmonious`/`discordant` addendum, shown only under a trine/sextile or
square/opposition respectively (either may be `""` if the source gives
none); a conjunction is treated as neutral — base only — since
Sepharial's own text says a conjunction "takes the nature of what it
conjoins," which isn't modelled here. The Moon and Pluto aren't in that
chapter (fast lunar transits were out of scope for a year-ahead
forecasting book; Pluto wasn't discovered until 1930) — their text is
original, written for this project, not drawn from Sepharial. Each
narrative is also framed by *where* it's happening: `narrative_print()`
takes the transiting planet's whole-sign house (1-12, relative to the
natal chart, same as everywhere else in this codebase) and prefixes an
"In matters of ..." line naming that house's traditional area of life,
from a small `k_house_area[12]` table of standard whole-sign house
significations — centuries-old convention, not attributed to any single
source (same status as the sign/aspect names already in `astro.c`).
Passing a house outside 1-12 (the same "no data" sentinel `reading_io.c`
uses elsewhere) omits that framing and prints the planet's narrative on
its own.
- **`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
@@ -261,10 +294,11 @@ between the two binaries (see the next bullet).
it before printing sign/house), since that's supplementary display
context rather than something scoring depends on.
- **Deliberately header-only dependency on the engine, throughout**:
`significance.h`/`reading_io.h` `#include engine/src/reading.h` for the
struct/enum *definitions*, but the root `Makefile` never compiles or
links any engine `.c` file (or the vendored Astronomy Engine) into the
interpreter's binary or tests — every
`significance.h`/`reading_io.h`/`narrative.h` `#include` engine headers
(`reading.h`/`astro.h`) for the struct/enum *definitions*, but the root
`Makefile` never compiles or links any engine `.c` file (or the
vendored Astronomy Engine) into the interpreter's binary or tests —
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/sign
@@ -287,3 +321,7 @@ between the two binaries (see the next bullet).
- `engine/i18n/de.lang`'s card/spread text is an original translation of
that same public-domain English text, made for this project — not
taken from any specific published German edition.
- Transit narrative text in `interpreter/src/narrative.c`: condensed from
Sepharial's *Transits and Planetary Periods* (1920, public domain —
`res/Transits_and_Planetary_Periods.pdf`), except the Moon and Pluto
entries, which are original (see narrative.c's own comment for why).