Skip to content

feat(api): accept suffixed sections in schemas, parse worker, PATCH, filenames#116

Merged
thewrz merged 24 commits into
mainfrom
feat/section-number-api
Jun 6, 2026
Merged

feat(api): accept suffixed sections in schemas, parse worker, PATCH, filenames#116
thewrz merged 24 commits into
mainfrom
feat/section-number-api

Conversation

@thewrz

@thewrz thewrz commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on the parsers PR. Closes the API-side gates:

  • ast/schemas: SpecTreeSchema.section accepts expanded shapes or the 'unknown' parser sentinel; PatchSpecBodySchema accepts expanded shapes only — PATCH /specs/:id no longer 422s legitimate suffixed sections, and clients cannot write the sentinel.
  • api/parse: worker-output schema gated to expanded-shape-or-'unknown' (closes the parse-vs-PATCH inconsistency); the optional body section override is normalized, with 400 on malformed input before job creation; section-gate job failures surface a friendly message instead of a Zod JSON blob.
  • parser/docx: free-text dc:subject metadata degrades to 'unknown' (content inference takes over) instead of poisoning the gated tree.
  • api/generate: download filename preserves the dot — 26-00-13.10-….docx.
  • Generator suffix-safety pins (markdown H1 + DOCX document.xml) and HTTP-level PATCH integration tests; four stale NN NN NN-only ARCHITECTURE.md examples refreshed.

Test Plan

  • pnpm test — 579 unit tests green at this commit
  • docker compose up -d postgres && cp -n .env.example .env; set -a && source .env && set +a && pnpm migrate && pnpm seed && pnpm test:integration — PATCH accepts 27 21 00.10 and 27 21 00.10 20 over HTTP; '27210' still 422s

Out of Scope

This PR does NOT touch the DB layer — normalization migration, CHECK constraints, and seed hardening land in PR 4. The MCP/file-loader direct-persist paths remain backstopped only after PR 4's CHECK constraints.

Summary by CodeRabbit

  • New Features

    • Added support for expanded CSI section number formats, including dotted suffixes (e.g., "27 21 00.10") and agency suffixes (e.g., "27 21 00.10 20").
    • Improved filename generation for document exports to preserve section distinctions.
  • Bug Fixes

    • Enhanced section number validation with clearer error messages for invalid formats.
    • Improved section normalization to handle extra whitespace consistently.
  • Documentation

    • Updated architectural documentation to reflect expanded CSI section format specifications.

thewrz added 19 commits June 5, 2026 19:00
safeFilename now allows '.' in the section part so '26 00 13.10'
renders as '26-00-13.10-Panelboards.docx' rather than mangling the
dot to a dash. Function exported for unit testing.
…CX title

Regression pins — no production change. Verifies that renderMarkdown
emits the section verbatim in the H1 header and that generateDocx
writes it unchanged into document.xml, so future refactors cannot
silently mangle dotted agency suffixes (e.g. '27 05 13.43').
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR expands CSI section number format support to include dotted and agency suffixes. The codebase now validates, preserves, and normalizes section values like 27 21 00.10 and 27 21 00.10 20 across parsing, API handlers, generation, and storage layers.

Changes

Section Format Expansion

Layer / File(s) Summary
Schema contracts and validation
src/ast/schemas.ts, src/ast/schemas.test.ts
Import SectionNumberSchema and update SpecTreeSchema.section to accept validated sections or 'unknown' sentinel; update PatchSpecBodySchema.section to use SectionNumberSchema.exactOptional() to disallow sentinel in PATCH payloads. Tests cover dotted/agency suffixes and sentinel acceptance/rejection.
Parser input normalization
src/parser/docx/index.ts, src/parser/docx/index.test.ts
Update parseCoreMetadata to normalize extracted dc:subject via normalizeSectionNumber, falling back to 'unknown' for non-conforming values. Tests verify degradation of free-text, preservation of conforming sections, and whitespace normalization.
Parse API handler section validation
src/api/parse.ts, src/api/parse.test.ts
Parse and normalize section overrides in request body, returning 400 on invalid formats. Tighten workerOutputSchema validation and introduce jobErrorMessage helper to convert section validation errors to user-friendly messages. Tests cover override normalization, malformed overrides, and error message flow.
Generate API filename sanitization
src/api/generate.ts, src/api/generate.test.ts
Export safeFilename and update section-part regex to permit . characters while preserving suffixes. Unit tests verify dotted-suffix preservation, agency-form handling, and base behavior.
Output generation and integration testing
src/generator/index.test.ts, src/generator/markdown.test.ts, src/api/specs.integration.test.ts
Add tests confirming suffixed sections appear in generated DOCX and markdown output. Add PATCH integration tests verifying successful update and reflection of suffixed sections in response bodies.
Architecture documentation
ARCHITECTURE.md
Update inline comments for CsiTree.section, specs.section, and spec_references.target_spec_section to document expanded format variants (ADR-020).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • wrzonance/SpecR#26: Introduces the safeFilename function in src/api/generate.ts for DOCX filename construction; this PR updates that function to allow . characters for section suffixes.

