FAILURE MAP
← Case archive

FA-69696 / Orbital propagation / Open access

Cylindrical Earth shadow test: Shadow test uses the along-axis distance · case 01

Satellites far behind Earth are shadowed even when well off the axis.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The umbra test compares |d| with R instead of the perpendicular distance.

THE FAILURE

The umbra test compares |d| with R instead of the perpendicular distance.

Unsuccessful approach: Comparing the full radius |r| with R never finds shadow.

Case contract

Input [r, s, R]: satellite position, sun direction (any length) and body radius. With u=s/|s| and d=r.u, the satellite is sunlit when d>=0; otherwise it is in umbra when the distance of r from the shadow axis |r-d u| is <= R. Return "umbra" or "sunlit".

Why this case matters

Orbit determination and mission planning chain many small conversions; one wrong branch or unit silently moves a spacecraft by kilometres.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    r,s,R=x
    sn=math.sqrt(sum(c*c for c in s))
    u=[c/sn for c in s]
    d=sum(a*b for a,b in zip(r,u))
    if d>=0: return 'sunlit'
    perp=[a-d*b for a,b in zip(r,u)]
    return 'umbra' if abs(d)<=R else 'sunlit'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra')], [('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit')], [('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0]', [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0]', [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0], 'umbra')], [('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0]', [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0]', [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra')], [('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit')]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]sunlitumbraFailed

SHA-256 / 424d3551eca6ee7676dc74e8005cd5841427b9d5e79d7bb461a8aa0cf45022a0

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    r,s,R=x
    sn=math.sqrt(sum(c*c for c in s))
    u=[c/sn for c in s]
    d=sum(a*b for a,b in zip(r,u))
    if d>=0: return 'sunlit'
    perp=[a-d*b for a,b in zip(r,u)]
    return 'umbra' if math.sqrt(sum(c*c for c in r))<=R else 'sunlit'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra')], [('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit')], [('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0]', [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0]', [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0], 'umbra')], [('cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]', [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-100.0, 7000.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0]', [[-42164.0, 0.0, 6000.0], [0.0, 0.0, 0.0001], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0]', [[3000.0, -7000.0, 0.0], [0.0, 0.5, 0.5], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra')], [('cylindrical earth shadow test [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0]', [[-5000.0, -5000.0, 1000.0], [3.0, 4.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]', [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0], 'sunlit'), ('cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'umbra'), ('cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]', [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0], 'sunlit')]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
cylindrical earth shadow test [[-7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[7000.0, 100.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[-7000.0, 6378.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[-7000.0, 6400.0, 0.0], [1.0, 0.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[0.0, -8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]sunlitumbraFailed
cylindrical earth shadow test [[0.0, 8000.0, 500.0], [0.0, 2.0, 0.0], 6378.0]sunlitsunlitPassed
cylindrical earth shadow test [[5000.0, 5000.0, 0.0], [-3.0, -4.0, 0.0], 6378.0]sunlitumbraFailed

SHA-256 / 698b2e9311fb0847f8b320c2d17ee9f970e2849003d501f6c0d9e8309b6ff0fa

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

Verification & scope

A deterministic toy two-body model with stipulated constants and conventions; not flight dynamics software or a validated SGP4 implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:48:13.831705+00:00.

Case digest / b1f6fcf79ad0de8310408c54917811567ac970788e2d18c702b3e39923d9fe88