Device-population service validation

Partially validated with documented limitations.

1. The component

rfgen.population creates a fixed, named set of virtual devices before scene generation. It derives a deterministic ID for each group/index pair, obtains one complete hardware-fingerprint record from an existing DeviceRegistry, and persists a version-1 JSON record. It is not a model of physical-device manufacture, propagation, event scheduling, trajectories, or waveform output.

class DevicePopulationService:
    def resolve(self, *, run_id: str, seed: int,
                groups: Mapping[str, int | Mapping[str, object] | PopulationGroup]
                | Iterable[PopulationGroup | Mapping[str, object]],
                namespace: str | None = None, pool_size: int | None = None,
                reuse_policy: str = "across_scenes", shard_count: int = 1) -> DevicePopulation: ...
    def resolve_shard(self, *, run_id: str, seed: int,
                      groups: Mapping[str, int | Mapping[str, object] | PopulationGroup]
                      | Iterable[PopulationGroup | Mapping[str, object]],
                      shard_index: int, shard_count: int, namespace: str | None = None,
                      pool_size: int | None = None,
                      reuse_policy: str = "across_scenes") -> PopulationShard: ...
    @staticmethod
    def reassemble_shards(shards: Iterable[PopulationShard]) -> DevicePopulation: ...
    def write_artifact(self, population: DevicePopulation, *, run_id: str,
                       root: str | Path = ".") -> Path: ...

Input or output

Contract

run_id and namespace

Nonempty NFC (Unicode’s composed text form) strings; run_id is one safe artifact-path segment.

seed

Non-boolean unsigned 64-bit integer used for fingerprint draws.

groups

Named non-boolean integer counts and existing fingerprint-family bindings.

shard_index, shard_count

Non-boolean integers; a device belongs to the partition selected by its canonical position modulo shard_count.

DevicePopulation

Closed version-1 record: every declared group/index position occurs once with its derived ID and complete FingerprintParams.

artifact Path

<root>/artifacts/populations/<run_id>/population.json, written as sorted compact UTF-8 JSON plus a newline.

The following reconstructs the small two-partition record used in the durable fixture. It produces a DevicePopulation, which can then be passed to write_artifact.

from rfgen.population import DevicePopulationService

service = DevicePopulationService()
shards = [
    service.resolve_shard(
        run_id="run-1337",
        seed=1337,
        groups={"drones": 2, "controllers": 1},
        shard_index=index,
        shard_count=2,
    )
    for index in range(2)
]
population = DevicePopulationService.reassemble_shards(shards)
assert len(population.devices) == 3

2. What we validated

  1. Canonical identity. Equivalent NFC spellings of a namespace and group name yield the same SHA-256 device ID, while group and index keep identities distinct.

  2. Request-pure deterministic resolution. The same valid request yields the same complete device records after real one- or N-shard partition and reassembly; a later request with a different seed is not overridden by a registry cache populated by an earlier request.

  3. Closed durable record. The written artifact has a stable path and bytes, contains the complete canonical FingerprintParams serialization, and rejects unsafe run IDs, duplicate groups, missing fingerprint families, incomplete stored fingerprints, coerced scalars, and device rows that do not exactly close over the declared group/index population.

3. Evidence

3.1 Canonical identity

tests/unit/test_device_population.py::test_ids_use_nfc_utf8_sha256_namespace_group_index compares the public device_population_id result with an independently computed SHA-256 digest of NFC UTF-8 text separated by NUL bytes. It also compares composed café and its decomposed spelling. SHA-256 is the standardized 256-bit Secure Hash Algorithm [1].

3.2 Request-pure deterministic resolution

test_resolve_is_shard_invariant_and_preserves_complete_fingerprint resolves two groups together and separately, compares sorted JSON device rows, then uses public resolve_shard(..., shard_index=0|1, shard_count=2) and reassemble_shards(...) calls before comparing the entire returned record. The test also checks that every serialized device has the exact FingerprintParams key set, including phase_noise_dbc_hz.

test_seed_1337_fixture_is_byte_equal_after_two_shard_reassembly compares both one-shard resolution and public two-shard reassembly against a checked-in seed-1337 artifact (drones: 2, controllers: 1) byte-for-byte after each result is written through write_artifact. The registry consumes a derived PCG64 unit variate and applies the explicit binary64 mapping low + (high - low) * unit, so this artifact contract does not depend on NumPy’s uniform(low, high) endpoint-arithmetic implementation. The fixed seed-1337 population was also regenerated in isolated NumPy 1.26.4 and 2.4.1 environments: both emitted the same 1,697-byte artifact with SHA-256 0e80277721938e433ca984b99b524e3eec3373000a6958eb27219dcbbee39928 and identical binary64 parameter values. This is release-boundary evidence for those two supported versions, not a claim about every platform or future NumPy release.

test_resolution_seed_is_not_overridden_by_a_reused_registry_cache resolves the same named device twice through one service with seeds 1 and 2. It checks that the ID remains stable while the fingerprint values differ, exercising the request-scoped registry key used by the service.

3.3 Closed durable record

test_artifact_path_schema_and_bytes_are_stable verifies the version-1 path, required top-level fields, and byte-stable rewrite of an unchanged record. test_group_overlap_and_missing_family_raise_structured_validation_errors checks the public structured errors for duplicate groups and absent family bindings. test_rejects_unsafe_run_id_bool_count_and_partial_persisted_fingerprint checks path-segment rejection, boolean-count rejection, and failure when the phase-noise field is removed from a persisted fingerprint. The Pydantic model validation used for the closed record is provided by Pydantic 2.13.3 [2].

test_artifact_rejects_coerced_scalars_before_persistence rejects string and boolean seeds and a non-text namespace rather than coercing them into an artifact. test_artifact_requires_exact_group_counts_and_derived_ids_before_persistence removes a required device row, then also uses Pydantic’s deliberately validator-bypassing model_copy(update=...) route to prove write_artifact revalidates closure at the persistence boundary.

4. Limits and what is not validated

  • These tests establish deterministic software behavior, not that the default fingerprint priors represent any particular fleet or radio hardware. That scientific question belongs to the device-fingerprint validation.

  • The shard check executes real local partition and reassembly behavior. It does not execute a multi-process scheduler, distributed filesystem, or concurrent writers.

  • pool_size is presently only a request-count upper bound. This report does not establish a device-pool allocation, admission-control, or reuse model.

  • The artifact makes no claim that an ID proves a real-world device’s origin, authorization, or physical uniqueness.

  • No event planning, channel impairment application, propagation, or signal-generation output is assessed here.

5. References

  1. National Institute of Standards and Technology, Secure Hash Standard (SHS), FIPS PUB 180-4, August 2015, FIPS 180-4 publication page.

  2. Pydantic 2.13.3 documentation. Documents the model validation and JSON serialization used by the record types.