Angle and sector descriptors, no target fit
+ 23.01 exact hub
+ 23.02 radius observations with dx/dy
→ exact polar angle observations
→ cyclic angular spacing descriptors
→ explicit sector membership
→ sector occupancy descriptors
NO approximate tolerance
NO equal-spacing target
NO score
NO layout generator
Ownership is narrow
Angle / spacing / sectors
Polar angles, cyclic gaps, explicit sector arcs, exact assignments and occupancy counts.
23.04 remains downstream
Approximation, target profiles, scoring, MetricResult and candidate generation remain outside this module.
Polar angle is derived from dx/dy
angleRadians = normalize(atan2(dy, dx)) ∈ [0, 2π) angleDegrees = angleRadians × 180 / π radius = 0 → direction undefined → N_A angle = 0 → valid eastward direction → OK
No angle is treated as semantic importance, hierarchy, mass or quality.
Cyclic spacing preserves exact geometry
Sectors are explicit arcs
| start < end | ordinary arc |
| start > end | wrap-around arc crossing 0 |
| start = end | INVALID; full-circle intent is not inferred |
| boundaries | startInclusive / endInclusive are explicit |
Membership keeps ambiguity
Exactly one explicit sector contains the angle.
No sector contains the angle; valid and non-judgmental.
Multiple sectors contain the angle → N_A, no winner.
Hub subject with radius=0 has no direction.
Occupancy is descriptive
occupancyCount = count(ASSIGNED subjects in sector) occupancyFraction = occupancyCount / applicableAngularSubjectCount 0 occupied subjects is valid numeric 0. It does not imply a defect or low quality.
Exact upstream lineage is preserved
Downstream boundary
| 23.03 | Exact angles, cyclic gaps, explicit sectors and occupancy only. |
| 23.04 | Approximation, target fit, scoring, bounded generator and final Topic23 tests. |
| Topic24 | Not started here. |
Descriptor ≠ quality
CANON → LAB → DATA → IDEAS
23.03 regression suite
Tests cover exact root/hub/radius lineage, atan2 normalization, hub-direction N_A semantics, cyclic gaps, explicit wrap-around sectors, boundary inclusion, ambiguity preservation, occupancy zeros, immutable attachment and 23.04/Topic24 firewalls.
DATA FOR LAYOUT ENGINE
{
"module": "Compo 23.03",
"name": "angular_spacing_sector_occupancy",
"version": "1.0-canonical",
"canonical_main_title": "Angular spacing / sector occupancy",
"topic": "23_РАДИАЛЬНЫЙ_БАЛАНС_И_ЦЕНТРАЛЬНЫЕ_СИСТЕМЫ",
"scope": "EXACT_COMPO23_00_ROOT_COMPO23_01_HUB_AND_COMPO23_02_RADIUS_LINEAGE_DERIVED_POLAR_ANGLES_EXPLICIT_ANGULAR_SECTORS_CYCLIC_GAP_DESCRIPTORS_AND_NONSCORING_SECTOR_OCCUPANCY_ONLY_WITHOUT_APPROXIMATION_TARGET_FIT_SCORING_OR_GENERATION",
"main_topic_contract": {
"topic_title": "Радиальный баланс и центральные системы",
"topic_goal": "Формализует радиальные композиции: hub, rings, radius bands, angular sectors и распределение элементов вокруг центра.",
"expected_output": "RadialGroupDescriptor, hub, rings, sectors",
"planned_files": [
"23.00 Radial system schema",
"23.01 Hub/center detection",
"23.02 Radius bands and orbital groups",
"23.03 Angular spacing / sector occupancy",
"23.04 Scoring, generator and tests"
]
},
"ownership": {
"owner": "Compo23.03",
"owns": [
"RadialAngularObservation",
"RadialAngularObservationSet",
"RadialAngularSpacingDescriptor",
"RadialAngularSpacingSet",
"RadialAngularSectorDefinition",
"RadialSectorMembershipClass taxonomy",
"RadialSectorAssignment",
"RadialSectorOccupancyDescriptor",
"RadialAngularSectorSet",
"RadialAngularSectorPolicy",
"RadialAngularSectorAttachment",
"exact atan2-derived polar angle normalization to [0, 2π)",
"deterministic cyclic angular ordering and adjacent-gap derivation",
"explicit angular-sector membership including wrap-around sectors",
"sector occupancy counts/fractions as non-scoring descriptors",
"identity/status/provenance rules for Topic23 angular layer",
"non-mutating correction request for angular/sector lineage"
],
"does_not_own": [
"RadialSystemSchema / RadialSystemSeed identity — Compo23.00",
"hub detection / hub truth — Compo23.01",
"radius observations, radius bands, rings and orbital groups — Compo23.02",
"raw point geometry or foreign position identities — upstream geometry owners",
"approximate angle/radius tolerance, target fit, scoring, MetricResult or generator — Compo23.04",
"symmetric balance / mirror correspondence — Topic21",
"visual center of mass, moments and counterweights — Topic22",
"hierarchy, dominance, semantic importance, beautyScore or final-layout ranking",
"foreign geometry/style/semantic mutation"
]
},
"consumes": [
"exact Compo23.00 root bundle",
"exact Compo23.01 RadialHubDescriptor + RadialHubAttachment lineage",
"exact Compo23.02 RadialRadiusObservationSet containing dx/dy/radius lineage",
"optional explicit RadialAngularSectorDefinition[] and bounded policy"
],
"provides": [
"RadialAngularObservation[]",
"RadialAngularObservationSet",
"RadialAngularSpacingDescriptor[]",
"RadialAngularSpacingSet",
"RadialAngularSectorDefinition[]",
"RadialSectorAssignment[]",
"RadialSectorOccupancyDescriptor[]",
"RadialAngularSectorSet",
"RadialAngularSectorAttachment"
],
"owns_metrics": [],
"independent_numeric_votes": 0,
"status_semantics": {
"OK": "valid exact local angular/sector descriptor",
"N_A": "missing/conflicting/ambiguous/not-applicable evidence; never numeric zero",
"INVALID": "malformed or impossible record; never numeric zero"
},
"angle_rules": [
"angleRadians = normalize(atan2(dy, dx)) into [0, 2π)",
"angleDegrees = angleRadians × 180 / π",
"radius=0 makes direction undefined -> N_A; angle is not coerced to zero",
"east=0, north=π/2, west=π, south=3π/2 in the bound coordinate frame",
"no orientation desirability is inferred"
],
"spacing_rules": [
"only OK angular observations participate in cyclic order",
"order is angle ascending with subjectRef lexical tie-break used only for deterministic identity",
"adjacent cyclic gaps are in [0, 2π] and exact zero is valid for coincident rays",
"with at least two applicable observations, cyclic gaps sum to 2π within floating arithmetic tolerance",
"gap size is a descriptor, not rhythm quality or target fit"
],
"sector_policy": {
"definitionMode": "EXPLICIT_ARCS_ONLY",
"membershipMode": "EXACT_ANGLE_ONLY",
"multipleMatchMode": "N_A_NO_GUESS",
"gapMode": "UNASSIGNED_OK",
"maxAngularObservations": [
1,
4096
],
"maxSectors": [
0,
512
],
"maxSpacingDescriptors": [
0,
4096
],
"overflow": "N_A_WITHOUT_TRUNCATION",
"autoSectorDiscovery": false,
"autoTolerance": false,
"autoEqualSpacingTarget": false,
"autoScoring": false
},
"sector_rules": [
"sector start/end angles must each be in [0,2π)",
"start < end defines a non-wrapping arc; start > end defines a wrap-around arc crossing 0",
"start == end is INVALID because full-circle intent must not be inferred",
"boundary inclusion is explicit per endpoint",
"zero occupied subjects is valid occupancyCount=0",
"overlapping explicit sectors may make one subject AMBIGUOUS -> N_A; no source/confidence winner",
"uncovered angle -> UNASSIGNED with OK status; not a quality failure"
],
"root_attachment_contract": {
"radialSystemSeedRef": "exact Compo23.00 seed lineage",
"hubDescriptorRef": "exact Compo23.01 descriptor identity",
"radiusObservationSetRef": "exact Compo23.02 radius set identity",
"angularObservationSetRef": "exact Compo23.03 angular set identity",
"angularSpacingSetRef": "exact Compo23.03 spacing set identity",
"angularSectorSetRef": "exact Compo23.03 sector set identity",
"rootMutation": false,
"metricResultRefs": []
},
"firewalls": [
"angle != radius",
"angle != hierarchy or semantic importance",
"angle=0 is valid east direction, not N_A",
"radius=0 direction is N_A, not angle 0",
"coincident rays may have exact zero angular gap",
"zero gap != zero score",
"equal angular spacing != automatically good",
"unequal angular spacing != automatically bad",
"sector occupancy count != visual mass",
"empty sector != defect",
"full sector != quality",
"angular sector != orbital group",
"angular sector != symmetry class",
"wrap-around sector != approximation",
"multiple sector match -> N_A, not winner selection",
"descriptor != score",
"N_A != 0",
"INVALID != 0",
"heuristic != law",
"local != global",
"geometry != interpretation",
"correction request != foreign mutation"
],
"topic23ProgressAfterThisModule": "4/5 local",
"next_module": "Compo 23.04 — Scoring, generator and tests",
"hard_stop": "No 23.04 implementation in this file"
}