1 min read
pyssg.core.incremental.hashing
Aspect hashing & node identity.
Each node hashes its facets independently (raw, frontmatter, body,
content_html, ...). Hashing is blake2b over newline-normalized bytes so a
\r\n vs \n difference never spuriously invalidates. Everything here is
deterministic and stdlib-only.
canonical_bytes(value: object) -> bytes
Deterministic byte encoding of a value for hashing.
bytes/str pass through (str newline-normalized); everything else goes
through canonical JSON (sorted keys, compact) so dict/list ordering can never
change the digest.
compute_raw_hash(data: bytes) -> Digest
Hash raw file bytes with newline normalization.
digest(*parts: object) -> Digest
Combine several values into one digest (used for composite cache keys).
hash_aspect(node: Node, aspect: Aspect, value: object) -> Digest
Compute, store and return the digest of one aspect of node.
resolve_identity(path: str, fm: Mapping[str, object], raw_hash: Digest, recently_deleted: dict[Digest, NodeId]) -> NodeId
Resolve the stable logical NodeId for a file.
Order: frontmatter id -> move-detect (raw hash of a just-deleted node) ->
slug -> path fallback. This is what keeps backlinks intact across renames.