@ai-content-space/loopx 0.1.2 → 0.1.4
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/README.md +422 -57
- package/README.zh-CN.md +485 -0
- package/assets/logo.svg +89 -0
- package/package.json +5 -1
- package/plugins/loopx/.codex-plugin/plugin.json +1 -1
- package/plugins/loopx/scripts/plugin-install.test.mjs +14 -0
- package/plugins/loopx/skills/archive/SKILL.md +49 -0
- package/plugins/loopx/skills/build/SKILL.md +111 -9
- package/plugins/loopx/skills/clarify/SKILL.md +129 -8
- package/plugins/loopx/skills/debug/SKILL.md +296 -0
- package/plugins/loopx/skills/debug/condition-based-waiting.md +115 -0
- package/plugins/loopx/skills/debug/defense-in-depth.md +122 -0
- package/plugins/loopx/skills/debug/find-polluter.sh +63 -0
- package/plugins/loopx/skills/debug/root-cause-tracing.md +169 -0
- package/plugins/loopx/skills/go-style/SKILL.md +71 -0
- package/plugins/loopx/skills/kratos/SKILL.md +74 -0
- package/plugins/loopx/skills/kratos/references/advanced-features.md +314 -0
- package/plugins/loopx/skills/kratos/references/architecture.md +488 -0
- package/plugins/loopx/skills/kratos/references/configuration.md +399 -0
- package/plugins/loopx/skills/kratos/references/http-customization.md +512 -0
- package/plugins/loopx/skills/kratos/references/middleware-logging.md +400 -0
- package/plugins/loopx/skills/kratos/references/proto-api-design.md +432 -0
- package/plugins/loopx/skills/kratos/references/security-auth.md +411 -0
- package/plugins/loopx/skills/kratos/references/troubleshooting.md +385 -0
- package/plugins/loopx/skills/plan/SKILL.md +24 -3
- package/plugins/loopx/skills/review/SKILL.md +98 -1
- package/plugins/loopx/skills/tdd/SKILL.md +371 -0
- package/plugins/loopx/skills/tdd/testing-anti-patterns.md +299 -0
- package/plugins/loopx/skills/verify/SKILL.md +139 -0
- package/scripts/codex-stop-hook.mjs +71 -0
- package/scripts/codex-workflow-hook.mjs +248 -0
- package/skills/archive/SKILL.md +49 -0
- package/skills/build/SKILL.md +111 -9
- package/skills/clarify/SKILL.md +129 -8
- package/skills/debug/SKILL.md +296 -0
- package/skills/debug/condition-based-waiting.md +115 -0
- package/skills/debug/defense-in-depth.md +122 -0
- package/skills/debug/find-polluter.sh +63 -0
- package/skills/debug/root-cause-tracing.md +169 -0
- package/skills/go-style/SKILL.md +71 -0
- package/skills/kratos/SKILL.md +74 -0
- package/skills/kratos/references/advanced-features.md +314 -0
- package/skills/kratos/references/architecture.md +488 -0
- package/skills/kratos/references/configuration.md +399 -0
- package/skills/kratos/references/http-customization.md +512 -0
- package/skills/kratos/references/middleware-logging.md +400 -0
- package/skills/kratos/references/proto-api-design.md +432 -0
- package/skills/kratos/references/security-auth.md +411 -0
- package/skills/kratos/references/troubleshooting.md +385 -0
- package/skills/plan/SKILL.md +20 -3
- package/skills/review/SKILL.md +98 -1
- package/skills/tdd/SKILL.md +371 -0
- package/skills/tdd/testing-anti-patterns.md +299 -0
- package/skills/verify/SKILL.md +139 -0
- package/src/build-runtime.mjs +311 -26
- package/src/build-stop-gate.mjs +94 -0
- package/src/cli.mjs +57 -5
- package/src/codex-exec-runtime.mjs +105 -5
- package/src/context-manifest.mjs +172 -0
- package/src/html-views.mjs +316 -0
- package/src/install-discovery.mjs +352 -5
- package/src/next-skill.mjs +57 -5
- package/src/plan-runtime.mjs +102 -122
- package/src/review-runtime.mjs +558 -0
- package/src/runtime-maintenance.mjs +429 -14
- package/src/template-governance.mjs +223 -0
- package/src/workflow.mjs +2341 -120
- package/src/workspace-context.mjs +166 -0
- package/src/workspace-memory.mjs +69 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Guide for common Kratos issues and debugging techniques.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Route override problems
|
|
8
|
+
- Zero-value field issues
|
|
9
|
+
- Validation errors on partial updates
|
|
10
|
+
- Enum display issues
|
|
11
|
+
- Debugging runtime behavior
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Route Override Issue
|
|
16
|
+
|
|
17
|
+
### Problem
|
|
18
|
+
|
|
19
|
+
Generic routes shadow specific routes when defined first:
|
|
20
|
+
|
|
21
|
+
```protobuf
|
|
22
|
+
// WRONG: specific route shadowed
|
|
23
|
+
rpc GetUser(GetUserRequest) returns (User) {
|
|
24
|
+
option (google.api.http) = {get: "/v1/user/{user_id}"}; // Matches "profile"!
|
|
25
|
+
}
|
|
26
|
+
rpc GetProfile(GetProfileRequest) returns (Profile) {
|
|
27
|
+
option (google.api.http) = {get: "/v1/user/profile"}; // Never matched
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Solution
|
|
32
|
+
|
|
33
|
+
Define specific routes before generic ones:
|
|
34
|
+
|
|
35
|
+
```protobuf
|
|
36
|
+
// CORRECT: specific route first
|
|
37
|
+
rpc GetProfile(GetProfileRequest) returns (Profile) {
|
|
38
|
+
option (google.api.http) = {get: "/v1/user/profile"}; // Matches first
|
|
39
|
+
}
|
|
40
|
+
rpc GetUser(GetUserRequest) returns (User) {
|
|
41
|
+
option (google.api.http) = {get: "/v1/user/{user_id}"}; // Matches remaining
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Why this matters:** HTTP routers match in order. `{user_id}` is a wildcard that matches any string including "profile".
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Zero-Value Field Issue
|
|
50
|
+
|
|
51
|
+
### Problem
|
|
52
|
+
|
|
53
|
+
Protobuf by default omits fields with zero values (empty string, 0, false, nil):
|
|
54
|
+
|
|
55
|
+
```go
|
|
56
|
+
// Proto message
|
|
57
|
+
message User {
|
|
58
|
+
string name = 1;
|
|
59
|
+
int32 age = 2;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Response
|
|
63
|
+
{name: "", age: 0}
|
|
64
|
+
|
|
65
|
+
// JSON output: {} // Empty! All fields omitted.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Solution 1: EmitUnpopulated
|
|
69
|
+
|
|
70
|
+
```go
|
|
71
|
+
import "google.golang.org/protobuf/encoding/protojson"
|
|
72
|
+
|
|
73
|
+
var MarshalOptions = protojson.MarshalOptions{
|
|
74
|
+
EmitUnpopulated: true, // Include zero values
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Custom codec
|
|
78
|
+
func (codec) Marshal(v interface{}) ([]byte, error) {
|
|
79
|
+
if m, ok := v.(proto.Message); ok {
|
|
80
|
+
return MarshalOptions.Marshal(m)
|
|
81
|
+
}
|
|
82
|
+
return json.Marshal(v)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Solution 2: anypb.New Wrapper
|
|
87
|
+
|
|
88
|
+
```go
|
|
89
|
+
import "google.golang.org/protobuf/types/known/anypb"
|
|
90
|
+
|
|
91
|
+
payload, err := anypb.New(m)
|
|
92
|
+
reply.Data = payload
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Note:** Adds `@type` field: `{"@type": "type.googleapis.com/...", "value": {...}}`
|
|
96
|
+
|
|
97
|
+
### Solution 3: Remove omitempty
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Makefile - remove omitempty from pb.go tags
|
|
101
|
+
find ./api -name '*.pb.go' -exec sed -i -e "s/,omitempty/,optional/g" {} \;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Partial Update Validation Issue
|
|
107
|
+
|
|
108
|
+
### Problem
|
|
109
|
+
|
|
110
|
+
Validate middleware checks all fields, but partial updates (PATCH) may only send some:
|
|
111
|
+
|
|
112
|
+
```protobuf
|
|
113
|
+
message UpdateUserRequest {
|
|
114
|
+
string user_id = 1 [(buf.validate.field).string.min_len = 1]; // Required
|
|
115
|
+
string name = 2 [(buf.validate.field).string.min_len = 1]; // Required
|
|
116
|
+
string email = 3 [(buf.validate.field).string.email = true]; // Required
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// PATCH request only sends name
|
|
120
|
+
{name: "John", user_id: "123", email: ""} // Fails validation! email is required.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Solution 1: Whitelist Operations
|
|
124
|
+
|
|
125
|
+
Skip validation for specific operations:
|
|
126
|
+
|
|
127
|
+
```go
|
|
128
|
+
func WhitelistValidateMiddleware(whitelist map[string]bool) middleware.Middleware {
|
|
129
|
+
return func(handler middleware.Handler) middleware.Handler {
|
|
130
|
+
return func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
131
|
+
if tr, ok := transport.FromServerContext(ctx); ok {
|
|
132
|
+
if whitelist[tr.Operation()] {
|
|
133
|
+
return handler(ctx, req) // Skip validation
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Normal validation
|
|
137
|
+
if err := validator.Validate(req); err != nil {
|
|
138
|
+
return nil, err
|
|
139
|
+
}
|
|
140
|
+
return handler(ctx, req)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Usage
|
|
146
|
+
whitelist := map[string]bool{
|
|
147
|
+
"/api.v1.UserService/PatchUser": true,
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Solution 2: Manual Validation
|
|
152
|
+
|
|
153
|
+
Validate only changed fields in biz layer:
|
|
154
|
+
|
|
155
|
+
```go
|
|
156
|
+
func (uc *UserUseCase) PatchUser(ctx context.Context, req *v1.PatchUserRequest) error {
|
|
157
|
+
// Only validate if field is set
|
|
158
|
+
if req.Name != "" && len(req.Name) < 1 {
|
|
159
|
+
return errors.New(400, "INVALID_NAME", "name too short")
|
|
160
|
+
}
|
|
161
|
+
if req.Email != "" && !isValidEmail(req.Email) {
|
|
162
|
+
return errors.New(400, "INVALID_EMAIL", "invalid email")
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Enum as String Issue
|
|
170
|
+
|
|
171
|
+
### Problem
|
|
172
|
+
|
|
173
|
+
Custom ResponseEncoder may display enums as strings instead of numbers:
|
|
174
|
+
|
|
175
|
+
```protobuf
|
|
176
|
+
enum Status {
|
|
177
|
+
UNKNOWN = 0;
|
|
178
|
+
ACTIVE = 1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Expected JSON: {"status": 1}
|
|
182
|
+
// Actual JSON: {"status": "ACTIVE"} // String!
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Solution: UseEnumNumbers
|
|
186
|
+
|
|
187
|
+
```go
|
|
188
|
+
var MarshalOptions = protojson.MarshalOptions{
|
|
189
|
+
EmitUnpopulated: true,
|
|
190
|
+
UseEnumNumbers: true, // Enums as numbers
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
type codec struct{}
|
|
194
|
+
|
|
195
|
+
func (codec) Marshal(v interface{}) ([]byte, error) {
|
|
196
|
+
if m, ok := v.(proto.Message); ok {
|
|
197
|
+
return MarshalOptions.Marshal(m)
|
|
198
|
+
}
|
|
199
|
+
return json.Marshal(v)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
func init() {
|
|
203
|
+
encoding.RegisterCodec(codec{})
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## HTTP Proto Unsupported Scenarios
|
|
210
|
+
|
|
211
|
+
### Problem
|
|
212
|
+
|
|
213
|
+
Some HTTP features can't be expressed in proto:
|
|
214
|
+
|
|
215
|
+
- File upload (multipart/form-data)
|
|
216
|
+
- WebSocket upgrade
|
|
217
|
+
- Server-Sent Events (SSE)
|
|
218
|
+
- Custom authentication flows
|
|
219
|
+
|
|
220
|
+
### Solution: Custom Routes
|
|
221
|
+
|
|
222
|
+
```go
|
|
223
|
+
func NewHTTPServer(c *conf.Server, svc *service.MyService) *http.Server {
|
|
224
|
+
srv := http.NewServer(
|
|
225
|
+
http.Address(c.Http.Addr),
|
|
226
|
+
http.Middleware(
|
|
227
|
+
recovery.Recovery(),
|
|
228
|
+
auth.Token(),
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
// Proto-generated routes
|
|
233
|
+
v1.RegisterMyServiceHTTPServer(srv, svc)
|
|
234
|
+
|
|
235
|
+
// Custom routes (inherit middleware)
|
|
236
|
+
route := srv.Route("/")
|
|
237
|
+
route.POST("/v1/upload", svc.UploadFile)
|
|
238
|
+
route.GET("/v1/ws", svc.WebSocketHandler)
|
|
239
|
+
|
|
240
|
+
return srv
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func (s *MyService) UploadFile(ctx http.Context) error {
|
|
244
|
+
http.SetOperation(ctx, "/upload.v1.UploadService/Upload")
|
|
245
|
+
|
|
246
|
+
// Use ctx.Middleware to inherit server middleware
|
|
247
|
+
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
248
|
+
return s.uc.Upload(ctx, req.(*UploadRequest))
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
resp, err := h(ctx, parseUploadRequest(ctx))
|
|
252
|
+
return ctx.JSON(200, resp)
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Debugging Tools
|
|
259
|
+
|
|
260
|
+
### statsviz - Real-time Runtime Metrics
|
|
261
|
+
|
|
262
|
+
Visualize Go runtime metrics in browser:
|
|
263
|
+
|
|
264
|
+
```go
|
|
265
|
+
import "github.com/arl/statsviz"
|
|
266
|
+
|
|
267
|
+
func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App {
|
|
268
|
+
statsviz.RegisterDefault() // Register /debug/statsviz/
|
|
269
|
+
|
|
270
|
+
return kratos.New(
|
|
271
|
+
kratos.Name("my-app"),
|
|
272
|
+
kratos.Server(hs, gs),
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Access at: `http://localhost:8000/debug/statsviz/`
|
|
278
|
+
|
|
279
|
+
Shows:
|
|
280
|
+
- Heap allocation
|
|
281
|
+
- Goroutine count
|
|
282
|
+
- GC pauses
|
|
283
|
+
- CPU usage
|
|
284
|
+
- Scheduler latency
|
|
285
|
+
|
|
286
|
+
### fgtrace - Timeline Profiler
|
|
287
|
+
|
|
288
|
+
```go
|
|
289
|
+
import "github.com/felixge/fgtrace"
|
|
290
|
+
|
|
291
|
+
// Enable in development only (causes stop-the-world pauses)
|
|
292
|
+
func init() {
|
|
293
|
+
if os.Getenv("ENV") == "dev" {
|
|
294
|
+
fgtrace.Start()
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### pprof - Standard Go Profiler
|
|
300
|
+
|
|
301
|
+
Built into Kratos HTTP server:
|
|
302
|
+
|
|
303
|
+
```go
|
|
304
|
+
import "net/http/pprof"
|
|
305
|
+
|
|
306
|
+
// Automatically available at /debug/pprof/
|
|
307
|
+
// - /debug/pprof/heap - memory profile
|
|
308
|
+
// - /debug/pprof/goroutine - goroutine profile
|
|
309
|
+
// - /debug/pprof/profile?seconds=30 - CPU profile
|
|
310
|
+
// - /debug/pprof/trace - execution trace
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Common Error Patterns
|
|
316
|
+
|
|
317
|
+
### Error Creation
|
|
318
|
+
|
|
319
|
+
```go
|
|
320
|
+
import "github.com/go-kratos/kratos/v2/errors"
|
|
321
|
+
|
|
322
|
+
// Standard errors
|
|
323
|
+
var ErrUserNotFound = errors.NotFound("USER_NOT_FOUND", "user not found")
|
|
324
|
+
|
|
325
|
+
// With details
|
|
326
|
+
func (uc *UserUseCase) GetUser(ctx context.Context, id string) (*User, error) {
|
|
327
|
+
user, err := uc.repo.FindByID(ctx, id)
|
|
328
|
+
if err != nil {
|
|
329
|
+
return nil, errors.NotFound("USER_NOT_FOUND", "user %s not found", id)
|
|
330
|
+
}
|
|
331
|
+
return user, nil
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Error Response Format
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"code": 404,
|
|
340
|
+
"reason": "USER_NOT_FOUND",
|
|
341
|
+
"message": "user 123 not found",
|
|
342
|
+
"metadata": {
|
|
343
|
+
"user_id": "123"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Error Checking
|
|
349
|
+
|
|
350
|
+
```go
|
|
351
|
+
// Check error type
|
|
352
|
+
if errors.Is(err, v1.ErrUserNotFound) {
|
|
353
|
+
// Handle user not found
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Check error code
|
|
357
|
+
if se := errors.FromError(err); se.Code == 404 {
|
|
358
|
+
// Handle not found
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## gRPC Error Mapping
|
|
365
|
+
|
|
366
|
+
Kratos HTTP gateway maps HTTP status to gRPC status:
|
|
367
|
+
|
|
368
|
+
| HTTP Status | gRPC Status |
|
|
369
|
+
|-------------|-------------|
|
|
370
|
+
| 400 | InvalidArgument |
|
|
371
|
+
| 401 | Unauthenticated |
|
|
372
|
+
| 403 | PermissionDenied |
|
|
373
|
+
| 404 | NotFound |
|
|
374
|
+
| 409 | AlreadyExists |
|
|
375
|
+
| 500 | Internal |
|
|
376
|
+
| 503 | Unavailable |
|
|
377
|
+
|
|
378
|
+
```go
|
|
379
|
+
// Create HTTP-compatible error
|
|
380
|
+
errors.BadRequest("INVALID_PARAM", "invalid parameter")
|
|
381
|
+
// → HTTP 400, gRPC InvalidArgument
|
|
382
|
+
|
|
383
|
+
errors.Unauthenticated("TOKEN_EXPIRED", "token expired")
|
|
384
|
+
// → HTTP 401, gRPC Unauthenticated
|
|
385
|
+
```
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -29,6 +29,7 @@ By default, `plan` includes the full consensus review loop formerly documented u
|
|
|
29
29
|
- Default planning is consensus-first, not lightweight-by-default.
|
|
30
30
|
- Treat the clarify spec as source of truth; do not re-interview unless the spec is incomplete or contradictory.
|
|
31
31
|
- Keep planning artifact-bound: produce PRD, architecture, development plan, and test plan outputs.
|
|
32
|
+
- Preserve accepted intent as durable change artifacts: proposal, spec delta, design, tasks, and artifact dependency graph.
|
|
32
33
|
- Separate planning approval from execution approval.
|
|
33
34
|
- Do not start implementation from `plan`.
|
|
34
35
|
- Prefer a smaller executable plan over a broad plan that cannot be verified.
|
|
@@ -39,7 +40,7 @@ By default, `plan` includes the full consensus review loop formerly documented u
|
|
|
39
40
|
Accepted inputs:
|
|
40
41
|
|
|
41
42
|
- an approved loopx clarify workflow slug
|
|
42
|
-
- `.loopx/
|
|
43
|
+
- `.loopx/intake/clarify-*.md`
|
|
43
44
|
- `.omx/specs/deep-interview-*.md`
|
|
44
45
|
- a direct task description when enough context is already present
|
|
45
46
|
- `--direct <spec-path>` to force a specific requirements artifact
|
|
@@ -59,8 +60,8 @@ If no requirements artifact is provided, derive a task slug and run pre-context
|
|
|
59
60
|
Before planning:
|
|
60
61
|
|
|
61
62
|
1. Derive a task slug.
|
|
62
|
-
2. Reuse the latest relevant `.
|
|
63
|
-
3. If none exists, create `.
|
|
63
|
+
2. Reuse the latest relevant `.loopx/context/{slug}-*.md` snapshot when available.
|
|
64
|
+
3. If none exists, create `.loopx/context/{slug}-{timestamp}.md` with:
|
|
64
65
|
- task statement
|
|
65
66
|
- desired outcome
|
|
66
67
|
- source requirements artifact
|
|
@@ -162,11 +163,19 @@ On approval, write canonical planning artifacts:
|
|
|
162
163
|
- `.loopx/workflows/<slug>/test-plan.md`
|
|
163
164
|
- `.loopx/plans/prd-<slug>.md`
|
|
164
165
|
- `.loopx/plans/test-spec-<slug>.md`
|
|
166
|
+
- `.loopx/changes/active/<change-id>/proposal.md`
|
|
167
|
+
- `.loopx/changes/active/<change-id>/spec-delta.md`
|
|
168
|
+
- `.loopx/changes/active/<change-id>/design.md`
|
|
169
|
+
- `.loopx/changes/active/<change-id>/tasks.md`
|
|
170
|
+
- `.loopx/changes/active/<change-id>/slices.json`
|
|
171
|
+
- `.loopx/changes/active/<change-id>/artifact-graph.json`
|
|
165
172
|
|
|
166
173
|
The final plan must include:
|
|
167
174
|
|
|
168
175
|
- ADR: Decision, Drivers, Alternatives considered, Why chosen, Consequences, Follow-ups
|
|
169
176
|
- concrete implementation steps sized to the actual task
|
|
177
|
+
- target long-lived spec domains and an OpenSpec-style requirements delta for archive
|
|
178
|
+
- vertical slices sized as independently verifiable tracer bullets, not horizontal layer-only task groups
|
|
170
179
|
- execution inputs mapped to concrete sources before build starts
|
|
171
180
|
- available execution lanes and recommended lane
|
|
172
181
|
- test and verification commands
|
|
@@ -199,6 +208,9 @@ Without `--interactive`, report the approved plan and recommended next command,
|
|
|
199
208
|
- `plan_architect_review_status`: `not-started|complete|changes-requested`
|
|
200
209
|
- `plan_critic_verdict`: `none|approve|iterate|reject`
|
|
201
210
|
- `plan_package_status`: `missing|partial|complete`
|
|
211
|
+
- `change_artifacts_status`: `missing|partial|complete|archived`
|
|
212
|
+
- `spec_delta_status`: `missing|partial|complete`
|
|
213
|
+
- `slice_artifacts_status`: `missing|partial|complete`
|
|
202
214
|
- `plan_acceptance_criteria_testable`: `true|false`
|
|
203
215
|
- `plan_verification_steps_resolved`: `true|false`
|
|
204
216
|
- `plan_execution_inputs_resolved`: `true|false`
|
|
@@ -207,6 +219,10 @@ Without `--interactive`, report the approved plan and recommended next command,
|
|
|
207
219
|
The plan gate is blocked until:
|
|
208
220
|
|
|
209
221
|
- plan package artifacts exist
|
|
222
|
+
- change proposal, spec delta, design, tasks, vertical slices, and artifact graph exist
|
|
223
|
+
- spec delta declares target domains and `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` blocks
|
|
224
|
+
- every ADDED or MODIFIED requirement uses `### Requirement:`, contains SHALL or MUST text, and includes at least one `#### Scenario:`
|
|
225
|
+
- vertical slices contain at least one `AFK` or `HITL` end-to-end slice with acceptance criteria and verification signal
|
|
210
226
|
- Architect review is complete
|
|
211
227
|
- Critic verdict is `approve`
|
|
212
228
|
- acceptance criteria are testable
|
|
@@ -229,6 +245,7 @@ Primary outputs:
|
|
|
229
245
|
|
|
230
246
|
- approved plan package under `.loopx/workflows/<slug>/`
|
|
231
247
|
- canonical PRD and test spec under `.loopx/plans/`
|
|
248
|
+
- change artifacts under `.loopx/changes/active/<change-id>/`
|
|
232
249
|
- consensus review summary with Planner / Architect / Critic evidence
|
|
233
250
|
- next-step recommendation
|
|
234
251
|
|
package/skills/review/SKILL.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: review
|
|
3
3
|
description: Repo-local acceptance surface for loopx.
|
|
4
|
+
argument-hint: "<execution-record path or workflow slug>"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# loopx Review
|
|
@@ -9,21 +10,117 @@ description: Repo-local acceptance surface for loopx.
|
|
|
9
10
|
|
|
10
11
|
Repo-local acceptance surface for loopx. Use it to evaluate the execution package from `build` and return an explicit go / no-go result.
|
|
11
12
|
|
|
13
|
+
## Inputs
|
|
14
|
+
|
|
15
|
+
Preferred skill input:
|
|
16
|
+
|
|
17
|
+
- `.loopx/workflows/<slug>/execution-record.md`
|
|
18
|
+
|
|
19
|
+
Compatible skill / CLI input:
|
|
20
|
+
|
|
21
|
+
- `<slug>`
|
|
22
|
+
|
|
23
|
+
When invoked with an execution record path, derive `<slug>` from the workflow directory and evaluate the matching active run.
|
|
24
|
+
|
|
12
25
|
## Expected Outputs
|
|
13
26
|
|
|
14
27
|
- a review artifact tied to the run being evaluated
|
|
15
28
|
- verdict and rationale
|
|
16
|
-
-
|
|
29
|
+
- code review findings for the implementation diff, including file / line references when issues are found
|
|
30
|
+
- architecture-smell findings from the internal review lane, focused on module depth, test seams, domain vocabulary, duplicated rules, and plan architecture alignment
|
|
31
|
+
- rollback/fix guidance when execution is incomplete, unstable, or needs another iteration
|
|
32
|
+
- an explicit `Next:` block with the exact next skill command when more work remains
|
|
33
|
+
|
|
34
|
+
## User Notification Language
|
|
35
|
+
|
|
36
|
+
The final user-facing review result must be written in Chinese.
|
|
37
|
+
|
|
38
|
+
Use stable machine values only where they are commands, file paths, JSON/state fields, or exact verdict identifiers. The human-readable summary, rationale, findings, residual risks, rollback guidance, and next-step instruction must be Chinese.
|
|
17
39
|
|
|
18
40
|
## Decision Boundary
|
|
19
41
|
|
|
20
42
|
- Use this only after build has produced execution and verification evidence for a specific run.
|
|
21
43
|
- Stop here if review evidence is incomplete. `review` remains an independent gate and does not auto-complete the workflow.
|
|
44
|
+
- Review must include code review of the build-owned implementation diff. Do not limit review to artifact/schema checks.
|
|
45
|
+
- Review must include the architecture-smell lane as part of review evidence. This is not a new workflow stage and must not create extra user steps.
|
|
46
|
+
- Review must compare the execution scope against the approved workflow scope. If `execution-record.md` declares non-empty `remaining_scope`, `completion_claim` other than `full`, or a mismatch between `planned_scope` and `implemented_scope`, review must return no-go and route to build or plan. A partial slice may be accepted as useful work, but it must not be approved as full workflow completion.
|
|
47
|
+
- Code review findings should focus on real bugs, regressions, missing tests, broken contracts, security/data-integrity risks, and user-visible behavior gaps.
|
|
48
|
+
- If code review finds blocking high or medium severity issues, return a no-go verdict and rollback guidance instead of approving completion.
|
|
49
|
+
- If architecture-smell findings are only advisory, record them as warnings without blocking. Block only when module seams, testability, domain boundaries, duplicated rules, or plan architecture assumptions are materially wrong.
|
|
50
|
+
- Route request-changes by problem type:
|
|
51
|
+
- implementation bugs, missing tests, small contract fixes: `review -> build`
|
|
52
|
+
- wrong plan, wrong architecture, unresolved execution inputs: `review -> plan`
|
|
53
|
+
- unclear product requirements or decision boundaries: `review -> clarify`
|
|
54
|
+
- Do not route implementation-only fixes back to plan unless the plan itself is wrong.
|
|
55
|
+
|
|
56
|
+
## Next Step Format
|
|
57
|
+
|
|
58
|
+
Every no-go review result must end with a concrete next command block.
|
|
59
|
+
|
|
60
|
+
For implementation fixes:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
Next:
|
|
64
|
+
$build --from-review .loopx/workflows/<slug>/review-report.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The review artifact is the direct rework contract for implementation fixes. `$build --from-review ...` must load the review findings first, while still using the approved PRD, test spec, previous `execution-record.md`, and workflow-local plan package as supporting context. Do not make the normal Codex-facing handoff require a separate bash `loopx approve ... --from review --to build` step.
|
|
68
|
+
|
|
69
|
+
For CLI/runtime debugging only, the equivalent state transition is:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
loopx build --from-review .loopx/workflows/<slug>/review-report.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For plan fixes:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Next:
|
|
79
|
+
loopx approve <slug> --from review --to plan
|
|
80
|
+
$plan <slug>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For clarify fixes:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
Next:
|
|
87
|
+
loopx approve <slug> --from review --to clarify
|
|
88
|
+
$clarify <slug>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For approval:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
Next:
|
|
95
|
+
loopx approve <slug> --from review --to done
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
After the workflow reaches `done`, run:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
$archive <slug>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This syncs the approved `.loopx/changes/active/<change-id>/spec-delta.md` into long-lived `.loopx/specs/` files and moves the change folder under `.loopx/changes/archive/<change-id>/`.
|
|
105
|
+
|
|
106
|
+
## Support Skill Review Lenses
|
|
107
|
+
|
|
108
|
+
Use loopx support skills as review lenses, not as implementation instructions:
|
|
109
|
+
|
|
110
|
+
- `verify`: Evidence lens. Reject completion, passing, or review-ready claims that lack fresh command output and exit status.
|
|
111
|
+
- `scope`: Completion lens. Reject full-completion claims when the execution record still declares remaining workflow scope or only a partial slice was implemented.
|
|
112
|
+
- `tdd`: Behavior-change lens. Feature work and bug fixes should include failing-test or regression-test evidence unless the execution record explicitly explains why tests are not applicable.
|
|
113
|
+
- `debug`: Failure-analysis lens. Fixes for bugs, test failures, build failures, and unexpected behavior should document root cause, not only symptoms or attempted patches.
|
|
114
|
+
- `go-style`: Go diff lens. For `.go` changes, review happy-path structure, error handling, context usage, interface boundaries, naming, table tests, and `gofmt`/Go verification evidence.
|
|
115
|
+
- `kratos`: Kratos diff lens. For Kratos/proto/service/biz/data/middleware/auth/config changes, review layer boundaries, generated-code flow, proto/package contracts, middleware/auth ordering, config compatibility, and project-native verification.
|
|
116
|
+
|
|
117
|
+
These lenses can produce review findings when the execution package violates them. Do not run new build work from `review`; request rollback or changes instead.
|
|
22
118
|
|
|
23
119
|
## Must Not Decide Automatically
|
|
24
120
|
|
|
25
121
|
- final completion without an explicit approval step
|
|
26
122
|
- re-running build work inside the review surface
|
|
123
|
+
- editing code or rerunning build from inside review
|
|
27
124
|
|
|
28
125
|
## Notes
|
|
29
126
|
|