workstate-bootstrap 0.5.2__tar.gz → 0.6.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.
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/CHANGELOG.md +41 -15
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/PKG-INFO +9 -9
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/README.md +7 -7
- workstate_bootstrap-0.6.0/docs/tasks/AHMCP-48-skills-imply-lifecycle-hoist-task-plan.md +263 -0
- workstate_bootstrap-0.6.0/docs/tasks/AHMCP-49-managed-server-versions-constant-task-plan.md +186 -0
- workstate_bootstrap-0.6.0/docs/tasks/AHMCP-50-mcp-sync-config-only-subcommand-task-plan.md +246 -0
- workstate_bootstrap-0.6.0/docs/tasks/AHMCP-56-cross-harness-install-manifest-task-plan.md +355 -0
- workstate_bootstrap-0.6.0/docs/tasks/AHMCP-57-stale-symlink-repoint-task-plan.md +274 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/pyproject.toml +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/__init__.py +1 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/cli.py +6 -6
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/install.py +224 -28
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/mcp_sync.py +6 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/subcommands.py +47 -10
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_bootstrap_install_rehearsal.py +19 -19
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_cli_profile.py +5 -5
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_doctor_repair_sync.py +3 -3
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_ensure_hooks_path_make.py +1 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_install.py +128 -83
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_install_manifest_walker.py +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_install_profile_all_lifecycle.py +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_install_profiles.py +5 -5
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_manifest_build.py +1 -1
- workstate_bootstrap-0.6.0/tests/test_mcp_legacy_rename.py +375 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_mcp_sync_cli.py +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_mcp_sync_e2e.py +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_mcp_sync_malformed.py +1 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_mcp_sync_prune.py +1 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_mcp_sync_unit.py +1 -1
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_render_seam.py +2 -2
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_root_visible_task_plans.py +2 -2
- workstate_bootstrap-0.6.0/tests/test_runtime_path_migration.py +269 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_subcommands.py +25 -25
- workstate_bootstrap-0.6.0/uv.lock +1754 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/.gitignore +0 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/src/workstate_bootstrap/__main__.py +0 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/__init__.py +0 -0
- {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.6.0}/tests/test_package_metadata.py +0 -0
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.6.0] — 2026-05-30
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **MCP server identity cutover (Plan 0013 Slice B).** Default managed servers
|
|
10
|
+
register under the canonical `workstate-handoff-mcp` /
|
|
11
|
+
`workstate-orchestrator-mcp` names. `LEGACY_MCP_SERVER_RENAMES` +
|
|
12
|
+
`_legacy_prune_for()` dedup and forward-rewrite a stale `agent-*-mcp`
|
|
13
|
+
registration across all three config surfaces (`.mcp.json`,
|
|
14
|
+
`.vscode/mcp.json`, `.codex/config.toml`) so a re-install collapses the
|
|
15
|
+
duplicate to one canonical entry — fixing the "MCP servers not loading"
|
|
16
|
+
symptom caused by deep-merge preserving both old and new entries.
|
|
17
|
+
- **Default managed server pins bumped** to `mcp-workstate-handoff@0.12.0` and
|
|
18
|
+
`mcp-workstate-orchestrator@0.5.0`. `workstate-protocol` floor raised to
|
|
19
|
+
`>=0.1.6`.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Runtime path migration `.agentic/` → `.workstate/` and
|
|
24
|
+
`docs/agentic/` → `docs/workstate/` (Plan 0013 Slice D).**
|
|
25
|
+
`migrate_runtime_paths()` / `plan_runtime_path_migration()` run on
|
|
26
|
+
`install`/`update`: idempotent, archive-backed (a both-present collision
|
|
27
|
+
moves the legacy tree aside rather than overwriting), dry-run-capable, and
|
|
28
|
+
routed through the shared `workstate_protocol.paths` constants. `doctor`
|
|
29
|
+
flags a surviving legacy tree as `legacy_runtime_path`.
|
|
30
|
+
|
|
5
31
|
## [0.5.2] — 2026-05-20
|
|
6
32
|
|
|
7
33
|
### Changed
|
|
@@ -15,7 +41,7 @@
|
|
|
15
41
|
|
|
16
42
|
### Fixed
|
|
17
43
|
|
|
18
|
-
- **
|
|
44
|
+
- **AHMCP-57 — stale shared-surface symlinks now repointed on rerun.**
|
|
19
45
|
When a consumer was installed pre-v0.2.0 (legacy root layout
|
|
20
46
|
`<clone>/<surface>`) and the layout subsequently moved into
|
|
21
47
|
`<clone>/packages/workstate-system/<surface>`, the target-side
|
|
@@ -35,7 +61,7 @@
|
|
|
35
61
|
|
|
36
62
|
### Changed
|
|
37
63
|
|
|
38
|
-
- **
|
|
64
|
+
- **AHMCP-56 — cross-harness install manifest is now the single source of
|
|
39
65
|
truth for hook adapter wiring.** `config/agent-workflows/portable_commands.json`
|
|
40
66
|
schema v2 introduces a top-level `hooks[]` array; install dispatches
|
|
41
67
|
adapter rows through a manifest-driven walker (closed-set operation
|
|
@@ -73,17 +99,17 @@
|
|
|
73
99
|
|
|
74
100
|
- **Bump default managed MCP server pins** to `mcp-workstate-handoff@0.11.1`
|
|
75
101
|
and `mcp-workstate-orchestrator@0.4.5` so consumer repos pick up the
|
|
76
|
-
|
|
102
|
+
AHMCP-54 (multi-active CURRENT_TASK projection, import/export
|
|
77
103
|
malformed-payload rejection, target_branch/worktree_path/plan_path
|
|
78
|
-
preservation) and
|
|
79
|
-
consolidation under `AGENT_HANDOFF_COMPACTION_*` with `
|
|
104
|
+
preservation) and AHMCP-55 (compaction env-var namespace
|
|
105
|
+
consolidation under `AGENT_HANDOFF_COMPACTION_*` with `AHMCP_*` kept
|
|
80
106
|
as a deprecated alias) fixes by default.
|
|
81
107
|
|
|
82
108
|
## [0.4.1] — 2026-05-09
|
|
83
109
|
|
|
84
110
|
### Fixed
|
|
85
111
|
|
|
86
|
-
- **`--profile all` now performs the lifecycle hoist** (
|
|
112
|
+
- **`--profile all` now performs the lifecycle hoist** (AHMCP-48). The
|
|
87
113
|
legacy default profile shipped lifecycle-referencing skills
|
|
88
114
|
(`branch-lifecycle`, `tdd`, `incremental-implementation`,
|
|
89
115
|
`branch-review`, `handoff-lifecycle`) but did not install the
|
|
@@ -116,11 +142,11 @@
|
|
|
116
142
|
### Added
|
|
117
143
|
|
|
118
144
|
- **Install profile contract: `--profile {minimal,lifecycle,all}`**
|
|
119
|
-
(
|
|
145
|
+
(Plan 0009 / AHMCP-40 Slice 1.5.a). The CLI now accepts an explicit
|
|
120
146
|
install profile flag and honors it across the manifest layers, so
|
|
121
147
|
consumer repos can pick a smaller hoist surface than the default.
|
|
122
|
-
- **Hoist `Makefile.d/plans.mk` + `git-plan-cat.sh` stub** (
|
|
123
|
-
|
|
148
|
+
- **Hoist `Makefile.d/plans.mk` + `git-plan-cat.sh` stub** (Plan 0007 /
|
|
149
|
+
AHMCP-38 Slice 0). Consumer repos installed via `workstate-bootstrap`
|
|
124
150
|
pick up `make plan-show / plan-edit / plans-list / plan-register`
|
|
125
151
|
out of the box; the targets shell out to `uvx mcp-workstate-handoff`
|
|
126
152
|
under the hood.
|
|
@@ -134,14 +160,14 @@
|
|
|
134
160
|
|
|
135
161
|
## [0.3.1] — 2026-05-03
|
|
136
162
|
|
|
137
|
-
- **
|
|
163
|
+
- **Plan 0006 BR-01 — raise `workstate-protocol` lower bound to
|
|
138
164
|
`>=0.1.2,<0.2.0`.** Bootstrap's default install path invokes
|
|
139
165
|
`uvx mcp-workstate-handoff`, which imports `workstate_protocol.branch_naming`
|
|
140
166
|
at startup; the previous `>=0.1.0` floor let `uvx` resolve a protocol
|
|
141
167
|
release missing the module, crashing init-state on a fresh install. A
|
|
142
168
|
new packaging test (`tests/test_package_metadata.py`) pins the floor
|
|
143
169
|
so the declaration cannot silently drift back below the contract.
|
|
144
|
-
- **
|
|
170
|
+
- **Plan 0006 Slice 5 — install rehearsal pins six-hook surface +
|
|
145
171
|
helper materialization.** `SHARED_GIT_HOOK_NAMES` now includes
|
|
146
172
|
`pre-commit` (in addition to `post-checkout`, `post-commit`,
|
|
147
173
|
`post-merge`, `post-rewrite`, `pre-push`); the install rehearsal
|
|
@@ -169,7 +195,7 @@
|
|
|
169
195
|
--workspace-root . serve-stdio` into `.mcp.json`,
|
|
170
196
|
`.vscode/mcp.json`, and `.codex/config.toml`, so external clients
|
|
171
197
|
start runnable MCP servers from a fresh install or update.
|
|
172
|
-
- **`regenerate-task-views` harness hook contract dropped (
|
|
198
|
+
- **`regenerate-task-views` harness hook contract dropped (Plan 0005).**
|
|
173
199
|
Bootstrap no longer materializes any Claude / VS Code / Codex hook
|
|
174
200
|
wiring that invokes `regenerate-task-views`; `DASHBOARD.txt` is now
|
|
175
201
|
auto-regenerated server-side inside `mcp-workstate-handoff` on every
|
|
@@ -182,7 +208,7 @@
|
|
|
182
208
|
|
|
183
209
|
## 0.3.0 — 2026-04-28
|
|
184
210
|
|
|
185
|
-
- **Install-time state provisioning (
|
|
211
|
+
- **Install-time state provisioning (Plan 0003).** `install` now runs
|
|
186
212
|
the handoff server's `init-state` after surface/config materialization
|
|
187
213
|
but before `core.hooksPath` is set, so a fresh install ends with a
|
|
188
214
|
schema-current `.task-state/handoff.db` and `.task-state/exports/`
|
|
@@ -206,7 +232,7 @@
|
|
|
206
232
|
gated on `.mcp.json` being present in the manifest's `configs` array
|
|
207
233
|
so config-only installs (`--no-mcp-servers`) do not produce
|
|
208
234
|
false-positive drift.
|
|
209
|
-
- **`switch_task` cold-start fix.**
|
|
235
|
+
- **`switch_task` cold-start fix.** Plan 0003 Slice 1 (in
|
|
210
236
|
`mcp-workstate-handoff` 0.5.0+) drops `BranchMismatchError` from
|
|
211
237
|
`switch_task`; the cold-start cycle (register task → `switch_task`
|
|
212
238
|
→ first content write) now completes from any branch. Branch
|
|
@@ -229,7 +255,7 @@
|
|
|
229
255
|
`packages/workstate-system/` (the workstate monorepo layout) with
|
|
230
256
|
fallback to the clone root for legacy hoisted overlays. Fixes
|
|
231
257
|
`BootstrapManifestValidationError: required surface 'scripts/hooks' was
|
|
232
|
-
not materialized` against monorepo refs at or after
|
|
258
|
+
not materialized` against monorepo refs at or after Plan 0002 step 1.
|
|
233
259
|
- Rehearsal fixture (`fake_remote_with_generator`) now mirrors the real
|
|
234
260
|
monorepo layout so this regression cannot return silently.
|
|
235
261
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: workstate-bootstrap
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Bootstrap CLI that hoists the shared workstate-system surface into consumer repos.
|
|
5
5
|
Project-URL: Homepage, https://github.com/darce/workstate
|
|
6
6
|
Project-URL: Source, https://github.com/darce/workstate/tree/main/packages/workstate-bootstrap
|
|
@@ -11,7 +11,7 @@ License: Proprietary
|
|
|
11
11
|
Requires-Python: >=3.11
|
|
12
12
|
Requires-Dist: pyyaml>=6
|
|
13
13
|
Requires-Dist: tomlkit>=0.13
|
|
14
|
-
Requires-Dist: workstate-protocol<0.2.0,>=0.1.
|
|
14
|
+
Requires-Dist: workstate-protocol<0.2.0,>=0.1.6
|
|
15
15
|
Provides-Extra: dev
|
|
16
16
|
Requires-Dist: mcp-workstate-handoff; (python_version >= '3.12') and extra == 'dev'
|
|
17
17
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
@@ -117,20 +117,20 @@ installer implementation in
|
|
|
117
117
|
| ------------------------------------ | ---------- | ----------- |
|
|
118
118
|
| `scripts/hooks/` | shared | symlink |
|
|
119
119
|
| `.github/hooks/` | shared | symlink |
|
|
120
|
-
| `docs/
|
|
121
|
-
| `docs/
|
|
120
|
+
| `docs/workstate/contracts/` | shared | symlink |
|
|
121
|
+
| `docs/workstate/rules/` | shared | symlink |
|
|
122
122
|
| `Makefile.d/` non-excluded children | shared | carved dir |
|
|
123
123
|
| `scripts/workstate/` non-excluded children | shared | carved dir |
|
|
124
124
|
| `.github/prompts/` | generated | real dir |
|
|
125
|
-
| `.
|
|
126
|
-
| `.
|
|
125
|
+
| `.workstate/generated/plugins/workstate-system/base/` | generated | real dir |
|
|
126
|
+
| `.workstate/generated/plugins/workstate-system/effective/` | generated | real dir |
|
|
127
127
|
| `.mcp.json` | generated | real file |
|
|
128
128
|
| `.vscode/mcp.json` | generated | real file |
|
|
129
129
|
| `.codex/config.toml` | generated | real file |
|
|
130
130
|
| `core.hooksPath` git config | generated | git config |
|
|
131
131
|
| `.task-state/handoff.db` | runtime | sqlite |
|
|
132
132
|
| `.task-state/exports/` | runtime | dir |
|
|
133
|
-
| `.
|
|
133
|
+
| `.workstate/remote/` | bootstrap | git clone |
|
|
134
134
|
| `.workstate-bootstrap.json` | bootstrap | manifest |
|
|
135
135
|
|
|
136
136
|
`.task-state/` is provisioned by the handoff server's `init-state`
|
|
@@ -161,13 +161,13 @@ regenerates it through `workstate-bootstrap install`.
|
|
|
161
161
|
`install`, `update`, `doctor`, or `repair` for a non-default root;
|
|
162
162
|
bootstrap records that path so later update/doctor/repair runs reuse
|
|
163
163
|
it. Override-aware installs generate effective plugin trees under
|
|
164
|
-
`.
|
|
164
|
+
`.workstate/generated/plugins/workstate-system/effective/{claude,codex}`
|
|
165
165
|
and point marketplace pins at those generated trees.
|
|
166
166
|
- `install` and `update` preserve plugin override files by default.
|
|
167
167
|
`--reset-overrides` is the explicit destructive path; it removes only
|
|
168
168
|
the resolved override root, refuses dirty git worktrees unless
|
|
169
169
|
`--backup` is supplied, and archives backups under
|
|
170
|
-
`.
|
|
170
|
+
`.workstate/override-backups/<timestamp>/` before removal.
|
|
171
171
|
|
|
172
172
|
## Development
|
|
173
173
|
|
|
@@ -98,20 +98,20 @@ installer implementation in
|
|
|
98
98
|
| ------------------------------------ | ---------- | ----------- |
|
|
99
99
|
| `scripts/hooks/` | shared | symlink |
|
|
100
100
|
| `.github/hooks/` | shared | symlink |
|
|
101
|
-
| `docs/
|
|
102
|
-
| `docs/
|
|
101
|
+
| `docs/workstate/contracts/` | shared | symlink |
|
|
102
|
+
| `docs/workstate/rules/` | shared | symlink |
|
|
103
103
|
| `Makefile.d/` non-excluded children | shared | carved dir |
|
|
104
104
|
| `scripts/workstate/` non-excluded children | shared | carved dir |
|
|
105
105
|
| `.github/prompts/` | generated | real dir |
|
|
106
|
-
| `.
|
|
107
|
-
| `.
|
|
106
|
+
| `.workstate/generated/plugins/workstate-system/base/` | generated | real dir |
|
|
107
|
+
| `.workstate/generated/plugins/workstate-system/effective/` | generated | real dir |
|
|
108
108
|
| `.mcp.json` | generated | real file |
|
|
109
109
|
| `.vscode/mcp.json` | generated | real file |
|
|
110
110
|
| `.codex/config.toml` | generated | real file |
|
|
111
111
|
| `core.hooksPath` git config | generated | git config |
|
|
112
112
|
| `.task-state/handoff.db` | runtime | sqlite |
|
|
113
113
|
| `.task-state/exports/` | runtime | dir |
|
|
114
|
-
| `.
|
|
114
|
+
| `.workstate/remote/` | bootstrap | git clone |
|
|
115
115
|
| `.workstate-bootstrap.json` | bootstrap | manifest |
|
|
116
116
|
|
|
117
117
|
`.task-state/` is provisioned by the handoff server's `init-state`
|
|
@@ -142,13 +142,13 @@ regenerates it through `workstate-bootstrap install`.
|
|
|
142
142
|
`install`, `update`, `doctor`, or `repair` for a non-default root;
|
|
143
143
|
bootstrap records that path so later update/doctor/repair runs reuse
|
|
144
144
|
it. Override-aware installs generate effective plugin trees under
|
|
145
|
-
`.
|
|
145
|
+
`.workstate/generated/plugins/workstate-system/effective/{claude,codex}`
|
|
146
146
|
and point marketplace pins at those generated trees.
|
|
147
147
|
- `install` and `update` preserve plugin override files by default.
|
|
148
148
|
`--reset-overrides` is the explicit destructive path; it removes only
|
|
149
149
|
the resolved override root, refuses dirty git worktrees unless
|
|
150
150
|
`--backup` is supplied, and archives backups under
|
|
151
|
-
`.
|
|
151
|
+
`.workstate/override-backups/<timestamp>/` before removal.
|
|
152
152
|
|
|
153
153
|
## Development
|
|
154
154
|
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# AHMCP-48 Task Plan — Bootstrap `all` Profile Implies Lifecycle Hoist (Skills→Lifecycle Drift Fix)
|
|
2
|
+
|
|
3
|
+
> - **Date**: 2026-05-08 EST
|
|
4
|
+
> - **Author**: Claude Opus 4.7
|
|
5
|
+
> - **Project**: agentic-bootstrap
|
|
6
|
+
> - **Owning Epic**: `docs/scopes/bootstrap-consumption-hardening-scope.md`
|
|
7
|
+
> - **Task ID**: AHMCP-48
|
|
8
|
+
> - **Task Plan Status**: `done`
|
|
9
|
+
> - **Target Branch**: `feature/ahmcp-48-skills-imply-lifecycle-hoist`
|
|
10
|
+
> - **Review Coverage Target**: 1
|
|
11
|
+
|
|
12
|
+
## AHMCP-48. Bootstrap `all` Profile Implies Lifecycle Hoist (Skills→Lifecycle Drift Fix)
|
|
13
|
+
|
|
14
|
+
## Objective
|
|
15
|
+
|
|
16
|
+
Make `agentic-bootstrap install --profile all` (the legacy/default profile that ships skills) also hoist `Makefile.d/lifecycle.mk` and `scripts/agentic/lifecycle/`, so a consumer cannot end up with the `branch-lifecycle` / `tdd` / `incremental-implementation` / `branch-review` / `handoff-lifecycle` skills referencing `make task-start` / `make slice-start` / `make context` / `make review-ready` / `make handoff-close-check` / `make format-all` while the matching make fragment and Python runner are absent.
|
|
17
|
+
|
|
18
|
+
## Intake (epic context)
|
|
19
|
+
|
|
20
|
+
- **Scope one-pager**: `docs/scopes/bootstrap-consumption-hardening-scope.md`
|
|
21
|
+
- **Key Q&A decisions**: Intake decisions 1–5 captured inline in the scope doc (MCP recording is a pre-planning blocker — recorded once `record_event` is reachable; until then this plan references the scope's inline table).
|
|
22
|
+
- **Not-Doing**: bootstrap will not write managed `.gitignore` blocks for harness-created files (`.claude/worktrees/`, `.claude/settings.local.json`); that gap is explicitly out of scope per user direction.
|
|
23
|
+
|
|
24
|
+
## Problem Statement
|
|
25
|
+
|
|
26
|
+
`altcontext-marketing-monorepo` was bootstrapped with the default profile (`all`) and ended up with the branch-lifecycle skill body but no `Makefile.d/lifecycle.mk` and no `scripts/agentic/lifecycle/`. Every `/branch-lifecycle` invocation in that consumer references make targets the install did not provide; the canonical-policy doc paths (`docs/agentic/...`) referenced from the skill are also absent.
|
|
27
|
+
|
|
28
|
+
The cause is structural, not transitional. `install.py:548-557` deliberately scopes the lifecycle hoist to `profile == PROFILE_LIFECYCLE`, while skills are materialized only under `profile == PROFILE_ALL` (`install.py:525-526`). The two profiles are disjoint paths in the same `install()` body, and `all` predates `lifecycle`. The code comment at `install.py:548-552` already anticipates folding the hoist into `all` ("folding the hoist into `all` is a follow-on once the seven-profile contract lands in full") — this task is that follow-on, scoped to the minimum diff that closes the drift class.
|
|
29
|
+
|
|
30
|
+
A consumer cannot fix this from their side: re-running `bootstrap install --profile lifecycle` would re-do the install in lifecycle-only mode and lose every other surface. The drift has to close at install time, in the bootstrap.
|
|
31
|
+
|
|
32
|
+
## Constraints
|
|
33
|
+
|
|
34
|
+
- The fix must be additive: `--profile lifecycle` must continue to mean "lifecycle-only" (no skills, no generated surfaces). Only `--profile all` gains the lifecycle hoist.
|
|
35
|
+
- `--profile minimal` must continue to be lean. It does not ship skills today; it must not start shipping `lifecycle.mk` either.
|
|
36
|
+
- Idempotency is required: re-running `install --profile all` against a consumer that already has lifecycle hoisted must not duplicate the `Makefile.d/lifecycle.mk` file, the runner directory, or the `-include Makefile.d/*.mk` sentinel block in the consumer `Makefile`.
|
|
37
|
+
- The manifest contract (`agentic_protocol.BootstrapManifest`) must continue to validate; lifecycle entries already appear under `surfaces` with `source: "lifecycle"` and `configs` (the Makefile-include directive) — those shapes do not change.
|
|
38
|
+
- No change to `LIFECYCLE_HOISTS` membership. The two existing entries (`Makefile.d/lifecycle.mk`, `scripts/agentic/lifecycle`) cover the consumer-visible surface today.
|
|
39
|
+
- No change to `--profile lifecycle` semantics. Operators who want lifecycle without skills keep using it.
|
|
40
|
+
|
|
41
|
+
## Workflow Principles
|
|
42
|
+
|
|
43
|
+
- Land the install-side hoist promotion and its regression test in one slice. They are inseparable: the test asserts the new behavior, and the production code is small enough that splitting them adds bookkeeping without buying revertability.
|
|
44
|
+
- Prefer asserting against materialized filesystem state (the consumer target after `install()` returns) rather than against the manifest dict alone. Manifest entries can drift from disk if a future bug skips a copy step; only filesystem assertions catch that.
|
|
45
|
+
- Do not re-derive the lifecycle hoist logic. Reuse `_install_lifecycle_profile` and `_ensure_consumer_makefile_include` exactly — both are already idempotent.
|
|
46
|
+
|
|
47
|
+
## Terminology
|
|
48
|
+
|
|
49
|
+
- **Profile**: A named install plan (`minimal`, `lifecycle`, `all`). Selects which surfaces, generated artifacts, and configs the bootstrap materializes.
|
|
50
|
+
- **Surface**: A path materialized into the consumer (skill bodies, hook scripts, `Makefile.d/lifecycle.mk`, the lifecycle runner package).
|
|
51
|
+
- **Lifecycle hoist**: The action of copying `Makefile.d/lifecycle.mk` and `scripts/agentic/lifecycle/` into the consumer and injecting the `-include` sentinel into the consumer `Makefile`. Implemented by `_install_lifecycle_profile` + `_ensure_consumer_makefile_include`.
|
|
52
|
+
- **Skills→Lifecycle drift**: The state where a consumer has skill bodies that reference lifecycle make targets but the runner / Makefile fragment that defines those targets is missing.
|
|
53
|
+
|
|
54
|
+
## Current State Analysis
|
|
55
|
+
|
|
56
|
+
- `packages/agentic-bootstrap/src/agentic_bootstrap/install.py:104-107` declares `LIFECYCLE_HOISTS = (("Makefile.d/lifecycle.mk", ...), ("scripts/agentic/lifecycle", ...))`.
|
|
57
|
+
- `install.py:380-405` (`_install_lifecycle_profile`) is idempotent: file copies use `shutil.copy2`; directory copies use `shutil.copytree(..., dirs_exist_ok=True)`; missing sources are silently skipped.
|
|
58
|
+
- `install.py:408-432` (`_ensure_consumer_makefile_include`) wraps the `-include Makefile.d/*.mk` directive in `LIFECYCLE_INCLUDE_SENTINEL_BEGIN`/`_END` markers. Re-runs short-circuit when the sentinel is already present (`action='already_present'`); first runs either create or append.
|
|
59
|
+
- `install.py:525-557` is the profile-dispatch body of `install()`. Today:
|
|
60
|
+
- `if profile == PROFILE_ALL`: materializes skills + generated surfaces; runs the workflow generator; writes harness configs; runs init-state.
|
|
61
|
+
- `if profile == PROFILE_LIFECYCLE`: hoists lifecycle, ensures Makefile include.
|
|
62
|
+
- The two branches are independent `if` statements (not `elif`), so a hypothetical caller could already pass `profile=PROFILE_ALL` and then re-run with `profile=PROFILE_LIFECYCLE` — but no caller does this in practice, and the CLI / API rejects multi-profile calls because `profile` is a single string.
|
|
63
|
+
- `install.py:96-103` comment: "Plan 0009 (AHMCP-40) lifecycle profile … destination paths are flat under the consumer root because the runner/Makefile fragment must be reachable from a vanilla consumer with no monorepo packaging knowledge." Confirms the hoist is the canonical mechanism.
|
|
64
|
+
- `install.py:548-552` comment: explicit acknowledgement that folding the hoist into `all` is the planned follow-on.
|
|
65
|
+
- The `branch-lifecycle` skill body (`packages/agentic-system/skills/branch-lifecycle/body.md`) references `make task-start`, `make slice-start`, `make slice-commit`, `make task-finish`, `make review-ready`, `make handoff-close-check`, `make context`, `make format-all`. These are all defined in `Makefile.d/lifecycle.mk` (verified at `packages/agentic-system/Makefile.d/lifecycle.mk:41-58`).
|
|
66
|
+
- The same skill is materialized into the consumer's `.claude/skills/branch-lifecycle/` and `.codex/skills/branch-lifecycle/` under `--profile all` via `_materialize_surfaces` + the workflow generator. The skill body and the make fragment ship from the same monorepo and the same `remote_sha`, so a single `--profile all` install can keep them in sync as long as both are hoisted.
|
|
67
|
+
- Existing test surface in `packages/agentic-bootstrap/tests/`: confirm with the test author whether `tests/test_install.py` (or equivalent) already exercises `_install_lifecycle_profile` under `--profile lifecycle`. The new regression must add coverage for `--profile all` hoisting lifecycle, not duplicate the lifecycle-only assertion.
|
|
68
|
+
|
|
69
|
+
### Lifecycle-touching skill inventory (closed audit)
|
|
70
|
+
|
|
71
|
+
The fix must close drift for *every* skill body that materializes under `--profile all` and references a lifecycle make target. Two disjoint sources contribute to that set: (a) the generated command map in `packages/agentic-system/config/agent-workflows/portable_commands.json`, and (b) skill body prose that references `make …` targets without exposing them through the manifest's `makefile_target` field. Both are covered by hoisting lifecycle under `PROFILE_ALL` because the skill body and the lifecycle make fragment ship from the same monorepo at the same `remote_sha`.
|
|
72
|
+
|
|
73
|
+
**(a) Generated `portable_commands.json` entries that route through a lifecycle make target.** The `command_id` → `makefile_target`/`secondary_targets` mapping is the closed, manifest-grade list:
|
|
74
|
+
|
|
75
|
+
| `command_id` | Lifecycle target(s) referenced via the manifest | Why `PROFILE_ALL ⇒ lifecycle` covers it |
|
|
76
|
+
| --------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `branch-lifecycle` | `make task-start`, `make review-ready`, `make handoff-close-check`, `make task-finish` | All four are defined in `packages/agentic-system/Makefile.d/lifecycle.mk` and only resolve in the consumer when the hoist runs. |
|
|
78
|
+
| `branch-review` | `make review-run` | Defined in `lifecycle.mk`; same hoist closes the gap. |
|
|
79
|
+
| `handoff-lifecycle` | `make context` | Defined in `lifecycle.mk`; hoist materializes the runner and the include sentinel. |
|
|
80
|
+
| `incremental-implementation`| `make slice-start`, `make slice-commit` | Defined in `lifecycle.mk`; covered by the hoist. |
|
|
81
|
+
| `plan-analyze` | `make plan-analyze DOC=<path>` | Defined in `lifecycle.mk`; covered by the hoist. |
|
|
82
|
+
| `planning-review` | `make plan-review DOC=<path>` | Defined in `lifecycle.mk`; covered by the hoist. |
|
|
83
|
+
| `tdd` | `make slice-start` | Defined in `lifecycle.mk`; covered by the hoist. |
|
|
84
|
+
| `scope` | (none — in-session intake) | No lifecycle dependency; included for completeness so the inventory is closed. |
|
|
85
|
+
| `auto-fix` | (none in the manifest target; **see (b)**) | Manifest does not advertise a lifecycle target, but the skill body does — see body-only audit below. |
|
|
86
|
+
| `review-parallel` | (none in the manifest target; **see (b)**) | Same as auto-fix: covered by the body-only audit. |
|
|
87
|
+
|
|
88
|
+
**(b) Body-only references that bypass the manifest's `makefile_target` field.** These are caught by `grep -n '\bmake \(task-start\|slice-start\|slice-commit\|task-finish\|review-ready\|review-run\|handoff-close-check\|context\|plan-analyze\|plan-review\|format-all\|status\|tasks\|maint-archive-stale\)\b'` against `packages/agentic-system/skills/*/body.md`:
|
|
89
|
+
|
|
90
|
+
| Skill body | Lifecycle target(s) referenced in prose only | Why `PROFILE_ALL ⇒ lifecycle` covers it |
|
|
91
|
+
| ------------------------------------------ | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `skills/auto-fix/body.md` | `make task-start` | Body cites `make task-start TASK=<id>` as the precondition recovery path. Hoisting `lifecycle.mk` under `--profile all` makes that target resolvable. |
|
|
93
|
+
| `skills/review-parallel/body.md` | `make context`, `make maint-archive-stale` | Body cites these as ambiguity-recovery commands. Both are defined in `lifecycle.mk`. |
|
|
94
|
+
| `skills/investigate/body.md` | `make status`, `make tasks`, `make context`, `make maint-archive-stale` | Body cites these as the orientation path before raw MCP reads. All are defined in `lifecycle.mk`. |
|
|
95
|
+
| `skills/branch-lifecycle/body.md` | (already covered by manifest row; body adds `make slice-start`, `make slice-commit`, `make format-all`) | All defined in `lifecycle.mk`; subsumed by manifest-row coverage. |
|
|
96
|
+
|
|
97
|
+
**Audit checklist (cold-start implementer must run before merging the fix):**
|
|
98
|
+
|
|
99
|
+
- [x] Run the manifest-row pass: open `packages/agentic-system/config/agent-workflows/portable_commands.json` and confirm the 7 lifecycle-target rows above (`branch-lifecycle`, `branch-review`, `handoff-lifecycle`, `incremental-implementation`, `plan-analyze`, `planning-review`, `tdd`) still resolve to targets defined in `Makefile.d/lifecycle.mk`. If a new row gains a lifecycle `makefile_target`, the table above must be extended.
|
|
100
|
+
- [x] Run the body-only grep above against `packages/agentic-system/skills/*/body.md` and confirm the only hits outside the manifest-row skills are `auto-fix`, `review-parallel`, and `investigate`. A new hit means a new skill ships with a lifecycle dependency and the inventory must be re-closed before merge.
|
|
101
|
+
- [x] Confirm every target referenced in either pass is defined in `packages/agentic-system/Makefile.d/lifecycle.mk` (so the hoist is sufficient). If a referenced target lives in a non-hoisted fragment (e.g. a future `Makefile.d/review.mk`), the hoist set must be extended — that is out of scope for AHMCP-48 but flagged here so the auditor cannot silently miss it.
|
|
102
|
+
|
|
103
|
+
This closes the drift class for the entire `--profile all` skill payload: every lifecycle-target reference, whether routed through the generated manifest or only in skill prose, is satisfied by the same `_install_lifecycle_profile` + `_ensure_consumer_makefile_include` pair this task promotes into `--profile all`.
|
|
104
|
+
|
|
105
|
+
## Target Outcome
|
|
106
|
+
|
|
107
|
+
`install(profile=PROFILE_ALL, ...)` returns with the consumer containing:
|
|
108
|
+
|
|
109
|
+
- All `--profile all` surfaces it produces today (skills, generated workflow files, harness configs, init-state).
|
|
110
|
+
- **Plus** `Makefile.d/lifecycle.mk` and `scripts/agentic/lifecycle/` materialized in the consumer (identical to what `--profile lifecycle` produces today).
|
|
111
|
+
- **Plus** the `-include Makefile.d/*.mk` sentinel block injected idempotently into the consumer's `Makefile`.
|
|
112
|
+
- A returned manifest whose `surfaces` list includes both `source: "lifecycle"` entries and whose `configs` list includes the Makefile-include directive entry (when newly added).
|
|
113
|
+
|
|
114
|
+
`install(profile=PROFILE_LIFECYCLE, ...)` and `install(profile=PROFILE_MINIMAL, ...)` are unchanged.
|
|
115
|
+
|
|
116
|
+
`install(profile=PROFILE_ALL, ...)` re-run against the same target is idempotent: no duplicate sentinel block, no duplicate manifest entries (or, if duplication is impossible-by-construction in the manifest writer, no diff in the materialized files).
|
|
117
|
+
|
|
118
|
+
## Context Loading
|
|
119
|
+
|
|
120
|
+
- Rules: `packages/agentic-system/docs/agentic/rules/development-workflow.md` (packaged anchor; the only loadable rule that bears on this task — bootstrap consumers receive a copy under `.agentic/rules/` after install). `docs/agentic/rules/planning-pipeline.md` does not exist in this monorepo and is intentionally not referenced.
|
|
121
|
+
- Contracts: `packages/agentic-protocol/...` for `BootstrapManifest` shape (only consult if a manifest field changes — this task does not change the shape).
|
|
122
|
+
- Code anchors: `packages/agentic-bootstrap/src/agentic_bootstrap/install.py:96-107`, `:380-432`, `:435-557`. Read once at session start; do not re-load on every slice.
|
|
123
|
+
- Existing tests: `packages/agentic-bootstrap/tests/` — locate the lifecycle profile test at session start. The new test sits next to it.
|
|
124
|
+
- Handoff/MCP state: scope decisions for `SCOPE-bootstrap-consumption-hardening-20260508` (inline in scope doc until MCP recording lands).
|
|
125
|
+
- External docs via `ctx7`: not required for this task.
|
|
126
|
+
|
|
127
|
+
## Contract and Boundary Impact
|
|
128
|
+
|
|
129
|
+
| Boundary | Owner | Current Contract | Expected Change | Compatibility Needed? | Verification |
|
|
130
|
+
| ---------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
131
|
+
| `agentic-bootstrap install` profile API | agentic-bootstrap | `profile in {minimal, lifecycle, all}`; `all` → skills + generated + configs; `lifecycle` → hoist lifecycle + Makefile-include | `all` additionally performs the lifecycle hoist + Makefile-include. `minimal` and `lifecycle` semantics unchanged. | yes — `--profile all` is the legacy/default profile; existing consumers must keep working. The change is purely additive (more files materialized) so no caller-visible removal. | New `tests/test_install_profile_all_lifecycle.py` (or extension of existing suite) asserts the hoist + idempotency after `--profile all`. |
|
|
132
|
+
| `BootstrapManifest` (`packages/agentic-protocol`) | agentic-protocol | `surfaces: list[{path, source}]`, `configs: list[{path, action}]`. Lifecycle entries use `source: "lifecycle"`; Makefile-include uses `action: "appended"\|"created"\|"already_present"`. | No shape change. New behavior produces additional list entries already supported by the schema. | no | Existing `BootstrapManifest.model_validate(manifest)` call at `install.py:585` continues to pass. |
|
|
133
|
+
| Consumer `Makefile` | consumer repo | If absent, bootstrap creates one with the sentinel block; if present, bootstrap appends or no-ops. Always wrapped in sentinels for clean uninstall. | No change to the writer logic itself. Now triggered under `--profile all` as well. | yes — must remain idempotent across profile re-runs. | Regression test invokes `install(profile=PROFILE_ALL, ...)` twice against the same target; asserts single sentinel block. |
|
|
134
|
+
|
|
135
|
+
## Proposed Solution
|
|
136
|
+
|
|
137
|
+
Replace the dedicated `if profile == PROFILE_LIFECYCLE:` block at `install.py:553-557` with a guard that fires for both `PROFILE_ALL` and `PROFILE_LIFECYCLE`. Concretely:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# Lifecycle hoist now fires for both `all` (so consumers that ship the
|
|
141
|
+
# branch-lifecycle / tdd / etc. skills also get the matching make
|
|
142
|
+
# fragment + runner) and `lifecycle` (the dedicated lean profile).
|
|
143
|
+
if profile in (PROFILE_ALL, PROFILE_LIFECYCLE):
|
|
144
|
+
surfaces.extend(_install_lifecycle_profile(target, clone))
|
|
145
|
+
include_entry = _ensure_consumer_makefile_include(target)
|
|
146
|
+
if include_entry is not None:
|
|
147
|
+
configs.append(include_entry)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Update the in-source comment block at `install.py:548-552` to note the follow-on has landed and reference AHMCP-48.
|
|
151
|
+
|
|
152
|
+
That is the entire production change. `_install_lifecycle_profile` and `_ensure_consumer_makefile_include` are already idempotent; the manifest schema already accepts the entries; the lifecycle hoist sources are already cloned via the existing `_resolve_in_clone` mechanism.
|
|
153
|
+
|
|
154
|
+
The reason a more elaborate "skill registry" design (per the scope's "skills-imply-lifecycle" framing) is not used here: today, skills are materialized only under `--profile all`. There is no profile that ships skills without `all`. Promoting `all` to imply lifecycle therefore covers every drift case in the current code, with the smallest possible diff and no new data structures. If a future profile adds skills, this plan must be reconsidered — captured in Stretch Goals as a follow-up guard.
|
|
155
|
+
|
|
156
|
+
## Files and Surfaces to Change
|
|
157
|
+
|
|
158
|
+
| Surface | File | Change |
|
|
159
|
+
| ---------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| backend (install body) | `packages/agentic-bootstrap/src/agentic_bootstrap/install.py:548-557` | Replace `if profile == PROFILE_LIFECYCLE:` with `if profile in (PROFILE_ALL, PROFILE_LIFECYCLE):`. Update comment block to reflect that the AHMCP-40 follow-on has landed. |
|
|
161
|
+
| backend (update path) | `packages/agentic-bootstrap/src/agentic_bootstrap/subcommands.py:461-492` | **No production change.** `update()` already delegates to `install()` (line 486), so the install fix automatically propagates to the `agentic-bootstrap update` path. Listed here so the auditor sees the surface explicitly and the test below has a named home. |
|
|
162
|
+
| tests (install profile) | `packages/agentic-bootstrap/tests/test_install_profile_all_lifecycle.py` (new file) | New regression test: `install(profile=PROFILE_ALL, ...)` materializes `Makefile.d/lifecycle.mk`, `scripts/agentic/lifecycle/`, and the `-include` sentinel block; second run is idempotent. |
|
|
163
|
+
| tests (update path) | `packages/agentic-bootstrap/tests/test_subcommands.py` (extend existing file) | Add a focused test that calls `update()` against a target previously bootstrapped with `--profile all` and asserts the consumer now contains `Makefile.d/lifecycle.mk`, `scripts/agentic/lifecycle/`, and exactly one `LIFECYCLE_INCLUDE_SENTINEL` block in `Makefile`. This proves the epic-level drift contract holds for the `update` path, not just first-time installs. |
|
|
164
|
+
| changelog | `packages/agentic-bootstrap/CHANGELOG.md` | Entry under the next unreleased version describing the behavior change ("`--profile all` now also hoists `Makefile.d/lifecycle.mk` so consumers that ship lifecycle-referencing skills can run them; `agentic-bootstrap update` inherits the same hoist via its existing `install()` delegation"). |
|
|
165
|
+
|
|
166
|
+
## Related Files
|
|
167
|
+
|
|
168
|
+
| File | Note |
|
|
169
|
+
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
170
|
+
| `packages/agentic-system/Makefile.d/lifecycle.mk` | Source for the hoist; not modified, but its existence at the resolved clone path is a precondition for the assertion in the new test. |
|
|
171
|
+
| `packages/agentic-system/scripts/agentic/lifecycle/` | Source for the hoist runner; same precondition. |
|
|
172
|
+
| `packages/agentic-system/skills/branch-lifecycle/body.md` | The skill whose `make task-start` references motivated the fix. Not modified by this task; AHMCP-62 (cold-start runbook + commit-prefix, formerly AHMCP-49) edits it separately. |
|
|
173
|
+
| `packages/agentic-bootstrap/tests/...` (existing lifecycle-profile test) | Locate at session start; the new test reuses any helpers it exposes (e.g. fixture clones, target tempdirs). Do not duplicate the lifecycle-only assertion. |
|
|
174
|
+
| `packages/agentic-protocol/...` (`BootstrapManifest`) | Validation continues unchanged; named for traceability. |
|
|
175
|
+
|
|
176
|
+
## Verification Strategy
|
|
177
|
+
|
|
178
|
+
- Deterministic tests:
|
|
179
|
+
- `cd packages/agentic-bootstrap && uv run pytest tests/test_install_profile_all_lifecycle.py -x`
|
|
180
|
+
- `cd packages/agentic-bootstrap && uv run pytest tests/test_subcommands.py -x` (must include the new `update`-path lifecycle-hoist assertion; protects against an `update()` regression that breaks the epic's drift contract even though the production code change lives entirely in `install.py`).
|
|
181
|
+
- `cd packages/agentic-bootstrap && uv run pytest -x` (full suite must remain green; in particular the existing `--profile lifecycle` and `--profile minimal` tests).
|
|
182
|
+
- Runtime-parity / environment checks:
|
|
183
|
+
- `cd /tmp && rm -rf bootstrap-smoke && mkdir bootstrap-smoke && cd bootstrap-smoke && git init -q && uvx --from /Users/daniel/Development/agentic-protocol-monorepo/packages/agentic-bootstrap agentic-bootstrap install --remote-url file:///Users/daniel/Development/agentic-protocol-monorepo --remote-ref HEAD --profile all && test -f Makefile.d/lifecycle.mk && test -d scripts/agentic/lifecycle && grep -q LIFECYCLE_INCLUDE_SENTINEL Makefile && echo "smoke OK"` _(adapt the `uvx` invocation to the local install path; the assertion is "lifecycle artifacts present after `--profile all`")._
|
|
184
|
+
- Idempotency: re-run the same install command and assert no second sentinel block (`grep -c "AGENTIC_BOOTSTRAP LIFECYCLE INCLUDE" Makefile` returns `1`).
|
|
185
|
+
- Contract/fixture verification:
|
|
186
|
+
- `BootstrapManifest.model_validate(manifest)` is exercised by the install path itself; no extra fixture needed.
|
|
187
|
+
- Manual verification:
|
|
188
|
+
- Re-bootstrap `altcontext-marketing-monorepo` against the candidate build and confirm `make task-start TASK=… OBJECTIVE=…` runs end-to-end. This is the epic-level done-signal and is verified after the PR lands, not as part of merge gating.
|
|
189
|
+
|
|
190
|
+
## Slice Delivery
|
|
191
|
+
|
|
192
|
+
### Slice 1: Promote `--profile all` to imply lifecycle hoist
|
|
193
|
+
|
|
194
|
+
**Goal**: `install(profile=PROFILE_ALL, ...)` materializes `Makefile.d/lifecycle.mk` + `scripts/agentic/lifecycle/` + Makefile `-include` sentinel; behavior under `lifecycle` and `minimal` is unchanged; re-runs are idempotent.
|
|
195
|
+
|
|
196
|
+
Changes:
|
|
197
|
+
|
|
198
|
+
- Replace the `if profile == PROFILE_LIFECYCLE:` guard at `install.py:553` with `if profile in (PROFILE_ALL, PROFILE_LIFECYCLE):`.
|
|
199
|
+
- Update the inline comment block at `install.py:548-552` to record that the AHMCP-40 follow-on has landed under AHMCP-48.
|
|
200
|
+
- Add `tests/test_install_profile_all_lifecycle.py` with at minimum:
|
|
201
|
+
- One test that asserts post-install file presence after `--profile all` (the three expected artifacts).
|
|
202
|
+
- One test that asserts manifest entries (`surfaces` has two `source: "lifecycle"` entries; `configs` has the Makefile-include entry on first run).
|
|
203
|
+
- One test that asserts idempotency on a second run against the same target (single sentinel; no exception).
|
|
204
|
+
- Extend `tests/test_subcommands.py` with one focused test that:
|
|
205
|
+
- Bootstraps a target via `install(profile=PROFILE_ALL, ...)`.
|
|
206
|
+
- Calls `update(target=..., remote_ref=...)` against that target.
|
|
207
|
+
- Asserts `Makefile.d/lifecycle.mk` and `scripts/agentic/lifecycle/` are present after the update and that `Makefile` contains exactly one `LIFECYCLE_INCLUDE_SENTINEL_BEGIN` marker (idempotent across the install+update sequence).
|
|
208
|
+
- This is the epic-level drift contract for the `update` path: even though `update()` delegates to `install()` and inherits the fix indirectly, an explicit assertion prevents a future refactor of `update()` from silently regressing the contract.
|
|
209
|
+
- CHANGELOG entry.
|
|
210
|
+
|
|
211
|
+
Proof:
|
|
212
|
+
|
|
213
|
+
- `uv run pytest tests/test_install_profile_all_lifecycle.py -v` shows three passing cases.
|
|
214
|
+
- `uv run pytest tests/test_subcommands.py -v` shows the new update-path lifecycle-hoist case passing alongside the existing subcommand tests.
|
|
215
|
+
- `uv run pytest tests/` full suite green.
|
|
216
|
+
- Smoke command from the Verification Strategy returns `smoke OK` and the idempotency `grep -c` returns `1`.
|
|
217
|
+
|
|
218
|
+
## Consolidated Checklist
|
|
219
|
+
|
|
220
|
+
## Context and Ownership
|
|
221
|
+
|
|
222
|
+
- [x] Loaded `install.py:96-107`, `:380-432`, `:525-557` and the existing lifecycle-profile test in `tests/`.
|
|
223
|
+
- [x] Confirmed `BootstrapManifest` shape does not require updates (entries are already supported).
|
|
224
|
+
- [x] Confirmed `_install_lifecycle_profile` and `_ensure_consumer_makefile_include` are idempotent before relying on them under a second profile.
|
|
225
|
+
|
|
226
|
+
### Checklist for Slice 1: Promote `--profile all` to imply lifecycle hoist
|
|
227
|
+
|
|
228
|
+
- [x] Edit `install.py` profile-dispatch guard from `== PROFILE_LIFECYCLE` to `in (PROFILE_ALL, PROFILE_LIFECYCLE)`.
|
|
229
|
+
- [x] Update the inline comment block at `install.py:548-552` to reflect AHMCP-48.
|
|
230
|
+
- [x] Add `tests/test_install_profile_all_lifecycle.py` covering filesystem state, manifest shape, and idempotency.
|
|
231
|
+
- [x] Extend `tests/test_subcommands.py` with a focused `update`-path test that asserts `Makefile.d/lifecycle.mk`, `scripts/agentic/lifecycle/`, and a single `LIFECYCLE_INCLUDE_SENTINEL_BEGIN` marker after `install(--profile all)` followed by `update()`.
|
|
232
|
+
- [x] Confirm by code reading that no other entry point bypasses `install()` (`subcommands.py:update`, `subcommands.py:repair`, CLI). Document the audit result in the slice-complete decision.
|
|
233
|
+
- [x] Add CHANGELOG entry under the next unreleased agentic-bootstrap version.
|
|
234
|
+
- [x] Run `uv run pytest -x` and capture green output.
|
|
235
|
+
|
|
236
|
+
## Review Readiness
|
|
237
|
+
|
|
238
|
+
- [x] No boundary-touching implementation is left without matching contract/test evidence (`BootstrapManifest` validation is exercised by the test path itself; no manifest schema change required).
|
|
239
|
+
- [x] Runtime-parity smoke test (manual, against a temp consumer repo) was run and produced the lifecycle artifacts under `--profile all`.
|
|
240
|
+
- [x] Handoff decision records the install-time behavior change and links to the AHMCP-48 PR.
|
|
241
|
+
|
|
242
|
+
## Stretch Goals
|
|
243
|
+
|
|
244
|
+
- [ ] Add a defensive runtime check in `install()` that detects "skills materialized but lifecycle hoist did not run" and refuses the install with a clear error. This is a guard against future profiles that add skills without auditing the lifecycle dependency. Stretch because the immediate drift class is closed by the `PROFILE_ALL ⇒ lifecycle` promotion alone.
|
|
245
|
+
|
|
246
|
+
## Success Criteria
|
|
247
|
+
|
|
248
|
+
- [ ] After `agentic-bootstrap install --profile all` against any target, `Makefile.d/lifecycle.mk`, `scripts/agentic/lifecycle/`, and the `-include` sentinel block are all present in the consumer.
|
|
249
|
+
- [ ] Re-running the same install against the same target produces no duplicate sentinel blocks and no test failures.
|
|
250
|
+
- [ ] `--profile lifecycle` and `--profile minimal` produce byte-identical surface and config sets to their pre-AHMCP-48 outputs (regression coverage in the existing test suite).
|
|
251
|
+
- [ ] After the PR lands and `altcontext-marketing-monorepo` re-bootstraps against the candidate build, `make task-start TASK=<ref> OBJECTIVE="…"` runs end-to-end without "missing target" errors. This is the epic-level done-signal; verified out-of-band, not as a merge gate for AHMCP-48 itself.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Epic Sequencing Note
|
|
256
|
+
|
|
257
|
+
This is task **1 of 4** under the `bootstrap-consumption-hardening` epic. The remaining sub-tasks each need their own task plan:
|
|
258
|
+
|
|
259
|
+
- **AHMCP-62** (formerly AHMCP-49, renamed 2026-05-17 to resolve a collision with the bootstrap `managed-server-versions-constant` plan): Document `<branch-name>:` commit-prefix convention + cold-start worktree-isolation runbook in `branch-lifecycle/body.md` (gaps 2 + 3 of the scope, bundled because both edit the same skill body).
|
|
260
|
+
- **AHMCP-50**: New canonical rule `docs/agentic/rules/planning-artifact-home.md` + optional `git status` guardrail for untracked `docs/scopes|plans|assessments/*` on `main` (gap 4 of the scope).
|
|
261
|
+
- **Verification**: Re-bootstrap `altcontext-marketing-monorepo` clean as the epic-level done-signal (not a code task).
|
|
262
|
+
|
|
263
|
+
These plans are deliberately not drafted in this file. Each gets its own branch and review cycle, per the scope's "one epic, sub-tasks each as their own task plan and branch" decision.
|