@su-record/vibe 3.2.49 → 3.2.51
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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/tools/loop/validateLoopDefinition.d.ts +30 -1
- package/dist/tools/loop/validateLoopDefinition.d.ts.map +1 -1
- package/dist/tools/loop/validateLoopDefinition.js +37 -1
- package/dist/tools/loop/validateLoopDefinition.js.map +1 -1
- package/package.json +1 -1
- package/skills/vibe.loop/SKILL.md +15 -1
- package/vibe/rules/loop-contract.md +28 -0
- package/vibe/templates/loop-template.md +10 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe",
|
|
3
3
|
"displayName": "Vibe",
|
|
4
|
-
"version": "3.2.
|
|
4
|
+
"version": "3.2.51",
|
|
5
5
|
"description": "Verification harness for AI coding agents — \"done\" is decided by deterministic gates (test exit codes, run-ledger, regression memory), not the model self-report.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "su-record",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.51",
|
|
4
4
|
"description": "Verification harness for AI coding agents — \"done\" is decided by deterministic gates (test exit codes, run-ledger, regression memory), not the model self-report.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "su-record",
|
|
@@ -5,8 +5,34 @@
|
|
|
5
5
|
* 조건부 필드(schedule, test_command)를 결정론적으로 검증한다.
|
|
6
6
|
*/
|
|
7
7
|
export type LoopTrigger = 'scheduled' | 'manual' | 'on-event';
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* 완료를 무엇으로 판정하는가.
|
|
10
|
+
*
|
|
11
|
+
* - `ledger` — run-ledger 의 `verifyPassed`
|
|
12
|
+
* - `tests` — `test_command` 의 exit code
|
|
13
|
+
* - `visual` — `visual_command` 의 exit code **+ 사람이 볼 산출물**
|
|
14
|
+
* - `none` — 판정 생략(보고만)
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ `visual` 이 "모델이 스크린샷을 보고 판단한다" 는 뜻이 **아니다.** 그건
|
|
17
|
+
* 자기보고이고, loop-contract 가 배제하는 바로 그것이다. 게이트는 명령의 exit
|
|
18
|
+
* code 다 — 베이스라인 diff·접근성 감사·토큰 드리프트처럼 임계값으로 떨어지는
|
|
19
|
+
* 검사여야 한다. `tests` 와 갈리는 지점은 **증거를 남긴다**는 것이다: 스크린샷이나
|
|
20
|
+
* diff 이미지를 남겨 나중에 사람이 눈으로 확인할 수 있어야 한다.
|
|
21
|
+
*/
|
|
22
|
+
export type LoopVerify = 'ledger' | 'tests' | 'visual' | 'none';
|
|
9
23
|
export type LoopIsolation = 'worktree' | 'none';
|
|
24
|
+
/**
|
|
25
|
+
* 한 번의 호출에서 몇 바퀴를 도는가.
|
|
26
|
+
*
|
|
27
|
+
* - `continuous` (기본) — `max_iterations` 한도까지 한 세션 안에서 계속 돈다.
|
|
28
|
+
* 회전 사이에 맥락이 남아 이어붙이기 좋지만, 컨텍스트가 단조 증가한다.
|
|
29
|
+
* - `per-iteration` — **한 바퀴만 돌고 끝낸다.** 반복은 스케줄러가 만든다.
|
|
30
|
+
* 호출마다 컨텍스트가 0에서 시작하므로 누적이 없다. 대신 매번 ANCHOR 문서를
|
|
31
|
+
* 다시 읽어야 하고(고정 비용), 회전 사이의 맥락은 파일로만 넘어간다.
|
|
32
|
+
*
|
|
33
|
+
* 어느 쪽이 결과가 나은지는 측정된 바 없다 — 축을 열어두고 선택하게 한다.
|
|
34
|
+
*/
|
|
35
|
+
export type LoopSession = 'continuous' | 'per-iteration';
|
|
10
36
|
export type LoopStatus = 'active' | 'paused';
|
|
11
37
|
/** 파싱된 루프 정의 */
|
|
12
38
|
export interface ParsedLoopDefinition {
|
|
@@ -18,8 +44,11 @@ export interface ParsedLoopDefinition {
|
|
|
18
44
|
pipeline: string[];
|
|
19
45
|
verify: LoopVerify;
|
|
20
46
|
test_command?: string;
|
|
47
|
+
visual_command?: string;
|
|
48
|
+
artifact_dir?: string;
|
|
21
49
|
max_iterations: number;
|
|
22
50
|
isolation: LoopIsolation;
|
|
51
|
+
session: LoopSession;
|
|
23
52
|
status: LoopStatus;
|
|
24
53
|
}
|
|
25
54
|
/** validateLoopDefinition 반환 타입 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateLoopDefinition.d.ts","sourceRoot":"","sources":["../../../src/tools/loop/validateLoopDefinition.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC9D,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"validateLoopDefinition.d.ts","sourceRoot":"","sources":["../../../src/tools/loop/validateLoopDefinition.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC9D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAChE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC;AACzD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7C,gBAAgB;AAChB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,mCAAmC;AACnC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACzC;AA0HD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAgJ5E"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
// ─── Constants ───────────────────────────────────────────────────────
|
|
8
8
|
const TRIGGER_VALUES = new Set(['scheduled', 'manual', 'on-event']);
|
|
9
|
-
const VERIFY_VALUES = new Set(['ledger', 'tests', 'none']);
|
|
9
|
+
const VERIFY_VALUES = new Set(['ledger', 'tests', 'visual', 'none']);
|
|
10
10
|
const ISOLATION_VALUES = new Set(['worktree', 'none']);
|
|
11
|
+
const SESSION_VALUES = new Set(['continuous', 'per-iteration']);
|
|
11
12
|
const STATUS_VALUES = new Set(['active', 'paused']);
|
|
12
13
|
/** 5-필드 cron 기본 패턴 (과도한 검증 금지) */
|
|
13
14
|
const CRON_PATTERN = /^\S+\s+\S+\s+\S+\s+\S+\s+\S+$/;
|
|
@@ -132,8 +133,11 @@ export function validateLoopDefinition(content) {
|
|
|
132
133
|
const discover = typeof fm['discover'] === 'string' ? fm['discover'].trim() : '';
|
|
133
134
|
const verify = typeof fm['verify'] === 'string' ? fm['verify'].trim() : '';
|
|
134
135
|
const test_command = typeof fm['test_command'] === 'string' ? fm['test_command'].trim() : undefined;
|
|
136
|
+
const visual_command = typeof fm['visual_command'] === 'string' ? fm['visual_command'].trim() : undefined;
|
|
137
|
+
const artifact_dir = typeof fm['artifact_dir'] === 'string' ? fm['artifact_dir'].trim() : undefined;
|
|
135
138
|
const maxIterRaw = fm['max_iterations'];
|
|
136
139
|
const isolation = typeof fm['isolation'] === 'string' ? fm['isolation'].trim() : 'none';
|
|
140
|
+
const session = typeof fm['session'] === 'string' ? fm['session'].trim() : 'continuous';
|
|
137
141
|
const status = typeof fm['status'] === 'string' ? fm['status'].trim() : '';
|
|
138
142
|
// 필수 필드 존재 검사
|
|
139
143
|
if (!name)
|
|
@@ -163,6 +167,9 @@ export function validateLoopDefinition(content) {
|
|
|
163
167
|
if (isolation && !ISOLATION_VALUES.has(isolation)) {
|
|
164
168
|
errors.push(`isolation: 유효하지 않은 값 "${isolation}" — worktree|none 중 하나여야 합니다`);
|
|
165
169
|
}
|
|
170
|
+
if (session && !SESSION_VALUES.has(session)) {
|
|
171
|
+
errors.push(`session: 유효하지 않은 값 "${session}" — continuous|per-iteration 중 하나여야 합니다`);
|
|
172
|
+
}
|
|
166
173
|
if (status && !STATUS_VALUES.has(status)) {
|
|
167
174
|
errors.push(`status: 유효하지 않은 값 "${status}" — active|paused 중 하나여야 합니다`);
|
|
168
175
|
}
|
|
@@ -187,6 +194,25 @@ export function validateLoopDefinition(content) {
|
|
|
187
194
|
else if (test_command !== undefined) {
|
|
188
195
|
errors.push('test_command: verify=tests 일 때만 허용됩니다');
|
|
189
196
|
}
|
|
197
|
+
// 조건부 필드: visual_command iff verify === 'visual'
|
|
198
|
+
if (verify === 'visual') {
|
|
199
|
+
if (!visual_command) {
|
|
200
|
+
errors.push('visual_command: verify=visual 일 때 필수 필드입니다');
|
|
201
|
+
}
|
|
202
|
+
// 증거가 남지 않으면 `tests` 와 다를 것이 없다 — 나중에 사람이 볼 것이 있어야 한다
|
|
203
|
+
if (!artifact_dir) {
|
|
204
|
+
errors.push('artifact_dir: verify=visual 일 때 필수 필드입니다 — 스크린샷·diff 를 남길 위치. '
|
|
205
|
+
+ '증거가 남지 않으면 verify=tests 와 다를 것이 없습니다.');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
if (visual_command !== undefined) {
|
|
210
|
+
errors.push('visual_command: verify=visual 일 때만 허용됩니다');
|
|
211
|
+
}
|
|
212
|
+
if (artifact_dir !== undefined) {
|
|
213
|
+
errors.push('artifact_dir: verify=visual 일 때만 허용됩니다');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
190
216
|
// max_iterations 범위 검사
|
|
191
217
|
const maxIter = Number(maxIterRaw);
|
|
192
218
|
if (maxIterRaw !== undefined && maxIterRaw !== null && maxIterRaw !== '') {
|
|
@@ -197,6 +223,13 @@ export function validateLoopDefinition(content) {
|
|
|
197
223
|
errors.push(`max_iterations: ${MAX_ITERATIONS_MIN}–${MAX_ITERATIONS_MAX} 범위여야 합니다 — 받은 값: ${maxIter}`);
|
|
198
224
|
}
|
|
199
225
|
}
|
|
226
|
+
// session: per-iteration 은 호출당 한 바퀴가 정의다 — max_iterations 와 어긋나면
|
|
227
|
+
// "한 바퀴만" 인지 "열 바퀴까지" 인지 두 값이 서로 다른 말을 하게 된다.
|
|
228
|
+
// 필드 하나가 두 뜻을 갖는 것을 막기 위해 일치를 요구한다.
|
|
229
|
+
if (session === 'per-iteration' && Number.isInteger(maxIter) && maxIter !== 1) {
|
|
230
|
+
errors.push(`session: per-iteration 은 max_iterations 가 1 이어야 합니다 — 받은 값: ${maxIter}. `
|
|
231
|
+
+ '반복은 스케줄러가 만든다 (trigger/schedule).');
|
|
232
|
+
}
|
|
200
233
|
// pipeline 항목 검사
|
|
201
234
|
for (const entry of pipeline) {
|
|
202
235
|
if (!entry.startsWith('vibe.')) {
|
|
@@ -215,7 +248,10 @@ export function validateLoopDefinition(content) {
|
|
|
215
248
|
pipeline,
|
|
216
249
|
verify: verify,
|
|
217
250
|
...(test_command !== undefined ? { test_command } : {}),
|
|
251
|
+
...(visual_command !== undefined ? { visual_command } : {}),
|
|
252
|
+
...(artifact_dir !== undefined ? { artifact_dir } : {}),
|
|
218
253
|
max_iterations: maxIter,
|
|
254
|
+
session: session,
|
|
219
255
|
isolation: isolation,
|
|
220
256
|
status: status,
|
|
221
257
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateLoopDefinition.js","sourceRoot":"","sources":["../../../src/tools/loop/validateLoopDefinition.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"validateLoopDefinition.js","sourceRoot":"","sources":["../../../src/tools/loop/validateLoopDefinition.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -46,8 +46,11 @@ HISTORY=".vibe/metrics/loop-history.jsonl"
|
|
|
46
46
|
- **목표(goal)**: 루프가 0으로 만들려는 것 (예: "open 회귀 0건", "P1 lint 0건")
|
|
47
47
|
- **트리거**: `scheduled`(cron) / `manual` / `on-event`
|
|
48
48
|
- **발견(discover)**: 일거리를 어떻게 찾는가 — 명령 또는 지시
|
|
49
|
-
- **검증(verify)**: `ledger`(vibe.verify 경유, 기본) / `tests`(테스트 명령 exit code) /
|
|
49
|
+
- **검증(verify)**: `ledger`(vibe.verify 경유, 기본) / `tests`(테스트 명령 exit code) /
|
|
50
|
+
`visual`(렌더 결과 검사 exit code + `artifact_dir` 에 증거) / `none`(보고만)
|
|
50
51
|
- **격리(isolation)**: 병렬 항목이 파일을 수정하면 `worktree`, 아니면 `none`
|
|
52
|
+
- **세션(session)**: `continuous`(기본, 한 호출에서 여러 바퀴) / `per-iteration`
|
|
53
|
+
(한 바퀴만 — 반복은 스케줄러가 만든다, `max_iterations: 1` 필수)
|
|
51
54
|
2. `{{VIBE_PATH}}/vibe/templates/loop-template.md`를 읽어 `.vibe/loops/<name>.md`를 생성한다.
|
|
52
55
|
3. **생성 직후 반드시 검증한다** — 실패 시 정의를 고치고 재검증, 통과 전에는 install/run 금지:
|
|
53
56
|
|
|
@@ -88,6 +91,12 @@ node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/loop/
|
|
|
88
91
|
6. VERIFY 완료 판정 — verify 모드별 결정론 기준:
|
|
89
92
|
· ledger: cat .vibe/metrics/run-ledger.json → verifyPassed === true 만 성공
|
|
90
93
|
· tests: 정의의 test_command 실행 → exit 0 만 성공
|
|
94
|
+
· visual: 정의의 visual_command 실행 → **exit 0 만 성공**.
|
|
95
|
+
산출물(스크린샷·diff)을 artifact_dir 에 남기고 그 경로를
|
|
96
|
+
종료 기록·인박스에 적는다 — 나중에 사람이 눈으로 확인할 것.
|
|
97
|
+
⛔ 모델이 스크린샷을 보고 "괜찮아 보인다"고 판정하는 것은
|
|
98
|
+
금지다. 그건 자기보고이고 게이트가 아니다. 판정은 exit code,
|
|
99
|
+
이미지는 증거 — 둘의 역할을 섞지 않는다.
|
|
91
100
|
· none: 판정 생략(보고만). "코드를 보니 잘 된 것 같다"는 판정이 아니다.
|
|
92
101
|
6-b. 회전 기록 node "$HOOKS_DIR/loop-ledger.js" iteration <name> <verified|unverified>
|
|
93
102
|
VERIFY 결과를 그대로 넣는다. 이어서 예산을 확인한다:
|
|
@@ -101,6 +110,11 @@ node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/loop/
|
|
|
101
110
|
· 확인할 것: `.vibe/metrics/loop-history.jsonl` 과 실제 변경 diff
|
|
102
111
|
· 이어서 돌리려면: loop-ledger.js trial-approve <name>
|
|
103
112
|
승인 없이 계속 도는 것 금지 — 정의가 맞는지 아직 아무도 모른다.
|
|
113
|
+
6-d. 세션 판정 `session: per-iteration` 이면 **여기서 끝낸다.** 남은 발견 항목이
|
|
114
|
+
있어도 다음 회전으로 넘어가지 않는다 — 반복은 스케줄러의 몫이다.
|
|
115
|
+
잔여 항목은 7·8 의 종료 기록과 인박스에 남겨 다음 호출이 집게 한다.
|
|
116
|
+
넘길 것을 파일에 적기 전에 끝내지 않는다. per-iteration 의 전제는
|
|
117
|
+
"맥락이 파일로만 넘어간다" 이고, 안 적으면 그냥 유실이다.
|
|
104
118
|
7. 종료 기록 node "$HOOKS_DIR/loop-ledger.js" end <name> <ok|fail|stuck> "<한 줄 요약>"
|
|
105
119
|
8. 인박스 node "$HOOKS_DIR/loop-ledger.js" inbox <name> <ok|fail|stuck> \
|
|
106
120
|
"발견: N건 / 처리: M건 / 검증: <기준과 결과>" \
|
|
@@ -195,6 +195,34 @@ JUDGE는 이번 feature의 **신규 생성 파일** 기준으로 검증 코드
|
|
|
195
195
|
| `ralplan` | 같은 계약을 계획 단계에 적용 |
|
|
196
196
|
| `ultrawork` / `ulw` | `automationLevel: autonomous` + 병렬 ACT — 루프 시맨틱이 아니라 자율성·병렬성 축. **병렬 항목이 파일을 수정하면 항목별 worktree 격리 필수** (`vibe.loop` 의 `isolation` 축과 같은 규칙) |
|
|
197
197
|
|
|
198
|
+
### 시각 검증 (`verify: visual`)
|
|
199
|
+
코드가 도는 것과 화면이 맞는 것은 다르다. `tests` 만으로 도는 UI 루프는 **초록불을 켜면서 화면을 망가뜨릴 수 있다.** 그래서 렌더 결과를 완료 기준으로 삼는 모드를 둔다.
|
|
200
|
+
|
|
201
|
+
| 필드 | 역할 |
|
|
202
|
+
|---|---|
|
|
203
|
+
| `visual_command` | **게이트** — exit 0 만 성공 |
|
|
204
|
+
| `artifact_dir` | **증거** — 스크린샷·diff 를 남길 위치 (필수) |
|
|
205
|
+
|
|
206
|
+
⛔ **모델이 스크린샷을 보고 판정하는 것이 아니다.** 그건 자기보고이고, 이 문서가 처음부터 배제하는 바로 그것이다. 판정은 명령의 exit code 이고, 이미지는 나중에 사람이 확인할 증거다. 둘의 역할을 섞으면 게이트가 아니라 분위기가 된다.
|
|
207
|
+
|
|
208
|
+
`visual_command` 는 **임계값으로 떨어지는 검사**여야 한다 — 베이스라인 픽셀 diff(임계 %), 접근성 감사(axe/WCAG), DESIGN.md 토큰 드리프트(`vibe.design verify`). "잘 나왔는지 본다" 는 명령이 될 수 없다.
|
|
209
|
+
|
|
210
|
+
`artifact_dir` 을 필수로 둔 이유: 증거가 남지 않으면 `tests` 와 기능적으로 같아진다. 이 모드가 존재할 이유가 증거이므로, 없으면 정의를 거부한다.
|
|
211
|
+
|
|
212
|
+
**비용을 감수하는 선택이다.** 렌더·캡처·비교는 단위 테스트보다 느리고, 검증이 비쌀수록 세션당 도는 루프가 줄어든다(위 사다리 참조). UI 결과물이 완료의 정의인 루프에만 쓴다.
|
|
213
|
+
|
|
214
|
+
### 세션 축 — 한 호출에서 몇 바퀴를 도는가
|
|
215
|
+
| 값 | 동작 | 얻는 것 | 치르는 것 |
|
|
216
|
+
|---|---|---|---|
|
|
217
|
+
| `continuous` (기본) | `max_iterations` 까지 한 세션에서 계속 | 회전 사이 맥락이 남는다 | 컨텍스트가 단조 증가 |
|
|
218
|
+
| `per-iteration` | **한 바퀴만** — 반복은 스케줄러가 | 호출마다 컨텍스트 0에서 시작 | 매번 ANCHOR 재독(고정 비용), 맥락은 파일로만 |
|
|
219
|
+
|
|
220
|
+
`per-iteration` 은 `max_iterations: 1` 을 요구한다 — 두 필드가 서로 다른 말을 하면 "한 바퀴만" 인지 "열 바퀴까지" 인지 정의가 모호해진다. 검증기가 막는다.
|
|
221
|
+
|
|
222
|
+
**어느 쪽이 결과가 나은지는 vibe 가 측정한 바 없다.** 컨텍스트 누적이 품질을 떨어뜨린다는 주장은 널리 퍼져 있지만 이 저장소에는 비교 데이터가 없다(수치 출처 규율 §3.5). 그래서 기본값을 바꾸지 않고 **축만 열어둔다** — 긴 무인 운전에서 컨텍스트 상한이 걱정되면 `per-iteration`, 회전 간 연속성이 중요하면 `continuous`.
|
|
223
|
+
|
|
224
|
+
전제 하나는 반드시 지킨다: `per-iteration` 에서 **넘길 것을 파일에 적기 전에 끝내지 않는다.** 맥락이 파일로만 넘어가는 구조이므로, 안 적으면 이월이 아니라 유실이다.
|
|
225
|
+
|
|
198
226
|
### 시운전 (처음 거는 루프)
|
|
199
227
|
승인 이력이 없는 루프는 **`trial_iterations`(기본 2) 회전만 돌고 멈춘다.** `max_iterations` 와 다른 축이다 — 그건 한 실행의 폭주를 막고, 이건 **정의가 검증되지 않은 루프**를 막는다. 폭주 예산은 매 `start` 마다 초기화되지만 시운전 회전은 실행을 가로질러 누적한다(다시 걸기만 해도 연장되면 게이트가 무의미하다).
|
|
200
228
|
|
|
@@ -11,9 +11,19 @@ pipeline:
|
|
|
11
11
|
- vibe.spec
|
|
12
12
|
- vibe.run
|
|
13
13
|
- vibe.verify
|
|
14
|
+
# ledger(기본) | tests | visual | none
|
|
15
|
+
# visual: 렌더 결과를 완료 기준으로 삼는다. visual_command(게이트, exit 0)와
|
|
16
|
+
# artifact_dir(증거, 스크린샷·diff)이 함께 필요하다.
|
|
17
|
+
# 모델이 화면을 보고 판정하는 것이 아니다 — 판정은 exit code 다.
|
|
14
18
|
verify: ledger
|
|
15
19
|
max_iterations: 10
|
|
16
20
|
isolation: none
|
|
21
|
+
# continuous: 한 호출에서 max_iterations 까지 계속 돈다 (기본)
|
|
22
|
+
# per-iteration: 한 바퀴만 돌고 끝낸다 — 반복은 스케줄러가 만든다.
|
|
23
|
+
# 컨텍스트가 호출마다 0에서 시작하므로 누적이 없다. 대신 매번 ANCHOR 문서를
|
|
24
|
+
# 다시 읽어야 하고, 회전 사이 맥락은 파일(원장·인박스)로만 넘어간다.
|
|
25
|
+
# 쓰려면 max_iterations 를 1 로 맞춰야 한다.
|
|
26
|
+
session: continuous
|
|
17
27
|
status: active
|
|
18
28
|
---
|
|
19
29
|
|