Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ name: CI
on:
push:
branches: ["main"]
# No base-branch filter: stacked sub-MVP PRs target feature branches and
# must pass CI independently (CLAUDE.md PR discipline).
pull_request:
branches: ["main"]

permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ docs/adr/
017-project-manual-publishing.md
018-document-concurrency-state-model.md
019-scope-boundaries-content-neutral-platform.md
020-section-number-expanded-shape.md
```

**ADR format:**
Expand Down
39 changes: 39 additions & 0 deletions docs/adr/020-section-number-expanded-shape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ADR-020: Expanded Section-Number Shape as Opaque Normalized String

## Status: Accepted

## Context

CSI MasterFormat Level 4 (`26 00 13.10`) and UFGS Level 5 agency suffixes
(`01 32 01.00 10`; 10 = Army Corps, 20 = NAVFAC, 30/40 = NASA/AFCEC) appear in
36% of the UFGS reference corpus and arrive through every ingest format (.SEC,
DOCX, plaintext). SpecR previously validated only `NN NN NN`, silently
truncating suffixes in prose-ref extraction and content inference — collapsing
distinct sections (e.g. `01 33 23` vs `01 33 23.33`) into one identity.

Two viable designs:
1. Opaque normalized string, grammar owned by one module.
2. Structured `SectionNumber` type with decomposed DB columns
(division/l2/l3/suffix/agency).

## Decision

Opaque normalized string (`src/lib/section-number.ts` owns the grammar).
Canonical form: single ASCII spaces, `NN NN NN`, `NN NN NN.NN`, or
`NN NN NN.NN NN`. Cross-reference linking remains **exact match only** — a ref
to `26 00 13` never resolves to `26 00 13.10` or vice versa. DB CHECK
constraints enforce shape on `specs.section` (plus the `'unknown'` inference
sentinel) and `spec_sections.section_number`;
`spec_references.target_spec_section` stays unconstrained because it records
what the source document said.

## Consequences

- One module to change when the grammar grows; consumers embed its fragment.
- Exact-match keeps broken refs honest (a base ref to a missing base section
is genuinely broken) at the cost of no family fallback.
- Structured queries (e.g. "all agency variants of X") require LIKE prefixes
rather than column equality — acceptable; no current feature needs them.
- Free-prose ambiguity: `Section 26 00 13.10 20 mm` mis-reads `20` as an
agency suffix. Documented as KNOWN AMBIGUITY; tagged .SEC refs are immune.
- Lexicographic ORDER BY remains correct for the fixed-width grammar.
Loading