From 3f617942029888f5fd950286b55a13550d73f8c7 Mon Sep 17 00:00:00 2001 From: GeneAI Date: Thu, 7 May 2026 22:44:27 -0400 Subject: [PATCH 1/2] =?UTF-8?q?release:=20v0.7.0=20=E2=80=94=20ship=20relo?= =?UTF-8?q?cated=20authoring=20modules;=20drop=20attune-help=20dep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #14 (B1 of architecture-realignment) inverted the manifest / staleness / freshness relocation: those modules now live natively in attune-author. This release packages that change and removes the leftover ``attune-help>=0.10.0`` runtime dependency, which was only there because attune-author used to re-export from attune-help. There are no remaining ``from attune_help`` imports in ``src/attune_author/``. Side effect: this also unblocks attune-help 0.11.0 (B2 shim PR #6), which declares ``attune-author>=0.7.0`` for its deprecation shims. Without this release the two packages would form a circular package-metadata edge. Co-Authored-By: Claude Opus 4.7 --- CHANGELOG.md | 22 ++++++++++++++++++++++ pyproject.toml | 3 +-- src/attune_author/__init__.py | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e888e..99ff65f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,28 @@ and this project adheres to Work in progress for the next release. Add entries here as changes land, not at tag time. +## [0.7.0] - 2026-05-08 + +### Changed + +- **`attune_author.manifest` / `attune_author.staleness` / + `attune_author.freshness` are now the source of truth.** These + modules previously re-exported from `attune-help`; with PR #14 + they ship natively in attune-author. Existing imports from + `attune_author.*` continue to work; downstream code using + `attune_help.*` now goes through deprecation shims (see + `attune-help` 0.11.0 CHANGELOG). + +### Removed (dependency) + +- **`attune-help>=0.10.0` runtime dependency dropped.** It was a + leftover from when `manifest`/`staleness`/`freshness` lived in + attune-help and this package re-exported them. After PR #14 + inverted the direction, no `from attune_help` imports remain in + `src/attune_author/`. Removing the dep also breaks the circular + package-metadata edge that would otherwise form once + `attune-help` 0.11.0 declares `attune-author>=0.7.0`. + ## [0.5.1] - 2026-04-30 ### Changed diff --git a/pyproject.toml b/pyproject.toml index 40ec2d3..e06e5f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "attune-author" -version = "0.6.2" +version = "0.7.0" description = "Documentation authoring and maintenance for the attune ecosystem — generate, maintain, and validate help content with AI assistance." readme = {file = "README.md", content-type = "text/markdown"} requires-python = ">=3.10" @@ -41,7 +41,6 @@ dependencies = [ "jinja2>=3.1.0", "python-frontmatter>=1.0.0", "pyyaml>=6.0", - "attune-help>=0.10.0", # manifest + staleness now live in attune-help; attune-author re-exports them as shims. ] [project.optional-dependencies] diff --git a/src/attune_author/__init__.py b/src/attune_author/__init__.py index 61eed9c..68b3613 100644 --- a/src/attune_author/__init__.py +++ b/src/attune_author/__init__.py @@ -5,7 +5,7 @@ attune-help (reader) and attune-ai (full dev workflows). """ -__version__ = "0.6.2" +__version__ = "0.7.0" from attune_author.manifest import Feature, Manifest, load_manifest from attune_author.staleness import StalenessReport, check_staleness, compute_source_hash From 829b138382c7bebce0caa6eaa9c964ecccd35924 Mon Sep 17 00:00:00 2001 From: GeneAI Date: Thu, 7 May 2026 22:48:06 -0400 Subject: [PATCH 2/2] fix(lint): resolve pre-existing ruff E501/I001 in relocated modules Three ruff failures inherited from PR #14's merge (the relocated content was previously in attune-help, which had different line- length tolerance): - src/attune_author/staleness.py: 107-char comment in docstring example wrapped across two lines. - tests/test_staleness_relocated.py: 107-char string literal in test data split into three concatenated string parts. - tests/test_manifest_relocated.py: import block reordered (ruff --fix). Folded into the 0.7.0 release PR so CI can pass and the release tag can be cut. Co-Authored-By: Claude Opus 4.7 --- src/attune_author/staleness.py | 15 +++++---------- tests/test_manifest_relocated.py | 1 + tests/test_staleness_relocated.py | 16 ++++++---------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/attune_author/staleness.py b/src/attune_author/staleness.py index c2a52ca..e8c79b9 100644 --- a/src/attune_author/staleness.py +++ b/src/attune_author/staleness.py @@ -194,19 +194,13 @@ def compute_semantic_hash( if abs_path.suffix == ".py": try: for record in extractor.extract(abs_path): - hash_parts.append( - f"{rel_path}::{record.qualname}::{record.signature_hash}" - ) + hash_parts.append(f"{rel_path}::{record.qualname}::{record.signature_hash}") except SyntaxError: content = abs_path.read_bytes() - hash_parts.append( - f"{rel_path}::{hashlib.sha256(content).hexdigest()}" - ) + hash_parts.append(f"{rel_path}::{hashlib.sha256(content).hexdigest()}") else: content = abs_path.read_bytes() - hash_parts.append( - f"{rel_path}::{hashlib.sha256(content).hexdigest()}" - ) + hash_parts.append(f"{rel_path}::{hashlib.sha256(content).hexdigest()}") except OSError as e: logger.warning("Cannot read %s: %s", rel_path, e) @@ -311,7 +305,8 @@ def parse_doc_footer(text: str) -> dict[str, str]: The footer format is:: - + The comment may appear anywhere in the file but is conventionally the last line. diff --git a/tests/test_manifest_relocated.py b/tests/test_manifest_relocated.py index bd03e0b..f507cd5 100644 --- a/tests/test_manifest_relocated.py +++ b/tests/test_manifest_relocated.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from attune_author.manifest import ( Feature, FeatureManifest, diff --git a/tests/test_staleness_relocated.py b/tests/test_staleness_relocated.py index 10b9f39..a653e76 100644 --- a/tests/test_staleness_relocated.py +++ b/tests/test_staleness_relocated.py @@ -138,9 +138,7 @@ def test_compute_source_hash_deterministic(tmp_path: Path): def test_compute_source_hash_changes_on_edit(tmp_path: Path): - f = _write_src( - tmp_path, "src/auth/login.py", "def login(name: str) -> str:\n return name\n" - ) + f = _write_src(tmp_path, "src/auth/login.py", "def login(name: str) -> str:\n return name\n") feat = Feature(name="auth", description="", files=["src/auth/**"]) h1, _ = compute_source_hash(feat, tmp_path) f.write_text( @@ -160,7 +158,9 @@ def test_compute_source_hash_stable_across_docstring_edit(tmp_path: Path): feat = Feature(name="auth", description="", files=["src/auth/**"]) h1, _ = compute_source_hash(feat, tmp_path) f.write_text( - 'def login(name: str) -> str:\n """Very detailed login documentation.\"\"\"\n return name\n', + "def login(name: str) -> str:\n" + ' """Very detailed login documentation."""\n' + " return name\n", encoding="utf-8", ) h2, _ = compute_source_hash(feat, tmp_path) @@ -169,14 +169,10 @@ def test_compute_source_hash_stable_across_docstring_edit(tmp_path: Path): def test_compute_source_hash_changes_on_signature_edit(tmp_path: Path): """Semantic hashing: adding a parameter changes the hash.""" - f = _write_src( - tmp_path, "src/auth/login.py", "def login(name: str) -> str:\n return name\n" - ) + f = _write_src(tmp_path, "src/auth/login.py", "def login(name: str) -> str:\n return name\n") feat = Feature(name="auth", description="", files=["src/auth/**"]) h1, _ = compute_source_hash(feat, tmp_path) - f.write_text( - "def login(name: str, password: str) -> str:\n return name\n", encoding="utf-8" - ) + f.write_text("def login(name: str, password: str) -> str:\n return name\n", encoding="utf-8") h2, _ = compute_source_hash(feat, tmp_path) assert h1 != h2