From PLAN.md step 2. Spec: docs/spec.md. Phase 1.
Files: src/flabel/models.py, src/flabel/errors.py, src/flabel/config.py, data/sources.toml, tests/test_models.py, tests/test_config.py
Changes: All frozen dataclasses from spec §4, in one module that imports nothing from the package. Typed exceptions mapped to exit codes (spec §12). Source-registry loader with validation. data/sources.toml populated with the ten sources and their authoritative class/basis/licence assignments from spec §5.
Test that proves it: SourceSpec.may_label is False exactly for identify; label_basis is indicator-reference exactly for ioc-name; unknown source_class or admission_basis raises; metadata-filter on a source without ET metadata raises; every exception type maps to exactly one exit code, and every exit code in spec §12 is reachable. Plus the architectural guard: a test asserting no pure module's source contains subprocess, urllib, or socket.
Depends on: 1. Blocks: 3, 4, 5, 6, 7, 8.
From
PLAN.mdstep 2. Spec:docs/spec.md. Phase 1.Files:
src/flabel/models.py,src/flabel/errors.py,src/flabel/config.py,data/sources.toml,tests/test_models.py,tests/test_config.pyChanges: All frozen dataclasses from spec §4, in one module that imports nothing from the package. Typed exceptions mapped to exit codes (spec §12). Source-registry loader with validation.
data/sources.tomlpopulated with the ten sources and their authoritative class/basis/licence assignments from spec §5.Test that proves it:
SourceSpec.may_labelisFalseexactly foridentify;label_basisisindicator-referenceexactly forioc-name; unknownsource_classoradmission_basisraises;metadata-filteron a source without ET metadata raises; every exception type maps to exactly one exit code, and every exit code in spec §12 is reachable. Plus the architectural guard: a test asserting no pure module's source containssubprocess,urllib, orsocket.Depends on: 1. Blocks: 3, 4, 5, 6, 7, 8.