feat(P03): multi-project support, NFR milestone versioning, phase context reset, install scripts (v0.3.0)

This commit is contained in:
CI
2026-05-29 15:13:45 +00:00
parent e4bb3a9970
commit ddf04792c7
57 changed files with 1748 additions and 59 deletions
+27
View File
@@ -115,6 +115,33 @@ git push origin main --tags
When the project undergoes a schema-breaking change (e.g., switching from file-based to git-native architecture), bump the major version. Major releases follow the same merge → tag → release flow.
## NFR Milestone Versioning
NFR milestones and feature milestones follow different versioning rules:
**NFR milestones** — all phases are `fix`, `chore`, `docs`, `perf`, `refactor`, or `test`:
- Each phase gets a progressive patch version (v0.1.1, v0.1.2, v0.1.3)
- No separate milestone tag — the milestone is implicit from the patch sequence
- Example: milestone v0.1 with phases P01 (chore), P02 (test), P03 (perf) → v0.1.1, v0.1.2, v0.1.3
**Feature milestones** — any phase is `feat`:
- Each phase gets a progressive patch version
- On milestone completion, tag a minor version (e.g., v0.2.0)
- Example: milestone v0.2 with phases P01 (feat), P02 (feat), P03 (fix) → v0.2.1, v0.2.2, v0.2.3 + milestone tag v0.3.0
Determine milestone type by checking `isNfrMilestone()` which inspects all phase commit types within the milestone.
## Multi-Project Branch Naming
When operating in multi-project mode (`.ci/config.json` has `projects[]` with length > 0):
| Branch Type | Format | Example |
|-------------|--------|---------|
| Phase | `<slug>/phase/NN-slug` | `auth/phase/01-jwt-setup` |
| Milestone | `<slug>/milestone/vX.X-slug` | `auth/milestone/v0.2-login` |
Single-project mode keeps the existing `phase/NN-slug` and `milestone/vX.X-slug` conventions (no slug prefix).
## Phase Discovery
```typescript
+33 -5
View File
@@ -4,15 +4,33 @@ How CI manages the `.ci/` directory — long-lived reference documents only. Dyn
---
## Multi-Project Directory Structure
In multi-project mode, `.ci/` uses subdirectories per project:
```
.ci/
config.json # Registry with projects[] and active_project
<project-slug>/
PROJECT.md
ARCHITECTURE.md
ROADMAP.md
REQUIREMENTS.md
```
`.ci/config.json` serves as the registry with `projects[]` (array of project entries) and `active_project` (slug of the currently active project).
**Backward compatibility:** if `.ci/` has flat files (PROJECT.md, ARCHITECTURE.md, etc.) and no project subdirectories, auto-migrate by creating `<default-slug>/` and moving files into it, then updating `config.json` with a single `projects[]` entry.
## What Lives in `.ci/`
| File | Purpose | Update Frequency |
|------|---------|-------------------|
| `config.json` | Project-level CI configuration | Rare (initialization, setting changes) |
| `PROJECT.md` | Vision, core value, requirements, constraints, key decisions | Low (phase boundaries) |
| `ARCHITECTURE.md` | System architecture, component boundaries, data flow | Low (major refactors) |
| `ROADMAP.md` | Phase breakdown, milestone mapping, success criteria | Low (phase transitions) |
| `REQUIREMENTS.md` | v1/v2 requirements with REQ-IDs, out of scope, traceability | Low (requirement changes) |
| `config.json` | Project registry with `projects[]` and `active_project` | Rare (initialization, project changes) |
| `<slug>/PROJECT.md` | Vision, core value, requirements, constraints, key decisions per project | Low (phase boundaries) |
| `<slug>/ARCHITECTURE.md` | System architecture, component boundaries, data flow per project | Low (major refactors) |
| `<slug>/ROADMAP.md` | Phase breakdown, milestone mapping, success criteria per project | Low (phase transitions) |
| `<slug>/REQUIREMENTS.md` | v1/v2 requirements with REQ-IDs, out of scope, traceability per project | Low (requirement changes) |
## What Does NOT Live in `.ci/`
@@ -137,6 +155,15 @@ interface ArchitectureMd {
}
```
## Research and .ci/ File Updates
Research is intermediate work product. Conclusions from research update `.ci/` static files:
- Key findings go in the commit body
- Decisions go in `---ci---` blocks
- Conclusions that change project structure update the appropriate `.ci/<slug>/` files (ARCHITECTURE.md, PROJECT.md, etc.)
Research commits are not final artifacts — they feed into planning and roadmap updates.
## Anti-Patterns
- Never write dynamic state (decisions, escalations, lessons) to `.ci/` files
@@ -145,5 +172,6 @@ interface ArchitectureMd {
- Never commit `.ci/` changes without a `---ci---` block
- Never create new files in `.ci/` without updating this reference document
- Never store counters, timestamps, or session state in `.ci/` files
- Never store research conclusions only in commits — update `.ci/<slug>/` static files with findings
</ci_files_discipline>
+18
View File
@@ -10,6 +10,7 @@ Canonical `---ci---` YAML block schema for CI commits. Every CI-generated commit
<type>(<scope>): <subject>
---ci---
project: <slug> # required in multi-project mode
phase: <number>
milestone: <string>
plan: <string> # optional
@@ -38,6 +39,23 @@ compound: # optional
---/ci---
```
The `project` field is required when in multi-project mode (`.ci/config.json` has `projects[]` with length > 0). In single-project mode, it is optional.
Example with project field:
```
feat(P01-01-01): implement JWT auth
---ci---
project: auth-service
phase: 1
milestone: v0.2
plan: 01-01
task: 01-01-01
status: execute
---/ci---
```
## Commit Types
| Type | Purpose | Scope |
@@ -93,6 +93,10 @@ const phaseDecisions = gitContext.getDecisions(3); // Phase 3 only
const commitDecisions = gitContext.getDecisionsFromCommits(commits, 3);
```
## Project-Scoped Decisions
Decisions can be project-scoped via the `project` field in `---ci---` blocks. When in multi-project mode, include the project slug so that `GitContext.getDecisions()` can filter decisions by project. Project-scoped decisions only apply to the specified project and do not affect other projects in the same repository.
## Anti-Patterns
- Never write decisions to a `.ci/audit/` file — commit them
@@ -76,6 +76,34 @@ interface ParsedCiCommit {
Commits without `---ci---` blocks have `ci: null` — these are treated as non-CI commits (e.g., manual edits by the developer).
## Phase Context Reset
Between phases, all state is committed to git, then the next phase starts with fresh context from git log — not accumulated conversation history.
**On opencode (subagent support):** spawn a fresh agent for the next phase. The new agent loads context from git log and `.ci/` files only.
**On platforms without subagents:** simulated reset — re-read git context from scratch, ignore prior conversation history. Treat the phase boundary as a hard context boundary.
**Checkpoint sequence:**
1. Commit all work from the current phase
2. Update `.ci/` files (ROADMAP.md phase status, REQUIREMENTS.md requirement statuses)
3. Verify `GitContext.reconstructState()` matches expected state
4. Reset context — next phase begins fresh
The phase context reset ensures that each phase operates on verified git state, preventing context drift across long-running projects.
## Multi-Project Context
GitContext supports multi-project mode with optional project scoping:
| Method | Returns | Purpose |
|--------|---------|---------|
| `GitContext(projectPath, projectSlug?)` | GitContext | Optional project slug for scoping |
| `detectProjectFromCommit()` | string \| null | Detect project from latest commit's `project` field |
| `isNfrMilestone()` | boolean | Check if current milestone is NFR-only (no feat phases) |
In multi-project mode, `detectProjectFromCommit()` reads the `project` field from the latest `---ci---` block to determine which project context to load. `isNfrMilestone()` inspects phase commit types to determine versioning behavior.
## Context Budget Strategy
When context is limited: