Log in
docs/new-lane-template.md 70 lines · 3.2 KB

New Lane Checklist

Every lane in this suite keeps five machine-checked promises: row contract, skip coherence, transport purity, measurement_source honesty, and catalog membership. tests/test_lane_contract.py enforces them over scripts/oakbench/lane_contract.py:LANE_TABLE; a lane missing its entry fails CI by design. Work the list top to bottom.

1. Name the lane

  • Pick a short, stable lane name (e.g. fleet-sync). Names are identity (ADR-0005): renames are new lanes, never silent changes.
  • Decide where rows are written: through ResultsStore(results, lane=...) so the row contract is validated at write time, not in a dashboard.

2. Declare the row contract

  • Add the lane to scripts/oakbench/rows.py: LANES plus a LANE_REQUIRED_KEYS entry listing only keys EVERY row carries β€” including skip and diagnostic rows (that is why token fields are not required at this layer). If the lane deliberately reuses another lane's keys (netshape uses core), say so in the emitter's docstring instead.

3. Add the LANE_TABLE entry

  • One LaneContract in scripts/oakbench/lane_contract.py: lane name, validate_lane (rows.py key or None + universal_keys), a pure sample_rows_builder mirroring your real emitter (measured row, total/ derived row if any, skip row), allowed_sources, catalog_path, and any catalog exemptions β€” documented reality, never wildcards.
  • If the lane has no rows.py entry yet, add its name to DE_FACTO_LANES.

4. Scenario YAML with immutable names

  • If the lane has a declared operation vocabulary, put it in scenarios/<lane>.yaml (an operation_catalog: map or per-scenario operations: lists). Scenario and operation names are immutable; parameters belong in the name (poll_until_merged_i10s).

5. Skip-row honesty

  • Anything unmeasurable emits a returncode-77 row with skipped: true and a skip_reason naming the exact fix (env var, platform, privilege). Skips are work items, not absences (ADR-0002). Never a fabricated zero.

6. Transport declaration

  • Every remote-touching row carries remote_repo, remote_transport, remote_server (use oakbench.remotes β€” do not hand-roll). One (subject, scenario, operation) never mixes transports; shaped rows must carry netshape_profile and compare same-pipe only.

7. measurement_source

  • State how each value was obtained. Top-level for whole-row sources, nested per metric block (agent/contention style) for composite rows. Whatever you emit, encode it in the entry's allowed_sources.

8. Devloop in or out

  • Decide whether the lane runs in devloop. Lanes with external variance (hosted platforms, real networks) stay out so changeset verdicts are never poisoned; record the decision in the lane script's docstring.

9. Tests with fake transports

  • Lane tests construct rows via your row builders with fake/local transports (bare repos, loopback servers) β€” never live credentials. Run python3 -m unittest tests.test_lane_contract and confirm your lane passes all five checks and the negative cases still have teeth.