basecamp / basecamp/basecamp-sdk

check-fixture-coverage cannot see a fabricated key, and search/results.json still carries the unroutable gauge URLs

Open
#733 0 comments 0 reactions 0 assignees View on GitHub
spec
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.