@@ -223,6 +223,64 @@ class RedisStorage(SessionStorage):
223223 def save (self , user_id : str , state : dict ) -> None : ...
224224```
225225
226+ ## Staleness Detection
227+
228+ ` attune-help ` tracks whether your help templates are up to date with
229+ your source code using SHA-256 hashes stored in template frontmatter.
230+
231+ ### Basic usage
232+
233+ ``` python
234+ from attune_help import load_manifest, check_staleness
235+
236+ manifest = load_manifest(" .help" )
237+ report = check_staleness(manifest, help_dir = " .help" , project_root = " ." )
238+
239+ for entry in report.stale_features:
240+ print (f " { entry} is stale — regenerate with attune-ai " )
241+ ```
242+
243+ ### Semantic hashing (v0.10+)
244+
245+ For pure-Python features, ` compute_source_hash ` automatically uses
246+ ** semantic hashing** : only public-symbol * contracts* (parameters, return
247+ types, decorators, base classes) contribute to the hash. Docstring
248+ edits, body rewrites, and formatter passes (` black ` , ` ruff ` ) are
249+ ignored. This eliminates spurious template regenerations when nothing
250+ meaningful changed.
251+
252+ ``` python
253+ from attune_help import compute_source_hash, compute_semantic_hash
254+ from attune_help.manifest import Feature
255+
256+ feat = Feature(name = " auth" , description = " " , files = [" src/auth/**" ])
257+
258+ # compute_source_hash uses semantic hashing automatically for .py-only features
259+ hash1, files = compute_source_hash(feat, project_root = " ." )
260+
261+ # Call compute_semantic_hash directly when you need the semantic hash
262+ # regardless of file mix (e.g. for reporting)
263+ hash2, files = compute_semantic_hash(feat, project_root = " ." )
264+ ```
265+
266+ Mixed-content features (Python + Jinja, YAML, etc.) and features with
267+ syntax errors in their source files fall back to byte-level SHA
268+ automatically — no configuration required.
269+
270+ ### Corpus validation
271+
272+ A 3-sweep validation harness ships in ` scripts/validate_against_corpus.py ` :
273+
274+ ``` bash
275+ # Validate against any repo with a .help/features.yaml
276+ python scripts/validate_against_corpus.py --repo /path/to/your/repo
277+ ```
278+
279+ Sweeps: (1) parse integrity — all ` .py ` files parse cleanly; (2)
280+ determinism — identical hashes on two consecutive calls; (3) HEAD vs
281+ HEAD^ — classifies symbol changes as signature drift / body-only /
282+ add / remove.
283+
226284## License
227285
228286Apache 2.0
0 commit comments