Sprint 007 전체 구현 — 마지막 스프린트. 프로젝트 완성:
CLI:
- rails doctor — 환경 헬스체크 (Node/pnpm/git/env/프로젝트 파일)
- rails scaffold [dir] — 신규 프로젝트 .plans/ 구조 생성
- rails migrate from-hanarang-harness <path> — 레거시 아카이브 스캐너
agents/scripts/workflows 분류 (portable vs deprecated)
xhigh 참조 경고 등 위험 패턴 감지
Docs (신규 3종):
- docs/migration-guide.md — 레거시 하네스 → rails 단계별 이전 가이드
- docs/operations.md — PM2, health check, 트러블슈팅, DB 유지보수
- docs/discord-setup.md — 봇 생성, DiscordPoster 구현 예시,
marker 프로토콜 완전 명세
README 대폭 업데이트:
- v0.1.0 상태 선언
- 빠른 시작 가이드
- CLI 13 서브커맨드 목록
- 문서 링크
Tests (4 신규, 105 total pass):
- 마이그레이션 스캐너 (agents/scripts/workflows 감지)
- node_modules/.git 제외
- 빈 아카이브 처리
- scaffold 디렉토리 구조 검증
검증: tsc --noEmit ✓ | vitest 105/105 ✓ | build ✓
rails doctor → 정상 출력 ✓
rails --help → 13 subcommands ✓
마감 상태:
- F1~F6 모든 실패 모드 코어에서 해결
- 7 스프린트 완료 (000: 계획, 001~006: 코어, 007: 릴리즈)
- 105 테스트, 19 문서 (.plans/) + 3 운영 문서 (docs/)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
181 lines
5.5 KiB
Markdown
181 lines
5.5 KiB
Markdown
# Migration Guide
|
||
|
||
> How to move from an existing agent pipeline (e.g., a Lobster-based `hanarang-harness` install) to `hanarang-rails`.
|
||
|
||
## Summary
|
||
|
||
`hanarang-rails` replaces the legacy "권고 기반" pipeline with a **deterministic, contract-enforced** one. The migration is safe: nothing in the archive is deleted, and rails can run side-by-side until you cut over.
|
||
|
||
## Before you start
|
||
|
||
- **Back up the old install.** Keep the archive read-only; don't delete it.
|
||
- **Install rails on a neutral host** — ideally the same machine that holds the SSOT repository, not one of the agent workers.
|
||
- **Confirm Node 22+ and pnpm are available** via `rails doctor`.
|
||
|
||
## Step 0 — Install rails
|
||
|
||
```bash
|
||
bash install.sh --dir /path/to/hanarang-rails --repo <your-rails-repo-url>
|
||
cd /path/to/hanarang-rails
|
||
cp .env.example .env # fill DATABASE_URL, DISCORD_TOKEN, etc.
|
||
pnpm prisma migrate deploy
|
||
pnpm rails doctor
|
||
```
|
||
|
||
## Step 1 — Scan the archive
|
||
|
||
```bash
|
||
rails migrate from-hanarang-harness /path/to/hanarang-harness-archive
|
||
```
|
||
|
||
This reports:
|
||
- Agents (md files) — candidates to port
|
||
- Scripts — portable vs deprecated (bridge.sh is deprecated)
|
||
- Workflows — Lobster files are flagged as deprecated
|
||
- Warnings — e.g., any `xhigh` thinking tier reference (forbidden)
|
||
|
||
No files are modified. Review the report and decide.
|
||
|
||
## Step 2 — Bring over agent definitions
|
||
|
||
Copy the agent markdown files you want to keep into the rails `agents/` directory. Rails does not prescribe a naming scheme; `rails.config.yaml` maps **stage** → **agent**, so you can keep role-specific personas.
|
||
|
||
```bash
|
||
mkdir -p agents/
|
||
cp /path/to/archive/agents/*.md agents/
|
||
```
|
||
|
||
Review each file and remove anything that references:
|
||
- `xhigh` thinking tier (forbidden in rails — causes infinite waits)
|
||
- Mention-based handoff instructions
|
||
- Direct discord bot behavior (rails now posts on their behalf)
|
||
|
||
## Step 3 — Port scaffolding
|
||
|
||
The legacy `scaffold.sh` is now `rails scaffold`:
|
||
|
||
```bash
|
||
rails scaffold /path/to/new-project --name my-project
|
||
```
|
||
|
||
This creates `.plans/` with the standard directory structure (`design/`, `sprints/`, `migration/`) plus a root `Plans.md`.
|
||
|
||
## Step 4 — Wire `rails.config.yaml`
|
||
|
||
```yaml
|
||
pipeline:
|
||
stages: [plan, implement, review, deploy]
|
||
|
||
agents:
|
||
plan:
|
||
role: plan
|
||
displayName: Planner
|
||
transport: discord
|
||
channelId: ${PLAN_CHANNEL}
|
||
timeoutMs: 30000
|
||
implement:
|
||
role: implement
|
||
displayName: Generator
|
||
transport: discord
|
||
channelId: ${IMPL_CHANNEL}
|
||
timeoutMs: 60000
|
||
review:
|
||
role: review
|
||
displayName: Evaluator
|
||
transport: discord
|
||
channelId: ${REVIEW_CHANNEL}
|
||
timeoutMs: 30000
|
||
deploy:
|
||
role: deploy
|
||
displayName: Deploy
|
||
transport: local
|
||
timeoutMs: 60000
|
||
|
||
discord:
|
||
enabled: true
|
||
railsToken: ${RAILS_DISCORD_TOKEN}
|
||
guildId: ${DISCORD_GUILD_ID}
|
||
pipelineChannelId: ${PIPELINE_THREAD_PARENT}
|
||
```
|
||
|
||
All secrets live in `.env`. The config file uses `${VAR}` interpolation — no token bytes in the repo.
|
||
|
||
## Step 5 — Update agent runtimes
|
||
|
||
Each agent host (e.g., a sister container) needs one change to its message handler:
|
||
|
||
```js
|
||
// Pseudocode — plug into your agent's discord event handler
|
||
onDiscordMessage(msg) {
|
||
if (msg.content.includes("<!-- rails:invoke v1 -->")) {
|
||
const req = extractJsonBlock(msg.content, "rails:invoke");
|
||
// Structured pipeline mode — LLM 우회
|
||
const result = await handleRailsInvoke(req);
|
||
await postResultMarker(msg.channel, result);
|
||
return;
|
||
}
|
||
// Otherwise: existing free-form conversation path
|
||
llmRespond(msg);
|
||
}
|
||
```
|
||
|
||
See `docs/discord-setup.md` for the full marker format.
|
||
|
||
## Step 6 — Cutover
|
||
|
||
1. **Smoke test with mock transport** first:
|
||
```bash
|
||
rails run --mock test-project -r "hello world"
|
||
rails status
|
||
```
|
||
This exercises the full FSM without touching real agents.
|
||
|
||
2. **Switch one stage at a time to discord**:
|
||
```yaml
|
||
agents:
|
||
plan:
|
||
transport: discord # flip this first
|
||
implement:
|
||
transport: mock # keep others on mock until plan is green
|
||
```
|
||
|
||
3. **Monitor escalations**:
|
||
```bash
|
||
rails status <pipeline-id>
|
||
```
|
||
Any unexpected escalation triggers discord alert (if configured).
|
||
|
||
4. **Disable legacy mention-based handoff** on the old agents once all stages run through rails.
|
||
|
||
## Step 7 — Decommission legacy bridge
|
||
|
||
After rails handles 100% of traffic:
|
||
|
||
1. Stop the old `bridge.sh` process(es).
|
||
2. Keep the archive as read-only reference.
|
||
3. Remove any cron jobs or systemd units that referenced the old install.
|
||
|
||
## Rollback
|
||
|
||
If rails fails badly:
|
||
|
||
```bash
|
||
rails abort <pipeline-id> # stop the misbehaving pipeline
|
||
pm2 stop hanarang-rails # stop the orchestrator
|
||
# Start the legacy bridge again if it's still present
|
||
```
|
||
|
||
The SSOT repository is untouched — both systems write to the same Gitea.
|
||
|
||
## Known limitations (v0.1.0)
|
||
|
||
- **Discord bot wiring requires an operator task.** Rails ships the `DiscordTransport` class but does not auto-connect discord.js; you plug in a client via the `DiscordPoster` interface. A default implementation will ship in v0.2.0.
|
||
- **Gitea webhook receiver** is scaffolded but not yet exposed as an HTTP endpoint in `rails serve` — tracked for v0.2.0.
|
||
- **Manual QA checks** are stubbed (SKIPPED by default). Provide a `manualResolver` to `runQaTemplate` to wire up a reviewer LLM.
|
||
|
||
## Further reading
|
||
|
||
- [`.plans/failure-audit.md`](../.plans/failure-audit.md) — why rails exists (F1–F6)
|
||
- [`.plans/design/`](../.plans/design/) — architecture docs
|
||
- `docs/operations.md` — day-to-day operations guide
|