Skip to content

Commit cdd4a0a

Browse files
Merge pull request #19 from AmedeoPelliccia/copilot/restrict-subbucket-usage
Restrict subbucket ranges to bucket-specific values in nomenclature validator
2 parents 80a453c + f7b6a6a commit cdd4a0a

File tree

3 files changed

+141
-63
lines changed

3 files changed

+141
-63
lines changed

00_00_CAT_LC01_SPACET_nomenclature-quick-reference_v02.md

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Nomenclature Standard Quick Reference
22

3-
## Pattern
3+
## Pattern (v2.0 - 8 Fields)
44

55
```
6-
[ROOT]_[BUCKET]_[TYPE]_[VARIANT]_[DESCRIPTION]_[VERSION].[EXT]
6+
[ROOT]_[BUCKET]_[TYPE]_[LC_OR_SUBBUCKET]_[VARIANT]_[DESCRIPTION]_[VERSION].[EXT]
77
```
88

99
## Field Rules
@@ -13,19 +13,26 @@
1313
| ROOT | 2-3 digits | `00`, `24`, `72`, `115`, `116` |
1414
| BUCKET | 2 digits | `00`, `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90` |
1515
| TYPE | 2-8 uppercase | `PLAN`, `FHA`, `REQ`, `STD`, `IDX` |
16-
| VARIANT | Uppercase + hyphens | `SPACET`, `DRAFT`, `SYS`, `LC02-SPACET` |
16+
| LC_OR_SUBBUCKET | LC01-LC14 or SB15-SB99 | `LC01`, `LC14`, `SB15`, `SB99` |
17+
| VARIANT | Uppercase + hyphens | `SPACET`, `DRAFT`, `SYS`, `HW-01` |
1718
| DESCRIPTION | lowercase-kebab-case | `safety-program`, `propulsion`, `hazard-log` |
1819
| VERSION | v + 2 digits | `v01`, `v02`, `v10` |
1920
| EXT | lowercase | `md`, `json`, `xlsx`, `pdf` |
2021

2122
## Special Rules
2223

23-
### ⚠️ CRITICAL: BUCKET=00 requires LC prefix
24+
### ⚠️ CRITICAL: Subject Category Rules
2425

25-
If `BUCKET=00`, then `VARIANT` **MUST** start with `LC01` through `LC14`
26+
**If `BUCKET=00`** → Use **LC** (Lifecycle) category:
27+
- `LC_OR_SUBBUCKET` **MUST** be `LC01` through `LC14`
28+
- Example: ✅ `00_00_PLAN_LC02_SPACET_safety-program_v01.md`
29+
- Invalid: ❌ `00_00_PLAN_SB15_SPACET_safety-program_v01.md`
2630

27-
`00_00_PLAN_LC02-SPACET_safety-program_v01.md`
28-
`00_00_PLAN_SPACET_safety-program_v01.md`
31+
**If `BUCKET≠00`** → Use **SB** (Sub-bucket) category:
32+
- `LC_OR_SUBBUCKET` **MUST** be `SB15` through `SB99`
33+
- Example: ✅ `00_70_FHA_SB15_SYS_propulsion_v01.md`
34+
- Invalid: ❌ `00_70_FHA_SB00_SYS_propulsion_v01.md`
35+
- Invalid: ❌ `00_70_FHA_LC01_SYS_propulsion_v01.md`
2936

3037
### Delimiters
3138

@@ -34,18 +41,18 @@ If `BUCKET=00`, then `VARIANT` **MUST** start with `LC01` through `LC14`
3441

3542
## BUCKET Values
3643

37-
| Code | Domain |
38-
|------|--------|
39-
| `00` | Lifecycle (requires LC prefix in VARIANT) |
40-
| `10` | Operations |
41-
| `20` | Primary Subsystem |
42-
| `30` | Circularity |
43-
| `40` | Software |
44-
| `50` | Structures |
45-
| `60` | Storages |
46-
| `70` | Propulsion |
47-
| `80` | Energy |
48-
| `90` | Tables/Schemas/Diagrams/Reference |
44+
| Code | Domain | Allowed Subbuckets |
45+
|------|--------|-------------------|
46+
| `00` | Lifecycle | LC01-LC14 |
47+
| `10` | Operations | SB15-SB19, SB80-SB85 |
48+
| `20` | Primary Subsystem | SB20-SB29 |
49+
| `30` | Circularity | SB30-SB39 |
50+
| `40` | Software | SB40-SB49 |
51+
| `50` | Structures | SB50-SB59 |
52+
| `60` | Storages | SB60-SB69 |
53+
| `70` | Propulsion | SB70-SB79 |
54+
| `80` | Energy | SB86-SB89 |
55+
| `90` | Tables/Schemas/Diagrams/Reference | SB90-SB99 |
4956

