Module: Textus::Manifest::Schema::Keys
- Defined in:
- lib/textus/manifest/schema/keys.rb
Overview
The manifest’s key whitelists and the rule-field registry — the schema’s data tables (ADR 0109; the vocabulary lives in Schema::Vocabulary).
Constant Summary collapse
- ROOT_KEYS =
%w[version roles zones entries rules audit].freeze
- ROLE_KEYS =
%w[name can].freeze
- ZONE_KEYS =
%w[name kind owner desc].freeze
- ENTRY_KEYS =
%w[ key path zone kind schema owner nested format source publish events ignore tracked ].freeze
- PUBLISH_KEYS =
ADR 0052: the typed publish block — ‘publish: { to: […] }` (file fan-out) xor `publish: { tree: “dir” }` (subtree mirror).
%w[to tree].freeze
- SOURCE_KEYS =
ADR 0093/0094: entry-level acquisition block. ‘from: project` sources expose flat projection fields (select/pluck/sort_by/transform) directly on the source block (ADR 0094). Render fields (template/inject_boot/ provenance) that were formerly on the source are retired — they live on publish targets. The legacy `project:` free hash and `template`/ `inject_boot`/`provenance` fields are kept here so the schema walk can still emit the migration hint rather than a bare “unknown key”.
%w[ from handler config template project command sources ttl on_write inject_boot provenance select pluck sort_by transform ].freeze
- RETENTION_KEYS =
ADR 0093: rule-level GC slot. drop/archive only (refresh gone).
%w[ttl action].freeze
- FIELD_REGISTRY =
The ONE source of truth for the rule-block field set (WS3). Adding a rule field means adding one entry here; everything downstream derives from it so the ~9 enumeration sites the audit found can’t drift:
- Schema::RULE_KEYS and the per-field sub-key walk (Schema::Validator) - Rules: the RuleSet members, EMPTY_SET, the `for` slots accumulator, Block's attr_readers, and the parse dispatch - Doctor::Check::RuleAmbiguity SLOTS (in_ambiguity) - Read::RuleList / Read::RuleExplain field membership (in_rule_list / in_rule_explain)Per field:
yaml_key manifest key (handler_allowlist's intake_ prefix disambiguates from entry-level intake:, ADR 0059) policy_class the Domain::Policy backing the field (nil = raw value) validation :immediate (instantiate the policy at parse, surfacing shape errors eagerly), :deferred (shape-check + carry the raw Hash; guard predicates validate at GuardFactory build time, ADR 0031), or :tagged (pass the raw Hash to a tagged-union policy that dispatches on its discriminator field, e.g. upkeep's on:) sub_keys allowed nested keys for a mapping field (drives both the schema sub-key walk and the kwargs splat into policy_class) arg_key for an immediate non-mapping field, the single kwarg the raw value is passed under in_pick participates in the most-specific `for(key)` resolution in_ambiguity linted by doctor's same-specificity tie check in_rule_list shown in the whole-manifest rule_list view in_rule_explain depths the field shows at: :lean and/or :detailKey order here fixes the order of RULE_KEYS (after match), the slots, the RuleSet members, and the doctor SLOTS.
{ handler_allowlist: { yaml_key: "intake_handler_allowlist", policy_class: Textus::Domain::Policy::HandlerAllowlist, validation: :immediate, sub_keys: nil, arg_key: :handlers, in_pick: true, in_ambiguity: true, in_rule_list: true, in_rule_explain: %i[detail] }, guard: { yaml_key: "guard", policy_class: nil, validation: :deferred, sub_keys: nil, arg_key: nil, in_pick: true, in_ambiguity: true, in_rule_list: true, in_rule_explain: %i[lean detail] }, retention: { yaml_key: "retention", policy_class: Textus::Domain::Policy::Retention, validation: :tagged, sub_keys: RETENTION_KEYS, arg_key: nil, in_pick: true, in_ambiguity: true, in_rule_list: true, in_rule_explain: %i[lean detail] }, }.freeze
- RULE_KEYS =
(["match"] + FIELD_REGISTRY.values.map { |m| m[:yaml_key] }).freeze
- AUDIT_KEYS =
%w[max_size keep].freeze
- OWNER_SUBJECT_PATTERN =
Syntactic shape of an ‘owner:` subject token (the `patrick` in `human:patrick`) — the subject half of the owner-validation rule below. Role supplies the archetype set (Role::NAMES); this pattern is the owner-specific part, so it lives with the rule that composes them (ADR 0045 D1). Acting-role names are gated by Role::NAMES, not a regex.
/\A[a-z][a-z0-9_-]*\z/