FAILURE MAP
← Case archive

FA-12176 / Astronomical coordinate conventions / Open access

A FITS CD matrix receives the CDELT axis scale a second time · case 01

A FITS CD matrix receives the CDELT axis scale a second time.

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

ROOT CAUSE

The adapter treats CD and PC as equivalent dimensionless matrices.

THE FAILURE

The adapter treats CD and PC as equivalent dimensionless matrices.

Unsuccessful approach: Ignoring CDELT universally fixes CD headers but breaks PC headers.

Case contract

Reduced two-axis linear FITS WCS model: delta is pixel offset, matrix is CD or PC according to mode. CD maps directly; PC requires output-row scaling by scale. Return two intermediate world coordinates, before sky projection.

Why this case matters

Astronomical coordinate adapters must preserve convention semantics. Primary background: https://docs.astropy.org/en/stable/api/astropy.wcs.Wcsprm.html

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(delta, matrix, scale, mode):
    return [scale[i]*sum(matrix[i][j]*delta[j] for j in range(2)) for i in range(2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('CD includes scale', solve([N,2], [[2,1],[1,3]], [5,7], "CD"), [2*N+2,N+6])
check('PC needs row scales', solve([N,2], [[2,1],[1,3]], [5,7], "PC"), [10*N+10,7*N+42])
check('reference pixel', solve([0,0], [[2,1],[1,3]], [5,7], "PC"), [0,0])
check('unit scales', solve([N,2], [[2,1],[1,3]], [1,1], "PC"), [2*N+2,N+6])
check('negative axis scale', solve([N,2], [[1,0],[0,1]], [-2,3], "PC"), [-2*N,6])
check('CD ignores stale scale', solve([N,2], [[1,0],[0,1]], [0,0], "CD"), [N,2])
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
CD includes scale[20, 49][4, 7]Failed
PC needs row scales[20, 49][20, 49]Passed
reference pixel[0, 0][0, 0]Passed
unit scales[4, 7][4, 7]Passed
negative axis scale[-2, 6][-2, 6]Passed
CD ignores stale scale[0, 0][1, 2]Failed

SHA-256 / 017516ae817b2deb35e4db8d9f7ca35481fecd7c3445a2aab076a8e3536c0e6f

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(delta, matrix, scale, mode):
    return [sum(matrix[i][j]*delta[j] for j in range(2)) for i in range(2)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('CD includes scale', solve([N,2], [[2,1],[1,3]], [5,7], "CD"), [2*N+2,N+6])
check('PC needs row scales', solve([N,2], [[2,1],[1,3]], [5,7], "PC"), [10*N+10,7*N+42])
check('reference pixel', solve([0,0], [[2,1],[1,3]], [5,7], "PC"), [0,0])
check('unit scales', solve([N,2], [[2,1],[1,3]], [1,1], "PC"), [2*N+2,N+6])
check('negative axis scale', solve([N,2], [[1,0],[0,1]], [-2,3], "PC"), [-2*N,6])
check('CD ignores stale scale', solve([N,2], [[1,0],[0,1]], [0,0], "CD"), [N,2])
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
CD includes scale[4, 7][4, 7]Passed
PC needs row scales[4, 7][20, 49]Failed
reference pixel[0, 0][0, 0]Passed
unit scales[4, 7][4, 7]Passed
negative axis scale[1, 2][-2, 6]Failed
CD ignores stale scale[1, 2][1, 2]Passed

SHA-256 / d99efc815a4cd89b14b606099a4330c52afb3f97653037fda7f8fc6c5a22a793

HELD IN THE MEMBER ARCHIVE

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

This mechanism has 6 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

Reduced deterministic algebraic model only; no ephemeris, full sky projection, or physical accuracy claims. 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:38:54.494566+00:00.

Case digest / fa56f8da276f3fcd2c0114eecc4e173fa8be1cc2c3252b6f6645ed603415e732