5057
## Approved TYPE Codes
5158

@@ -76,40 +83,55 @@ python validate_nomenclature.py --check-all
7683
### ✅ Valid
7784

7885
```
79-
00_00_PLAN_LC02-SPACET_safety-program_v01.md
80-
00_70_FHA_SYS_propulsion_v01.md
81-
00_40_REQ_SW_software-safety-reqs_v01.md
82-
00_20_TRC_SPACET_traceability-matrix_v01.xlsx
83-
00_90_SCH_GEN_hazard-log-schema_v01.json
84-
24_40_REQ_SW-01_electrical-power-software_v01.md
86+
00_00_PLAN_LC02_SPACET_safety-program_v01.md
87+
00_70_FHA_SB70_SYS_propulsion_v01.md
88+
00_40_REQ_SB40_SW_software-safety-reqs_v01.md
89+
00_20_TRC_SB20_SPACET_traceability-matrix_v01.xlsx
90+
00_90_SCH_SB90_GEN_hazard-log-schema_v01.json
91+
24_40_REQ_SB40_SW_electrical-power-software_v01.md
92+
00_10_PLAN_SB15_GEN_operations-plan_v01.md
93+
00_80_FHA_SB86_SYS_energy-system_v01.md
8594
```
8695

8796
### ❌ Invalid
8897

8998
```
90-
00_00_PLAN_SPACET_safety-program_v01.md # Missing LC prefix
91-
00-70-FHA-SYS-propulsion-v01.md # Wrong delimiter
92-
00_70_FHA_SYS_propulsion_v1.md # VERSION must be vNN
93-
00_99_LST_GEN_glossary_v01.md # Invalid BUCKET
94-
00_70_FHA_SYS_PropulsionFHA_v01.md # Uppercase in DESCRIPTION
95-
00_70_fha_SYS_propulsion_v01.md # Lowercase TYPE
99+
00_00_PLAN_SB15_SPACET_safety-program_v01.md # BUCKET=00 requires LC, not SB
100+
00_70_FHA_SB00_SYS_propulsion_v01.md # SB00 not allowed (reserved)
101+
00_70_FHA_SB40_SYS_propulsion_v01.md # BUCKET=70 requires SB70-SB79
102+
00_70_FHA_LC01_SYS_propulsion_v01.md # BUCKET≠00 requires SB, not LC
103+
00_40_REQ_SB70_SW_software_v01.md # BUCKET=40 requires SB40-SB49
104+
00-70-FHA-SB70-SYS-propulsion-v01.md # Wrong delimiter
105+
00_70_FHA_SB70_SYS_propulsion_v1.md # VERSION must be vNN
106+
00_99_LST_SB90_GEN_glossary_v01.md # Invalid BUCKET
107+
00_70_FHA_SB70_SYS_PropulsionFHA_v01.md # Uppercase in DESCRIPTION
108+
00_70_fha_SB70_SYS_propulsion_v01.md # Lowercase TYPE
96109
```
97110

98111
## Common Mistakes
99112

100-
1. **Missing LC prefix for BUCKET=00**
101-
- Fix: Add `LC01` through `LC14` to start of VARIANT
102-
- Example: `SPACET``LC02-SPACET`
113+
1. **Wrong subject category for BUCKET=00**: Must use LC01-LC14, not SB
114+
- Fix: Use LC_OR_SUBBUCKET field with LC01-LC14
115+
- Example: `00_00_PLAN_SB15_SPACET_...``00_00_PLAN_LC02_SPACET_...`
103116

104-
2. **Wrong delimiters**
117+
2. **Using wrong subbucket range for bucket**: Each bucket has specific ranges
118+
- Fix: Use the correct subbucket range for your bucket
119+
- Example: `00_70_FHA_SB40_SYS_...``00_70_FHA_SB70_SYS_...`
120+
- Example: `00_40_REQ_SB20_SW_...``00_40_REQ_SB40_SW_...`
121+
122+
3. **Using SB00-SB14**: These are reserved and not allowed
123+
- Fix: Use bucket-specific ranges starting from SB15
124+
- Example: `00_70_FHA_SB00_SYS_...``00_70_FHA_SB70_SYS_...`
125+
126+
4. **Wrong delimiters**
105127
- Fix: Use `_` between fields, `-` inside fields only
106128
- Example: `00-70-FHA``00_70_FHA`
107129

