Skip to content

Feature: include nested template dependencies in composition fingerprints #360

Description

@randlee

Problem

The current SHA/fingerprint approach is insufficient for composed templates with nesting. A content-only SHA treats identical files at different paths as identical, and it does not change when a transitive nested include changes.

An array of child SHAs would help with auditability, but it should not be the primary identity: consumers need one stable value to compare the complete composed template.

This matters for SkillRx-style consumers and any sc-compose workflow that treats nested templates/includes as one logical artifact.

Recommended solution

Introduce a versioned Merkle-style composition fingerprint.

For each template node:

node_sha = SHA256(
  "skillrx-node-v2\\0" +
  canonical_relative_path +
  "\\0" +
  exact_file_bytes
)

For the composed root:

composition_sha = SHA256(
  "skillrx-composition-v2\\0" +
  root_relative_path +
  "\\0" +
  root_node_sha +
  "\\0" +
  ordered_include_edges
)

Represent each include edge in the canonical manifest as:

{
  "include_path": "shared/header.md",
  "child_sha": "...",
  "occurrence": 0
}

The dependency edge list must preserve include order and repeated includes. If the rendered output depends on profile, pass, or other render options, include a canonical hash of those options in the composition identity as well.

The implementation should expose the full dependency manifest/tree and node SHAs for diagnostics, while consumers compare the single composition_sha.

Required invariants

  • Canonical relative paths with normalized separators.
  • Deterministic serialization.
  • Exact source bytes, or an explicitly documented normalization rule.
  • Nested/transitive dependencies included recursively.
  • Include order and repeated occurrences preserved.
  • Cycles and missing dependencies produce stable diagnostics.
  • Algorithm/version identifier included so future changes do not silently collide.
  • Separate source_composition_sha and rendered_output_sha if output verification is required.
  • No dependence on mtime, filesystem traversal order, or absolute machine-specific paths.

Acceptance criteria

  • Identical content at different canonical paths produces different node fingerprints.
  • Changing only a nested include changes the root composition_sha.
  • Adding, removing, reordering, or repeating an include changes the root fingerprint.
  • A nested dependency manifest is reproducible across machines.
  • Equivalent source trees produce the same fingerprint regardless of traversal order.
  • Cyclic and missing includes fail deterministically.
  • Existing non-nested templates retain a documented compatibility path or migration behavior.
  • Tests cover one-level nesting, multi-level nesting, repeated includes, path collisions, changed child content, and render-context changes.

Non-goal

Do not use an unordered array of independent file SHAs as the sole identity. Keep the array/tree as inspectable evidence, but derive one root composition fingerprint from the ordered dependency graph.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions