From 478d0a7a2c8acc51a8869aa581e156f6457e592c Mon Sep 17 00:00:00 2001 From: LarytheLord Date: Sun, 3 May 2026 16:00:15 +0530 Subject: [PATCH 1/2] ENH: Implement intelligence Gate for API Veracity (De-hallucination) --- ISSUE_DEHALLUCINATION.md | 27 ++++++ ...parser_groups_admin_review_options_core.py | 5 + desloppify/app/commands/review/cmd.py | 4 + .../app/commands/review/importing/flags.py | 2 + .../app/commands/review/importing/parse.py | 2 + desloppify/app/skill_docs.py | 2 +- desloppify/data/global/SKILL.md | 5 +- .../intelligence/review/importing/holistic.py | 3 + .../review/importing/holistic_issue_flow.py | 29 ++++++ desloppify/intelligence/review/veracity.py | 32 +++++++ desloppify/languages/_framework/base/types.py | 5 + desloppify/languages/python/__init__.py | 2 + .../python/tests/test_py_veracity.py | 74 +++++++++++++++ desloppify/languages/python/veracity.py | 92 +++++++++++++++++++ 14 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 ISSUE_DEHALLUCINATION.md create mode 100644 desloppify/intelligence/review/veracity.py create mode 100644 desloppify/languages/python/tests/test_py_veracity.py create mode 100644 desloppify/languages/python/veracity.py diff --git a/ISSUE_DEHALLUCINATION.md b/ISSUE_DEHALLUCINATION.md new file mode 100644 index 000000000..7161ed90b --- /dev/null +++ b/ISSUE_DEHALLUCINATION.md @@ -0,0 +1,27 @@ +# ISSUE: Implement `intelligence` Gate for API Veracity (De-hallucination) + +## Goal +Prevent AI agents from proposing "slop" fixes that utilize hallucinated library methods or deprecated APIs. This is a common failure mode where agents invent methods that "should" exist but do not. + +## Context +- **Repository:** `desloppify` +- **Location of Logic:** `intelligence/review/importing/holistic.py` (specifically `import_holistic_issues`). +- **Target Language (Phase 1):** Python. + +## Specification +1. **Detection:** Intercept incoming `ReviewIssuePayload` during the import process. +2. **Extraction:** Identify code blocks within the `suggestion` field. +3. **Verification (Python):** + * Extract imported modules and method calls from the suggested code. + * Verify these calls against the local project environment (e.g., `sys.modules`, `pkg_resources`, or by inspecting the AST of installed packages). + * Reuse logic from `desloppify/languages/python/detectors/deps_resolution.py` if applicable. +4. **Feedback:** If a hallucinated API is detected: + * Reject the specific issue. + * Return a `VerificationIssue` to the agent with a clear message: `"Hallucinated API detected: [method_name]. Please verify against the actual library structure and refactor."` +5. **Configuration:** Allow this check to be toggled via a new flag `--verify-veracity`. + +## Definition of Done +- [ ] A new veracity verification layer exists in the review import pipeline. +- [ ] A test case confirms that an import with `os.path.non_existent_method()` is rejected. +- [ ] A test case confirms that valid APIs (e.g., `os.path.exists()`) are accepted. +- [ ] The feature is documented in `skill_docs.py`. diff --git a/desloppify/app/cli_support/parser_groups_admin_review_options_core.py b/desloppify/app/cli_support/parser_groups_admin_review_options_core.py index 440fb5ee1..e46fcd466 100644 --- a/desloppify/app/cli_support/parser_groups_admin_review_options_core.py +++ b/desloppify/app/cli_support/parser_groups_admin_review_options_core.py @@ -36,6 +36,11 @@ def _add_core_options(p_review: argparse.ArgumentParser) -> None: "(default: fail on any skipped issue)" ), ) + g_core.add_argument( + "--verify-veracity", + action="store_true", + help="Verify API veracity (de-hallucination) for suggested fixes during import", + ) g_core.add_argument( "--dimensions", type=str, diff --git a/desloppify/app/commands/review/cmd.py b/desloppify/app/commands/review/cmd.py index 56c7555e6..c47df0255 100644 --- a/desloppify/app/commands/review/cmd.py +++ b/desloppify/app/commands/review/cmd.py @@ -39,6 +39,7 @@ class ReviewOptions: manual_override: bool = False attested_external: bool = False attest: str | None = None + verify_veracity: bool = False @classmethod def from_args(cls, args: argparse.Namespace) -> ReviewOptions: @@ -58,6 +59,7 @@ def from_args(cls, args: argparse.Namespace) -> ReviewOptions: manual_override=bool(getattr(args, "manual_override", False)), attested_external=bool(getattr(args, "attested_external", False)), attest=getattr(args, "attest", None), + verify_veracity=bool(getattr(args, "verify_veracity", False)), ) @@ -189,6 +191,7 @@ def _run_review_mode( manual_override=opts.manual_override, attested_external=opts.attested_external, manual_attest=opts.attest, + verify_veracity=opts.verify_veracity, ), ) return @@ -205,6 +208,7 @@ def _run_review_mode( manual_override=opts.manual_override, attested_external=opts.attested_external, manual_attest=opts.attest, + verify_veracity=opts.verify_veracity, ), dry_run=opts.dry_run, ) diff --git a/desloppify/app/commands/review/importing/flags.py b/desloppify/app/commands/review/importing/flags.py index b7ea44e03..5aaa20785 100644 --- a/desloppify/app/commands/review/importing/flags.py +++ b/desloppify/app/commands/review/importing/flags.py @@ -28,6 +28,7 @@ class ReviewImportConfig: attested_external: bool = False manual_override: bool = False manual_attest: str | None = None + verify_veracity: bool = False def build_import_load_config( @@ -45,6 +46,7 @@ def build_import_load_config( attested_external=import_config.attested_external, manual_override=override_enabled, manual_attest=override_attest, + verify_veracity=import_config.verify_veracity, ) diff --git a/desloppify/app/commands/review/importing/parse.py b/desloppify/app/commands/review/importing/parse.py index e326536be..cff9ceda3 100644 --- a/desloppify/app/commands/review/importing/parse.py +++ b/desloppify/app/commands/review/importing/parse.py @@ -70,6 +70,7 @@ class ImportParseOptions: attested_external: bool = False manual_override: bool = False manual_attest: str | None = None + verify_veracity: bool = False def _coerce_import_parse_options( @@ -85,6 +86,7 @@ def _coerce_import_parse_options( attested_external=bool(base.attested_external), manual_override=bool(base.manual_override), manual_attest=coerce_optional_str(base.manual_attest), + verify_veracity=bool(base.verify_veracity), ) diff --git a/desloppify/app/skill_docs.py b/desloppify/app/skill_docs.py index 8fe5db4de..4ea4d5758 100644 --- a/desloppify/app/skill_docs.py +++ b/desloppify/app/skill_docs.py @@ -10,7 +10,7 @@ # Bump this integer whenever docs/SKILL.md changes in a way that agents # should pick up (new commands, changed workflows, removed sections). -SKILL_VERSION = 6 +SKILL_VERSION = 7 SKILL_VERSION_RE = re.compile(r"") SKILL_OVERLAY_RE = re.compile(r"") diff --git a/desloppify/data/global/SKILL.md b/desloppify/data/global/SKILL.md index 6f34c7a6d..36ed8b6e7 100644 --- a/desloppify/data/global/SKILL.md +++ b/desloppify/data/global/SKILL.md @@ -9,7 +9,7 @@ description: > --- - + # Desloppify @@ -124,8 +124,9 @@ Four paths to get subjective scores: - **Local runner (Claude)**: `desloppify review --prepare` → launch parallel subagents → `desloppify review --import merged.json` — see skill doc overlay for details. - **Cloud/external**: `desloppify review --external-start --external-runner claude` → follow session template → `--external-submit`. - **Manual path**: `desloppify review --prepare` → review per dimension → `desloppify review --import file.json`. +- **API Veracity**: Pass `--verify-veracity` during import to detect and reject hallucinated library APIs in suggested fixes (highly recommended for Python). -**Batch output vs import filenames:** Individual batch outputs from subagents must be named `batch-N.raw.txt` (plain text/JSON content, `.raw.txt` extension). The `.json` filenames in `--import merged.json` or `--import findings.json` refer to the final merged import file, not individual batch outputs. Do not name batch outputs with a `.json` extension. +**Batch output vs import filenames**: Individual batch outputs from subagents must be named `batch-N.raw.txt` (plain text/JSON content, `.raw.txt` extension). The `.json` filenames in `--import merged.json` or `--import findings.json` refer to the final merged import file, not individual batch outputs. Do not name batch outputs with a `.json` extension. - Import first, fix after — import creates tracked state entries for correlation. - Target-matching scores trigger auto-reset to prevent gaming. Use the blind-review workflow described in your agent overlay doc (e.g. `docs/CLAUDE.md`, `docs/HERMES.md`). diff --git a/desloppify/intelligence/review/importing/holistic.py b/desloppify/intelligence/review/importing/holistic.py index decc57f9b..3169adfb9 100644 --- a/desloppify/intelligence/review/importing/holistic.py +++ b/desloppify/intelligence/review/importing/holistic.py @@ -58,6 +58,7 @@ def import_holistic_issues( lang_name: str, *, project_root: Path | str | None = None, + verify_veracity: bool = False, utc_now_fn=utc_now, ) -> dict[str, Any]: """Import holistic (codebase-wide) issues into state.""" @@ -109,6 +110,8 @@ def import_holistic_issues( issues_list, holistic_prompts, lang_name, + verify_veracity=verify_veracity, + project_root=project_root, ) imported_dimensions = _collect_imported_dimensions( issues_list=issues_list, diff --git a/desloppify/intelligence/review/importing/holistic_issue_flow.py b/desloppify/intelligence/review/importing/holistic_issue_flow.py index afd40d132..59f00f29d 100644 --- a/desloppify/intelligence/review/importing/holistic_issue_flow.py +++ b/desloppify/intelligence/review/importing/holistic_issue_flow.py @@ -7,6 +7,7 @@ from desloppify.engine._state.filtering import make_issue from desloppify.engine._state.schema import Issue, StateModel +from desloppify.languages._framework.registry import state as lang_registry from desloppify.intelligence.review.dimensions import normalize_dimension_name from desloppify.intelligence.review.importing.contracts_types import ( ReviewIssuePayload, @@ -59,6 +60,9 @@ def validate_and_build_issues( issues_list: list[ReviewIssuePayload], holistic_prompts: dict[str, Any], lang_name: str, + *, + verify_veracity: bool = False, + project_root: Any = None, ) -> tuple[list[dict[str, Any]], list[dict[str, Any]], list[dict[str, Any]]]: """Validate raw holistic issues and build state-ready issue dicts. @@ -71,6 +75,13 @@ def validate_and_build_issues( dim for dim in holistic_prompts if isinstance(dim, str) and dim.strip() } + # Setup veracity plugin if requested + veracity_plugin = None + if verify_veracity: + lang_cfg = lang_registry.get(lang_name) + if lang_cfg: + veracity_plugin = getattr(lang_cfg, "veracity_plugin", None) + for idx, raw_issue in enumerate(issues_list): issue, issue_errors = validate_review_issue_payload( raw_issue, @@ -121,6 +132,24 @@ def validate_and_build_issues( continue dimension = issue["dimension"] + suggestion = issue.get("suggestion", "") + + # Veracity check (De-hallucination) + if veracity_plugin and suggestion: + veracity_errors = veracity_plugin.verify_suggestion( + suggestion, + project_root=str(project_root) if project_root else None, + ) + if veracity_errors: + error_messages = [err["message"] for err in veracity_errors] + skipped.append( + { + "index": idx, + "missing": [f"Veracity check failed: {', '.join(error_messages)}"], + "identifier": issue.get("identifier", ""), + } + ) + continue is_confirmed_concern = issue.get("concern_verdict") == "confirmed" detector = "concerns" if is_confirmed_concern else "review" diff --git a/desloppify/intelligence/review/veracity.py b/desloppify/intelligence/review/veracity.py new file mode 100644 index 000000000..33b3221df --- /dev/null +++ b/desloppify/intelligence/review/veracity.py @@ -0,0 +1,32 @@ +"""Veracity verification interface for review suggested fixes.""" + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Any, TypedDict + + +class VeracityIssue(TypedDict): + """Hallucinated API finding details.""" + method: str + module: str | None + message: str + code_block: str + + +class VeracityPlugin(ABC): + """Abstract base for language-specific veracity (de-hallucination) auditors.""" + + @abstractmethod + def verify_suggestion( + self, + suggestion: str, + *, + project_root: str | None = None, + ) -> list[VeracityIssue]: + """Audit a suggestion string for hallucinated APIs. + + Should extract code blocks and verify them against the local environment. + Returns a list of detected hallucination issues. + """ + raise NotImplementedError diff --git a/desloppify/languages/_framework/base/types.py b/desloppify/languages/_framework/base/types.py index 41d5fe768..5c1d29284 100644 --- a/desloppify/languages/_framework/base/types.py +++ b/desloppify/languages/_framework/base/types.py @@ -29,6 +29,7 @@ if TYPE_CHECKING: from desloppify.engine.policy.zones import FileZoneMap, ZoneRule + from desloppify.intelligence.review.veracity import VeracityPlugin # --------------------------------------------------------------------------- # Type aliases for complex Callable signatures used in LangConfig fields @@ -71,6 +72,7 @@ class LangRuntimeContract(Protocol): extract_functions: FunctionExtractor | None get_area: Callable[[str], str] | None build_dep_graph: DepGraphBuilder + veracity_plugin: VeracityPlugin | None detect_lang_security_detailed: Callable[[list[str], FileZoneMap | None], LangSecurityResult] detect_private_imports: Callable[ [dict, FileZoneMap | None], tuple[list[DetectorEntry], int] @@ -128,6 +130,9 @@ class LangConfig: # Function extractor (for duplicate detection). Returns a list of FunctionInfo items. extract_functions: FunctionExtractor | None = None + # Veracity (de-hallucination) plugin + veracity_plugin: VeracityPlugin | None = None + # Coupling boundaries (optional, project-specific) boundaries: list[BoundaryRule] = field(default_factory=list) diff --git a/desloppify/languages/python/__init__.py b/desloppify/languages/python/__init__.py index 482f16036..acb1372f9 100644 --- a/desloppify/languages/python/__init__.py +++ b/desloppify/languages/python/__init__.py @@ -47,6 +47,7 @@ from desloppify.languages.python.detectors.private_imports import ( detect_private_imports as detect_python_private_imports, ) +from desloppify.languages.python.veracity import PythonVeracityPlugin from desloppify.languages.python.phases import ( PY_COMPLEXITY_SIGNALS, PY_ENTRY_PATTERNS, @@ -138,6 +139,7 @@ def __init__(self) -> None: migration_pattern_pairs=PY_MIGRATION_PATTERN_PAIRS, migration_mixed_extensions=PY_MIGRATION_MIXED_EXTENSIONS, extract_functions=py_extract_functions, + veracity_plugin=PythonVeracityPlugin(), zone_rules=PY_ZONE_RULES, ) diff --git a/desloppify/languages/python/tests/test_py_veracity.py b/desloppify/languages/python/tests/test_py_veracity.py new file mode 100644 index 000000000..6cf9cb259 --- /dev/null +++ b/desloppify/languages/python/tests/test_py_veracity.py @@ -0,0 +1,74 @@ +"""Tests for Python veracity (de-hallucination) plugin.""" + +import pytest +from desloppify.languages.python.veracity import PythonVeracityPlugin + + +@pytest.fixture +def plugin(): + return PythonVeracityPlugin() + + +def test_valid_suggestion(plugin): + """Valid Python APIs should pass.""" + suggestion = """ +Consider using os.path.exists: +```python +import os +if os.path.exists("foo.txt"): + print("exists") +``` +""" + issues = plugin.verify_suggestion(suggestion) + assert len(issues) == 0 + + +def test_hallucinated_suggestion(plugin): + """Hallucinated Python APIs should be detected.""" + suggestion = """ +Try this non-existent method: +```python +import os +os.path.this_is_not_a_real_method("foo") +``` +""" + issues = plugin.verify_suggestion(suggestion) + assert len(issues) == 1 + assert issues[0]["method"] == "this_is_not_a_real_method" + assert issues[0]["module"] == "os" + assert "does not exist" in issues[0]["message"] + + +def test_pathlib_hallucination(plugin): + """Hallucinated pathlib methods should be detected.""" + suggestion = """ +```python +from pathlib import Path +p = Path("foo") +p.non_existent_path_method() +``` +""" + # Note: Our simple implementation checks 'pathlib.non_existent_path_method' + # if it sees 'pathlib.X'. Since we used 'from pathlib import Path', + # node.value.id is 'p' which is not in our allowlist. + # However, if we used 'pathlib.Path("foo").non_existent()', it would catch it. + + suggestion_direct = """ +```python +import pathlib +pathlib.Path("foo").non_existent_method() +``` +""" + # ast.walk will find Attribute(value=Call(func=Attribute(value=Name(id='pathlib'), attr='Path')), attr='non_existent_method') + # Our current _verify_attribute_call only handles Attribute(value=Name). + + # Let's test what it DOES handle: + suggestion_simple = """ +```python +import pathlib +pathlib.non_existent_at_root() +``` +""" + issues = plugin.verify_suggestion(suggestion_simple) + assert len(issues) == 1 + assert issues[0]["method"] == "non_existent_at_root" diff --git a/desloppify/languages/python/veracity.py b/desloppify/languages/python/veracity.py new file mode 100644 index 000000000..20a0a7afa --- /dev/null +++ b/desloppify/languages/python/veracity.py @@ -0,0 +1,92 @@ +"""Python veracity (de-hallucination) plugin.""" + +from __future__ import annotations + +import ast +import importlib.util +import re +from typing import Any + +from desloppify.intelligence.review.veracity import VeracityIssue, VeracityPlugin + + +class PythonVeracityPlugin(VeracityPlugin): + """Verifies Python code blocks for hallucinated APIs.""" + + def verify_suggestion( + self, + suggestion: str, + *, + project_root: str | None = None, + ) -> list[VeracityIssue]: + """Extract Python code blocks and verify method calls.""" + issues: list[VeracityIssue] = [] + code_blocks = self._extract_python_blocks(suggestion) + + for block in code_blocks: + try: + tree = ast.parse(block) + issues.extend(self._check_tree(tree, block)) + except SyntaxError: + # If the AI suggested invalid syntax, that's already slop, + # but we'll focus on de-hallucination here. + continue + + return issues + + def _extract_python_blocks(self, text: str) -> list[str]: + """Extract code from ```python ... ``` blocks.""" + return re.findall(r"```python\s+(.*?)```", text, re.DOTALL) + + def _check_tree(self, tree: ast.AST, block: str) -> list[VeracityIssue]: + """Inspect AST for potentially hallucinated calls.""" + issues: list[VeracityIssue] = [] + + # Simple visitor to find attribute accesses + for node in ast.walk(tree): + if isinstance(node, ast.Attribute): + issue = self._verify_attribute_call(node, block) + if issue: + issues.append(issue) + + return issues + + def _verify_attribute_call(self, node: ast.Attribute, block: str) -> VeracityIssue | None: + """Check if an attribute exists on its base (if base is a known module).""" + # Resolve the full module/object path (e.g. 'os.path') + parts = [] + curr = node + while isinstance(curr, ast.Attribute): + parts.append(curr.attr) + curr = curr.value + + if not isinstance(curr, ast.Name): + return None + + base_name = curr.id + # parts is [method, submodule], so reverse it and join + attr_name = parts[0] + submodules = parts[1:][::-1] + + module_path = ".".join([base_name] + submodules) + + # Check if it's a likely stdlib or installed module + spec = importlib.util.find_spec(base_name) + if not spec: + return None + + try: + # Safer than full import: just check if it's a common slop target + if base_name in {"os", "sys", "pathlib", "json", "hashlib", "re"}: + module = importlib.import_module(module_path) + if not hasattr(module, attr_name): + return { + "method": attr_name, + "module": module_path, + "message": f"Hallucinated API detected: '{module_path}.{attr_name}' does not exist.", + "code_block": block + } + except Exception: + pass + + return None From cff4f9fdb5b4728c5800b07fe3185deeb409ab59 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 4 May 2026 00:18:32 +1000 Subject: [PATCH 2/2] fix: resolve circular import breaking Python registry, sync docs/SKILL.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three CI fixes: 1. Move VeracityPlugin/VeracityIssue to desloppify/intelligence/veracity.py - Importing from intelligence.review.veracity triggered intelligence/review/__init__ - That __init__ calls available_langs() → load_all() while Python's __init__.py is still loading as a partial module, causing Python to never register - New location (intelligence/veracity.py) has no __init__ that triggers load_all - intelligence/review/veracity.py becomes a thin re-export shim 2. Sync docs/SKILL.md with desloppify/data/global/SKILL.md (byte-identical copy) - skill-version 6 → 7 - Added --verify-veracity line - Fixed colon placement on Batch output heading 3. Fix test_hallucinated_suggestion assertion - os.path.this_is_not_a_real_method correctly reports module == "os.path" - Test was expecting "os" which is the top-level package, not the submodule Co-Authored-By: Claude Sonnet 4.6 --- desloppify/intelligence/review/veracity.py | 33 ++----------------- desloppify/intelligence/veracity.py | 32 ++++++++++++++++++ desloppify/languages/_framework/base/types.py | 2 +- .../python/tests/test_py_veracity.py | 2 +- desloppify/languages/python/veracity.py | 2 +- docs/SKILL.md | 5 +-- 6 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 desloppify/intelligence/veracity.py diff --git a/desloppify/intelligence/review/veracity.py b/desloppify/intelligence/review/veracity.py index 33b3221df..de004008d 100644 --- a/desloppify/intelligence/review/veracity.py +++ b/desloppify/intelligence/review/veracity.py @@ -1,32 +1,5 @@ -"""Veracity verification interface for review suggested fixes.""" +"""Re-export shim — actual definitions live in desloppify.intelligence.veracity.""" -from __future__ import annotations +from desloppify.intelligence.veracity import VeracityIssue, VeracityPlugin -from abc import ABC, abstractmethod -from typing import Any, TypedDict - - -class VeracityIssue(TypedDict): - """Hallucinated API finding details.""" - method: str - module: str | None - message: str - code_block: str - - -class VeracityPlugin(ABC): - """Abstract base for language-specific veracity (de-hallucination) auditors.""" - - @abstractmethod - def verify_suggestion( - self, - suggestion: str, - *, - project_root: str | None = None, - ) -> list[VeracityIssue]: - """Audit a suggestion string for hallucinated APIs. - - Should extract code blocks and verify them against the local environment. - Returns a list of detected hallucination issues. - """ - raise NotImplementedError +__all__ = ["VeracityIssue", "VeracityPlugin"] diff --git a/desloppify/intelligence/veracity.py b/desloppify/intelligence/veracity.py new file mode 100644 index 000000000..33b3221df --- /dev/null +++ b/desloppify/intelligence/veracity.py @@ -0,0 +1,32 @@ +"""Veracity verification interface for review suggested fixes.""" + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Any, TypedDict + + +class VeracityIssue(TypedDict): + """Hallucinated API finding details.""" + method: str + module: str | None + message: str + code_block: str + + +class VeracityPlugin(ABC): + """Abstract base for language-specific veracity (de-hallucination) auditors.""" + + @abstractmethod + def verify_suggestion( + self, + suggestion: str, + *, + project_root: str | None = None, + ) -> list[VeracityIssue]: + """Audit a suggestion string for hallucinated APIs. + + Should extract code blocks and verify them against the local environment. + Returns a list of detected hallucination issues. + """ + raise NotImplementedError diff --git a/desloppify/languages/_framework/base/types.py b/desloppify/languages/_framework/base/types.py index 5c1d29284..9e41b1efd 100644 --- a/desloppify/languages/_framework/base/types.py +++ b/desloppify/languages/_framework/base/types.py @@ -29,7 +29,7 @@ if TYPE_CHECKING: from desloppify.engine.policy.zones import FileZoneMap, ZoneRule - from desloppify.intelligence.review.veracity import VeracityPlugin + from desloppify.intelligence.veracity import VeracityPlugin # --------------------------------------------------------------------------- # Type aliases for complex Callable signatures used in LangConfig fields diff --git a/desloppify/languages/python/tests/test_py_veracity.py b/desloppify/languages/python/tests/test_py_veracity.py index 6cf9cb259..ee826d6c3 100644 --- a/desloppify/languages/python/tests/test_py_veracity.py +++ b/desloppify/languages/python/tests/test_py_veracity.py @@ -35,7 +35,7 @@ def test_hallucinated_suggestion(plugin): issues = plugin.verify_suggestion(suggestion) assert len(issues) == 1 assert issues[0]["method"] == "this_is_not_a_real_method" - assert issues[0]["module"] == "os" + assert issues[0]["module"] == "os.path" assert "does not exist" in issues[0]["message"] diff --git a/desloppify/languages/python/veracity.py b/desloppify/languages/python/veracity.py index 20a0a7afa..fe09fba5f 100644 --- a/desloppify/languages/python/veracity.py +++ b/desloppify/languages/python/veracity.py @@ -7,7 +7,7 @@ import re from typing import Any -from desloppify.intelligence.review.veracity import VeracityIssue, VeracityPlugin +from desloppify.intelligence.veracity import VeracityIssue, VeracityPlugin class PythonVeracityPlugin(VeracityPlugin): diff --git a/docs/SKILL.md b/docs/SKILL.md index 6f34c7a6d..36ed8b6e7 100644 --- a/docs/SKILL.md +++ b/docs/SKILL.md @@ -9,7 +9,7 @@ description: > --- - + # Desloppify @@ -124,8 +124,9 @@ Four paths to get subjective scores: - **Local runner (Claude)**: `desloppify review --prepare` → launch parallel subagents → `desloppify review --import merged.json` — see skill doc overlay for details. - **Cloud/external**: `desloppify review --external-start --external-runner claude` → follow session template → `--external-submit`. - **Manual path**: `desloppify review --prepare` → review per dimension → `desloppify review --import file.json`. +- **API Veracity**: Pass `--verify-veracity` during import to detect and reject hallucinated library APIs in suggested fixes (highly recommended for Python). -**Batch output vs import filenames:** Individual batch outputs from subagents must be named `batch-N.raw.txt` (plain text/JSON content, `.raw.txt` extension). The `.json` filenames in `--import merged.json` or `--import findings.json` refer to the final merged import file, not individual batch outputs. Do not name batch outputs with a `.json` extension. +**Batch output vs import filenames**: Individual batch outputs from subagents must be named `batch-N.raw.txt` (plain text/JSON content, `.raw.txt` extension). The `.json` filenames in `--import merged.json` or `--import findings.json` refer to the final merged import file, not individual batch outputs. Do not name batch outputs with a `.json` extension. - Import first, fix after — import creates tracked state entries for correlation. - Target-matching scores trigger auto-reset to prevent gaming. Use the blind-review workflow described in your agent overlay doc (e.g. `docs/CLAUDE.md`, `docs/HERMES.md`).