108-
3. **Wrong version format**
130+
5. **Wrong version format**
109131
- Fix: Always use 2 digits after `v`
110132
- Example: `v1``v01`
111133

112-
4. **Uppercase in DESCRIPTION**
134+
6. **Uppercase in DESCRIPTION**
113135
- Fix: Use lowercase-kebab-case only
114136
- Example: `SafetyProgram``safety-program`
115137

00_00_STD_LC01_SPACET_nomenclature-standard_v02.md

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ All files must strictly adhere to the **8-field format**:
3636
| **ROOT** | ATA Chapter or Project Code | 2-3 digits | `^\d{2,3}$` |
3737
| **BUCKET** | Domain Classification (OPT-IN + LC) | 2 digits (enum) | `^(00\|10\|20\|30\|40\|50\|60\|70\|80\|90)$` |
3838
| **TYPE** | Artifact Type | 2–8 uppercase alphanumeric | `^[A-Z0-9]{2,8}$` |
39-
| **LC_OR_SUBBUCKET** | Lifecycle Stage or Sub-bucket | LC01-LC14 or SB00-SB99 | `^(LC(0[1-9]\|1[0-4])\|SB\d{2})$` |
39+
| **LC_OR_SUBBUCKET** | Lifecycle Stage or Sub-bucket | LC01-LC14 or SB15-SB99 | `^(LC(0[1-9]\|1[0-4])\|SB(1[5-9]\|[2-9]\d))$` |
4040
| **VARIANT** | Configuration / Baseline / Item Class | uppercase alphanumeric; hyphen allowed | `^[A-Z0-9]+(?:-[A-Z0-9]+)*$` |
4141
| **DESCRIPTION** | Human-readable content label | lowercase kebab-case | `^[a-z0-9]+(?:-[a-z0-9]+)*$` |
4242
| **VERSION** | Revision Control | `v` + 2 digits | `^v\d{2}$` |
@@ -94,7 +94,7 @@ The following set is **approved** for v1.0. Extensions require Configuration Man
9494

9595
This mandatory field encodes either:
9696
- **Lifecycle stage** (LC01-LC14) for `BUCKET=00` files
97-
- **Sub-bucket** identifier (SB00-SB99) for all other buckets
97+
- **Sub-bucket** identifier (SB15-SB99) for all other buckets
9898

9999
**Conditional rules (mandatory):**
100100

@@ -103,21 +103,36 @@ This mandatory field encodes either:
103103
^LC(0[1-9]|1[0-4])$
104104
```
105105
* Valid: `LC01`, `LC02`, ..., `LC14`
106-
* Invalid: `SB00`, `LC00`, `LC15`
106+
* Invalid: `SB15`, `LC00`, `LC15`
107107

108-
2. **If `BUCKET ≠ 00`**`LC_OR_SUBBUCKET` **must** match:
108+
2. **If `BUCKET ≠ 00`**`LC_OR_SUBBUCKET` **must** match bucket-specific ranges:
109109
```regex
110-
^SB\d{2}$
110+
^SB(1[5-9]|[2-9]\d)$
111111
```
112-
* Valid: `SB00`, `SB01`, ..., `SB99`
113-
* Invalid: `LC01`, `SB`, `SBXX`
114-
* **Convention**: Use `SB00` if no sub-bucket applies
112+
113+
**Bucket-specific subbucket ranges:**
114+
115+
| BUCKET | Domain | Allowed Subbuckets |
116+
|--------|--------|-------------------|
117+
| `10` | Operations | SB15-SB19, SB80-SB85 |
118+
| `20` | Primary Subsystem | SB20-SB29 |
119+
| `30` | Circularity | SB30-SB39 |
120+
| `40` | Software | SB40-SB49 |
121+
| `50` | Structures | SB50-SB59 |
122+
| `60` | Storages | SB60-SB69 |
123+
| `70` | Propulsion | SB70-SB79 |
124+
| `80` | Energy | SB86-SB89 |
125+
| `90` | Tables/Schemas/Diagrams | SB90-SB99 |
126+
127+
* Invalid: `LC01`, `SB00`, `SB01`, ..., `SB14`, `SB`, `SBXX`
128+
* Invalid: Subbuckets outside the allowed range for the specific BUCKET
129+
* **Convention**: SB00-SB14 are reserved; each bucket has designated ranges
115130

116131
**Sub-bucket mapping:**
117-
* `SB00` = No sub-bucket / Not applicable
118-
* `SB01` = Maps to directory sub-bucket `*-01_*` (e.g., `00-20-01_*`)
119-
* `SB02` = Maps to directory sub-bucket `*-02_*`
120-
* etc.
132+
* Each BUCKET uses designated subbucket ranges aligned with the domain
133+
* Ranges are enforced to maintain clear separation between buckets
134+
* Note: SB00-SB14 are reserved and not available for use
135+
121136

122137
### 4.5 `[VARIANT]` (Configuration / Baseline)
123138

@@ -138,7 +153,7 @@ Hyphenated variants are allowed: `SYS-01`, `SW-PLAT-A`.
138153

139154
* Must be lowercase kebab-case.
140155
* Must not duplicate semantic content already encoded in `TYPE` or `BUCKET`.
141-
* Example: avoid `..._FHA_SYS_propulsion-fha_...` → use `..._FHA_SB00_SYS_propulsion_...`
156+
* Example: avoid `..._FHA_SYS_propulsion-fha_...` → use `..._FHA_SB15_SYS_propulsion_...`
142157

143158
### 4.7 `[VERSION]`
144159

@@ -154,7 +169,7 @@ Hyphenated variants are allowed: `SYS-01`, `SW-PLAT-A`.
154169
This regex validates the general filename structure for v2.0:
155170

156171
```regex
157-
^(?<root>\d{2})_(?<bucket>00|10|20|30|40|50|60|70|80|90)_(?<type>[A-Z0-9]{2,8})_(?<stage>(LC(0[1-9]|1[0-4])|SB\d{2}))_(?<variant>[A-Z0-9]+(?:-[A-Z0-9]+)*)_(?<desc>[a-z0-9]+(?:-[a-z0-9]+)*)_(?<ver>v\d{2})\.(?<ext>[a-z0-9]{1,6})$
172+
^(?<root>\d{2})_(?<bucket>00|10|20|30|40|50|60|70|80|90)_(?<type>[A-Z0-9]{2,8})_(?<stage>(LC(0[1-9]|1[0-4])|SB(1[5-9]|[2-9]\d)))_(?<variant>[A-Z0-9]+(?:-[A-Z0-9]+)*)_(?<desc>[a-z0-9]+(?:-[a-z0-9]+)*)_(?<ver>v\d{2})\.(?<ext>[a-z0-9]{1,6})$
158173
```
159174

160175
### 5.2 Conditional Rules (Mandatory)
@@ -166,10 +181,11 @@ CI shall additionally enforce:
166181
^LC(0[1-9]|1[0-4])$
167182
```
168183

169-
* **If `bucket != "00"`** then `stage` matches:
184+
* **If `bucket != "00"`** then `stage` matches bucket-specific ranges:
170185
```regex
171-
^SB\d{2}$
186+
^SB(1[5-9]|[2-9]\d)$
172187
```
188+
And falls within the bucket's designated range (see section 4.4)
173189

174190
---
175191

@@ -179,17 +195,21 @@ CI shall additionally enforce:
179195

180196
* Lifecycle (LC) plan:
181197
* `00_00_PLAN_LC02_SPACET_safety-program_v02.md`
182-
* Propulsion FHA (domain bucket with no sub-bucket):
183-
* `00_70_FHA_SB00_SYS_propulsion_v02.md`
198+
* Propulsion FHA (domain bucket with sub-bucket):
199+
* `00_70_FHA_SB70_SYS_propulsion_v02.md`
184200
* Software safety requirements:
185-
* `00_40_REQ_SB00_SW_software-safety-reqs_v02.md`
201+
* `00_40_REQ_SB40_SW_software-safety-reqs_v02.md`
186202
* Traceability matrix workbook:
187-
* `00_20_TRC_SPACET_traceability-matrix_v01.xlsx`
203+
* `00_20_TRC_SB20_SPACET_traceability-matrix_v01.xlsx`
188204
* Reference schema:
189-
* `00_90_SCH_GEN_hazard-log-schema_v01.json`
205+
* `00_90_SCH_SB90_GEN_hazard-log-schema_v01.json`
206+
* Operations plan:
207+
* `00_10_PLAN_SB15_GEN_operations-plan_v01.md`
208+
* Energy system FHA:
209+
* `00_80_FHA_SB86_SYS_energy-system_v01.md`
190210
* Extended ATA code (3-digit ROOT):
191211
* `115_00_PLAN_LC01_SPACET_supply-chain-plan_v01.md`
192-
* `116_70_FHA_SB00_SYS_facility-systems_v01.md`
212+
* `116_70_FHA_SB70_SYS_facility-systems_v01.md`
193213

