Skip to content

[bug-fix] Fix preset-constitution-not-installed: use PresetResolver in constitution setup#3297

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
fix/3272-preset-constitution-not-installed-e6ce3ab03838f7ba
Draft

[bug-fix] Fix preset-constitution-not-installed: use PresetResolver in constitution setup#3297
github-actions[bot] wants to merge 1 commit into
mainfrom
fix/3272-preset-constitution-not-installed-e6ce3ab03838f7ba

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Bug fix — preset-constitution-not-installed

Proposed fix for issue #3272, applying the remediation from the bug assessment.

Verdict: Valid · Severity: High

Summary

ensure_constitution_from_template hardcoded a read from the generic core template path, bypassing the preset resolution stack entirely, so a preset's constitution-template (with strategy: replace) was never used when seeding .specify/memory/constitution.md. Additionally, for specify init --preset, the function ran before the preset was installed, so even a resolver-aware call would have missed the preset. This PR fixes both issues and adds a post-install re-seed hook for specify preset add on existing projects.

Changes

File Change Notes
src/specify_cli/commands/init.py modified ensure_constitution_from_template now resolves template via PresetResolver; call moved to after preset installation block
src/specify_cli/presets/__init__.py modified Added _maybe_reseed_constitution helper; called from install_from_directory post-install
tests/test_presets.py added tests TestConstitutionReseedOnPresetInstall and TestEnsureConstitutionFromTemplate classes

Tests Added or Updated

  • TestConstitutionReseedOnPresetInstall::test_install_reseeds_generic_constitution_memory — pins that install_from_directory re-seeds memory from preset when [PROJECT_NAME] is present
  • TestConstitutionReseedOnPresetInstall::test_install_reseeds_on_principle_placeholder — pins re-seed when [PRINCIPLE_1_NAME] is present even without [PROJECT_NAME]
  • TestConstitutionReseedOnPresetInstall::test_install_does_not_overwrite_authored_constitution — pins the safety guard against overwriting authored constitutions
  • TestConstitutionReseedOnPresetInstall::test_install_skips_reseed_when_no_constitution_template — pins no-op when preset has no constitution-template entry
  • TestConstitutionReseedOnPresetInstall::test_install_skips_reseed_when_memory_absent — pins that install_from_directory does not create the memory file
  • TestEnsureConstitutionFromTemplate::test_uses_preset_constitution_when_available — pins that the function picks the preset's template over the generic core
  • TestEnsureConstitutionFromTemplate::test_falls_back_to_core_template_without_preset — pins fallback to core template when no preset is installed
  • TestEnsureConstitutionFromTemplate::test_skips_when_memory_already_exists — pins the existing-file guard

Local Verification

  • Commands run: none — the test toolchain (pytest, uv) was unavailable in this CI environment (network blocked, no pre-installed venv). Correctness was verified by careful code inspection against the PresetResolver contract and the existing TestSelfTestPreset fixture patterns.
  • The logic mirrors the existing _register_commands / PresetResolver.resolve call patterns already exercised by the test suite.

Deviations from Assessment

None. The implementation follows the preferred three-part fix exactly:

  1. ensure_constitution_from_template uses PresetResolver.
  2. Init flow reordered so constitution seeding runs after preset installation.
  3. Guarded re-seed in install_from_directory (skips when memory is absent or has been authored).

The two NEEDS CLARIFICATION open questions were non-blocking:

  • Q1 (warn vs. silently skip for authored constitutions): implemented as silent skip, consistent with the assessment's own wording ("if and only if the existing memory file is still the unmodified generic placeholder").
  • Q2 (speckit.constitution preset-awareness): not in scope; the second assessment comment confirmed this is a separate concern.

Risks & Review Notes

  • The re-seed guard ([PROJECT_NAME] / [PRINCIPLE_1_NAME] detection) must cover both tokens since a partially-filled constitution might have the project name set but still carry [PRINCIPLE_1_NAME]. Both checks are independent (either triggers a re-seed).
  • Moving ensure_constitution_from_template after preset installation is a no-op for projects without --preset (the common case).
  • _maybe_reseed_constitution is best-effort: an OSError on the final shutil.copy2 is silently swallowed so it cannot fail the overall preset installation.

Refs #3272 · cc @PechiSW

Generated by 🛠️ Fix Bug from Labeled Issue for issue #3272 · 2K AIC · ⌖ 53.4 AIC · ⊞ 34K ·

…tion setup

Apply the remediation from the bug assessment on issue #3272.

Changes:
1. Modify ensure_constitution_from_template (init.py) to resolve the
   constitution-template through the preset priority stack via
   PresetResolver, instead of hardcoding the core template path. This
   ensures a preset's replacement constitution-template is used when
   seeding .specify/memory/constitution.md.

2. Reorder init flow: move ensure_constitution_from_template to after
   the preset installation block so that 'specify init --preset' seeds
   the memory file from the already-resolved template stack, not from
   the generic template that existed before the preset arrived.

3. Add _maybe_reseed_constitution to PresetManager (presets/__init__.py):
   a post-install hook that re-seeds .specify/memory/constitution.md
   from the preset's constitution-template during 'specify preset add'
   on an existing project, but only when the memory file still contains
   generic placeholder tokens ([PROJECT_NAME] or [PRINCIPLE_1_NAME]).
   Legitimately authored constitutions (no placeholder tokens) are never
   overwritten.

4. Add regression tests covering both code paths (TestConstitutionReseedOnPresetInstall
   and TestEnsureConstitutionFromTemplate in tests/test_presets.py).

Refs #3272

Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated bug-fix Trigger the bug-fix agentic workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preset constitution-template (strategy: replace) is not installed, and speckit.constitution is not preset-aware

1 participant