Skip to content

T-B1Y3-test-scaffold-sys-modules-registration

Status: closed/superseded · Impact: low · Complexity: small

Auto-generated from a /sdlc:task-work post-mortem. Review and promote to open/ready before picking up.

Per-skill test files that load their target script via importlib.util.spec_from_file_location fail with a confusing AttributeError: 'NoneType' object has no attribute '__dict__' when the target script uses @dataclass, because Python 3.14’s dataclass machinery now looks the module up in sys.modules during decoration. The fix is a one-line sys.modules[name] = mod before exec_module, but the error surface is opaque enough that the next contributor will spend the same debugging time. Standardize the loader pattern so the registration is built in. Cited by T-A2C6-spawn-from-post-mortem-stronger-dedup.

plugin/skills/task-work/test_start_task.py uses the bare importlib loader without sys.modules registration, and gets away with it only because start_task.py has no dataclasses. plugin/skills/task-work/test_dedup_search.py (added in the same PR) registers manually after hitting the failure. No central helper exists — every new test file copy-pastes the loader.

A small helper — either a function in a shared test-support module under plugin/skills/ or an inlined snippet documented as canonical — that wraps the spec_from_file_locationmodule_from_specsys.modules[name] = modexec_module sequence so the registration cannot be omitted. Update existing test files to use it.

  1. Decide the shape: a shared helper module (e.g. plugin/skills/_test_support/load_module.py) vs an inline pattern documented in a CLAUDE.md under plugin/skills/. The shared module is cleaner but adds an import path; the documented pattern is friction-free but relies on copy-paste discipline.
  2. Implement whichever shape wins; cover the dataclass-bearing case in a self-test.
  3. Migrate test_start_task.py and test_dedup_search.py to use the helper. Spot-check by deleting their dataclass workaround and confirming the helper still passes the suite.
  • plugin/skills/_test_support/load_module.py (new) — or plugin/skills/CLAUDE.md with a documented snippet.
  • plugin/skills/task-work/test_dedup_search.py — switch to the helper.
  • plugin/skills/task-work/test_start_task.py — switch to the helper for consistency.
  • AC-1: A test file that loads a target script containing @dataclass(frozen=True) via the helper does not raise AttributeError on Python 3.14.
  • AC-2: Existing tests (test_start_task.py, test_dedup_search.py) keep passing after migration.
  • Migrating every importlib-loaded test in the plugin in one PR. Two callers is enough to validate the helper shape; the rest can convert as they’re touched.
  • Switching to pytest or another test framework that hides the loader detail entirely — that’s a bigger architectural conversation.
  • none

Spawned by /sdlc:task-work post-mortem of T-A2C6-spawn-from-post-mortem-stronger-dedup on 2026-05-21.

Bullet: importlib.util.spec_from_file_location + dataclass raised AttributeError on Python 3.14 because dynamically-loaded module wasnt registered in sys.modules before exec — per-skill test scaffolding should standardize the sys.modules registration step Keywords searched: spec_from_file_location, dynamically-loaded, attributeerror, registration, scaffolding, standardize, registered, importlib Top candidates (score / status / headline):

  • 11 / in-progress / 2026-05-21-spawn-from-post-mortem-stronger-dedup — Strengthen spawn-from-post-mortem dedup and record the search trail (self-match; excluded from decision)
  • 3 / closed/partially-superseded / 2026-05-19-task-new-flags-cascading-schema-edits — Flag cascading schema-aware script/skill edits in task scaffolding guidance
  • 3 / in-progress / 2026-05-20-task-work-preflight-permissions-probe — /sdlc:task-work pre-flight should probe for tool-family permission allowlists
  • 2 / closed/done / 2026-05-19-new-scripts-derive-patterns-from-schema — Derive wikilink/id patterns from schema in new_*.py scripts
  • 1 / closed/done / 2026-05-19-add-orchestrate-skill — Add /sdlc:orchestrate skill — one-tick reconcile + dispatch loop Decision: SPAWNED Rationale: Top candidate is the originating task itself (self-match). Excluding it, the next-best score is 3, well below the min-score floor of 6, and unrelated to importlib/sys.modules. The self-match exposure is itself tracked in T-HC03-dedup-search-excludes-originating-task.

← Back to Tasks