feat: stack development in three phases - stack-dev (design), stack-build, stack-close, handed over through tracker states (#168)
stack-build and stack-close carry disable-model-invocation, so each phase change is the operator's slash command; no skill offers a mid-session /model or /effort switch. Mode rules and the phase table move to instructions/dev/stack-mode.md, publish and CI waiting to instructions/dev/publish-and-ci.md, the ready definition to issue-tracking.md. Files changed: - AGENTS.md - CHANGES.md - DEVELOPMENT.md - README.md - VERSION - docs/model-and-effort-selection.md - instructions/CONTRACT.md - instructions/dev/commonplace-kb.md - instructions/dev/dev-setup.md - instructions/dev/doc-pull-through.md - instructions/dev/issue-tracking.md - instructions/dev/publish-and-ci.md - instructions/dev/stack-build/SKILL.md - instructions/dev/stack-close/SKILL.md - instructions/dev/stack-dev/SKILL.md - instructions/dev/stack-mode.md - instructions/dev/testing-conventions.md - instructions/dev/version-parts.md - tools/chemenu/commands/git_publish.py - tools/chemenu/tests/test_git_publish.py - tools/chemenu/tests/test_instructions_cmd.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
1 parent
80488bee38
commit
d8224ee2ab
21 files changed
+631
-331
No files matched your search
@@ -393,20 +393,21 @@ STACK_MACHINERY_PREFIXES = ("tools/", "types/", "instructions/")
|
||||
STACK_MACHINERY_NAMES = ("AGENTS.md",)
|
||||
|
||||
STACK_MACHINERY_NOTE = (
|
||||
"Note: this publish touched stack machinery. What a stack-dev session "
|
||||
"does next - closing prose, a changelog entry's accuracy, whether a "
|
||||
"docs/ page went stale - is not covered by docs verify, instructions "
|
||||
"verify, or pytest. No tool checks it; a session has to."
|
||||
"Note: this publish touched stack machinery. CI on the pushed commit is "
|
||||
"the last mechanical check still to come. What follows a green run - "
|
||||
"closing prose, a changelog entry's accuracy, whether a docs/ page went "
|
||||
"stale - is covered by no tool; a session has to check it."
|
||||
)
|
||||
|
||||
|
||||
def touches_stack_machinery(changed_files: list[str]) -> bool:
|
||||
"""Whether `changed_files` includes a path under the stack version's own
|
||||
scope - `tools/`, `types/`, `instructions/`, `AGENTS.md`, or a path ending
|
||||
in `CONTRACT.md` at any depth. A publish in this class is, by construction
|
||||
of the `stack-dev`/`stack-close` split, always followed by the unchecked
|
||||
closing phase - `STACK_MACHINERY_NOTE` times a reminder to land exactly
|
||||
there, for any session, not only one that read the skill that names it.
|
||||
in `CONTRACT.md` at any depth. A publish in this class is followed first by
|
||||
CI - still a mechanical check - and then by the unchecked closing phase of
|
||||
the `stack-dev`/`stack-build`/`stack-close` split. `STACK_MACHINERY_NOTE`
|
||||
names both, in that order, for any session, not only one that read the
|
||||
skills that name them.
|
||||
|
||||
Deliberately a shade broader than CI's version gate, which matches
|
||||
`<one-segment>/CONTRACT.md` only: this decides whether to print a sentence,
|
||||
|
||||
@@ -395,7 +395,7 @@ def test_below_threshold_publish_goes_straight_through(repo):
|
||||
|
||||
|
||||
def test_publish_notes_stack_machinery_after_success(repo, capsys):
|
||||
"""The closing-phase reminder lands exactly once, after the OK line, and
|
||||
"""The CI-then-closing-phase reminder lands exactly once, after the OK line, and
|
||||
only when the changeset actually falls under version-parts.md's scope."""
|
||||
(repo / "instructions").mkdir()
|
||||
(repo / "instructions/example.md").write_text("x\n", encoding="utf-8")
|
||||
@@ -405,6 +405,17 @@ def test_publish_notes_stack_machinery_after_success(repo, capsys):
|
||||
assert out.count(STACK_MACHINERY_NOTE) == 1
|
||||
|
||||
|
||||
def test_stack_machinery_note_puts_ci_before_the_unchecked_phase():
|
||||
"""A stack publish is followed by CI first - a mechanical check - and only
|
||||
after a green run by the phase nothing checks. The note must not claim the
|
||||
unchecked phase starts right at the publish (#168): that sent CI waiting
|
||||
into the closing phase, where a red run turned it back into a build."""
|
||||
ci = STACK_MACHINERY_NOTE.find("CI")
|
||||
unchecked = STACK_MACHINERY_NOTE.find("covered by no tool")
|
||||
assert ci != -1 and unchecked != -1
|
||||
assert ci < unchecked
|
||||
|
||||
|
||||
def test_publish_stays_quiet_for_ordinary_content(repo, capsys):
|
||||
_write_files(repo, 1)
|
||||
_publish(message="ordinary content")
|
||||
|
||||
@@ -64,7 +64,7 @@ def test_the_real_repo_publishes_every_skill():
|
||||
"""Guards the actual layout, not a fixture: these are the skills the
|
||||
harness is expected to offer, one per naming family - `wiki-` for the
|
||||
knowledge pipeline, `gtd-` for the commitment layer, `stack-` for the
|
||||
stack's own development. The `stack-` pair is nested under
|
||||
stack's own development. The `stack-` trio is nested under
|
||||
instructions/dev/, discovered the same way as the top-level ones."""
|
||||
names = {p.name for p in instructions_cmd.skill_dirs()}
|
||||
assert {
|
||||
@@ -75,10 +75,26 @@ def test_the_real_repo_publishes_every_skill():
|
||||
"wiki-status",
|
||||
"gtd-weekly-review",
|
||||
"stack-dev",
|
||||
"stack-build",
|
||||
"stack-close",
|
||||
} <= names
|
||||
|
||||
|
||||
def test_only_the_operator_starts_the_build_and_close_phases():
|
||||
"""#168: the phase changes are the operator's slash command, so
|
||||
`stack-build` and `stack-close` carry `disable-model-invocation: true`,
|
||||
while `stack-dev` - the entry point the harness has to find on its own -
|
||||
does not. `sync` copies the frontmatter byte for byte, which the drift
|
||||
check in `verify` already holds the published copies to."""
|
||||
skills = {p.name: p for p in instructions_cmd.skill_dirs()}
|
||||
flags = {}
|
||||
for name in ("stack-dev", "stack-build", "stack-close"):
|
||||
frontmatter, error = instructions_cmd._read_frontmatter(skills[name] / "SKILL.md")
|
||||
assert frontmatter is not None, error
|
||||
flags[name] = frontmatter.get("disable-model-invocation", False)
|
||||
assert flags == {"stack-dev": False, "stack-build": True, "stack-close": True}
|
||||
|
||||
|
||||
_NO_PROVIDER_FORBIDDEN_TERMS = [
|
||||
"super productivity",
|
||||
"azure devops",
|
||||
|
||||
Reference in new issue
Block a user