Skip to content

feat: remove variant as behavioral gate, recursive implementations, scoped two-phase traversal#328

Merged
jimisola merged 6 commits intomainfrom
feat/324-remove-variant-behavioral-gate
Mar 19, 2026
Merged

feat: remove variant as behavioral gate, recursive implementations, scoped two-phase traversal#328
jimisola merged 6 commits intomainfrom
feat/324-remove-variant-behavioral-gate

Conversation

@jimisola
Copy link
Member

@jimisola jimisola commented Mar 19, 2026

Summary

  • Removes variant (system/microservice/external) as a behavioral gate — parsing is now presence-based (closes feat: investigate removing variant (system/microservice/external) #324)
  • Adds two-phase graph traversal: import chain (full insert) then implementation chain (metadata-only for requirements) — recursive library-uses-library model (closes Allow SVCs on external variant projects #73)
  • Post-parse _remove_implementation_requirements() in DatabaseFilterProcessor deletes out-of-scope requirement rows via SQL DELETE + CASCADE
  • Adds CircularImplementationError and cycle detection for implementation chains (independent visited set, mirrors CircularImportError)
  • Adds docs/DESIGN.md as a permanent architectural reference
  • Updates CLAUDE.md with a Design Decisions section capturing 7 architectural rules
  • Rewrites docs/modules/ROOT/pages/how_it_works.adoc to reflect current SQLite pipeline and two-phase traversal

Design decisions

Decision Rationale
Implementation traversal is recursive Think library-uses-library (lib-a → lib-b → lib-c), not system→microservice. Flat traversal silently misses evidence.
requirements.yml always fully parsed Validation runs for all nodes regardless of role; only DB insertion differs.
Cleanup is post-parse, not ingest-time ~30 lines in filter processor vs ~150 lines restructuring generator + populator. DB is ephemeral.
FK constraints do scoping work for SVCs/MVRs/annotations Rows referencing out-of-scope requirements are silently rejected on insert — no explicit filter needed.
Test results need explicit scoping No FK (keyed by FQN), so scope check required when inserting from implementation children.

Test plan

  • test_circular_import_raises — node-a → node-b → node-a cycle raises CircularImportError
  • test_circular_implementation_raises — lib-a → lib-b → lib-a cycle raises CircularImplementationError
  • test_implementation_traversal_recursive — root → lib-a → lib-b → lib-c, all 4 URNs in raw_datasets, correct graph edges
  • All 303 unit tests pass (hatch run dev:pytest tests/unit)
  • flake8 clean
  • Regression smoke tests match baseline (test_standard, test_basic, reqstool-demo)

Closes

Closes #73
Closes #324

…ection (#324)

Parsing is now presence-based instead of gated by variant:
- All sections (imports, implementations, filters, requirements) are parsed
  unconditionally based on their presence in the YAML
- variant field is optional in JSON Schema and domain model
- Cycle detection added to import traversal (CircularImportError)
- parsing_graph edges now carry edge_type ('import'/'implementation')
- Filter processor uses edge_type instead of variant to skip implementation edges
- Removed model_is_external utility and all variant assertions/match blocks

Signed-off-by: Jimisola Laursen <jimisola@users.noreply.github.com>
Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
@jimisola
Copy link
Member Author

Traversal Design Decision

From any initial URN's perspective:

  • Imports = parents (upward): "whose requirements do I reference?" → follow recursively
  • Implementations = children (downward): "who implements my requirements?" → load their annotations/SVCs/tests, but NOT their imports

Example (4-layer graph, C1 as initial)

  • Up (imports): C1 → B1 → A1, A4 — these define the requirements C1 can reference
  • Down (implementations): C1 → D1 — D1 provides annotations/SVCs/test results for C1's requirements
  • D1's import of C2: irrelevant. D1 may also implement C2's requirements, but that's C2's concern, not C1's

Decisions

  • Implementation import traversal: Implementations are leaf nodes. Their imports are out of scope because they point to requirements outside the initial URN's parent chain.
  • Cycle detection scope: Import chain only — cycles can only occur going up the import chain. Implementation edges point down and aren't recursed into.

See docs/PLAN_remove_variants.md for the full discussion graph and scenarios.

- Add test_circular_import_raises with fixture data (node-a ↔ node-b cycle)
- Add Q3 answer to PLAN_remove_variants.md (presence-based parsing for all URNs)

Signed-off-by: Jimisola Laursen <jimisola@users.noreply.github.com>
…se cleanup (closes #73, closes #324)

- Implementation chains are now traversed recursively (library-uses-library model)
  replacing the flat leaf-node approach
- Add CircularImplementationError with cycle detection for implementation chains
- Add DatabaseFilterProcessor._remove_implementation_requirements() to exclude
  implementation-child requirement rows via post-parse SQL DELETE + CASCADE
- Add docs/DESIGN.md capturing traversal architecture and key decisions
- Update CLAUDE.md with Design Decisions section and corrected architecture description
- Update docs/modules/ROOT/pages/how_it_works.adoc to reflect SQLite pipeline
  and two-phase traversal
- Update docs/PLAN_remove_variants.md: revise Q1/Q2, add Q4-Q6

Signed-off-by: Jimisola Laursen <jimisola@users.noreply.github.com>
@jimisola jimisola changed the title feat: remove variant as behavioral gate, make optional, add cycle detection feat: remove variant as behavioral gate, recursive implementations, scoped two-phase traversal Mar 19, 2026
datamodel-codegen no longer needs a RootModel wrapper after the variant
field became optional in 5c052a2.
#324)

commit 889ecbb regenerated requirements_schema.py, collapsing
Model(RootModel[Model1]) into a flat Model(BaseModel). The generator
was still calling validated.root; replace with validated directly.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
@jimisola jimisola self-assigned this Mar 19, 2026
Design decisions are now documented in CLAUDE.md and DESIGN.md.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
@jimisola jimisola merged commit 195eaf5 into main Mar 19, 2026
7 checks passed
@jimisola jimisola deleted the feat/324-remove-variant-behavioral-gate branch March 19, 2026 22:08
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.

feat: investigate removing variant (system/microservice/external) Allow SVCs on external variant projects

1 participant