project-guide 2.7.2__tar.gz → 2.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. {project_guide-2.7.2 → project_guide-2.9.0}/.project-guide.yml +2 -2
  2. {project_guide-2.7.2 → project_guide-2.9.0}/CHANGELOG.md +48 -0
  3. {project_guide-2.7.2 → project_guide-2.9.0}/PKG-INFO +12 -2
  4. {project_guide-2.7.2 → project_guide-2.9.0}/README.md +11 -1
  5. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/features.md +4 -3
  6. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/project-essentials.md +41 -16
  7. project_guide-2.9.0/docs/specs/stories.md +756 -0
  8. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/tech-spec.md +13 -2
  9. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/cli.py +194 -42
  10. project_guide-2.9.0/project_guide/stories.py +293 -0
  11. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/best-practices-guide.md +85 -34
  12. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/production-github-guide.md +3 -3
  13. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/project-guide.md +8 -8
  14. project_guide-2.9.0/project_guide/templates/project-guide/templates/modes/_header-common.md +65 -0
  15. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/_phase-letters.md +15 -0
  16. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/code-direct-mode.md +2 -2
  17. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/debug-mode.md +10 -0
  18. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-phase-mode.md +1 -1
  19. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-production-phase-mode.md +1 -1
  20. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-stories-mode.md +3 -3
  21. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/refactor-document-mode.md +31 -0
  22. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/refactor-plan-mode.md +30 -1
  23. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/version.py +1 -1
  24. {project_guide-2.7.2 → project_guide-2.9.0}/pyproject.toml +1 -1
  25. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_cli.py +476 -3
  26. project_guide-2.9.0/tests/test_stories.py +318 -0
  27. project_guide-2.7.2/docs/specs/stories.md +0 -375
  28. project_guide-2.7.2/project_guide/stories.py +0 -154
  29. project_guide-2.7.2/project_guide/templates/project-guide/templates/modes/_header-common.md +0 -58
  30. project_guide-2.7.2/tests/test_stories.py +0 -141
  31. {project_guide-2.7.2 → project_guide-2.9.0}/.github/FUNDING.yml +0 -0
  32. {project_guide-2.7.2 → project_guide-2.9.0}/.github/dependabot.yml +0 -0
  33. {project_guide-2.7.2 → project_guide-2.9.0}/.github/workflows/ci.yml +0 -0
  34. {project_guide-2.7.2 → project_guide-2.9.0}/.github/workflows/deploy-docs.yml +0 -0
  35. {project_guide-2.7.2 → project_guide-2.9.0}/.github/workflows/publish.yml +0 -0
  36. {project_guide-2.7.2 → project_guide-2.9.0}/.github/workflows/test.yml +0 -0
  37. {project_guide-2.7.2 → project_guide-2.9.0}/.gitignore +0 -0
  38. {project_guide-2.7.2 → project_guide-2.9.0}/.pyve/config +0 -0
  39. {project_guide-2.7.2 → project_guide-2.9.0}/.tool-versions +0 -0
  40. {project_guide-2.7.2 → project_guide-2.9.0}/CONTRIBUTING.md +0 -0
  41. {project_guide-2.7.2 → project_guide-2.9.0}/LICENSE +0 -0
  42. {project_guide-2.7.2 → project_guide-2.9.0}/SECURITY.md +0 -0
  43. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/.gitignore +0 -0
  44. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/about/changelog.md +0 -0
  45. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/about/license.md +0 -0
  46. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/developer-guide/contributing.md +0 -0
  47. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/developer-guide/development.md +0 -0
  48. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/developer-guide/testing.md +0 -0
  49. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/getting-started.md +0 -0
  50. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/images/project-guide-banner-landing.png +0 -0
  51. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/images/project-guide-header-readme.png +0 -0
  52. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/index.html +0 -0
  53. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/commands.md +0 -0
  54. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/configuration.md +0 -0
  55. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/install-options.md +0 -0
  56. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/modes.md +0 -0
  57. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/overrides.md +0 -0
  58. {project_guide-2.7.2 → project_guide-2.9.0}/docs/site/user-guide/workflow.md +0 -0
  59. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-j-modes-plan.md +0 -0
  60. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-k-release-lifecycle-plan.md +0 -0
  61. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-l-no-input-init-plan.md +0 -0
  62. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-m-project-essentials-plan.md +0 -0
  63. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-n-mode-naming-cli-memory-plan.md +0 -0
  64. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-o-pyve-quiet-embedding-subplan.md +0 -0
  65. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/phase-o-quiet-non-interactive-embedding-feature.md +0 -0
  66. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/project-guide-no-input-spec.md +0 -0
  67. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/stories-v1.3.1.md +0 -0
  68. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/stories-v2.0.20.md +0 -0
  69. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/stories-v2.3.9.md +0 -0
  70. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/stories-v2.4.19.md +0 -0
  71. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/stories-v2.5.15.md +0 -0
  72. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/.archive/ux-problems-v2.0.10.md +0 -0
  73. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/brand-descriptions.md +0 -0
  74. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/concept.md +0 -0
  75. {project_guide-2.7.2 → project_guide-2.9.0}/docs/specs/phase-p-auto-heal-plan.md +0 -0
  76. {project_guide-2.7.2 → project_guide-2.9.0}/mkdocs.yml +0 -0
  77. {project_guide-2.7.2 → project_guide-2.9.0}/project-guide-old-template.md +0 -0
  78. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/__init__.py +0 -0
  79. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/__main__.py +0 -0
  80. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/actions.py +0 -0
  81. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/config.py +0 -0
  82. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/exceptions.py +0 -0
  83. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/metadata.py +0 -0
  84. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/render.py +0 -0
  85. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/runtime.py +0 -0
  86. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/sync.py +0 -0
  87. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/.project-guide.yml.template +0 -0
  88. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/.metadata.yml +0 -0
  89. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/README.md +0 -0
  90. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/brand-descriptions-guide.md +0 -0
  91. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/codecov-setup-guide.md +0 -0
  92. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/debug-guide.md +0 -0
  93. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/landing-page-guide.md +0 -0
  94. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/developer/python-editable-install.md +0 -0
  95. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/brand-descriptions.md +0 -0
  96. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/concept.md +0 -0
  97. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/features.md +0 -0
  98. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/project-essentials.md +0 -0
  99. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/pyve-essentials.md +0 -0
  100. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/stories.md +0 -0
  101. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/artifacts/tech-spec.md +0 -0
  102. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/llm_entry_point.md +0 -0
  103. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/_header-cycle.md +0 -0
  104. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/_header-sequence.md +0 -0
  105. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/archive-stories-mode.md +0 -0
  106. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/code-test-first-mode.md +0 -0
  107. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/default-mode.md +0 -0
  108. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/document-brand-mode.md +0 -0
  109. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/document-landing-mode.md +0 -0
  110. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-concept-mode.md +0 -0
  111. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-features-mode.md +0 -0
  112. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/plan-tech-spec-mode.md +0 -0
  113. {project_guide-2.7.2 → project_guide-2.9.0}/project_guide/templates/project-guide/templates/modes/scaffold-project-mode.md +0 -0
  114. {project_guide-2.7.2 → project_guide-2.9.0}/requirements-dev.txt +0 -0
  115. {project_guide-2.7.2 → project_guide-2.9.0}/tests/__init__.py +0 -0
  116. {project_guide-2.7.2 → project_guide-2.9.0}/tests/conftest.py +0 -0
  117. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_actions.py +0 -0
  118. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_archive_stories_mode.py +0 -0
  119. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_config.py +0 -0
  120. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_integration.py +0 -0
  121. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_metadata.py +0 -0
  122. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_purge.py +0 -0
  123. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_render.py +0 -0
  124. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_runtime.py +0 -0
  125. {project_guide-2.7.2 → project_guide-2.9.0}/tests/test_sync.py +0 -0
@@ -1,8 +1,8 @@
1
1
  version: '2.0'
2
- installed_version: 2.7.2
2
+ installed_version: 2.8.0
3
3
  target_dir: docs/project-guide
4
4
  metadata_file: .metadata.yml
5
- current_mode: debug
5
+ current_mode: code_direct
6
6
  test_first: false
7
7
  pyve_version: pyve version 2.6.2
8
8
  project_name: project-guide
@@ -7,6 +7,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.9.0] - 2026-05-20
11
+
12
+ **`project-guide git-push` learns to read and write bundled commits (P.u).** When a developer commits multiple `[Done]` stories under one bundled subject (e.g., `H.a, H.b, H.c InputSource ...`), the wrapper now correctly recognizes all bundled IDs as committed instead of misreporting them as uncommitted. When 2+ `[Done]` stories remain uncommitted, the wrapper offers a bundled commit subject with a `[Y/n]` gate rather than forcing the developer to hand-type one. A new duplicate-`<id>` warning surfaces git-log anomalies where the same story ID appears in multiple commits.
13
+
14
+ ### Added
15
+ - **P.u — Bundled-commit recognition in already-committed check.** `parse_committed_ids_from_subject` (new, in `project_guide/stories.py`) extracts the full ordered list of story IDs from a commit subject across single-ID, legacy `Story <id>:`, legacy bundle (no colons), canonical unversioned bundle (`H.a, H.b, H.c: title`), per-story-versioned bundle (`H.j: v0.10.0, H.k: v0.11.0 title`), mixed-version bundle, and single-trailing-version bundle forms. The parser is permissive on read (every `:` optional) and the formatter is strict on emit (colon precedes a version or a title, never separates two bare IDs).
16
+ - **P.u — Bundle-offer flow.** When 2+ uncommitted `[Done]` stories exist, the wrapper proposes a bundled commit subject `<id1>[: <ver1>], <id2>[: <ver2>], ... <title1> + <title2> + ...` and prompts `Use this message? [Y/n]` (default `Y`). Accept → invoke `git-push` with the bundled message. Decline → exit 1 with the existing `"use git-push directly"` manual-resolution hint. New `derive_bundle_commit_message` formatter in `project_guide/stories.py` handles per-story version detection, backtick / double-quote sanitization (same rules as single-story), title joining with `" + "`, and whitespace trim-and-collapse on the final subject.
17
+ - **P.u — Duplicate-`<id>` warning.** When the same bare story ID appears in 2+ commit subjects in `git log`, the wrapper emits a stderr warning listing each duplicate ID and the offending subjects, and prompts `Continue? [Y/n]` (default `Y`). The version is incidental — duplicate detection is keyed on `<id>` only, so a story shipped under two different versions still surfaces.
18
+ - **P.u — `--no-input` flag on `git-push`.** New `--no-input/--input` option auto-declines both the bundle offer and the duplicate-`<id>` continuation prompt (also auto-enabled by `CI=1` or non-TTY stdin per the standard `--no-input` contract). Auto-no is chosen for both gates because accepting either would change the shape of a commit (or paper over a history anomaly) silently — a developer decision, not a CI default.
19
+
20
+ ### Changed
21
+ - **P.u — `_get_committed_story_ids` return type.** The helper now returns `tuple[set[str], dict[str, list[str]]]` (committed-IDs set + duplicates map) instead of `set[str]`. This is an internal-only API; no public surface affected.
22
+ - **P.u — Commit-subject parser location.** Retired `_COMMIT_SUBJECT_STORY_ID_RE` from `project_guide/cli.py` (introduced by P.k, made permissive in P.s) in favor of the structured `parse_committed_ids_from_subject` parser in `project_guide/stories.py`. Tests that referenced the regex directly have been migrated to call the parser.
23
+ - **P.u — `project-essentials.md` `git-push` section.** Expanded with the bundle-offer flow, the colon-precedes-version-or-title rule, the duplicate-`<id>` warning, the `--no-input` defaults, and the parse-permissive / emit-strict invariant.
24
+
25
+ ### Fixed
26
+ - **P.u — Field bug: bundled commits no longer misclassified as uncommitted.** Pre-P.u, a bundled commit like `H.a, H.b, H.c InputSource ...` was invisible to the single-ID regex, so all bundled stories appeared "uncommitted" on the next `git-push` invocation — the wrapper either re-proposed the oldest one or fell through to the multi-uncommitted error path. Now correctly recognized.
27
+
28
+ ## [2.8.0] - 2026-05-20
29
+
30
+ **Phase P closing bundle: cycle-mode LLM-workflow discipline + XP methodology grounding + untracked-by-default `go.md` policy.** Six stories shipped between v2.7.2 and v2.8.0 (P.n–P.s). The one consumer-visible behavior change is the new tracked-`go.md` heal warning and the matching `git rm --cached docs/project-guide/go.md` consumer migration (P.o); the remaining five stories are template/doc reshapes that change how the LLM behaves on the next `project-guide mode <X>` render, with no consumer migration required.
31
+
32
+ ### Changed
33
+ - **P.o — Untracked-by-default `go.md` policy.** `project_guide/cli.py:heal` now detects when `docs/project-guide/go.md` is in the consumer's git index and emits a stderr warning with a copyable migration command (`git rm --cached docs/project-guide/go.md && git commit`). Silent when go.md is untracked, when cwd is not a git repo, under the recursion guard, or under `--no-input`. `project_guide/cli.py:init` emits a stderr note after the initial render that `go.md` is intentionally untracked. The warning is non-fatal and never runs git operations itself — same wrapper-initiates-git-ops constraint that bounded the P.k `git-push` wrapper.
34
+ - **P.s — Permissive commit-subject regex.** `_COMMIT_SUBJECT_STORY_ID_RE` now accepts both the bare `<id>: <title>` form (canonical going forward; matches `derive_commit_message`'s output) and the legacy `Story <id>: <title>` form (still seen in consumer repos). Resolves a field bug where mixed-form commit history caused the `git-push` wrapper to miss `Story `-prefixed commits and emit a spurious "multiple uncommitted" error.
35
+
36
+ ### Added
37
+ - **P.p — Three-flavor spike taxonomy.** `developer/best-practices-guide.md`'s "Hello World First — Spike Early, Spike Often" section now documents three spike flavors: **integration spike** (will external systems connect?), **architectural spike** (Beck-canonical; will this design work?), **investigation spike** (is there a viable path at all?). Each flavor has a question-answered framing, triggers, and output. New section closing with the canonical 3-story foundation table (A.a Scaffolding / A.b Hello World / A.c integration spike).
38
+ - **P.p — XP methodology grounding.** New top-level section in `developer/best-practices-guide.md` covering lineage (Beck 1999, C3 team), why XP practices counter known LLM failure modes (test-first vs. "looks right" hallucination, small steps vs. context-window drift, spikes vs. fabricated confidence, documented decisions vs. invisible scope creep, pair-style developer/LLM rotation), and a bibliography (Beck 1999/2004, Jeffries/Anderson/Hendrickson 2000).
39
+ - **P.p — Inserting-a-new-story rules.** New "Inserting a new story" subsection in `_phase-letters.md` covering Append (default) / Sub-number extension / Renumber (last-resort) with both P.s-triage precision rules: Sub-number is valid only when the parent is the latest top-level committed ID; Renumber is valid only on working-tree-only IDs.
40
+ - **P.q — Four cycle-discipline rules** in `_header-common.md`'s universal Rules block: **Sequential, story-by-story documentation**, **Documentation timing** (default write-then-execute + debug exception, on-disk-before-gate invariant), **Spikes for uncertainty reduction** (cross-references P.p's three-flavor taxonomy), **Approval-gate documentation handoff** (LLM authors the story before pausing, not after the developer asks).
41
+ - **P.q — Debug-mode Step-5 reinforcement.** New "Documentation timing in `debug`" paragraph names debug as the one legitimate exception to the universal timing rule and states explicitly that the LLM authors the story. New **"Deferring the Gate Artifact to the Developer"** anti-pattern entry sibling to "Declaring the Fix Complete After Step 4."
42
+ - **P.r — Mode echo + step-name conventions** in `_header-common.md`: the "After reading" protocol now has `**First line, always:** "Mode: <mode_name>."` as the always-first line, and a new universal Rules-block bullet requires step references to include the step's name in parens on first mention (e.g., "Cycle Step 1 (read stories) done; per Step 2 (announce next story), …").
43
+
44
+ ### Fixed
45
+ - **P.n — Scope-of-authority guardrail.** Closed a drift path where cycle modes could rationalize creating new `## Phase` headings in `stories.md`. New universal Rules-block bullet plus debug-mode Step-5 "Scope reminder" paragraph: cycle modes may append stories under an *existing* phase and edit story bodies, but may **not** create new phase headings, re-theme existing phases, or move stories between phases — phase creation is the exclusive job of `plan_phase` / `plan_production_phase`.
46
+ - **P.p — Foundation-story reconciliation.** Three docs (`plan-stories-mode.md`, `developer/best-practices-guide.md`, `developer/project-guide.md`) previously disagreed on the foundation-story structure (3-story vs. 2-story; A.a "Hello World" vs. A.a Scaffolding). Reconciled to the canonical 3-story foundation that `plan-stories-mode.md` already produces: **A.a Scaffolding** (in `scaffold_project` mode), **A.b Hello World** (runtime self-proof), **A.c integration spike** (integration self-proof). The terminology rename "end-to-end stack spike" → "integration spike" propagated across `plan-stories-mode.md`, `plan-phase-mode.md`, and `plan-production-phase-mode.md`.
47
+ - **P.s docs reconciliation.** Commit-message examples across `project-essentials.md`, `code-direct-mode.md`, `best-practices-guide.md`, and `production-github-guide.md` flipped from the legacy `"Story <id>: <title>"` form to the bare `"<id>: <title>"` form (canonical; matches the wrapper's emitted output).
48
+ - **P.t (this release) — Foundation cleanup follow-up.** Fixed stale "Start with Story A.a (Hello World)" line in `code-direct-mode.md:39` left over from P.p's reconciliation (A.a is now Scaffolding; A.b is Hello World; A.c is the integration spike).
49
+ - **P.t (this release) — Refactor modes now author session-level stories.** Closed the gap surfaced by P.t's mode-template audit: `refactor-plan-mode.md` and `refactor-document-mode.md` did not previously create `stories.md` entries, leaving refactor work outside the universal P.q Rule 1 "every chunk of LLM-produced work is captured as a story" invariant. Both modes now have a new **Session Story** section (authored once per session, after Step 1 of the first document; checklist captures one task per document touched + the project-essentials revisit for `refactor_plan`) and a closing **Session Close** / **Step F.5** that flips the checklist `[x]`, marks the story `[Done]`, defers the version-bump decision to the developer, and presents the session story at a session-level gate distinct from the per-document gates. One refactor session = one story = one developer commit.
50
+
51
+ ### Migration
52
+ Consumers upgrading from v2.6.x – v2.7.x: run once on your default branch to migrate `go.md` to untracked-by-default per the new policy:
53
+ ```bash
54
+ git rm --cached docs/project-guide/go.md && git commit -m "untrack go.md per project-guide v2.8.0"
55
+ ```
56
+ `heal` continues to warn until the migration is applied. Consumers who never migrate continue to function — `go.md` keeps appearing in their working-tree diff on every mode switch, but no command fails. See P.o's body in `docs/specs/stories.md` for full rationale. No migration required for the five template/doc stories beyond the standard `project-guide update` on next invocation.
57
+
10
58
  ## [2.7.2] - 2026-05-19
11
59
 
12
60
  Bug fix: `project-guide git-push` (and version/phase detection) silently dropped sub-numbered story IDs (`J.m.1`, `J.m.2`, …). When the latest `[Done]` story used the sub-numbered form, the wrapper fell back to the previous bare-letter heading and reported it as "already committed," blocking the push of the new story.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: project-guide
3
- Version: 2.7.2
3
+ Version: 2.9.0
4
4
  Summary: Stay organized and in control with adaptive LLM workflow prompts.
5
5
  Project-URL: Homepage, https://github.com/pointmatic/project-guide
6
6
  Project-URL: Documentation, https://pointmatic.github.io/project-guide/
@@ -122,11 +122,19 @@ project-guide init
122
122
 
123
123
  This creates:
124
124
  - `.project-guide.yml` - Configuration file (tracked)
125
- - `docs/project-guide/go.md` - Rendered LLM instructions (tracked — must be visible to IDE-integrated LLMs)
125
+ - `docs/project-guide/go.md` - Rendered LLM instructions (**unignored but intentionally untracked** as of v2.8.0 — must be visible to IDE-integrated LLMs, but kept out of git so branch switches don't trip on it)
126
126
  - `docs/project-guide/` - Mode templates, artifact templates, and metadata (gitignored bundled data)
127
127
 
128
128
  Everything under `docs/project-guide/` is gitignored **except** `go.md` (which the LLM reads). The gitignored template tree is bundled static data — `project-guide heal` repopulates it on first invocation in a fresh clone, and the auto-hook makes that healing run silently before any other command.
129
129
 
130
+ **Upgrading from v2.6.x – v2.7.x?** Earlier project-guide versions left `go.md` tracked by historical accident. v2.8.0 flips the policy to untracked-by-default to eliminate branch-switch and merge friction. If `heal` warns that `go.md` is tracked, run once on your default branch:
131
+
132
+ ```bash
133
+ git rm --cached docs/project-guide/go.md && git commit -m "untrack go.md per project-guide v2.8.0"
134
+ ```
135
+
136
+ The file stays visible to your IDE LLM (the gitignore block hasn't changed), but it stops appearing in diffs and stops blocking `git switch`.
137
+
130
138
  ### 2. Tell your LLM to read the guide
131
139
 
132
140
  ```
@@ -365,6 +373,8 @@ project-guide heal [OPTIONS]
365
373
 
366
374
  **Auto-hook:** every `project-guide` invocation (including `--help` and `--version`) calls heal first via a group-level hook, so the fresh-clone case usually resolves itself silently the first time you run *any* command. The hook is silent in the steady state and prompts only when there's actual drift.
367
375
 
376
+ **Tracked-`go.md` warning (v2.8.0+):** if `docs/project-guide/go.md` is in your git index, `heal` emits a stderr warning with a copyable migration command. The current policy is untracked-by-default — `go.md` stays visible to IDE LLMs (because it's unignored) but is kept out of the index so branch switches don't trip on it. The warning is non-fatal; the consumer applies the migration on their own schedule.
377
+
368
378
  **Examples:**
369
379
  ```bash
370
380
  # Interactive: prompts on drift
@@ -86,11 +86,19 @@ project-guide init
86
86
 
87
87
  This creates:
88
88
  - `.project-guide.yml` - Configuration file (tracked)
89
- - `docs/project-guide/go.md` - Rendered LLM instructions (tracked — must be visible to IDE-integrated LLMs)
89
+ - `docs/project-guide/go.md` - Rendered LLM instructions (**unignored but intentionally untracked** as of v2.8.0 — must be visible to IDE-integrated LLMs, but kept out of git so branch switches don't trip on it)
90
90
  - `docs/project-guide/` - Mode templates, artifact templates, and metadata (gitignored bundled data)
91
91
 
92
92
  Everything under `docs/project-guide/` is gitignored **except** `go.md` (which the LLM reads). The gitignored template tree is bundled static data — `project-guide heal` repopulates it on first invocation in a fresh clone, and the auto-hook makes that healing run silently before any other command.
93
93
 
94
+ **Upgrading from v2.6.x – v2.7.x?** Earlier project-guide versions left `go.md` tracked by historical accident. v2.8.0 flips the policy to untracked-by-default to eliminate branch-switch and merge friction. If `heal` warns that `go.md` is tracked, run once on your default branch:
95
+
96
+ ```bash
97
+ git rm --cached docs/project-guide/go.md && git commit -m "untrack go.md per project-guide v2.8.0"
98
+ ```
99
+
100
+ The file stays visible to your IDE LLM (the gitignore block hasn't changed), but it stops appearing in diffs and stops blocking `git switch`.
101
+
94
102
  ### 2. Tell your LLM to read the guide
95
103
 
96
104
  ```
@@ -329,6 +337,8 @@ project-guide heal [OPTIONS]
329
337
 
330
338
  **Auto-hook:** every `project-guide` invocation (including `--help` and `--version`) calls heal first via a group-level hook, so the fresh-clone case usually resolves itself silently the first time you run *any* command. The hook is silent in the steady state and prompts only when there's actual drift.
331
339
 
340
+ **Tracked-`go.md` warning (v2.8.0+):** if `docs/project-guide/go.md` is in your git index, `heal` emits a stderr warning with a copyable migration command. The current policy is untracked-by-default — `go.md` stays visible to IDE LLMs (because it's unignored) but is kept out of the index so branch switches don't trip on it. The warning is non-fatal; the consumer applies the migration on their own schedule.
341
+
332
342
  **Examples:**
333
343
  ```bash
334
344
  # Interactive: prompts on drift
@@ -376,15 +376,16 @@ The bundled `templates/artifacts/pyve-essentials.md` artifact covers: two-enviro
376
376
  - `.project-guide.yml` is absent (let `init` bootstrap; the hook does not error).
377
377
  - The config fails to load (schema mismatch, parse error) — the subcommand surfaces the error with its own guidance.
378
378
 
379
- **Inverted gitignore policy.** `init`'s gitignore writer produces a canonical block under a `# project-guide` header that ignores everything under `target_dir` *except* `go.md`. The block has gone through three shapes (P.d → P.j → P.l):
379
+ **Inverted gitignore policy.** `init`'s gitignore writer produces a canonical block under a `# project-guide` header that ignores everything under `target_dir` *except* `go.md`. The block has gone through three shapes; the **tracking status** of `go.md` flipped in v2.8.0 (P.d → P.j → P.l → P.o):
380
380
 
381
381
  - **v2.6.0 (P.d):** 4-line negation form (`<target>/**` + `!<target>/go.md` + redundant `<target>/**/*.bak.*`).
382
382
  - **v2.6.1 (P.j):** 3-line negation form — dropped the redundant `.bak.*` line.
383
383
  - **v2.7.1 (P.l):** **negation-free explicit-list form** — lists every top-level entry under `target_dir` other than `go.md`, plus a `<target>/**/*.bak.*` catch-all for top-level backups. The list is generated dynamically from the bundled template tree, so new top-level files/subdirectories added in future releases are picked up automatically.
384
+ - **v2.8.0 (P.o):** **untracked-by-default `go.md`**. The gitignore block is unchanged from v2.7.1 — `go.md` is still un-listed (and therefore unignored), preserving IDE-LLM visibility. What flips is the **tracking status**: `go.md` is no longer in the consumer's git index. `heal` warns (stderr) when it detects a tracked `go.md` with a copyable `git rm --cached docs/project-guide/go.md && git commit` migration command; `init` emits a stderr note that fresh installs leave `go.md` untracked. Branch switches and merges no longer trip on `go.md`.
384
385
 
385
- P.l abandoned the negation form because several IDE-integrated tools (Cursor, parts of the VS Code fork ecosystem, certain LSP-based search backends) implement a subset of `.gitignore` semantics that does not honor re-include negation — they apply the broad `**` rule, hide `go.md` from @-mention / fuzzy-search, and defeat the IDE-LLM-visibility constraint that's the whole reason `go.md` is tracked.
386
+ P.l abandoned the negation form because several IDE-integrated tools (Cursor, parts of the VS Code fork ecosystem, certain LSP-based search backends) implement a subset of `.gitignore` semantics that does not honor re-include negation — they apply the broad `**` rule, hide `go.md` from @-mention / fuzzy-search, and defeat the IDE-LLM-visibility constraint that's the whole reason `go.md` stays unignored. The v2.8.0 tracking flip preserves that visibility — `go.md` remains unignored — while removing the version-control churn and branch-switch failure mode that motivated P.o.
386
387
 
387
- Consumers migrating from a pre-Phase-P install run `project-guide init --force` to refresh the gitignore block; `git rm --cached` is the manual cleanup for previously tracked files. Existing v2.6.x/v2.7.0 installs heal to the v2.7.1 explicit-list form on the next `init --force` — every prior shape stays recognized by `_is_recognized_block_line()`. The track-only-`go.md` policy is unchanged across all three shapes; only the syntax that expresses it differs.
388
+ Consumers migrating from a pre-Phase-P install run `project-guide init --force` to refresh the gitignore block. Consumers upgrading from v2.6.x/v2.7.x to v2.8.0 run `git rm --cached docs/project-guide/go.md && git commit` once on their default branch to migrate the tracking status; `heal` surfaces the warning until the migration is applied. Existing pre-v2.7.1 installs heal to the v2.7.1 explicit-list form on the next `init --force` — every prior shape stays recognized by `_is_recognized_block_line()`.
388
389
 
389
390
  ### FR-15: Story-Aware `git-push` Wrapper (gitbetter integration)
390
391
 
@@ -32,9 +32,10 @@ Any future interactive prompt added to a CLI command **must** use the `should_sk
32
32
 
33
33
  ### Commit workflow
34
34
 
35
- - **Commit messages reference the story ID**; include **`vX.Y.Z`** when this commit is the **single** version bump for that story — examples:
36
- - `"Story M.a: v2.3.0 project-essentials render hook"` (M.a owns v2.3.0)
37
- - `"Story M.c: align specs with FR-9"` (doc-only; no version in title — rides M.b's or whichever code story owns the release line)
35
+ - **Commit messages reference the story ID** in the bare form `<id>: <title>` (no `Story ` prefix — the prefix is implicit context and adds no information the `<id>:` anchor doesn't already convey). Include **`vX.Y.Z`** when this commit is the **single** version bump for that story — examples:
36
+ - `"M.a: v2.3.0 project-essentials render hook"` (M.a owns v2.3.0)
37
+ - `"M.c: align specs with FR-9"` (doc-only; no version in title — rides M.b's or whichever code story owns the release line)
38
+ - The `project-guide git-push` wrapper's commit-subject parser (`parse_committed_ids_from_subject` in `stories.py`; retired the single-regex `_COMMIT_SUBJECT_STORY_ID_RE` in Story P.u) accepts both bare and legacy `Story <id>:` forms for backward compatibility with historical hand-typed commits (Story P.s), but **bare is canonical** for new commits.
38
39
  - **Direct commits to main** in `code_direct` mode — no branches, no PRs.
39
40
 
40
41
  ### Config schema versioning
@@ -63,23 +64,31 @@ The hook is silent in the steady state (no drift → no output). It is recursion
63
64
 
64
65
  **Skip conditions:** the hook returns silently when `PROJECT_GUIDE_HEALING=1` is set, when `.project-guide.yml` is absent (let `init` bootstrap; `heal` would error otherwise), or when config load / drift detection fails. Missing `.project-guide.yml` is a hard error from the **`heal` subcommand itself** but a silent skip from the **hook** — the original subcommand surfaces the missing-config error with its own guidance.
65
66
 
66
- ### Inverted gitignore policy (added v2.6.0, tightened v2.6.1, IDE-compat reshape v2.7.1)
67
+ ### Inverted gitignore policy (added v2.6.0, tightened v2.6.1, IDE-compat reshape v2.7.1, untracked-by-default v2.8.0)
67
68
 
68
- `init`'s gitignore writer produces a canonical block that ignores everything under `target_dir` *except* `go.md`. The policy has gone through three shapes:
69
+ `init`'s gitignore writer produces a canonical block that ignores everything under `target_dir` *except* `go.md`. The block has gone through three shapes; the **tracking status** of `go.md` flipped in v2.8.0:
69
70
 
70
71
  - **v2.6.0 (P.d):** 4-line negation form (`<target>/**` + `!<target>/go.md` + redundant `<target>/**/*.bak.*`).
71
72
  - **v2.6.1 (P.j):** 3-line negation form — dropped the redundant `.bak.*` line.
72
73
  - **v2.7.1 (P.l):** **negation-free explicit-list form** — lists every top-level entry under `target_dir` other than `go.md`, plus a `<target>/**/*.bak.*` defensive catch-all. The list is dynamically enumerated from the bundled template root at write time, so new top-level files/directories added in future stories are picked up automatically.
74
+ - **v2.8.0 (P.o):** gitignore block unchanged from v2.7.1; **tracking status of `go.md` flips** from "tracked by historical accident" to **untracked-by-default**. `heal` emits a stderr warning with a copyable `git rm --cached docs/project-guide/go.md && git commit` command when it detects `go.md` in the consumer's git index. `init` emits a stderr note that the file is intentionally untracked.
73
75
 
74
76
  P.l abandoned negation because several IDE-integrated tools (Cursor, parts of the VS Code fork ecosystem, certain LSP-based search backends) implement a subset of `.gitignore` semantics that does **not** honor re-include negation — they apply the broad `**` rule, hide `go.md` from @-mention / fuzzy-search, and defeat the IDE-LLM-visibility constraint the policy is trying to enforce. **Future maintainers: do not "simplify" back to `**` + `!` — the regression is invisible from git's perspective but breaks the IDE workflow.**
75
77
 
76
78
  **Idempotent rewrite:** `_ensure_gitignore_entry()` uses `_is_recognized_block_line(line, target_dir)` as its "ours-vs-foreign" predicate. It accepts anything anchored at `/<target>/` (the v2.7.1+ form) plus every prior legacy form (v2.6.1 3-line, v2.6.0 4-line, pre-P.d `.bak.*`-only, legacy `<target>/go.md`). Any block whose lines all satisfy the predicate is rewritten cleanly to the current canonical form. A foreign hand-customized block under a `# project-guide` header is left untouched with a stderr warning; migrate manually or run `init --force`.
77
79
 
78
- ### IDE-LLM visibility constraint (added v2.6.0)
80
+ ### IDE-LLM visibility constraint (added v2.6.0, untracked-by-default refinement v2.8.0)
79
81
 
80
- `go.md` **must remain non-gitignored** because IDE-integrated LLMs (Cursor, Claude Code, etc.) typically hide gitignored files from the LLM's view, and the LLM's instruction to `Read docs/project-guide/go.md` requires the file to be visible. The repo-history value of `go.md` is incidental — the file churns on every mode switch — and that churn is the acceptable cost for LLM visibility.
82
+ `go.md` **must remain non-gitignored** because IDE-integrated LLMs (Cursor, Claude Code, etc.) typically hide gitignored files from the LLM's view, and the LLM's instruction to `Read docs/project-guide/go.md` requires the file to be visible.
81
83
 
82
- This is the constraint that forces the **inverted** gitignore policy rather than the simpler "ignore the entire `target_dir`" approach. Future refactors of the gitignore logic must preserve the `!<target>/go.md` exception.
84
+ **Visibility vs. tracking the key distinction (clarified v2.8.0):**
85
+
86
+ - **Gitignore status** governs IDE-LLM visibility. The constraint is: `go.md` must remain **non-gitignored** so Cursor / Claude Code / VS Code-fork LLM tooling can read it. The v2.7.1 explicit-list gitignore block already leaves `go.md` un-listed (and therefore unignored).
87
+ - **Tracking status** governs version-control churn and branch-switch safety. Pre-v2.8.0 `go.md` was tracked by historical accident, which made every mode switch appear in diffs and (more dangerously) caused `git switch` aborts when a feature branch had a different `go.md` than its base. v2.8.0 flips the tracking status to **untracked-but-unignored**: IDE LLMs still see the file (because it's not gitignored), but it stays out of the consumer's index so branch switches and merges no longer trip on it.
88
+
89
+ The canonical state is therefore: `go.md` is **untracked-but-unignored**. Future refactors of the gitignore logic must preserve `go.md` as un-listed in the block (visibility), and project-guide itself must never `git add` it (tracking).
90
+
91
+ **Warn-don't-auto-fix:** `heal` warns when `go.md` is tracked but does **not** auto-run `git rm --cached` — same wrapper-initiates-git-ops constraint that bounded the P.k `git-push` wrapper. The consumer applies the migration command on their own schedule.
83
92
 
84
93
  ### `heal` vs. `update` vs. `init` (added v2.6.0)
85
94
 
@@ -101,19 +110,35 @@ Auto-healing N templates under --no-input.
101
110
 
102
111
  The notice is **non-suppressible** (always emitted even with `--quiet`) so CI logs and embedding callers (pyve scaffolding, etc.) have a visible signal that file writes occurred. This is the heal-specific application of the `--no-input` contract documented earlier in this file.
103
112
 
104
- ### `project-guide git-push` is developer-lane (added v2.7.0)
113
+ ### `project-guide git-push` is developer-lane (added v2.7.0, bundled-commit support added v2.9.0)
105
114
 
106
- `project-guide git-push` is a thin wrapper over [gitbetter](https://github.com/pointmatic/gitbetter)'s `git-push` that auto-derives the commit message from the most-recently-completed-and-not-yet-committed `[Done]` story heading. It is a **developer-lane convenience command** — the LLM **must not** initiate it. The approval-gate discipline rule earlier in this file ("do not propose commits, pushes, or bundling options ... do not offer 'want me to also …?' follow-ups") remains in force, and applies to this wrapper just as it does to raw `git`. The wrapper exists to shorten the developer's typing at commit time, not to give the LLM a new excuse to volunteer commits.
115
+ `project-guide git-push` is a thin wrapper over [gitbetter](https://github.com/pointmatic/gitbetter)'s `git-push` that auto-derives the commit message from `[Done]` story headings. It is a **developer-lane convenience command** — the LLM **must not** initiate it. The approval-gate discipline rule earlier in this file ("do not propose commits, pushes, or bundling options ... do not offer 'want me to also …?' follow-ups") remains in force, and applies to this wrapper just as it does to raw `git`. The wrapper exists to shorten the developer's typing at commit time, not to give the LLM a new excuse to volunteer commits.
107
116
 
108
- **Heading-to-message rules:**
109
- - Output is `"<id>: <title>"`. The colon after the story ID is preserved — it is the anchor the already-committed check searches for in `git log --pretty=%s` via the regex `^([A-Z]\.[a-z]+):\s`.
117
+ **Heading-to-message rules (single story):**
118
+ - Output is `"<id>: <title>"`. The colon after the story ID is preserved — it is the anchor the already-committed check searches for in `git log --pretty=%s`.
110
119
  - Backticks (`` ` ``) in the title become single quotes.
111
120
  - Double quotes (`"`) in the title become single quotes.
112
121
  - Single quotes pass through unchanged. The wrapper invokes gitbetter via `subprocess.run([...], shell=False)`, so there is no shell-quoting concern.
113
122
 
114
- **Branch logic:**
115
- - 0 uncommitted `[Done]` stories exit 1 "Story <last id> is already committed."
116
- - 1 uncommitted `[Done]` story derive message, invoke `git-push`.
117
- - 2+ uncommitted `[Done]` stories exit 1 listing the IDs; developer commits them one at a time with raw `git-push`.
123
+ **Bundle-offer flow (P.u, v2.9.0):** when 2+ `[Done]` stories are uncommitted, the wrapper proposes a bundled commit subject and asks `[Y/n]`:
124
+ - **Emit format:** per-story tokens joined with `", "`; each token is `<id>` or `<id>: <version>`; titles joined with `" + "` after the title boundary. Concrete shapes:
125
+ - All versionless `H.a, H.b, H.c: title1 + title2 + title3`
126
+ - All versioned `H.j: v0.10.0, H.k: v0.11.0 title1 + title2` (last token's `: <ver>` doubles as the title boundary)
127
+ - Mixed → `H.a, H.b: v1.2.3, H.c: title1 + title2 + title3`
128
+ - **Colon rule:** a colon precedes a *version* or a *title*; it does not separate two bare IDs.
129
+ - **Whitespace:** the assembled message is trimmed and any internal whitespace run collapsed to a single space.
130
+ - **Title sanitization:** same backtick / double-quote rules as single-story.
131
+ - **Decline (`n`)** → exit 1 with `"Multiple uncommitted [Done] stories: ..."` (today's manual-resolution hint).
132
+ - **`--no-input`** → auto-decline (bundling changes the shape of the commit; that is a developer decision, not a CI default). The interactive default at the `[Y/n]` prompt is `Y`.
133
+
134
+ **Bundled-commit recognition (P.u, v2.9.0):** the already-committed check parses each commit subject via `parse_committed_ids_from_subject` (in `stories.py`), which recognizes single-ID subjects (bare and `Story <id>:` legacy), legacy bundled subjects with no colons (`H.a, H.b, H.c InputSource ...`), and every canonical bundled form the wrapper itself emits. The parser is intentionally permissive on the read side and strict on the emit side. **Important:** the parser only inspects the ID-prefix shape — title text is never used to match. Story titles may contain `+` separators or any other prose without confusing the wrapper.
135
+
136
+ **Duplicate-`<id>` warning (P.u, v2.9.0):** when the same bare `<id>` appears in 2+ commit subjects (regardless of version), the wrapper emits a stderr warning listing the offending subjects and asks `Continue? [Y/n]` (default `Y`). Under `--no-input`, auto-aborts with exit 1 so CI surfaces the history anomaly rather than papering over it.
137
+
138
+ **Branch logic (post-P.u):**
139
+ - 0 uncommitted `[Done]` stories → exit 1 `"Story <last id> is already committed."`
140
+ - 1 uncommitted `[Done]` story → derive single-story message, invoke `git-push`.
141
+ - 2+ uncommitted `[Done]` stories → propose bundled subject, prompt `[Y/n]`. Accept → invoke `git-push` with the bundled message. Decline (or `--no-input`) → exit 1 with the manual-resolution hint.
142
+ - Duplicate `<id>` in git log → warning + prompt `Continue? [Y/n]` (defaults `Y` interactive, `n` under `--no-input`).
118
143
 
119
144
  **External CLI dependency pattern.** `git-push` is the first `project-guide` subcommand that depends on an external binary being on PATH. See `tech-spec.md` § "External CLI Dependencies" for the canonical pattern (discover via `shutil.which`, invoke via `subprocess.run(..., check=False)` with no captured output, propagate exit code). Future workflow-integration commands should follow the same shape.