On-demand signature computation for staleness detection.
Signatures are short hashes of normalized function source code. When a function's implementation changes, its signature changes, allowing detection of stale test coverage.
The signature is computed by:
Signature format:
The signature function automatically detects leaf vs non-leaf and
returns the appropriate format. Use it for all signature needs.
Performance options (Java system properties):
On-demand signature computation for staleness detection. Signatures are short hashes of normalized function source code. When a function's implementation changes, its signature changes, allowing detection of stale test coverage. The signature is computed by: 1. Extracting full source using clojure.repl/source-fn 2. Removing docstrings (so doc changes don't invalidate tests) 3. Normalizing whitespace (so formatting changes don't invalidate tests) 4. Hashing with SHA-256 and taking first 6 characters Signature format: - LEAF functions (no in-scope callees): Single-field "xxxxxx" - NON-LEAF functions: Two-field "xxxxxx,yyyyyy" where: - xxxxxx: 6-char hash of the function's own source - yyyyyy: 6-char hash of all transitive callees' signatures The `signature` function automatically detects leaf vs non-leaf and returns the appropriate format. Use it for all signature needs. Performance options (Java system properties): - fulcro-spec.auto-skip: Enable auto-skipping of already-checked tests - fulcro-spec.sigcache: Cache signatures for duration of JVM
(already-checked? covers-map scope-ns-prefixes)Returns true if this test's coverage declarations indicate it has already been verified and nothing has changed since.
IMPORTANT: Zero overhead when disabled - property check short-circuits first. No expensive signature computation occurs unless auto-skip is enabled.
A test is considered 'already checked' when:
This means: the test was previously run, passed, and the developer sealed it by recording the signatures in the :covers metadata. Since then, neither the covered functions nor any functions they call have changed.
For fast full-suite runs, also enable -Dfulcro-spec.sigcache=true
Args: covers-map - Map of {fn-symbol sealed-signature} from test's :covers metadata scope-ns-prefixes - Set of namespace prefix strings for transitive analysis
Returns: true if test can be skipped, false otherwise
Returns true if this test's coverage declarations indicate it has already
been verified and nothing has changed since.
IMPORTANT: Zero overhead when disabled - property check short-circuits first.
No expensive signature computation occurs unless auto-skip is enabled.
A test is considered 'already checked' when:
1. -Dfulcro-spec.auto-skip=true
2. scope-ns-prefixes configured (passed as argument)
3. Every covered function's sealed signature matches current signature
This means: the test was previously run, passed, and the developer sealed
it by recording the signatures in the :covers metadata. Since then, neither
the covered functions nor any functions they call have changed.
For fast full-suite runs, also enable -Dfulcro-spec.sigcache=true
Args:
covers-map - Map of {fn-symbol sealed-signature} from test's :covers metadata
scope-ns-prefixes - Set of namespace prefix strings for transitive analysis
Returns:
true if test can be skipped, false otherwise(auto-skip-enabled?)Returns true if the fulcro-spec.auto-skip system property is set. Presence of the property (even with empty value) enables the feature. Result is cached at first call for zero overhead on subsequent checks.
Returns true if the fulcro-spec.auto-skip system property is set. Presence of the property (even with empty value) enables the feature. Result is cached at first call for zero overhead on subsequent checks.
(leaf? fn-sym scope-ns-prefixes)Returns true if the function has no in-scope transitive callees.
A leaf function is one that doesn't call any other guardrailed functions within the given namespace scope. Leaf functions use single-field signatures because there are no dependencies to track.
Args: fn-sym - Fully qualified symbol of the function scope-ns-prefixes - Set of namespace prefix strings to include
Example: (leaf? 'myapp.utils/format-date #{"myapp"}) ;; => true (if it calls no other myapp.* guardrailed functions)
Returns true if the function has no in-scope transitive callees.
A leaf function is one that doesn't call any other guardrailed functions
within the given namespace scope. Leaf functions use single-field signatures
because there are no dependencies to track.
Args:
fn-sym - Fully qualified symbol of the function
scope-ns-prefixes - Set of namespace prefix strings to include
Example:
(leaf? 'myapp.utils/format-date #{"myapp"})
;; => true (if it calls no other myapp.* guardrailed functions)(self-signature fn-sym)Computes a short signature (first 6 chars of SHA256) for a function's own source.
This is an internal helper - use signature for the public API which
automatically handles leaf vs non-leaf functions.
Args: fn-sym - Fully qualified symbol of the function
Returns: 6-character signature string, or nil if source not available.
Computes a short signature (first 6 chars of SHA256) for a function's own source. This is an internal helper - use `signature` for the public API which automatically handles leaf vs non-leaf functions. Args: fn-sym - Fully qualified symbol of the function Returns: 6-character signature string, or nil if source not available.
(sigcache-enabled?)Returns true if the fulcro-spec.sigcache system property is set. Presence of the property (even with empty value) enables the feature. Result is cached at first call for zero overhead on subsequent checks.
Returns true if the fulcro-spec.sigcache system property is set. Presence of the property (even with empty value) enables the feature. Result is cached at first call for zero overhead on subsequent checks.
(signature fn-sym)(signature fn-sym scope-ns-prefixes)Returns the appropriate signature for a function based on its call graph.
For LEAF functions (no in-scope callees): Returns single-field: "xxxxxx"
For NON-LEAF functions (has in-scope callees): Returns two-field: "xxxxxx,yyyyyy"
This design ensures:
Args: fn-sym - Fully qualified symbol of the function scope-ns-prefixes - Optional set of namespace prefix strings to include. If not provided, reads from .fulcro-spec.edn config file.
Uses signature caching if -Dfulcro-spec.sigcache=true
Examples: ;; Using config from .fulcro-spec.edn (1-arity) (signature 'myapp.utils/format) ;; => "a1b2c3"
;; With explicit scope (2-arity) (signature 'myapp.orders/process #{"myapp"}) ;; => "a1b2c3,d4e5f6"
Returns the appropriate signature for a function based on its call graph.
For LEAF functions (no in-scope callees):
Returns single-field: "xxxxxx"
- Just the 6-char hash of the function's own source
For NON-LEAF functions (has in-scope callees):
Returns two-field: "xxxxxx,yyyyyy"
- xxxxxx: 6-char hash of the function's own source
- yyyyyy: 6-char hash of all transitive callees' signatures (sorted)
This design ensures:
- Leaf functions don't have redundant ',000000' suffix
- Non-leaf functions MUST have the callee hash (single-field rejected)
- Changes to any function in the call chain invalidate dependent tests
Args:
fn-sym - Fully qualified symbol of the function
scope-ns-prefixes - Optional set of namespace prefix strings to include.
If not provided, reads from .fulcro-spec.edn config file.
Uses signature caching if -Dfulcro-spec.sigcache=true
Examples:
;; Using config from .fulcro-spec.edn (1-arity)
(signature 'myapp.utils/format)
;; => "a1b2c3"
;; With explicit scope (2-arity)
(signature 'myapp.orders/process #{"myapp"})
;; => "a1b2c3,d4e5f6"cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |