check-stale
41 beliefs (38 IN, 3 OUT)
The check-stale topic covers the staleness detection subsystem of the TMS, which verifies whether beliefs remain consistent with their source material on disk. This is a critical integrity mechanism: beliefs in the network are grounded in specific source files (with line ranges), and when those files change or disappear, the corresponding beliefs may no longer be accurate. The system works by comparing stored SHA-256 hashes against current file contents, using full 64-character hex digests (hash-file-full-sha256) rather than the truncated 16-character prefixes that were used previously (hash-truncation-is-16-hex, now OUT as that behavior was fixed in PR #40). A key limitation is that this mechanism can only detect source staleness — cases where the file itself changed — and cannot detect world staleness, where a belief has become outdated even though its source file is unchanged (check-stale-detects-source-staleness-only). This asymmetry also extends to node types: premises have source-level grounding that makes them verifiable, while derived beliefs can only be structurally validated by checking that their antecedents exist and are IN (premise-derived-verifiability-asymmetry).
The check_stale function is deliberately read-only (check-stale-is-read-only), returning a list of structured result dicts without mutating the network. An earlier duplicate belief (check-stale-report-only, now OUT) restated this same property. This contrasts with hash_sources, which does mutate the network by writing directly to node.source_hash (hash-sources-mutates-network), though it is safe to call repeatedly because it skips nodes that already have hashes unless force=True is passed (hash-sources-idempotent-without-force, hash-sources-is-additive-by-default). Neither function persists changes — the caller must save (check-stale-and-hash-sources-mutate-in-place). The check_stale function only examines IN nodes (check-stale-skips-out-nodes), requires both source and source_hash fields to be non-empty (check-stale-requires-both-source-fields), and uses two reason codes: "content_changed" when a file's hash differs and "source_deleted" when the file is missing from disk (stale-result-reasons). An earlier belief that missing files were silently skipped (missing-source-file-is-silent) is now OUT, reflecting a fix (issue #25) that introduced explicit source_deleted reporting with None hashes (check-stale-source-deleted-returns-none-hashes). Source path resolution follows a precedence chain through db_dir, agent repo, and repo-key-split strategies (resolve-source-path-db-dir-precedence), falling back to ~/git/<repo>/<path> by convention (resolve-source-defaults-to-home-git), and returns None rather than raising on missing files (resolve-source-path-never-raises).
The output of check_stale is carefully designed for programmatic consumption and CI integration. All result dicts share a uniform 6-key schema — node_id, old_hash, new_hash, source, source_path, reason — regardless of whether the reason is content_changed or source_deleted (check-stale-result-schema-uniform, result-schema-uniformity). Results are sorted lexicographically by node_id for deterministic output (check-stale-results-sorted-by-node-id, results-sorted-by-node-id), and no exceptions are raised even for error conditions like missing files (check-stale-never-raises-on-missing-files, staleness-results-are-dicts-not-exceptions). The cmd_check_stale wrapper exits nonzero when stale nodes are found (check-stale-exits-nonzero), making it directly usable as a CI or pre-commit gate without wrapper scripts (staleness-output-is-ci-pipeline-ready, staleness-is-conservative-ci-gate). Several higher-level beliefs synthesize these properties: the staleness gate is claimed to catch all forms of source drift without false negatives (staleness-gate-catches-all-drift), and staleness information survives the binary IN/OUT truth model through metadata preservation during import and compact output (staleness-information-survives-binary-truth-model, staleness-is-surfaced-despite-binary-truth-model). The TMS maps STALE status in beliefs.md to OUT during import (stale-maps-to-out, stale-maps-to-out-on-import), since there is no distinct STALE truth value in the data model — but downstream consumers can still distinguish intentional retractions from staleness-driven ones via metadata.
-
IN
check-stale-and-hash-sources-mutate-in-place
Both `check_stale` (with `upgrade_hashes=True`) and `hash_sources` modify `node.source_hash` directly on the Network object; neither persists — the caller must save. -
IN
check-stale-detects-source-staleness-only
`check-stale` detects source staleness (source file changed on disk) via hash comparison but cannot detect world staleness (the belief is outdated even though the source file hasn't changed) — beliefs can silently decay without any artifact triggering re-examination. -
IN
check-stale-exits-nonzero
`cmd_check_stale` calls `sys.exit(1)` when any stale nodes are found, making it usable as a CI or pre-commit gate. -
IN
check-stale-is-read-only
`check_stale` never mutates the network; it returns a list of stale-node dicts and leaves all nodes unchanged — staleness detection is separated from staleness resolution. -
IN
check-stale-never-raises-on-missing-files
`check_stale()` returns a structured `source_deleted` dict for nodes whose source files don't exist on disk; it never raises `FileNotFoundError` or any exception. -
IN
check-stale-no-dedup-by-source-path
Multiple nodes referencing the same missing source file each produce independent `source_deleted` results — no deduplication by file path. -
IN
check-stale-output-is-deterministic-and-structured
Staleness checking produces deterministic (sorted by node ID), uniformly structured (consistent 6-key schema across all result types), and exception-free (returns structured dicts for missing files rather than raising) output suitable for programmatic consumption and diffing. -
OUT
check-stale-report-only
Duplicate of existing belief `check-stale-is-read-only`. -
IN
check-stale-requires-both-source-fields
A node must have both `source` (non-empty) and `source_hash` (non-empty) to be eligible for staleness checking; nodes missing either field are silently skipped. -
IN
check-stale-result-schema-uniform
All `check_stale` result dicts share the same 6-key schema (`node_id`, `old_hash`, `new_hash`, `source`, `source_path`, `reason`) regardless of reason type, so consumers can iterate results without type-checking. -
IN
check-stale-results-sorted-by-node-id
The list returned by `check_stale` is sorted ascending by `node_id`, providing deterministic output for consumers. -
IN
check-stale-skips-out-nodes
Only nodes with `truth_value == "IN"` are checked for staleness; retracted (OUT) nodes are ignored even if their source file has changed. -
IN
check-stale-source-deleted-returns-none-hashes
When a source file is missing, `check_stale` returns a result dict with `reason="source_deleted"`, `new_hash=None`, and `source_path=None` (fix for issue #25 — previously this case was silently skipped). -
IN
hash-file-full-sha256
`hash_file` returns a full 64-character hex SHA-256 digest (per the fix in PR #40 that removed the earlier `[:16]` truncation). -
IN
hash-sources-idempotent-without-force
`hash_sources` with default `force=False` skips nodes that already have a `source_hash`, making repeated backfill calls safe; `force=True` rehashes unconditionally. -
IN
hash-sources-is-additive-by-default
`hash_sources` without `force=True` never overwrites an existing non-empty `source_hash`; it only backfills nodes with empty or missing hashes. -
IN
hash-sources-mutates-network
`hash_sources` writes directly to `node.source_hash` on the in-memory network, while `check_stale` is purely read-only — an intentional asymmetry. -
IN
hash-sources-no-overwrite-default
`hash_sources` with `force=False` (the default) only backfills missing hashes and will never modify a node that already has a `source_hash` value. -
OUT
hash-truncation-is-16-hex
Source hashes are SHA-256 truncated to the first 16 hex characters (64 bits), reducing collision resistance to ~32 bits for birthday attacks compared to the full 256-bit hash. -
IN
inspection-outputs-are-uniformly-normalized
Both inspection mechanisms — belief review and staleness checking — produce normalized, schema-consistent, fail-safe output with deterministic structure suitable for automated consumption. -
IN
lifecycle-awareness-spans-checking-and-propagation
Both read-only inspection and mutation-driven propagation respect node lifecycle consistently: staleness checking skips OUT nodes and never mutates state, while propagation skips retracted nodes and preserves trigger identity — lifecycle state is honored across the system regardless of whether the operation is read or write. -
OUT
missing-source-file-is-silent
If a node's source file no longer exists on disk, `check_stale` silently skips it; callers cannot distinguish "file deleted" from "file never tracked." -
IN
premise-derived-verifiability-asymmetry
Premises record source file and line range at assertion time, enabling check-stale to verify them against current code; derived beliefs have no equivalent source-level grounding and can only be structurally validated (references exist and are IN). -
IN
resolve-source-defaults-to-home-git
When no `repos` mapping is provided, `resolve_source_path` falls back to `~/git// ` by convention. -
IN
resolve-source-fallback-path
When no `repos` mapping is provided, `resolve_source_path` constructs paths as `~/git// ` by convention. -
IN
resolve-source-path-db-dir-precedence
`resolve_source_path` follows a strict precedence chain: `db_dir` resolution takes priority over agent repo resolution, which takes priority over repo-key-split resolution; missing files return `None`. -
IN
resolve-source-path-never-raises
`resolve_source_path` returns `None` for nonexistent files instead of raising exceptions; callers must check the `None` case. -
IN
resolve-source-path-returns-none-on-missing
`resolve_source_path` returns `None` (not an exception) when the resolved file does not exist on disk or when the source string is empty. -
IN
result-schema-uniformity
Both `content_changed` and `source_deleted` results from `check_stale` share exactly the same six keys: `node_id`, `old_hash`, `new_hash`, `source`, `source_path`, `reason` — consumers can handle both uniformly. -
IN
results-sorted-by-node-id
`check_stale()` returns results sorted lexicographically by `node_id`, enforced by iterating `sorted(network.nodes.items())`. -
IN
stale-maps-to-out
STALE status in `beliefs.md` is mapped to OUT (retracted) in the network; there is no distinct STALE state in the TMS data model. -
IN
stale-maps-to-out-on-import
Nodes marked `[STALE]` in beliefs.md are stored with truth value OUT during both initial import and subsequent syncs -
IN
stale-result-reasons
`check_stale` uses two distinct reason codes: `"content_changed"` when the source file exists but its hash differs, and `"source_deleted"` when the file is gone from disk. -
IN
staleness-checking-is-comprehensive
Staleness checking detects all nodes whose source material has changed on disk -
IN
staleness-gate-catches-all-drift
The staleness CI gate detects all forms of source material drift without false negatives. -
IN
staleness-information-survives-binary-truth-model
Despite the TMS using binary IN/OUT truth values with no distinct STALE state, staleness information is preserved end-to-end: stale beliefs are mapped to OUT on import with stale_reason metadata, and the compact output surfaces this metadata for OUT nodes — so downstream consumers can distinguish intentional retractions from staleness-driven ones. -
IN
staleness-is-conservative-ci-gate
Staleness checking is designed as a safe CI gate: it never mutates state, only checks IN nodes, requires both source fields, and exits nonzero to fail the pipeline -
IN
staleness-is-surfaced-despite-binary-truth-model
Staleness information not only survives the binary IN/OUT truth model (via metadata-based preservation through import and compact surfacing) but also emerges as deterministic, uniformly-structured, machine-parseable CI output with conservative non-mutating semantics — no information is lost between the TMS representation and the external consumer. -
IN
staleness-output-is-ci-pipeline-ready
Staleness checking produces deterministic, uniformly-structured, machine-parseable output with conservative non-mutating semantics and nonzero exit codes, making it directly consumable by automated CI pipelines without wrapper scripts -
IN
staleness-results-are-dicts-not-exceptions
Both `check_stale` and `hash_sources` report problems (missing files, changed content, deleted sources) as list-of-dict return values, never raising exceptions — designed for batch audit operations that report all problems rather than aborting on the first. -
IN
staleness-uses-full-sha256
Staleness detection compares full 64-character SHA-256 hex digests via exact string equality, not truncated prefixes or fuzzy comparison.