feat: enforce shared UI foundations and pin reference journey
This commit is contained in:
@@ -17,6 +17,70 @@ MODULE_NAME_PATTERN = re.compile(
|
||||
r"[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*"
|
||||
)
|
||||
REQUIRED_DOCUMENTATION_TYPES = frozenset({"admin", "user"})
|
||||
CANONICAL_PRODUCT_AREAS = {
|
||||
"work": (
|
||||
"i18n:govoplan-core.product_area.work",
|
||||
"list-checks",
|
||||
"i18n:govoplan-core.product_area.work_description",
|
||||
10,
|
||||
),
|
||||
"services-cases": (
|
||||
"i18n:govoplan-core.product_area.services_cases",
|
||||
"landmark",
|
||||
"i18n:govoplan-core.product_area.services_cases_description",
|
||||
20,
|
||||
),
|
||||
"records-documents": (
|
||||
"i18n:govoplan-core.product_area.records_documents",
|
||||
"folder",
|
||||
"i18n:govoplan-core.product_area.records_documents_description",
|
||||
30,
|
||||
),
|
||||
"communication": (
|
||||
"i18n:govoplan-core.product_area.communication",
|
||||
"mail",
|
||||
"i18n:govoplan-core.product_area.communication_description",
|
||||
40,
|
||||
),
|
||||
"meetings-decisions": (
|
||||
"i18n:govoplan-core.product_area.meetings_decisions",
|
||||
"calendar",
|
||||
"i18n:govoplan-core.product_area.meetings_decisions_description",
|
||||
50,
|
||||
),
|
||||
"data-assurance": (
|
||||
"i18n:govoplan-core.product_area.data_assurance",
|
||||
"database-zap",
|
||||
"i18n:govoplan-core.product_area.data_assurance_description",
|
||||
60,
|
||||
),
|
||||
"people-responsibility": (
|
||||
"i18n:govoplan-core.product_area.people_responsibility",
|
||||
"users",
|
||||
"i18n:govoplan-core.product_area.people_responsibility_description",
|
||||
70,
|
||||
),
|
||||
}
|
||||
# These surfaces are intentionally global, administrative, security-policy, or
|
||||
# shell infrastructure. They remain discoverable through their dedicated shell
|
||||
# affordance or through "All available tools" instead of a business area.
|
||||
PRODUCT_AREA_EXEMPT_MODULES = frozenset(
|
||||
{
|
||||
"access",
|
||||
"admin",
|
||||
"audit",
|
||||
"dashboard",
|
||||
"docs",
|
||||
"encryption",
|
||||
"identity_trust",
|
||||
"ops",
|
||||
"policy",
|
||||
"quick_access",
|
||||
"search",
|
||||
"tenancy",
|
||||
"views",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
@@ -113,6 +177,42 @@ def main() -> int:
|
||||
)
|
||||
continue
|
||||
|
||||
frontend = manifest.frontend
|
||||
has_user_facing_surface = frontend is not None and bool(
|
||||
frontend.routes
|
||||
or frontend.public_routes
|
||||
or frontend.nav_items
|
||||
or frontend.settings_routes
|
||||
)
|
||||
if (
|
||||
has_user_facing_surface
|
||||
and not frontend.product_areas
|
||||
and manifest.id not in PRODUCT_AREA_EXEMPT_MODULES
|
||||
):
|
||||
errors.append(
|
||||
f"{repository_name}: user-facing module {manifest.id!r} has no "
|
||||
"ProductAreaContribution and is not an explicit global/technical exemption"
|
||||
)
|
||||
if frontend is not None:
|
||||
for contribution in frontend.product_areas:
|
||||
expected = CANONICAL_PRODUCT_AREAS.get(contribution.id)
|
||||
actual = (
|
||||
contribution.label,
|
||||
contribution.icon,
|
||||
contribution.description,
|
||||
contribution.order,
|
||||
)
|
||||
if expected is None:
|
||||
errors.append(
|
||||
f"{repository_name}: module {manifest.id!r} uses unknown product "
|
||||
f"area {contribution.id!r}"
|
||||
)
|
||||
elif actual != expected:
|
||||
errors.append(
|
||||
f"{repository_name}: module {manifest.id!r} redefines canonical "
|
||||
f"product area {contribution.id!r}; expected {expected!r}, found {actual!r}"
|
||||
)
|
||||
|
||||
repository_root = manifest_path.parents[3]
|
||||
if manifest.architecture is None:
|
||||
if args.require_architecture:
|
||||
@@ -142,6 +242,23 @@ def main() -> int:
|
||||
print("\n".join(errors), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
contributed_product_areas = {
|
||||
contribution.id
|
||||
for manifest in manifests
|
||||
if manifest.frontend is not None
|
||||
for contribution in manifest.frontend.product_areas
|
||||
}
|
||||
missing_product_areas = sorted(
|
||||
set(CANONICAL_PRODUCT_AREAS) - contributed_product_areas
|
||||
)
|
||||
if missing_product_areas:
|
||||
print(
|
||||
"Canonical product areas have no contributing module: "
|
||||
+ ", ".join(missing_product_areas),
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
registry = PlatformRegistry()
|
||||
try:
|
||||
for manifest in manifests:
|
||||
|
||||
Reference in New Issue
Block a user