Set the Game Clock — ephemeris narrowing (hard CSP): placements shrink the REAL date window; narrowed range prints below the prompt; unreachable signs dim + reject — TDD
- PySwiss gains its FIRST reverse lookup: GET /api/windows/?placements=
Uranus:Aquarius,…&next=Saturn — sign_windows (per-planet stride scan +
bisection edge refine to the hour) folds thru narrowed_windows
(slowest planet first, each scan restricted to the prior intersection
so the fast bodies only ever scan slivers) over the game window
(settings GAME_WINDOW_START/END, default 1781-03-13 — Uranus's
discovery — → 2100-12-31, the snapshot span); present_signs reports
the next planet's reachable signs. Self-validating UTs (every window
forward-checked at midpoint + edges) + 8 API ITs
- epic clock_windows endpoint (lazy, table_sky-shaped — room views stay
HTTP-free) proxies the lookup, cached per room+placements (six felts
polling one ritual state = ONE upstream call; failures cached 60s);
fails OPEN {available:false} when PySwiss is unreachable
- place_clock_planet enforces the HARD constraint: a sign outside the
narrowed windows' reach → 409 sign_unreachable; fail-open w.o PySwiss
(the ritual never bricks on microservice downtime); PlaceClockPlanet
ITs sever PySwiss in setUp so the turn walk stays deterministic
against a live local service
- felt: #id_clock_windows readout below the prompt for ALL viewers —
"1995-04-01 → 1998-04-17 · 2 windows" — fetched at parse + after own
placement + on every clock_placement broadcast; drawRim opts gain
allowedSigns → unreachable wedges .nw-sign--blocked (dimmed, inert,
no handlers); SkyWheelSpec R10/R11
- SeedMapClockNarrowingTest FT stubs PySwiss in-process (real proxy,
real gating): readout renders, blocked Aries won't place, allowed
Pisces lands Saturn, readout re-narrows
[[project-voronoi-spec]]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,12 +5,19 @@ from timezonefinder import TimezoneFinder
|
||||
|
||||
import swisseph as swe
|
||||
|
||||
from django.conf import settings as django_settings
|
||||
|
||||
from .calc import (
|
||||
DEFAULT_HOUSE_SYSTEM,
|
||||
PLANET_CODES,
|
||||
SIGNS,
|
||||
calculate_aspects,
|
||||
get_element_counts,
|
||||
get_julian_day,
|
||||
get_planet_positions,
|
||||
jd_to_iso,
|
||||
narrowed_windows,
|
||||
present_signs,
|
||||
set_ephe_path,
|
||||
)
|
||||
from .models import EphemerisSnapshot
|
||||
@@ -68,6 +75,53 @@ def chart(request):
|
||||
})
|
||||
|
||||
|
||||
def windows(request):
|
||||
"""GET /api/windows/ — REVERSE ephemeris lookup (Set the Game Clock).
|
||||
|
||||
Query params:
|
||||
placements — comma list of Planet:Sign pairs (may be absent/empty)
|
||||
next — planet name; report which signs it can reach in the windows
|
||||
|
||||
Folds each placement's sign residences into the intersected date windows
|
||||
where ALL placements hold simultaneously, bounded by the game window
|
||||
(settings GAME_WINDOW_START/END — defaults span the precomputed snapshot
|
||||
range: 1781-03-13, Uranus's discovery year, → 2100-12-31).
|
||||
|
||||
Returns {windows: [{start, end}…], days, next?: {planet, signs: {sign:
|
||||
bool ×12}}} 200 · 400 on an unknown planet/sign or malformed pair.
|
||||
"""
|
||||
placements = {}
|
||||
for pair in [p for p in request.GET.get('placements', '').split(',') if p]:
|
||||
planet, sep, sign = pair.partition(':')
|
||||
if not sep or planet not in PLANET_CODES or sign not in SIGNS:
|
||||
return HttpResponse(status=400)
|
||||
placements[planet] = sign
|
||||
next_planet = request.GET.get('next') or None
|
||||
if next_planet is not None and next_planet not in PLANET_CODES:
|
||||
return HttpResponse(status=400)
|
||||
|
||||
set_ephe_path()
|
||||
start = getattr(django_settings, 'GAME_WINDOW_START', '1781-03-13')
|
||||
end = getattr(django_settings, 'GAME_WINDOW_END', '2100-12-31')
|
||||
base = [(
|
||||
get_julian_day(datetime.fromisoformat(start).replace(tzinfo=timezone.utc)),
|
||||
get_julian_day(datetime.fromisoformat(end).replace(tzinfo=timezone.utc)),
|
||||
)]
|
||||
wins = narrowed_windows(placements, base)
|
||||
|
||||
payload = {
|
||||
'windows': [{'start': jd_to_iso(a), 'end': jd_to_iso(b)} for a, b in wins],
|
||||
'days': round(sum(b - a for a, b in wins), 2),
|
||||
}
|
||||
if next_planet:
|
||||
reachable = present_signs(next_planet, wins)
|
||||
payload['next'] = {
|
||||
'planet': next_planet,
|
||||
'signs': {s: s in reachable for s in SIGNS},
|
||||
}
|
||||
return JsonResponse(payload)
|
||||
|
||||
|
||||
_tf = TimezoneFinder()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user