basecamp / basecamp/basecamp-sdk
check-fixture-coverage cannot see a fabricated key, and search/results.json still carries the unroutable gauge URLs
- Dominant language
- Go
- Stars
- 49
- Forks
- 12
- Avg merge
- 20h 47m
- Merged PRs (30d)
- 89
Description
Two related findings from the #719 gauge work. Both are about the same blind spot.
## 1. The guard validates presence and type, never "no key beyond the schema"
`make check-fixture-coverage` checks that every manifest'd fixture carries its schema's required fields with the right types/nullability, that every `covered_schemas` entry keeps a concrete representative, and that rich-text emitters are accounted for. It does **not** reject a key the schema has never heard of.
Demonstrated directly: adding `"comment_count": 2` to `spec/fixtures/gauges/needle_get.json` — a key `GaugeNeedle` does not model (see #731) — leaves the gate green:
```
==> Fixture coverage clean — 33 covered schemas, 51 manifest targets, ...
REAL_EXIT=0
```
That is exactly the failure mode the fabricated `spec/fixtures/tools/*.json` hit. Manifesting a fixture closes the *missing-required-field* half of the problem and none of the *invented-key* half, so "it's manifested now" is weaker assurance than it reads.
Naming the failure this guards against: not an adversary, but the ordinary drift of a fixture author inventing a plausible key, or a spec change removing one and leaving the fixture behind. An additional-properties check against the schema would catch both, and is a pure addition — no existing fixture should need to change if the spec is right. Worth confirming that claim by running it before deciding.
## 2. `search/results.json` `/7` carries gauge-needle URLs that route nowhere
The gauge fixtures were corrected in #719's branch: both used `Recordable#route`'s **default** bucket shape, which `Gauge` and `Gauge::Needle` each override.
```
Gauge#route -> [ :project_gauge, bucket ] (app/models/gauge.rb:31-33)
Gauge::Needle#route -> [ :project_gauge_needle, bucket, r ] (app/models/gauge/needle.rb:12-14)
```
bc3 draws exactly three gauge route lines (`config/routes.rb:186`, `741-742`, `836`) and none of them is bucket-scoped, so `/buckets/:bid/gauges/:id.json` and `/buckets/:bid/gauge_needles/:id.json` are not merely unusual — they are unroutable.
The `search-result-needle` representative (`spec/fixtures/search/results.json` pointer `/7`, schema `SearchResult`) still carries both, plus the same invented `"title": "Progress update"` where bc3 hard-codes `"Moved the needle"`, and a `parent` titled `"Gauge"` where bc3 says `"How far along are we?"`.
Left alone deliberately in #719: it is outside that issue's scope, existing search tests in three SDKs stub against that file, and correcting it wants its own verification pass rather than being smuggled into a gauge-coverage PR.
Same root cause as (1): nothing validates fixture *values*, only shapes — so the wrong route family propagated from one fixture to another unchallenged.
Contributor guide
Research direction
Start with `make check-fixture-coverage` and the schema/fixture coverage logic, using `spec/fixtures/gauges/needle_get.json` to reproduce the fabricated-key gap. Then inspect `spec/fixtures/search/results.json` at pointer `/7`, `app/models/gauge.rb`, `app/models/gauge/needle.rb`, and the cited routes in `config/routes.rb`; run the existing search tests in the three SDKs. Done means unknown fixture keys are rejected and the representative uses routable, schema-consistent values.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100