Poem

🐰 Sections now dance with dots and grace,
From 27 21 00 to 27 21 00.10,
The parser normalizes, the schema holds tight,
And suffixes flow through the pipeline just right!
✨ No more section surprises—only clarity!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: accepting expanded (suffixed) section numbers across multiple API/parsing components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/section-number-api

Comment @coderabbitai help to get the list of available commands and usage tips.

@thewrz

thewrz commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
ARCHITECTURE.md (1)

347-347: 💤 Low value

Consider adding the agency suffix example for consistency.

Lines 228 and 265 document all three expanded section formats (basic, dotted suffix, and agency suffix), but this comment only shows two examples. Adding "01 32 01.00 10" or similar would maintain consistency across all three section-related schema comments.

📝 Suggested addition
-  target_spec_section VARCHAR(20),           -- "09 91 00" / "26 00 13.10" — for section refs
+  target_spec_section VARCHAR(20),           -- "09 91 00" / "26 00 13.10" / "01 32 01.00 10" — for section refs
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ARCHITECTURE.md` at line 347, The comment for target_spec_section (the column
definition containing "09 91 00" / "26 00 13.10") is missing the agency-suffix
example; update the inline schema comment for target_spec_section to include a
third example showing an agency suffix (e.g., "01 32 01.00 10") so it matches
the expanded formats documented elsewhere (lines that show basic, dotted suffix,
and agency suffix formats).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/parse.ts`:
- Around line 68-79: Update the /parse handler to validate the incoming req.body
with a Zod schema using safeParse before calling parseBody: define a zod object
that enforces title and section (if present) are strings (or optional strings),
call schema.safeParse(req.body) and if it fails return res.status(400).json({
success: false, error: ... }) immediately; only after successful validation call
parseBody(req.body) to produce rawBody and then proceed with
normalizeSectionNumber and creation of the ParseBody object (referencing
parseBody, rawBody, normalizeSectionNumber, ParseBody, req, and res).

---

Nitpick comments:
In `@ARCHITECTURE.md`:
- Line 347: The comment for target_spec_section (the column definition
containing "09 91 00" / "26 00 13.10") is missing the agency-suffix example;
update the inline schema comment for target_spec_section to include a third
example showing an agency suffix (e.g., "01 32 01.00 10") so it matches the
expanded formats documented elsewhere (lines that show basic, dotted suffix, and
agency suffix formats).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 144f123a-583e-40f2-9dae-6bc6d12a2a89

📥 Commits

Reviewing files that changed from the base of the PR and between 0d7ecd4 and 1d2dd44.

📒 Files selected for processing (12)
  • ARCHITECTURE.md
  • src/api/generate.test.ts
  • src/api/generate.ts
  • src/api/parse.test.ts
  • src/api/parse.ts
  • src/api/specs.integration.test.ts
  • src/ast/schemas.test.ts
  • src/ast/schemas.ts
  • src/generator/index.test.ts
  • src/generator/markdown.test.ts
  • src/parser/docx/index.test.ts
  • src/parser/docx/index.ts

Comment thread src/api/parse.ts Outdated
Base automatically changed from feat/section-number-parsers to main June 6, 2026 20:50
@thewrz thewrz merged commit 269cf81 into main Jun 6, 2026
5 checks passed
@thewrz thewrz deleted the feat/section-number-api branch June 6, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant