meta:
  version: "v1"
  source: https://superpowers.frontis.nl/conventions/naming-convention.yaml
  snapshotDate: 2026-05-21
  description: |
    This file encodes the Frontis project naming constitution in a machine-readable
    format. AI systems read this file to generate compliant project names, validate
    existing names, and derive local directory paths.

    Usage for AI:
    1. Read the 'pattern' section to understand the naming structure.
    2. Check 'vocabulary_examples' for illustrative Company, Product, and Component examples (not a restrictive allowlist).
    3. Apply 'validation_rules' to verify or construct a name.
    4. Follow 'policies' for artifact alignment and test naming conventions.
    5. Use 'directory' to derive the local clone path and Azure DevOps project.
    6. Reference 'examples' for valid and invalid name demonstrations.
    7. Read 'pipeline_filenames' for pipeline YAML file naming rules.

# Section 2 — Paths to authoritative external files
external_references:
  project_context: "https://superpowers.frontis.nl/conventions/project-context.yaml"

pattern:
  template: "{company}.{product}.{component}"
  separator: "."
  segments:
    - name: company
      position: 1
      required: true
      casing_rule: registered
      examples_ref: companies
      description: >
        Owning organisation or customer. Uses registered casing as-is
        (not PascalCase-enforced). Doubles as the Azure DevOps project name.
        Any company name is valid as long as it follows the casing/format rules.
    - name: product
      position: 2
      required: true
      casing_rule: pascal_case
      examples_ref: products
      description: >
        Product or product line within the company.
        Must use PascalCase.
        Any product name is valid as long as it follows the casing/format rules.
    - name: component
      position: 3
      required: true
      casing_rule: pascal_case
      description: >
        Specific deliverable or module within the product.
        Must describe its purpose (no generic names like Helpers or Common).
        Must use PascalCase.
    - name: sub_component
      position: 4
      required: false
      casing_rule: pascal_case
      description: >
        Optional deeper module. Only permitted when a component is large
        enough to warrant independent packaging. Requires governance approval.
        Must use PascalCase.

vocabulary_examples:
  description: >
    The entries below are illustrative examples — not a restrictive allowlist.
    Any company, product, or component name is valid as long as it follows
    the casing and format rules defined in the pattern and validation_rules
    sections. AI systems should use these examples to understand naming
    patterns and conventions, not to restrict valid names.
  companies:
    - name: "FrontisRAD"
      description: "Frontis internal R&D projects"
    - name: "AALP"
      description: "Customer: AALP — product information & corporate web"
  products:
    - name: "Conventions"
      description: "Standards and conventions tooling"
    - name: "ProductInformationSystem"
      description: "AALP product information management"
    - name: "Corporate"
      description: "AALP corporate web presence"
  components:
    - name: "Naming"
      description: "Project naming rules and validation"
    - name: "Api"
      description: "Backend API service"
    - name: "UmbracoWebsite"
      description: "Umbraco-based website"

validation_rules:
  - id: min-segments
    description: "Name must have at least 3 segments (Company.Product.Component)"
    severity: error
    check:
      min_segments: 3
      message: "Name has fewer than 3 segments. Expected: Company.Product.Component."

  - id: max-segments
    description: "Name must not exceed 4 segments without governance approval"
    severity: error
    check:
      max_segments: 4
      message: "Name exceeds 4 segments. A sub-component requires governance approval."

  - id: pascal-case
    description: "Product, Component, and SubComponent segments must use PascalCase"
    severity: error
    check:
      casing: pascal_case
      applies_to:
        - product
        - component
        - sub_component
      message: "Segment must use PascalCase (e.g., MyProduct not myproduct)."

  - id: no-hyphens
    description: "Hyphens are forbidden in project names"
    severity: error
    check:
      forbidden_pattern: "-"
      message: "Hyphens are not allowed. Use dot-separated PascalCase segments."

  - id: no-underscores
    description: "Underscores are forbidden in project names"
    severity: error
    check:
      forbidden_pattern: "_"
      message: "Underscores are not allowed. Use dot-separated PascalCase segments."

  - id: no-embedded-versions
    description: "Version numbers must not be embedded in names"
    severity: error
    check:
      forbidden_pattern: "[Vv]\\d+"
      message: "Version numbers embedded in names are forbidden (e.g., ApiV2)."

  - id: no-pluralised-segments
    description: "Company and Product segments must not be pluralised"
    severity: warning
    check:
      forbidden_pattern: "^[A-Z][a-zA-Z]+(?:es|s)\\."
      message: "Avoid pluralised Company or Product segments."

  - id: no-generic-components
    description: "Generic names like Utilities, Helpers, Common, Misc are forbidden as the final component"
    severity: error
    check:
      forbidden_values:
        - "Utilities"
        - "Helpers"
        - "Common"
        - "Misc"
      applies_to: component
      message: "Component must describe what it does, not merely that it exists."

