Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RFC-0009: Source Scan Selection and Ignore Semantics

Version: 0.3.0 | Status: normative | Phase: stable Owners: @govctl-org

References: RFC-0002


1. Summary

[RFC-0009:C-SUMMARY] Source Scan Model (Informative)

Source reference scanning has two independent path-selection layers. The source-scan include list defines the positive scan domain. Repository .gitignore files and governance-specific .govignore files define traversal exclusions and explicit re-inclusions. Keeping these layers separate lets projects reuse established ignore policy, override it for governance evidence, and avoid enumerating excluded directory trees.

Since: v0.1.0


2. Specification

[RFC-0009:C-SOURCE-SELECTION] Source Selection (Normative)

When source_scan.enabled is false, source reference validation MUST NOT enumerate project source paths.

When source reference validation is enabled, a regular file is eligible for content scanning only when its normalized project-relative path matches at least one source_scan.include entry and its final ignore decision is not excluded. Normalized paths MUST use / as the separator, MUST omit a leading ./, and MUST be matched case-sensitively on every platform.

Each include entry represents one positive Git gitignore path pattern evaluated from the project root. A leading / anchors the pattern to the project root. A pattern with no / MUST match at any depth. A trailing / MUST select regular-file descendants of a matching directory. An empty entry or an unescaped leading ! MUST be rejected. Because include entries are configuration values rather than ignore-file lines, a leading # MUST be treated as a pattern character rather than a comment marker. Git escaping and wildcard forms, including *, ?, character classes, and **, MUST retain their gitignore meanings.

An empty include list MUST select no files. An ignore re-inclusion MUST NOT admit a file that is outside the positive include domain.

Since: v0.1.0

[RFC-0009:C-IGNORE-RULES] Ignore Sources and Precedence (Normative)

Source traversal MUST evaluate .gitignore and .govignore files located at the project root and in reached descendant directories. Both file types MUST use Git gitignore pattern syntax, including comments, escaping, directory-only patterns, ordered matches, and ! re-inclusion. Matching MUST use normalized project-relative paths and MUST NOT depend on whether a path is tracked by Git or whether the project root is a Git repository.

When matching rules conflict, a matching .govignore rule MUST take precedence over a matching .gitignore rule. Within one file type, a rule in a deeper directory MUST take precedence over a rule inherited from an ancestor directory. Within one ignore file, the last matching rule MUST win.

When the winning rule is a re-inclusion, the path MUST become non-excluded unless an ancestor remains excluded. Otherwise, a winning exclusion MUST keep the path excluded. After ignore resolution, source_scan.include MUST be applied only to decide whether a non-excluded regular file is eligible for content scanning; it MUST NOT prevent traversal through a non-excluded directory.

Source traversal MUST NOT consult ignore rules outside the project root, user-level or global Git ignore configuration, .git/info/exclude, or generic .ignore files. A path MUST NOT be excluded solely because its name is hidden.

Since: v0.1.0

[RFC-0009:C-TRAVERSAL] Traversal and Pruning (Normative)

The final ignore decision for a reached directory MUST be evaluated before enumerating its child entries. When the final decision excludes a directory, source traversal MUST prune the directory without enumerating its descendants.

A re-inclusion that targets a descendant of an excluded directory MUST have no effect unless every excluded ancestor is also re-included by rules available from reached directories. Ignore files beneath a pruned directory MUST NOT be read and MUST NOT re-include that directory or its descendants.

Source traversal MUST NOT follow symbolic links.

While source scanning is enabled, an invalid include rule, an unreadable or invalid ignore file discovered in a reached directory, an error while traversing a directory that was not pruned, or a read or decoding error for a selected regular file MUST produce a validation diagnostic. Source reference validation MUST NOT report success after such an error.

A directory named .git MUST be treated as repository metadata and pruned before its child entries are enumerated, regardless of source_scan.include or ignore-file rules.

Since: v0.1.0

[RFC-0009:C-IGNORE-MIGRATION] Ignore Configuration Migration (Normative)

Project schema version 5 MUST establish the source-selection and ignore contract in this RFC. Normal project commands other than govctl migrate that load a version 4 project MUST reject the project without mutation and instruct the user to run govctl migrate. Project-independent commands MUST NOT require repository migration. Migration from version 4 to version 5 MUST follow the transactional and dry-run behavior in RFC-0002:C-GLOBAL-COMMANDS.

The version 5 configuration MUST remove source_scan.exclude. When that legacy list is non-empty, migration MUST place each entry as one root .govignore rule, preserving array order and placing the migrated rules before any pre-existing .govignore content. A leading ! or # that was a literal character in a legacy entry MUST be escaped when written as an ignore-file rule. A legacy entry containing a carriage return or line feed MUST cause migration to fail without mutation and identify that entry.

Pre-existing .govignore content MUST remain byte-for-byte unchanged after the inserted migration block. The version 5 source-scan migration step MUST NOT modify .gitignore; independent project-support synchronization required by RFC-0002:C-GLOBAL-COMMANDS MAY modify .gitignore in the same govctl migrate invocation.

Migrated entries adopt Git gitignore matching semantics in version 5. Migration MUST NOT claim that their match sets remain identical to the legacy glob matcher. govctl migrate --dry-run MUST show the resulting configuration and .govignore changes before they are applied.

When the legacy list is empty, migration MUST remove the field without creating .govignore. A version 5 project without a .govignore file MUST be valid and MUST behave as though it has no governance-specific ignore rules. A version 5 configuration that contains source_scan.exclude MUST be rejected without mutation, and the diagnostic MUST identify the unsupported field.

Since: v0.1.0

[RFC-0009:C-REFERENCE-REPORTING] Source Reference Reporting (Normative)

A configured source_scan.pattern MUST compile successfully and MUST define capture group 1 as the artifact-reference target. govctl check MUST report E0501 when either condition is not met, whether or not source-file traversal is enabled. Every full match MUST produce a present, non-empty capture group 1; otherwise source scanning MUST report E0501 and MUST NOT treat that match as a reference.

A diagnostic about an unknown or outdated detected source reference MUST identify the normalized project-relative source path and the one-based line and byte-column position at which capture group 1 starts.

Source-reference diagnostics MUST be ordered by ascending normalized path, line, and byte column, with diagnostic code and captured target as ascending tie-breakers. Diagnostics with the same code, normalized path, capture-start position, and captured target MUST be emitted once.

Since: v0.2.0


Changelog

v0.3.0 (2026-07-30)

Exclude Git metadata from source traversal

Changed

  • Prune .git directories before enumerating their contents

v0.2.0 (2026-07-30)

Make source-reference diagnostics precise and deterministic

Added

  • Define reference-pattern validation and source locations

Changed

  • Order and deduplicate source-reference diagnostics

v0.1.1 (2026-07-30)

Close source traversal failure gaps

Fixed

  • Treat selected source read and decoding failures as validation errors

v0.1.0 (2026-07-29)

Initial draft