Stability policy¶
From version 1.0.0 on, HandoverLab follows Semantic Versioning for its public surface. This page says what the public surface is, what each kind of release may change, and how something is deprecated before it goes.
The public surface¶
| Part | Where it is defined |
|---|---|
| Configuration files: experiment and study keys, their meaning and defaults | user guide, handoverlab.config, handoverlab.studies.config |
| File formats: result CSV and JSON, event-log and trace tables, study directories | user guide, handoverlab.io, handoverlab.eventlog |
| Schema version of configuration and result files | handoverlab.stability.SCHEMA_VERSION (now 1) |
| Metric and count names and their definitions | metric reference, handoverlab.engine.METRICS |
The rule interface: hooks, their arguments, the fields of RuleContext, Observation, OutcomeRecord, FailureRecord, the outcome labels and the registry |
handoverlab.rules, version handoverlab.stability.RULE_API_VERSION (now 1) |
Python names exported by handoverlab, handoverlab.rules, handoverlab.studies, handoverlab.stability, and the documented functions of handoverlab.eventlog, handoverlab.testing, handoverlab.verify and handoverlab.stats |
API reference |
| Commands and options of the command line | command-line reference |
Not public: modules and names starting with an underscore, the engine internals
(handoverlab.engine.core, procedures, batch), the dashboard page (handoverlab.gui.app), the
layout of the report pages, the wording of messages, and timing figures.
The test tests/test_stability.py compares the surface with a snapshot
(tests/data/public_api.json, written by handoverlab.stability.public_surface), so that no part
of it changes by accident.
What a release may change¶
| Release | May | May not |
|---|---|---|
| Patch (2.0.x) | fix bugs, documentation and performance | change a result that was correct, or the surface |
| Minor (2.x.0) | add keys with defaults that keep earlier results, add metrics, rules, scenarios, commands, options, optional hook arguments and record fields; deprecate | remove or rename any part of the surface, change a default |
| Major (x.0.0) | remove what was deprecated, rename, change defaults and file formats | remove something that was not deprecated in a minor release before |
Results. The model version (handoverlab.studies.MODEL_VERSION, now 2) identifies the
simulation model. A change of what a run computes for the same inputs, such as a corrected
channel formula, raises it, is listed in the changelog with its effect and comes with new golden
fingerprints. Such a change is made only in a minor or major release, never in a patch, unless it
corrects a bug; study directories of the old model version then run their jobs again instead of
reusing them.
File formats. Every configuration and result file has the top-level key schema (a file
without it is schema 1). A new schema version comes only with a major release. HandoverLab reads
every schema up to its own and refuses a newer one with a message that names it, instead of
misreading it.
Rules. A rule written for interface version 1 runs unchanged on every 1.x and 2.x release (2.0.0 only added hooks). New hooks get a default implementation in the base class; new fields of the observation and the records are only appended.
Getting the results of an earlier major release¶
2.0.0 changed defaults (see moving from 1.x to 2.0). handoverlab.stability.LEGACY_1X
holds the 1.x values of every changed key; with it (and mobility.profile: veh16 on the urban-grid cards) a
configuration gives the 1.x event log bit for bit. Since 2.1.0 it also holds radio.channel_detail: simple
(the large-scale channel of 2.0.0 and 1.x), and handoverlab.stability.LEGACY_CARDS holds the old values of
the built-in cards that 2.1.0 changed (apply them after LEGACY_1X to a scenario built from such a card). handoverlab verify --only fingerprints checks this on
every golden run of 1.12.0 (section fingerprints-1x).
from handoverlab.stability import LEGACY_1X
sc = hl.builtin_scenario("ns3-urban-3.5ghz").with_overrides(LEGACY_1X)
Deprecation¶
Something that is to be removed or renamed is first deprecated in a minor release and removed at
the earliest in the next major release. While deprecated it keeps working and issues a
HandoverLabDeprecationWarning (a FutureWarning, so it is shown by default) that names the
version that deprecated it, the version that removes it and the replacement:
from handoverlab.stability import deprecated, deprecated_alias
def old_option_used():
deprecated("the key 'tuning.foo'", since="1.2", removed_in="2.0", instead="'tuning.bar'")
old_name = deprecated_alias(new_name, "old_name", since="1.2", removed_in="2.0")
A renamed metric keeps its old name in handoverlab.stability.METRIC_ALIASES; study files and
handoverlab.stability.metric_name accept the old name with a warning. The changelog lists every
deprecation under Deprecated. To turn the warnings into errors while testing your own code:
python -W error::FutureWarning or filterwarnings = ["error::FutureWarning"] for pytest.
Changing the surface (for contributors)¶
- Make the change in a backwards-compatible way where possible (a new key with a default that keeps earlier results, an alias for a new name).
- Write the new snapshot:
python -m handoverlab.stability --write tests/data/public_api.json, and check its diff: only additions belong in a minor release. - Document the change in the user guide or reference and in
CHANGELOG.md(Added, Changed, Deprecated or Removed).