policies:
  artifact_alignment:
    rule: "All project-level artifacts must share the canonical base name."
    description: >
      Repository, solution/workspace file, root namespace or module name,
      build output, and package identifier must all use the same canonical
      Company.Product.Component name. AI systems map this to the relevant
      artifacts for the technology in use.

  test_naming:
    rule: "Test artifacts append a test-type suffix to the canonical name."
    default_suffixes:
      unit: ".Tests"
      integration: ".Tests.Integration"
    description: >
      These are default suffix examples. AI systems should adapt the suffix
      convention to the technology in use (e.g., .Tests for .NET, __tests__
      for Node, tests/ for Python).

directory:
  root: "P:\\Git"
  pattern: "{root}\\{company}\\{canonical_name}"
  devops_mapping: >
    The Company segment equals the Azure DevOps project name and the
    folder directly under root. For example, company "AALP" maps to
    Azure DevOps project "AALP" and local folder P:\Git\AALP\.
  max_depth: 2
  description: >
    All Frontis developers use P:\Git as their root working directory
    (provisioned by OPS on every developer laptop). Repositories are
    cloned into P:\Git\{AzureDevOpsProject}\{CanonicalRepoName}\.
    No deeper nesting is permitted. The folder name of a cloned
    repository must be the canonical repository name — no renaming
    on clone.

    To resolve a clone path from a canonical name
    (e.g., "AALP.ProductInformationSystem.Api"):
      1. {company} = first segment before the first dot → "AALP"
      2. {canonical_name} = the full canonical name → "AALP.ProductInformationSystem.Api"
      3. Substitute into pattern: P:\Git\AALP\AALP.ProductInformationSystem.Api

