From 9a498333393c3e3914b8e8c2da355ea132ba153a Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 23 Oct 2026 12:17:29 +0000 Subject: [PATCH] Remove the completed operator convention audit --- docs/roadmap/audit.md | 444 ------------------------------------------ 1 file changed, 444 deletions(-) delete mode 100644 docs/roadmap/audit.md diff --git a/docs/roadmap/audit.md b/docs/roadmap/audit.md deleted file mode 100644 index c0a086e..0000000 --- a/docs/roadmap/audit.md +++ /dev/null @@ -1,444 +0,0 @@ -# Operator Convention Audit: ConfigKit and Ansible - -Status: audit complete; no behavior changes proposed or authorized by this document. - -## Scope and evidence - -Reviewed ConfigKit revision: `2baf14d`. Comparison date: 2026-10-19. -The [configuration contract](../config.md) owns ConfigKit behavior; this audit -records differences, not an alternative contract or implementation plan. - -The closest Ansible counterpart is usually YAML **variable data** loaded through -`ansible.builtin.include_vars`, not a playbook's task language or `ansible.cfg` -(which is INI). Where useful, comparisons explicitly identify `fileglob`, `find`, -variable precedence, filters, or task syntax. Those mechanisms have different -conventions even within Ansible. - -Evidence consists of current official Ansible documentation, the versioned -[ansible-core v2.19.0 include-vars implementation][include-source] and -[YAML constructor][constructor], and the -[PyYAML 6.0.2 scalar resolver][resolver]. Implementation observations below are -identified separately from documented interfaces; they are not promises about -every Ansible version or plugin. The `/latest/` documentation links are moving -references. No Ansible executable is available in the development environment, -so this is a documentation/source comparison, not a side-by-side runtime test. - -ConfigKit's parser and import-policy implementations were inspected alongside -their tests and maintained consumer examples. Focused YAML, import, composition, -overlay, inheritance, version, decode, secret, and consumer tests passed on the -reviewed tree. No code or existing policy was changed for this audit. - -## Summary - -| Area | Main operator surprise | -| --- | --- | -| YAML values | Several accepted Ansible scalar spellings are errors in ConfigKit; dates remain strings. | -| Discovery | Directory recursion, filename filtering, missing-input handling, and wildcard syntax are not drop-in equivalents. | -| Composition | Import overlap is a conflict, not permission for a later file to replace an earlier value. | -| Precedence | ConfigKit recursively combines mappings across explicit tiers; Ansible normally replaces dictionary variables unless merging is requested. | -| Reuse | ConfigKit's post-assembly sibling `extends` is neither YAML anchor reuse nor Ansible task/role inheritance. | -| Evaluation | YAML is configuration data, not Jinja expressions, lookups, conditionals, or a task program. | -| Secrets and inspection | Typed environment-name references and classified frozen inspection differ from Vault, lookups, and task-output controls. | - -These differences are not automatically defects. Many follow accepted ConfigKit -decisions, especially strict composition, predictable precedence, presence -tracking, typed validation, and the complete-on-return lifecycle. - -## 1. YAML parsing and scalar conventions - -ConfigKit authority: [YAML documents](../config.md#yaml-documents), -[scalars](../config.md#scalars), and -[parser policy tests](../../internal/yaml/parse_test.go). - -### Y1 — Boolean and null spellings are narrower - -ConfigKit accepts plain lowercase `true`, `false`, and `null`, plus `~` and an -empty mapping value for null. Unquoted `yes`, `no`, `on`, `off`, and case variants -such as `True` or `NULL` fail rather than becoming strings. Quoting makes them -strings, not typed booleans. - -Ansible's YAML conventions accept additional boolean spellings; the inspected -PyYAML resolver also recognizes mixed-case null forms. An operator copying -`enabled: yes` must change the value to `true`, not merely quote it when the -application expects a boolean. [Ansible YAML][ansible-yaml], -[resolver source][resolver]. - -### Y2 — Numeric spellings and timestamp interpretation differ - -ConfigKit uses JSON-number syntax, rejecting forms such as `010`, `0x10`, -`1_000`, `+1`, `.5`, and `.inf`. Date/time-looking plain values remain strings. -The inspected PyYAML resolver recognizes several non-JSON numeric forms and -timestamps; Ansible's constructor retains timestamp construction. Do not assume -that accepting the same YAML text produces the same scalar type. -[Resolver source][resolver], [Ansible constructor][constructor]. - -ConfigKit also retains exact integer spelling for configured version checks, -but ordinary typed and dynamic destinations still enforce their documented -ranges. Ansible's Python-backed numeric data is not a guarantee that a value will -fit a ConfigKit application's Go field. - -### Y3 — Duplicate keys are always errors - -ConfigKit rejects duplicate decoded mapping keys at every depth. Ansible's -documented default is a warning; its constructor retains the last value. Ansible -also offers error and ignore settings. A file that loads with an Ansible warning -can therefore fail ConfigKit outright. [Duplicate-key setting][duplicate-setting], -[constructor source][constructor]. - -### Y4 — Anchors, aliases, merge keys, and explicit tags are unavailable - -ConfigKit rejects anchors, aliases, all explicit YAML tags, and even an ordinary -quoted key named `<<`. Ansible documents anchor/alias/merge reuse and recognizes -tags including `!unsafe` and `!vault`; its constructor also supports standard -tags such as `!!str`. These files require semantic rewriting, not just moving -them into an import directory. [Advanced syntax][advanced-syntax], -[constructor source][constructor]. - -### Y5 — Empty variable files are not empty configuration mappings - -ConfigKit requires one nonempty mapping document: `{}` is valid; an empty file, -document-only marker, null root, or sequence root is not. The inspected -`include_vars` implementation turns a null/empty parsed result into an empty -dictionary. Explicitly use `{}` for an intentionally empty ConfigKit fragment. -[Include-vars implementation][include-source]. - -Mapping roots themselves are **not** a divergence from normal Ansible variable -files. Playbook sequence roots belong to a different interface. Likewise, Ansible -has an explicit `from_yaml_all` filter for streams; that does not mean ordinary -`include_vars` automatically accepts multiple documents. ConfigKit loading has -no corresponding stream mode. [Variable files][variables], -[multi-document filter guidance][filters]. - -### Y6 — Mapping keys are data strings, not Ansible variable identifiers - -ConfigKit requires string-classified keys, quoting numeric/boolean-looking keys -when needed. Literal dots, slashes, spaces, and numeric-looking quoted keys are -not split into paths. Ansible distinguishes restricted top-level variable names -from nested dictionary keys; its YAML constructor can construct non-string -hashable keys. Porting arbitrary nested Ansible dictionary keys may require -quoting, while imposing Ansible variable-name rules on every ConfigKit key would -be unnecessarily restrictive. [Variable naming and dictionary access][variables], -[constructor source][constructor]. - -## 2. Import declarations and filesystem discovery - -ConfigKit authority: [explicit imports](../config.md#explicit-imports), -[input destinations](../config.md#input-destinations), and -[import internals](../internal/imports.md). - -Defaults below are ConfigKit's library defaults. Applications can supply -load-wide `ImportDefaults`; an explicit declaration field wins over that -application default. Transitive declarations use the same application defaults, -not the options authored on the declaration that selected their parent source. -An operator must therefore check the consuming application's selected defaults. - -| ID | ConfigKit convention | Closest Ansible convention and difference | -| --- | --- | --- | -| I1 | Enabled documents contain root `configkit.imports`; each declaration chooses `path`, `dir`, or `glob`. `path`/`dir` accept a string or list. | `include_vars` is a task with `file` or `dir`, normally one string; `fileglob` is a separate lookup. Ansible variable data does not recursively execute embedded include declarations. [Module][include-vars], [lookup][fileglob]. | -| I2 | Directory discovery is shallow by default. `recursive: true` enables descendants; `depth` requires effective recursion. | `include_vars: dir` recurses by default. `find` instead defaults to `recurse: false`, with that setting overriding depth rather than making depth invalid. [Include-vars][include-vars], [find][find]. | -| I3 | `pattern` is one or more case-sensitive basename globs; omitted means unrestricted, `[]` means no matches. | `include_vars.files_matching` is one regular expression. `find.patterns` is closer, but its documented empty/default pattern selects all rather than none. [Include-vars][include-vars], [find][find]. | -| I4 | `exclude` uses the same basename-glob grammar. | `include_vars.ignore_files` is described as filenames; the inspected implementation actually uses suffix-anchored regex searches. `find.excludes` accepts glob/regex patterns. Do not translate fields by renaming alone. [Module][include-vars], [implementation][include-source], [find][find]. | -| I5 | There is no extension whitelist: discovery attempts every selected filename, including `.txt` or extensionless files. | Directory `include_vars` defaults to `json`, `yaml`, and `yml`; unknown extensions fail unless configured to be ignored. This restriction does not mean an explicitly named `file` has the same filtering. [Module][include-vars], [implementation][include-source]. | -| I6 | Missing imports are optional by default. `required: true` checks every named path, or requires a nonempty directory/glob result. | Direct `include_vars` missing-file/directory access fails. `fileglob` may return no matches, and `first_found(skip=True)` provides a different explicit absence mechanism. [Implementation][include-source], [fileglob][fileglob], [first_found][first-found]. | -| I7 | `hidden` and `follow` default to true for discovered entries; explicit roots retain normal access. | `find` defaults both to false, and automatic `host_group_vars` ignores hidden/backup entries. The inspected `include_vars` walk follows directory links and has no equivalent hidden/follow switches; do not call ConfigKit's defaults universally unlike Ansible. [Find][find], [vars plugin][host-group-vars], [implementation][include-source]. | -| I8 | Import paths are slash-relative to their declaring source's directory, inside its selected namespace/root. Absolute paths and URLs are invalid. | Ansible accepts absolute controller paths and uses role/play/task search contexts for relative resource lookup. Copying a role-relative name can select another file or fail in ConfigKit. [Search paths][paths], [loader source][data-loader]. | -| I9 | A path list is a normalized set union; lexical duplicates coalesce within a declaration. Repeated admitted sources across declarations/routes fail within a strict tier. | Repeating `include_vars` tasks is allowed by the inspected implementation; no equivalent load-wide repeated-source rejection is applied there. `first_found` lists select the first hit, not all files. [Implementation][include-source], [first_found][first-found]. | -| I10 | Source acquisition is authored/depth-first, but assembly uses the smallest dependency-ready stable source key within each strict scope. | Directory `include_vars` uses alphabetic file loading, not ConfigKit's import dependency schedule. Prefixing filenames cannot authorize ConfigKit replacement or force arbitrary dependency-violating item order. [Module][include-vars]. | -| I11 | Optional whole-declaration empty results retain source-local `ImportSelections` evidence, not fake sources or warnings. | `include_vars` returns included file paths, rather than this optional-empty declaration record. The inspection models are not interchangeable. [Return values][include-vars]. | - -**Depth alignment:** direct files are depth 1, and recursive depth 0 means -unlimited subject to budgets. That is consistent with the inspected -`include_vars` depth convention; the significant differences are recursion's -default and whether depth is independently applicable. -[Implementation][include-source]. - -**Empty-set behavior:** ConfigKit `path: []` succeeds even when required because -no named target is missing. A required `dir: []` or `pattern: []` search fails -because it selects no files. An explicit empty pattern list also overrides an -application's nonempty default patterns. These are set meanings, not automatic -fallback to unrestricted search. - -### I12 — Even shell-style wildcard grammars are not identical - -ConfigKit uses Go `path.Match`, not Python `fnmatch` or regex: character-class -negation uses `[^a]`, whereas Python uses `[!a]`; Go backslashes escape pattern -characters. For example, copying `[!a]*.yml` can change the selected set rather -than producing an obvious error. Match full basenames, not regex substrings. -[Go pattern grammar][go-match], [Python filename grammar][python-fnmatch]. - -ConfigKit's `glob` can wildcard directory components and explicitly rejects -recursive `**`. Ansible's `fileglob` contract supports filename patterns in a -single directory, not wildcard directory search as an interchangeable feature. -Python glob's ordinary wildcard treatment also excludes dot-prefixed names -unless requested by the pattern, unlike ConfigKit's default `hidden: true`. -[Fileglob][fileglob], [Python glob][python-glob]. - -### I13 — Discovery errors and resource bounds are load failures - -ConfigKit optionality permits absence, not malformed selected YAML, unreadable -contributions, containment failures, active traversal cycles, or exhausted -source/byte/node/entry budgets. The inspected Ansible directory walker logs -`os.walk` errors through its verbosity callback rather than applying the same -fail-the-load rule. Neither `ignore_errors` nor lookup `errors='ignore'` is an -equivalent of ConfigKit's narrowly scoped `required: false`. -[Implementation][include-source], [first_found behavior][first-found]. - -ConfigKit's fixed budgets have no shared, portable Ansible equivalence established -by this audit. This is not a claim that Ansible or its parsers have no limits. - -## 3. Combination, precedence, and inheritance - -### C1 — Imports compose strictly rather than overriding - -Within a main tier or one underlay group, shared mappings recurse, but overlapping -non-mapping values conflict even when equal. Ansible variable precedence normally -chooses a winning definition; directory `include_vars` also overwrites colliding -keys in its accumulated results. `10-base.yml` plus `90-local.yml` is therefore -not an override scheme for ConfigKit imports. Intentional replacement needs a -higher ConfigKit tier. [ConfigKit strict composition](../config.md#strict-document-composition), -[Ansible precedence][precedence], [include-vars implementation][include-source]. - -### C2 — Cross-tier mapping combination is recursive by default - -ConfigKit retains omitted lower-tier mapping children, including when a higher -tier supplies `{}`; other present values replace, and `[]` clears a sequence. -Ansible's default dictionary-variable behavior is replacement, and its `combine` -filter defaults to nonrecursive merging. ConfigKit's mapping overlay is closer -to explicit `combine(recursive=true)` than ordinary variable reassignment. -Ansible's global hash-merge setting is configurable and discouraged upstream; -it is not a portable equivalence. [ConfigKit overlays](../config.md#selected-overlays), -[hash behavior][hash-setting], [combine][combine]. - -### C3 — Registered sequence composition is not merge-by-identity - -ConfigKit appends distinct string-ID records only at application-registered -strict-tier paths; repeated IDs conflict. Higher-tier sequences still replace -wholesale. Ansible `combine` offers selectable list policies, while the separate -`community.general.lists_mergeby` filter combines records sharing an attribute. -That optional collection filter does not describe ConfigKit's distinct-ID rule -or Ansible's universal default. [ConfigKit registration](../config.md#strict-document-composition), -[combine][combine], [lists_mergeby][lists-mergeby]. - -### C4 — The precedence model and lifetime are different - -ConfigKit loads application defaults, ordered underlays, main, selected overlay, -and explicit CLI values into one completed result. It supplies no general -environment-variable overlay. Ansible has host/play/task scopes and runtime -variable definitions; ordinary command-line options are not generally highest -priority, while `-e` extra variables are. Environment also configures Ansible -itself. Do not equate every application flag with Ansible's ordinary CLI category. -[ConfigKit layered loading](../config.md#layered-loading), -[Ansible precedence][precedence]. - -ConfigKit rejects duplicate or overlapping explicit override records rather -than providing a last-argument-wins channel. It accepts typed values supplied by -the application; it does not define an Ansible-style `key=value` parser. -Ansible extra-vars `key=value` values are strings; JSON/YAML forms preserve -other types. [ConfigKit overrides](../config.md#explicit-cli-overrides), -[Ansible extra vars][variables]. - -### C5 — Defaults depend on presence, not truthiness - -ConfigKit preserves explicit false, zero, empty text/list, and allowed null; -omission retains defaults. Null is not universally legal: application Go scalar -and struct fields reject it, while supported nullable fields accept it. Ansible -can distinguish undefined from false/null too. Its ordinary Jinja `default` -filter handles undefined, while `default(value, true)` additionally treats falsey -values as needing replacement; `omit` is a separate task-argument mechanism. -That opt-in truthiness behavior has no ConfigKit YAML equivalent. -[ConfigKit decoding](../config.md#defaults-and-typed-decoding), -[Ansible default and omit guidance][filters]. - -### C6 — `extends` is post-assembly sibling inheritance - -ConfigKit resolves an exact immediate sibling mapping after all tiers combine; -the child recursively overlays its parent. `extends: null` cancels a relationship, -and enclosing inheritance precedes nested destination-local resolution. All -effective relationships are resolved, not just an application-selected preset. - -Ansible YAML anchors/`<<` reuse nodes within one document during parsing, and -YAML merge does not recursively combine an already-present nested child mapping. -Ansible play/block/task keyword inheritance is another distinct mechanism. -Neither is a drop-in equivalent of ConfigKit `extends`; explicit Ansible -recursive `combine` expressions can approximate parts of the value operation. -[ConfigKit inheritance](../config.md#sibling-inheritance), -[Ansible advanced syntax][advanced-syntax], [YAML merge definition][yaml-merge], -[keyword inheritance][precedence], [combine][combine]. - -## 4. Structural controls, evaluation, and schema - -### S1 — Reserved data keys and destination syntax differ - -ConfigKit reserves `configkit` for root directives and rejects it below the root; -with imports disabled it is still not ordinary application data. `extends` is -structural input, and quoting a key does not bypass either control. Ansible -variable dictionaries do not give these two names ConfigKit's structural meaning. -Do not confuse this with Ansible's own magic-variable and playbook-keyword rules. -[ConfigKit imports](../config.md#explicit-imports), -[inheritance](../config.md#sibling-inheritance), [Ansible variable rules][variables]. - -Import `destination: [catalog, entries]` means literal mapping segments relative -to the immediate importer; `[]` adds none. `placement: sequence-item` builds a -record in that destination's sequence, with a local helper scope. Ansible's -`include_vars.name` wraps data under one variable, not this relative mount/item -model; dots are not a substitute for ConfigKit segment lists. -[ConfigKit destinations](../config.md#input-destinations), -[Ansible include-vars namespace][include-vars]. - -### S2 — Jinja, conditional includes, and lookups are not evaluated - -In ConfigKit, `"{{ value }}"`, `"{{ lookup('env', 'TOKEN') }}"`, and `${TOKEN}` -are ordinary strings unless application code gives them domain meaning; no -generic template pass exists. `when`, `loop`, `tags`, and `ignore_errors` are -not import-declaration controls. Ansible supports Jinja references/lookups and -task-level conditionals and loops. Configuration must be translated structurally -or handled by deliberate application resolution, not presumed executable. -[ConfigKit resolution](../config.md#recorded-application-resolution), -[Ansible variables][variables], [task keywords][keywords], [env lookup][env]. - -### S3 — Final typed validation and version ownership are library boundaries - -ConfigKit strictly decodes the assembled result against the application's Go -shape: unknown struct fields and incompatible values fail; dynamic maps leave -domain-key validation to the application. Its configured version rule accepts -string/integer declarations, can consume non-main headers, and protects the main -version path from imports/upper tiers/inheritance. None of those policies should -be inferred from the word `version` alone. - -Ansible variable-file loading is not validation against one final application -schema; validation occurs at other boundaries, including module/role argument -specifications. A variable named `version` is not by itself a ConfigKit-style -protected, consumed header. [ConfigKit versions](../config.md#shared-source-version-checks), -[typed decoding](../config.md#defaults-and-typed-decoding), -[Ansible role validation][roles], [include-vars data loading][include-source]. - -ConfigKit's integer-version-to-string exception is specific to that configured -path. It does not establish general Ansible-like filter coercion elsewhere. -[Ansible type conversion filters][filters]. - -For a field typed as `time.Duration`, ConfigKit requires a duration string such -as `5s`, not an integer count of seconds. Ansible duration arguments are module -specific; for example, `wait_for.timeout` uses integer seconds. Translate the -particular field's representation rather than assuming one shared duration type. -[ConfigKit decoding](../config.md#defaults-and-typed-decoding), -[Ansible wait_for][wait-for]. - -### S4 — Overlay selection and module objects are ConfigKit/application conventions - -A selected ConfigKit overlay uses exactly `overlays/.yml`; empty or exact -`default` means no overlay. There is no extension fallback or stack. Ansible's -inventory/role variable directories are different selection and precedence -mechanisms, not this named overlay convention. -[ConfigKit overlays](../config.md#selected-overlays), [Ansible vars plugin][host-group-vars], -[roles][roles]. - -The canonical module-object guidance uses an explicit identifier and options -mapping; individual field names belong to applications. Ansible tasks instead -name an action/module or use `action`/`args`, with task keywords alongside it. -A generic ConfigKit configuration object is not an Ansible task, and ConfigKit -does not provide an Ansible module registry or execute a module-named mapping. -[ConfigKit module guidance](../config.md#canonical-module-options), -[Ansible task syntax][playbooks], [keywords][keywords]. - -## 5. Secrets, resources, and inspection - -### O1 — A typed secret field contains an environment name - -For a ConfigKit `Secret` slot, `api_key: SERVICE_TOKEN` is a reference to one -nonempty effective environment value; ordinary string slots do not gain that -behavior. Missing/unset/empty required secrets fail. Ansible uses explicit env -lookups or other secret providers; its env lookup defaults to an empty string -for undefined names unless configured otherwise. These are different missing-value -and evaluation conventions. [ConfigKit secrets](../config.md#typed-secret-references), -[Ansible env lookup][env]. - -Vault-encrypted files or `!vault` values are not ConfigKit inputs to decrypt. -Ansible Vault protects stored content and supplies decryption through Ansible; -ConfigKit's typed reference deliberately keeps credential bytes out of YAML -composition/history. Its separate secrets-directory bootstrap is an application -startup operation, not another YAML include or a Vault equivalent. -[ConfigKit bootstrap](../config.md#explicit-secrets-directory-bootstrap), -[Ansible Vault][vault]. - -### O2 — Redaction and serialization are not task `no_log` - -ConfigKit has application-classified paths and typed secret references, with -frozen redacted effective/explanation output; there is no YAML `no_log` control -or unredacted renderer option. Ansible `no_log` controls task output and does not -make every debug operation safe. Vault encryption and `!unsafe` also have -different purposes; neither is a synonym for ConfigKit classification. -[ConfigKit inspection](../config.md#secret-classification-and-effective-rendering), -[Ansible logging][logging], [advanced syntax][advanced-syntax]. - -ConfigKit effective YAML uses a fixed deterministic layout and may not be -reloadable after redaction. Ansible `to_nice_yaml` exposes formatting options -such as indentation and key sorting; it is serialization, not ConfigKit's frozen -safe-inspection contract. Do not use either output interchangeably without -checking the consumer's required representation. [Ansible YAML filter][nice-yaml]. - -### O3 — Resource paths are passive data, not generic Ansible file lookup - -ConfigKit retains the declaring source's resource context, including through -inheritance; applications explicitly open resource-valued fields. It does not -automatically resolve every string that resembles a path. Ansible file resources -are interpreted by their specific module/lookup and controller/remote search -context. These differ from ConfigKit import paths as well as from arbitrary -application data. [ConfigKit resource contexts](../config.md#source-resource-contexts), -[Ansible path contexts][paths]. - -## Assessment and follow-up - -The most plausible convention-alignment discussion is discovery: recursion, -filter names/grammar, filename defaults, absence handling, and hidden/link -defaults. First choose the intended comparison (`include_vars`, `fileglob`, or -`find`); copying pieces from each would not create one coherent Ansible convention. - -Preserve ConfigKit's accepted composition, presence, lifecycle, and provenance -decisions unless the maintainer explicitly chooses to change them. YAML scalar -and reuse differences likewise reflect an owned parsing policy, not an accidental -failure to inherit upstream YAML behavior. Documenting a difference does not -authorize adding a compatibility mode, a new restriction, or an implementation. - -Immediate operator guidance from the audit is to review imported files for -overlapping values, use explicit directory filters/requiredness when intended, -translate regex/Python patterns rather than copying them, and replace Ansible -tags/templates/anchors with supported application data and ConfigKit mechanisms. - -Validation for this documentation pass: focused ConfigKit YAML and engine tests, -maintained consumer examples, local documentation links, and whitespace checks. -External sources were reviewed online; no Ansible installation or application -consumer dependencies were changed. This is not an exhaustive audit of Ansible's -third-party plugin ecosystem or a claim that its behavior is uniform across -versions and application-specific modules. - -[ansible-yaml]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/YAMLSyntax.html -[advanced-syntax]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_advanced_syntax.html -[include-vars]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/include_vars_module.html -[include-source]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/plugins/action/include_vars.py -[constructor]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/_internal/_yaml/_constructor.py -[resolver]: https://github.com/yaml/pyyaml/blob/6.0.2/lib/yaml/resolver.py -[data-loader]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/parsing/dataloader.py -[duplicate-setting]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html#duplicate-yaml-dict-key -[hash-setting]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html#default-hash-behaviour -[fileglob]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/fileglob_lookup.html -[first-found]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/first_found_lookup.html -[find]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/find_module.html -[host-group-vars]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/host_group_vars_vars.html -[paths]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbook_pathing.html -[go-match]: https://pkg.go.dev/path#Match -[python-fnmatch]: https://docs.python.org/3/library/fnmatch.html -[python-glob]: https://docs.python.org/3/library/glob.html -[precedence]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/general_precedence.html -[variables]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_variables.html -[filters]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_filters.html -[combine]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/combine_filter.html -[lists-mergeby]: https://docs.ansible.com/projects/ansible/latest/collections/community/general/lists_mergeby_filter.html -[yaml-merge]: https://yaml.org/type/merge.html -[roles]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_reuse_roles.html -[keywords]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/playbooks_keywords.html -[playbooks]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_intro.html -[env]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/env_lookup.html -[vault]: https://docs.ansible.com/projects/ansible/latest/vault_guide/vault_encrypting_content.html -[logging]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/logging.html -[nice-yaml]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/to_nice_yaml_filter.html -[wait-for]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/wait_for_module.html