# ============================================================
# src/accountable_record/stage_040_elements/base/constants.py
# ============================================================
"""Elements-stage constants and diagnostic codes (Layer 0).

WHY:
    Stage 040 validates the target repository's *authored element source
    quartets* under data/elements/<category>/<element>/. This module is the
    stage's Layer 0 vocabulary: the AR.EL.* diagnostic codes plus the
    structural constants that name the quartet members and the minimal observed
    shape of each. Mirrors stage 030's constants module.

OBS (data-driven requirement):
    Discovery walks data/elements/ and identifies an element directory by
    the presence of the quartet. This module therefore contains NO list of
    categories, NO list of element names, and NO count of elements. The only
    constants are the structural invariants every quartet shares, observed
    across real examples: the four filenames, the two schema tag values,
    and the minimal required keys. Categories and names are read from the
    filesystem path at runtime, never hardcoded.

OBS (scope):
    s040 owns authored source elements under data/elements/ only. Generated
    export JSON under data/export/elements/ and lock reconciliation against
    data/locks/elements.lock.json are NOT owned here; the lock digests
    generated JSON (digest_target = "canonical-generated-json") and belongs
    to a later export/generated stage. A reconciliation seam is left in the
    model, not folded into this stage.

REQ:
    - No internal dependencies beyond the shared Layer 0 diagnostics module.
    - Concern is Concern.ELEMENTS ("EL"), already defined in the shared
      diagnostics enum; 040 does not mint new concerns.
"""

STAGE_NAME = "stage_040_elements"

# Manifest opt-out for authored elements, mirroring [traceability]
# identifier_map = "none". Absence of authored elements must be DECLARED.
MANIFEST_ELEMENTS_TABLE = "elements"
MANIFEST_DECLARATIONS_KEY = "declarations"
DECLARATIONS_NONE = "none"

# WHERE authored element quartets live, relative to the target repository root.
# A path segment, not a hardcoded category set: discovery walks beneath it.
ELEMENTS_DIRNAME = "data/elements"

# The required quartet. These four members define an element directory; a
# directory missing any member is not a complete element (reported
# structurally). The examples file lives under an examples/ subdirectory.
ELEMENT_FILENAME = "element.toml"
CHECKS_FILENAME = "checks.toml"
SCHEMA_FILENAME = "schema.schema.json"
EXAMPLES_DIRNAME = "examples"
EXAMPLE_VALID_FILENAME = "valid.json"

# The quartet as a tuple, for iteration in discovery/messages without repeating
# the member list. examples/valid.json is represented by its joined relative
# path so a single loop can check all four.
QUARTET_MEMBERS: tuple[str, ...] = (
    ELEMENT_FILENAME,
    CHECKS_FILENAME,
    SCHEMA_FILENAME,
    f"{EXAMPLES_DIRNAME}/{EXAMPLE_VALID_FILENAME}",
)

# Observed top-level schema tags. Used for minimal shape checks, not semantic
# validation: an element.toml that does not declare the element-type schema tag
# is structurally suspect. Kept as the observed values, centralized here.
ELEMENT_SCHEMA_TAG = "ar-element-type-1"
CHECKS_SCHEMA_TAG = "ar-element-checks-1"

# Minimal required keys observed in every real quartet. These are STRUCTURAL
# (presence/shape), not semantic. They are the smallest set that held across
# inspected examples; richer rule content is intentionally not validated here.
ELEMENT_REQUIRED_TABLES: tuple[str, ...] = (
    "identity",
    "classification",
    "structure",
)
# Within [identity], the keys observed as always present and load-bearing for
# downstream identity (compact_id is the element type id used elsewhere).
ELEMENT_IDENTITY_REQUIRED_KEYS: tuple[str, ...] = (
    "compact_id",
    "local_name",
)
# Within [classification], the key naming the component group, which is
# expected to equal the on-disk <category> segment (structural cross-link).
ELEMENT_CLASSIFICATION_GROUP_KEY = "component_group"

# checks.toml: the field naming the element type these checks apply to,
# expected to equal element.toml [identity].compact_id (structural cross-link).
CHECKS_ELEMENT_TYPE_ID_KEY = "element_type_id"

# schema.schema.json: minimal JSON-Schema keys observed in every example.
SCHEMA_REQUIRED_KEYS: tuple[str, ...] = ("$schema", "$id", "type")

# examples/valid.json: must be a JSON object (mapping). Field-level
# requirements are governed by the element's own schema, which full semantic
# validation (a later stage) would enforce; s040 checks only that it parses
# and is an object.
