Conversation
…, glossary (FEAT-035) A domain is a directory of UMF tables with a domain.yaml: the DDD bounded context. Its exports are the published language (each exported table must declare a primary key), its suppliers are the context map (with a DDD integration pattern per edge), and its glossary is the vocabulary that new `term` fields on tables and columns resolve against. Models - models/domain.py: DomainMetadata, SupplierRelationship, IntegrationPattern, Glossary/GlossaryTerm, load_domain (name must equal directory), load_glossary. - ForeignKey: references_domain + integration; legacy references_pipeline is reconciled both ways, disagreement is an error, cross_pipeline forced true; extra="forbid" so unknown keys fail on load instead of vanishing on save. - UMF.term / UMFColumn.term persisted through split format; canonical_name untouched. - umf.schema.json regenerated; new test pins it to UMF.model_json_schema(). Validation - domains.py: find_domain_dirs (root + direct children), load_domain_dir, discover_domains. - domain_validator.py: DOM-EXPORT, DOM-SUPPLIER, DOM-XREF (cross-domain FK must target an exported table's PK via a declared supplier), DOM-TERM, DOM-DRIFT (warning), DOM-LOAD. - validator.validate_domain_root; `tablespec validate <root>` enters domain mode when the root is or contains domain.yaml directories. Guidebook - domain_map.py renders domains.html (owners, exports, supplier edges, cross-domain references) linked from the top index. Supplier/consumer wording; upstream/downstream stay reserved for lineage (ADR-018). - reverse_lineage reads references_domain / target_table. Governance and docs - ADR-020, FEAT-035, US-051, SD-035 (surface contract), PRD FR-24.1..24.5, registry + frame index rows, implementation-plan module map, brand-voice approved terms, docs/guide/domains.md, CLI reference, guidebook guide. Domains do not drive catalog/schema routing (ADR-013 preserved). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sary surfaces (ADR-021) Second FEAT-035 slice, re-scoped after a Codex adversarial review of the DDD follow-up plan (BLOCK; 11 blocking findings, all accepted). Record: docs/helix/06-iterate/alignment-reviews/AR-2026-09-15-ddd-follow-up-plan-review.md Versioning - domain.version is strict MAJOR.MINOR.PATCH; suppliers.<d>.version is a small explicit range grammar (>=, <=, ==, !=, >, < clauses), not PEP 440. - DOM-PIN: supplier version outside the consumer's range, or unversioned supplier pinned. DOM-VERSION (warning): exports without a version. - `tablespec validate <root> --baseline <old>`: pairs domains by name, compares the union of export lists, runs check_compatibility on tables exported on both sides (forward-only breaks downgraded to warning), prints "Published-language changes", and fails DOM-COMPAT when a breaking change lacks a MAJOR bump or a version is missing on either side. Read-only; no changelog mutation; no new command. Patterns - Integration patterns are advisory (consumer-only declaration cannot establish bilateral or supplier-side facts). Only separate_ways is enforced: DOM-WAYS on a consumes list or a crossing foreign key. Glossary surfaces - render_table_page(glossary=...): cited terms render as chips with the definition as tooltip and an inline definition line; generator passes the owning domain's glossary. - generate_documentation_prompt(umf_data, *, glossary=None): lists only the terms the table and columns cite, sorted, aliases canonicalized; output unchanged without a glossary. Deferred (ADR-021 decision 7): UMF.kind entity/event/reference, subdomain kind, executable conformist/anti-corruption/shared-kernel rules. Docs and governance - ADR-021, US-052 (AC1-AC5 cited by tests), FEAT-035 areas VER/GLOSS, SD-035 contracts (version grammar, rule IDs, published-language boundary, CLI, glossary markup), PRD FR-24.6/24.7, registry and index rows. - Microsite concepts/domains page with DDD-to-tablespec mapping and sources (primary DDD sources separated from adjacent ideas); concepts card, link-check seed, Playwright coverage; CLI reference --baseline row. - docs/guide/domains.md: versioning, glossary surfaces, mapping table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing-aware domain rules `tablespec validate <path>` previously switched into a separate mode when a domain.yaml sat at or directly under the path. That design was wrong in three ways, each reproduced before the fix: - A metadata file decided whether tables were validated at all. Directory validation looked one level down only, so tables organized into group folders (`eligibility/member`, `claims/medical_claims`) validated ZERO tables unless a domain.yaml happened to be present. - Validating one domain directory loaded only what sat under that path, so its suppliers (one directory up) were reported as "not found" (spurious DOM-SUPPLIER and DOM-XREF). - Validating a single table never checked that table's keys into other domains, and `--baseline` was silently ignored outside the mode. Now there is one behavior: - `validate_pipeline` finds table directories at any depth (hidden and vendored dirs skipped; no descent into a table dir). Direct children keep their bare `table_name` key; nested tables are `<parent path>/<table_name>`. `recursive=False` keeps the old one-level lookup for API callers. - `domains.resolve_domain_scopes(path)` finds the domain roots a path involves: walking up when the path is a domain or inside one (stopping at a repository root), walking down otherwise. Each root's full sibling set is loaded, because a consumer's supplier lives next to it, not beneath it. - `validator.validate_domain_scopes(path, baseline=)` runs the rules over the full sibling set and narrows findings to the domains, or the single table, the path covers. A path above several roots labels each domain with its root. A domain.yaml that fails to load is a DOM-LOAD error instead of a silent skip. - `--baseline` resolves its roots the same way, pairs them with the current ones, covers a domain removed from a covered root, and prints a note when no domain.yaml applies on either side. - Removed the unreleased `is_domain_root`, `validate_domain_root`, NO_DOMAIN. Behavior change for existing users: directory validation is now recursive, so a repo that silently validated nothing may surface real failures. Docs: SD-035 CLI contract rewritten (and records the rejected mode design), ADR-020 decision 7, F035-VAL-01/05, US-051-AC4, US-052-AC4, domains guide, CLI guide, microsite CLI reference. No doc says "domain mode" any more. Tests: tests/unit/test_validate_scopes.py pins each failure above plus multi-root labelling, pruning, nested domain.yaml, DOM-LOAD, and baseline pairing. Full suite: 3991 passed, 119 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Domain-Driven Design integration for tablespec. A domain is a directory of UMF tables with a
domain.yaml: the bounded context. Itsexportsare the published language (versioned), itssuppliersare the context map (advisory patterns, with consumer pins), and its glossary is the vocabulary thattermfields resolve against and that the guidebook and prompts show.Models (ADR-020)
models/domain.py:DomainMetadata,SupplierRelationship,IntegrationPattern,Glossary;load_domain(name must equal directory).ForeignKey:references_domain+integration.extra="forbid", so an unknown key fails on load instead of vanishing on save. Legacyreferences_pipelineis read the same way and never rewritten: a spec that does not usereferences_domainloads, saves, and compiles byte-for-byte as before.UMF.term/UMFColumn.term;canonical_nameuntouched.umf.schema.jsonregenerated and pinned by a new test (it was already stale).Validation: one behavior, no mode
tablespec validate <path>validates every table beneath the path at any depth, and applies the rules between domains whenever adomain.yamlapplies to the path (the path is a domain, is inside one, or has domains beneath it). Sibling domains are loaded from the directory that holds them, so validating one domain or one table still checks its references into the others. Findings are narrowed to what the path covers.An earlier commit on this branch used a separate "domain mode". It was removed because it made a metadata file decide whether tables were validated at all, and reported a lone domain's suppliers as "not found". SD-035 records the rejected design.
Rules:
DOM-EXPORT,DOM-SUPPLIER,DOM-XREF,DOM-TERM,DOM-WAYS,DOM-PIN,DOM-LOAD,DOM-COMPAT(with--baseline), warningsDOM-VERSION,DOM-DRIFT. No new CLI command.Published-language versioning (ADR-021)
domain.versionis strict SemVer core;suppliers.<d>.versionis a small explicit range grammar (not PEP 440).tablespec validate <path> --baseline <old>compares each covered domain's exports across revisions and failsDOM-COMPATwhen a breaking change lacks a MAJOR bump. Read-only; no changelog change.Integration patterns are advisory: only the consumer declares an edge, so bilateral or supplier-side facts cannot be verified. Only
separate_waysis enforced. This and the deferral ofUMF.kindand subdomain kind came out of a Codex adversarial review of the follow-up plan (BLOCK, 11 blocking findings, all accepted):docs/helix/06-iterate/alignment-reviews/AR-2026-09-15-ddd-follow-up-plan-review.md.Guidebook and prompts
domains.htmldomain map (supplier/consumer wording; upstream/downstream stay reserved for lineage per ADR-018). Table pages show each cited term's definition.generate_documentation_prompt(..., glossary=)lists only cited terms.Docs and governance
ADR-020, ADR-021, FEAT-035, US-051, US-052, SD-035 (surface contract), PRD FR-24.1–24.7, registry/index rows,
docs/guide/domains.md, micrositeconcepts/domainspage with a DDD-to-tablespec mapping and sources, CLI reference.User-facing impact
If you add no
domain.yaml:validate_pipeline(..., recursive=False)keeps the old lookup for API callers.canonical_name, command count) is unchanged.If you adopt domains: cross-domain references are checked, breaking export changes require a MAJOR bump that consumers must accept, and the guidebook gains the map and term definitions.
Decisions a reviewer should weigh
domain, notcontext("context" is the line-of-business axis in this codebase).wip:subject; a squash merge makes it moot.Verification
ruff format --check/ruff checkpyright src🤖 Generated with Claude Code