pipeline_filenames:
  template: "{company}-{product}-{component}-{pipeline_type}-{hosting_variant}.yml"
  separator: "-"
  extension: ".yml"
  description: |
    Naming convention for Azure DevOps multi-stage pipeline YAML files.
    Pipeline filenames are derived from the project's canonical name
    (Company.Product.Component) with dots replaced by hyphens, followed by
    a pipeline type token and a hosting variant token.

    This convention governs ONLY the pipeline filename — not the content,
    stage names, variable names, or any internal pipeline structure.

    Usage for AI:
    1. Take the canonical project name and replace dots with hyphens.
    2. Append the pipeline type token (infra or release).
    3. Append the hosting variant token (shared or dedicated).
    4. Add the .yml extension.

  segments:
    - name: company
      position: 1
      required: true
      casing_rule: registered
      examples_ref: companies
      description: >
        Company segment from the canonical project name.
        Uses registered casing as-is. Any company name is valid
        as long as it follows the casing/format rules.

    - name: product
      position: 2
      required: true
      casing_rule: pascal_case
      examples_ref: products
      description: >
        Product segment from the canonical project name.
        Must use PascalCase. Any product name is valid
        as long as it follows the casing/format rules.

    - name: component
      position: 3
      required: true
      casing_rule: pascal_case
      description: >
        Component segment from the canonical project name.
        Must use PascalCase.

    - name: pipeline_type
      position: 4
      required: true
      casing_rule: lowercase
      allowed_values:
        - value: "infra"
          description: "Infrastructure provisioning — creates/manages Azure resources"
        - value: "release"
          description: "Build and release — compiles, tests, packages, and deploys the application"
      description: >
        Identifies the pipeline's purpose. Must be one of the allowed values.

    - name: hosting_variant
      position: 5
      required: true
      casing_rule: lowercase
      allowed_values:
        - value: "shared"
          description: "Targets the predefined shared high-performance App Service Plan (multi-tenant)"
        - value: "dedicated"
          description: "Targets a dedicated/isolated App Service Plan (single-tenant)"
      description: >
        Identifies the hosting model the pipeline targets. Must be one of the allowed values.

  validation_rules:
    - id: pipeline-segment-count
      description: "Pipeline filename must have exactly 5 hyphen-separated segments before the .yml extension"
      severity: error
      check:
        segment_count: 5
        message: "Pipeline filename must have exactly 5 segments: {company}-{product}-{component}-{type}-{variant}.yml"

    - id: pipeline-type-token
      description: "Pipeline type segment must be 'infra' or 'release'"
      severity: error
      check:
        allowed_values:
          - "infra"
          - "release"
        applies_to: pipeline_type
        message: "Pipeline type must be 'infra' (infrastructure) or 'release' (build and release)."

    - id: pipeline-hosting-token
      description: "Hosting variant segment must be 'shared' or 'dedicated'"
      severity: error
      check:
        allowed_values:
          - "shared"
          - "dedicated"
        applies_to: hosting_variant
        message: "Hosting variant must be 'shared' (shared service plan) or 'dedicated' (dedicated hosting plan)."

    - id: pipeline-extension
      description: "Pipeline file must use .yml extension"
      severity: error
      check:
        required_extension: ".yml"
        message: "Pipeline files must use the .yml extension (not .yaml or other)."

    - id: pipeline-canonical-match
      description: "First 3 segments must follow the canonical project name format and casing rules"
      severity: error
      check:
        canonical_name_validation: true
        applies_to:
          - company
          - product
          - component
        message: "The first 3 segments of the pipeline filename must follow the Company-Product-Component format with correct casing."

    - id: pipeline-no-dots
      description: "No dots allowed in the filename except before the .yml extension"
      severity: error
      check:
        forbidden_pattern_in_name: "\\."
        message: "Pipeline filenames use hyphens as separators. Dots are only used for the .yml extension."

    - id: pipeline-lowercase-tokens
      description: "Pipeline type and hosting variant tokens must be lowercase"
      severity: error
      check:
        casing: lowercase
        applies_to:
          - pipeline_type
          - hosting_variant
        message: "Pipeline type and hosting variant tokens must be lowercase (e.g., 'infra' not 'Infra')."

  examples:
    # Valid infrastructure pipeline examples
    - name: "AALP-ProductInformationSystem-Api-infra-shared.yml"
      valid: true
      explanation: "Infrastructure pipeline for AALP.ProductInformationSystem.Api on shared service plan."

    - name: "AALP-Corporate-UmbracoWebsite-infra-dedicated.yml"
      valid: true
      explanation: "Infrastructure pipeline for AALP.Corporate.UmbracoWebsite on dedicated hosting plan."

    - name: "FrontisRAD-Conventions-Naming-infra-shared.yml"
      valid: true
      explanation: "Infrastructure pipeline for FrontisRAD.Conventions.Naming on shared service plan."

    # Valid build-and-release pipeline examples
    - name: "AALP-ProductInformationSystem-Api-release-shared.yml"
      valid: true
      explanation: "Build-and-release pipeline for AALP.ProductInformationSystem.Api on shared service plan."

    - name: "AALP-Corporate-UmbracoWebsite-release-dedicated.yml"
      valid: true
      explanation: "Build-and-release pipeline for AALP.Corporate.UmbracoWebsite on dedicated hosting plan."

    - name: "FrontisRAD-Conventions-Naming-release-shared.yml"
      valid: true
      explanation: "Build-and-release pipeline for FrontisRAD.Conventions.Naming on shared service plan."

    # Invalid pipeline filename examples
    - name: "build.yml"
      valid: false
      explanation: "Generic name with no canonical project name, pipeline type, or hosting variant."
      violates:
        - pipeline-segment-count
        - pipeline-canonical-match
        - pipeline-type-token
        - pipeline-hosting-token

    - name: "AALP.ProductInformationSystem.Api.infra.shared.yml"
      valid: false
      explanation: "Uses dots instead of hyphens as segment separators."
      violates:
        - pipeline-no-dots

    - name: "AALP-ProductInformationSystem-Api-deploy-shared.yml"
      valid: false
      explanation: "'deploy' is not an allowed pipeline type token. Use 'infra' or 'release'."
      violates:
        - pipeline-type-token

    - name: "AALP-ProductInformationSystem-Api-infra-premium.yml"
      valid: false
      explanation: "'premium' is not an allowed hosting variant token. Use 'shared' or 'dedicated'."
      violates:
        - pipeline-hosting-token

    - name: "AALP-ProductInformationSystem-Api-infra.yml"
      valid: false
      explanation: "Missing hosting variant segment. Must have exactly 5 segments."
      violates:
        - pipeline-segment-count
        - pipeline-hosting-token

    - name: "aalp-productinformationsystem-api-infra-shared.yml"
      valid: false
      explanation: "Company and product/component segments must preserve their registered/PascalCase casing."
      violates:
        - pipeline-canonical-match

    - name: "AALP-ProductInformationSystem-Api-Infra-Shared.yml"
      valid: false
      explanation: "Pipeline type and hosting variant tokens must be lowercase."
      violates:
        - pipeline-lowercase-tokens

    - name: "my-deploy.yaml"
      valid: false
      explanation: "Generic name, wrong extension (.yaml instead of .yml), and no canonical project name."
      violates:
        - pipeline-segment-count
        - pipeline-extension
        - pipeline-canonical-match
        - pipeline-type-token
        - pipeline-hosting-token

examples:
  # Valid examples
  - name: "AALP.ProductInformationSystem.Api"
    valid: true
    explanation: "3 segments, company AALP, PascalCase product and component."

  - name: "AALP.Corporate.UmbracoWebsite"
    valid: true
    explanation: "3 segments, company AALP, descriptive component."

  - name: "FrontisRAD.Conventions.Naming"
    valid: true
    explanation: "3 segments, company FrontisRAD, semantic component."

  - name: "FrontisRAD.Conventions.Naming.Validation"
    valid: true
    explanation: "4 segments (max allowed), sub-component for independent packaging."

  # Invalid examples
  - name: "Frontis.Api"
    valid: false
    explanation: "Only 2 segments — missing Product segment."
    violates:
      - min-segments

  - name: "frontis.webportal.api"
    valid: false
    explanation: "All segments are lowercase — must use PascalCase (or registered casing for company)."
    violates:
      - pascal-case

  - name: "Frontis-WebPortal-Api"
    valid: false
    explanation: "Uses hyphens instead of dots as separator. Treated as a single segment when split on dots, so also violates the minimum segment count."
    violates:
      - no-hyphens
      - min-segments

  - name: "Frontis.WebPortal.ApiV2"
    valid: false
    explanation: "Contains embedded version number V2."
    violates:
      - no-embedded-versions
