Symptom
`opena2a check express --json` returns:
```json
{
"score": 100,
"maxScore": 100,
"trustLevel": 2,
"trustScore": 0.67,
"verdict": "listed",
"scanStatus": "pending"
}
```
Three score-shaped numbers, three different scales, two different sources, no documented relationship:
- `score: 100` — derived from local scan
- `trustScore: 0.67` — registry-derived, 0..1 fractional
- `trustLevel: 2` — registry-derived, 1..5 ordinal
- `scanStatus: pending` makes `score: 100` meaningless (a perfect score for an unscanned package)
A consumer cannot pick which one to gate CI on without reading source.
Why this matters
UX standard rule 5 (score sanity) and rule 7 (machine-readable JSON schema is documented and self-consistent).
Suggested fix
Two options:
-
Document the relationship — pick one canonical `score` field on the response, mark the others as `_legacy` or remove them in the next breaking version. Add a JSDoc-level schema in `packages/cli/src/types/check-json.ts` (create if missing).
-
Unify the representation — collapse `trustScore` (0..1) and `trustLevel` (1..5) into a single 0..100 `registryScore`, keep `score` for the local-scan derivation, and add a top-level `compositeScore` that applies a documented function over both.
Recommend (1) for this release window. (2) is a 1.0.0 break.
`scanStatus: 'pending'` returning `score: 100` is its own bug — when the package has not been scanned, the score should be `null` or omitted, not 100.
Reproduction
`opena2a check express --json` for any package without a recent scan.
Surfaced by
opena2a-cli UX audit, 2026-04-29 (audit row 3 / bug M).
Symptom
`opena2a check express --json` returns:
```json
{
"score": 100,
"maxScore": 100,
"trustLevel": 2,
"trustScore": 0.67,
"verdict": "listed",
"scanStatus": "pending"
}
```
Three score-shaped numbers, three different scales, two different sources, no documented relationship:
A consumer cannot pick which one to gate CI on without reading source.
Why this matters
UX standard rule 5 (score sanity) and rule 7 (machine-readable JSON schema is documented and self-consistent).
Suggested fix
Two options:
Document the relationship — pick one canonical `score` field on the response, mark the others as `_legacy` or remove them in the next breaking version. Add a JSDoc-level schema in `packages/cli/src/types/check-json.ts` (create if missing).
Unify the representation — collapse `trustScore` (0..1) and `trustLevel` (1..5) into a single 0..100 `registryScore`, keep `score` for the local-scan derivation, and add a top-level `compositeScore` that applies a documented function over both.
Recommend (1) for this release window. (2) is a 1.0.0 break.
`scanStatus: 'pending'` returning `score: 100` is its own bug — when the package has not been scanned, the score should be `null` or omitted, not 100.
Reproduction
`opena2a check express --json` for any package without a recent scan.
Surfaced by
opena2a-cli UX audit, 2026-04-29 (audit row 3 / bug M).