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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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