194214
### 6.2 Invalid examples
195215

validate_nomenclature.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class NomenclatureValidator:
4444
r'^(?P<root>\d{2,3})_'
4545
r'(?P<bucket>00|10|20|30|40|50|60|70|80|90)_'
4646
r'(?P<type>[A-Z0-9]{2,8})_'
47-
r'(?P<stage>(LC(0[1-9]|1[0-4])|SB\d{2}))_'
47+
r'(?P<stage>(LC(0[1-9]|1[0-4])|SB(1[5-9]|[2-9]\d)))_'
4848
r'(?P<variant>[A-Z0-9]+(?:-[A-Z0-9]+)*)_'
4949
r'(?P<desc>[a-z0-9]+(?:-[a-z0-9]+)*)_'
5050
r'(?P<ver>v\d{2})'
@@ -54,15 +54,28 @@ class NomenclatureValidator:
5454
# LC stage pattern (LC01-LC14)
5555
LC_PATTERN = re.compile(r'^LC(0[1-9]|1[0-4])$')
5656

57-
# SB stage pattern (SB00-SB99)
58-
SB_PATTERN = re.compile(r'^SB\d{2}$')
57+
# SB stage pattern (SB15-SB99)
58+
SB_PATTERN = re.compile(r'^SB(1[5-9]|[2-9]\d)$')
5959

6060
# VERSION format pattern
6161
VERSION_PATTERN = re.compile(r'^v\d{2}$')
6262

6363
# Allowed buckets
6464
ALLOWED_BUCKETS = {'00', '10', '20', '30', '40', '50', '60', '70', '80', '90'}
6565

66+
# Bucket-specific subbucket ranges
67+
BUCKET_SUBBUCKET_RANGES = {
68+
'10': [(15, 19), (80, 85)], # Operations: SB15-SB19 + SB80-SB85
69+
'20': [(20, 29)], # Primary Subsystem: SB20-SB29
70+
'30': [(30, 39)], # Circularity: SB30-SB39
71+
'40': [(40, 49)], # Software: SB40-SB49
72+
'50': [(50, 59)], # Structures: SB50-SB59
73+
'60': [(60, 69)], # Storages: SB60-SB69
74+
'70': [(70, 79)], # Propulsion: SB70-SB79
75+
'80': [(86, 89)], # Energy: SB86-SB89
76+
'90': [(90, 99)], # Tables/Schemas/Diagrams/Reference: SB90-SB99
77+
}
78+
6679
# Approved TYPE vocabulary
6780
APPROVED_TYPES = {
6881
# Planning / Control
@@ -178,8 +191,31 @@ def validate_filename(self, filename: str) -> ValidationResult:
178191
# BUCKET≠00 requires SB stage
179192
if not self.SB_PATTERN.match(stage):
180193
errors.append(
181-
f"BUCKET={bucket} requires LC_OR_SUBBUCKET to be SB00-SB99, got '{stage}'"
194+
f"BUCKET={bucket} requires LC_OR_SUBBUCKET to be SB format, got '{stage}'"
182195
)
196+
else:
197+
# Validate bucket-specific subbucket range
198+
if bucket in self.BUCKET_SUBBUCKET_RANGES:
199+
try:
200+
# Extract numeric part from stage (e.g., "SB15" -> 15)
201+
sb_num = int(stage[2:])
202+
ranges = self.BUCKET_SUBBUCKET_RANGES[bucket]
203+
204+
# Check if subbucket number is in any of the allowed ranges for this bucket
205+
in_range = any(start <= sb_num <= end for start, end in ranges)
206+
207+
if not in_range:
208+
# Format ranges for error message
209+
range_strs = [f"SB{start:02d}-SB{end:02d}" for start, end in ranges]
210+
allowed = " or ".join(range_strs)
211+
errors.append(
212+
f"BUCKET={bucket} requires LC_OR_SUBBUCKET to be {allowed}, got '{stage}'"
213+
)
214+
except (ValueError, IndexError):
215+
# This should not happen if SB_PATTERN matched, but handle defensively
216+
errors.append(
217+
f"Invalid subbucket format '{stage}' for BUCKET={bucket}"
218+
)
183219

184220
# Check for redundancy in DESCRIPTION
185221
desc_lower = desc.lower()

0 commit comments

Comments
 (0)