mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
- Read URL tab parameter using useSearchParams - Initialize locationFilter to 'hub' when tab=hub is present - Allows /skill-hub route to correctly display hub content
347 lines
12 KiB
Markdown
347 lines
12 KiB
Markdown
# Analyze Task Generation Spec
|
|
|
|
> **Purpose**: Quality standards for converting `conclusions.json` recommendations into `.task/*.json` files.
|
|
> **Consumer**: Phase 5 of `analyze-with-file` workflow.
|
|
> **Execution**: Handled by `unified-execute-with-file` — this document covers generation only.
|
|
|
|
---
|
|
|
|
## Task Generation Flow
|
|
|
|
```
|
|
conclusions.json ──┐
|
|
├── resolveTargetFiles() ──┐
|
|
codebaseContext ───┘ ├── .task/TASK-001.json
|
|
├── .task/TASK-002.json
|
|
explorations.json ── enrichContext() ─────────┘
|
|
```
|
|
|
|
**Input artifacts** (all from session folder):
|
|
|
|
| Artifact | Required | Provides |
|
|
|----------|----------|----------|
|
|
| `conclusions.json` | Yes | `recommendations[]` with action, rationale, priority, target_files, changes, implementation_hints, evidence_refs |
|
|
| `exploration-codebase.json` | No | `relevant_files[]`, `patterns[]`, `constraints[]`, `integration_points[]` — primary source for file resolution |
|
|
| `explorations.json` | No | `sources[]`, `key_findings[]` — fallback for file resolution |
|
|
| `perspectives.json` | No | Multi-perspective findings — alternative to explorations.json |
|
|
|
|
---
|
|
|
|
## File Resolution Algorithm
|
|
|
|
Target files are resolved with a 3-priority fallback chain:
|
|
|
|
```javascript
|
|
function resolveTargetFiles(rec, codebaseContext, explorations) {
|
|
// Priority 1: Explicit target_files from recommendations (Phase 4 enriched)
|
|
if (rec.target_files?.length) {
|
|
return rec.target_files.map(path => ({
|
|
path,
|
|
action: 'modify',
|
|
target: null,
|
|
changes: rec.changes || []
|
|
}))
|
|
}
|
|
|
|
// Priority 2: Match from exploration-codebase.json relevant_files
|
|
if (codebaseContext?.relevant_files?.length) {
|
|
const keywords = extractKeywords(rec.action + ' ' + rec.rationale)
|
|
const matched = codebaseContext.relevant_files.filter(f =>
|
|
keywords.some(kw =>
|
|
f.path.toLowerCase().includes(kw) ||
|
|
f.summary?.toLowerCase().includes(kw) ||
|
|
f.relevance?.toLowerCase().includes(kw)
|
|
)
|
|
)
|
|
if (matched.length) {
|
|
return matched.map(f => ({
|
|
path: f.path,
|
|
action: 'modify',
|
|
target: null,
|
|
changes: rec.changes || []
|
|
}))
|
|
}
|
|
}
|
|
|
|
// Priority 3: Match from explorations.json sources
|
|
if (explorations?.sources?.length) {
|
|
const actionVerb = rec.action.split(' ')[0].toLowerCase()
|
|
const matched = explorations.sources.filter(s =>
|
|
s.summary?.toLowerCase().includes(actionVerb) ||
|
|
s.file?.includes(actionVerb)
|
|
)
|
|
if (matched.length) {
|
|
return matched.map(s => ({
|
|
path: s.file,
|
|
action: 'modify',
|
|
target: null,
|
|
changes: []
|
|
}))
|
|
}
|
|
}
|
|
|
|
// Fallback: empty array — task relies on description + implementation for guidance
|
|
return []
|
|
}
|
|
|
|
function extractKeywords(text) {
|
|
return text
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9\u4e00-\u9fa5\s]/g, ' ')
|
|
.split(/\s+/)
|
|
.filter(w => w.length > 2)
|
|
.filter(w => !['the', 'and', 'for', 'with', 'from', 'that', 'this'].includes(w))
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Task Type Inference
|
|
|
|
| Recommendation Pattern | Inferred Type |
|
|
|------------------------|---------------|
|
|
| fix, resolve, repair, patch, correct | `fix` |
|
|
| refactor, restructure, extract, reorganize, decouple | `refactor` |
|
|
| add, implement, create, build, introduce | `feature` |
|
|
| improve, optimize, enhance, upgrade, streamline | `enhancement` |
|
|
| test, coverage, validate, verify, assert | `testing` |
|
|
|
|
```javascript
|
|
function inferTaskType(rec) {
|
|
const text = (rec.action + ' ' + rec.rationale).toLowerCase()
|
|
const patterns = [
|
|
{ type: 'fix', keywords: ['fix', 'resolve', 'repair', 'patch', 'correct', 'bug'] },
|
|
{ type: 'refactor', keywords: ['refactor', 'restructure', 'extract', 'reorganize', 'decouple'] },
|
|
{ type: 'feature', keywords: ['add', 'implement', 'create', 'build', 'introduce'] },
|
|
{ type: 'enhancement', keywords: ['improve', 'optimize', 'enhance', 'upgrade', 'streamline'] },
|
|
{ type: 'testing', keywords: ['test', 'coverage', 'validate', 'verify', 'assert'] }
|
|
]
|
|
for (const p of patterns) {
|
|
if (p.keywords.some(kw => text.includes(kw))) return p.type
|
|
}
|
|
return 'enhancement' // safe default
|
|
}
|
|
```
|
|
|
|
## Effort Inference
|
|
|
|
| Signal | Effort |
|
|
|--------|--------|
|
|
| priority=high AND files >= 3 | `large` |
|
|
| priority=high OR files=2 | `medium` |
|
|
| priority=medium AND files <= 1 | `medium` |
|
|
| priority=low OR single file | `small` |
|
|
|
|
```javascript
|
|
function inferEffort(rec) {
|
|
const fileCount = rec.target_files?.length || 0
|
|
if (rec.priority === 'high' && fileCount >= 3) return 'large'
|
|
if (rec.priority === 'high' || fileCount >= 2) return 'medium'
|
|
if (rec.priority === 'low' || fileCount <= 1) return 'small'
|
|
return 'medium'
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Convergence Quality Validation
|
|
|
|
Every task's `convergence` MUST pass quality gates before writing to disk.
|
|
|
|
### Quality Rules
|
|
|
|
| Field | Requirement | Validation |
|
|
|-------|-------------|------------|
|
|
| `criteria[]` | **Testable** — assertions or concrete manual steps | Reject vague patterns; each criterion must reference observable behavior |
|
|
| `verification` | **Executable** — shell command or explicit step sequence | Must contain a runnable command or step-by-step verification procedure |
|
|
| `definition_of_done` | **Business language** — non-technical stakeholder can judge | Must NOT contain technical commands (jest, tsc, npm, build) |
|
|
|
|
### Vague Pattern Detection
|
|
|
|
```javascript
|
|
const VAGUE_PATTERNS = /正常|正确|好|可以|没问题|works|fine|good|correct|properly|as expected/i
|
|
const TECHNICAL_IN_DOD = /compile|build|lint|npm|npx|jest|tsc|eslint|cargo|pytest|go test/i
|
|
|
|
function validateConvergenceQuality(tasks) {
|
|
const issues = []
|
|
tasks.forEach(task => {
|
|
// Rule 1: No vague criteria
|
|
task.convergence.criteria.forEach((c, i) => {
|
|
if (VAGUE_PATTERNS.test(c) && c.length < 20) {
|
|
issues.push({
|
|
task: task.id, field: `criteria[${i}]`,
|
|
problem: 'Vague criterion', value: c,
|
|
fix: 'Replace with specific observable condition from evidence'
|
|
})
|
|
}
|
|
})
|
|
|
|
// Rule 2: Verification should be executable
|
|
if (task.convergence.verification && task.convergence.verification.length < 5) {
|
|
issues.push({
|
|
task: task.id, field: 'verification',
|
|
problem: 'Too short to be executable', value: task.convergence.verification,
|
|
fix: 'Provide shell command or numbered step sequence'
|
|
})
|
|
}
|
|
|
|
// Rule 3: DoD should be business language
|
|
if (TECHNICAL_IN_DOD.test(task.convergence.definition_of_done)) {
|
|
issues.push({
|
|
task: task.id, field: 'definition_of_done',
|
|
problem: 'Contains technical commands', value: task.convergence.definition_of_done,
|
|
fix: 'Rewrite in business language describing user/system outcome'
|
|
})
|
|
}
|
|
|
|
// Rule 4: files[].changes should not be empty when files exist
|
|
task.files?.forEach((f, i) => {
|
|
if (f.action === 'modify' && (!f.changes || f.changes.length === 0) && !f.change) {
|
|
issues.push({
|
|
task: task.id, field: `files[${i}].changes`,
|
|
problem: 'No change description for modify action', value: f.path,
|
|
fix: 'Describe what specifically changes in this file'
|
|
})
|
|
}
|
|
})
|
|
|
|
// Rule 5: implementation steps should exist
|
|
if (!task.implementation || task.implementation.length === 0) {
|
|
issues.push({
|
|
task: task.id, field: 'implementation',
|
|
problem: 'No implementation steps',
|
|
fix: 'Add at least one step describing how to realize this task'
|
|
})
|
|
}
|
|
})
|
|
|
|
// Auto-fix where possible, log remaining issues
|
|
issues.forEach(issue => {
|
|
// Attempt auto-fix based on available evidence
|
|
// If unfixable, log warning — task still generated but flagged
|
|
})
|
|
return issues
|
|
}
|
|
```
|
|
|
|
### Good vs Bad Examples
|
|
|
|
**Criteria**:
|
|
|
|
| Bad | Good |
|
|
|-----|------|
|
|
| `"Code works correctly"` | `"refreshToken() returns a new JWT with >0 expiry when called with expired token"` |
|
|
| `"No errors"` | `"Error handler at auth.ts:45 returns 401 status with { error: 'token_expired' } body"` |
|
|
| `"Performance is good"` | `"API response time < 200ms at p95 for /api/users endpoint under 100 concurrent requests"` |
|
|
|
|
**Verification**:
|
|
|
|
| Bad | Good |
|
|
|-----|------|
|
|
| `"Check it"` | `"jest --testPathPattern=auth.test.ts && npx tsc --noEmit"` |
|
|
| `"Run tests"` | `"1. Run npm test -- --grep 'token refresh' 2. Verify no TypeScript errors with npx tsc --noEmit"` |
|
|
|
|
**Definition of Done**:
|
|
|
|
| Bad | Good |
|
|
|-----|------|
|
|
| `"jest passes"` | `"Users remain logged in across token expiration without manual re-login"` |
|
|
| `"No TypeScript errors"` | `"Authentication flow handles all user-facing error scenarios with clear error messages"` |
|
|
|
|
---
|
|
|
|
## Required Task Fields (analyze-with-file producer)
|
|
|
|
Per `task-schema.json` `_field_usage_by_producer`, the `analyze-with-file` producer MUST populate:
|
|
|
|
| Block | Fields | Required |
|
|
|-------|--------|----------|
|
|
| IDENTITY | `id`, `title`, `description` | Yes |
|
|
| CLASSIFICATION | `type`, `priority`, `effort` | Yes |
|
|
| DEPENDENCIES | `depends_on` | Yes (empty array if none) |
|
|
| CONVERGENCE | `convergence.criteria[]`, `convergence.verification`, `convergence.definition_of_done` | Yes |
|
|
| FILES | `files[].path`, `files[].action`, `files[].changes`/`files[].change` | Yes (if files identified) |
|
|
| IMPLEMENTATION | `implementation[]` with step + description | Yes |
|
|
| CONTEXT | `evidence`, `source.tool`, `source.session_id`, `source.original_id` | Yes |
|
|
|
|
### Task JSON Example
|
|
|
|
```json
|
|
{
|
|
"id": "TASK-001",
|
|
"title": "Fix authentication token refresh",
|
|
"description": "Token refresh fails silently when JWT expires, causing users to be logged out unexpectedly",
|
|
"type": "fix",
|
|
"priority": "high",
|
|
"effort": "medium",
|
|
"files": [
|
|
{
|
|
"path": "src/auth/token.ts",
|
|
"action": "modify",
|
|
"target": "refreshToken",
|
|
"changes": [
|
|
"Add await to refreshToken() call at line 89",
|
|
"Add error propagation for refresh failure"
|
|
],
|
|
"change": "Add await to refreshToken() call and propagate errors"
|
|
},
|
|
{
|
|
"path": "src/middleware/auth.ts",
|
|
"action": "modify",
|
|
"target": "authMiddleware",
|
|
"changes": [
|
|
"Update error handler at line 45 to distinguish refresh failures from auth failures"
|
|
],
|
|
"change": "Update error handler to propagate refresh failures"
|
|
}
|
|
],
|
|
"depends_on": [],
|
|
"convergence": {
|
|
"criteria": [
|
|
"refreshToken() returns new valid JWT when called with expired token",
|
|
"Expired token triggers automatic refresh without user action",
|
|
"Failed refresh returns 401 with { error: 'token_expired' } body"
|
|
],
|
|
"verification": "jest --testPathPattern=token.test.ts && npx tsc --noEmit",
|
|
"definition_of_done": "Users remain logged in across token expiration without manual re-login"
|
|
},
|
|
"implementation": [
|
|
{
|
|
"step": "1",
|
|
"description": "Add await to refreshToken() call in token.ts",
|
|
"actions": ["Read token.ts", "Add await keyword at line 89", "Verify async chain"]
|
|
},
|
|
{
|
|
"step": "2",
|
|
"description": "Update error handler in auth middleware",
|
|
"actions": ["Read auth.ts", "Modify error handler at line 45", "Add refresh-specific error type"]
|
|
}
|
|
],
|
|
"evidence": ["src/auth/token.ts:89", "src/middleware/auth.ts:45"],
|
|
"source": {
|
|
"tool": "analyze-with-file",
|
|
"session_id": "ANL-auth-token-refresh-2025-01-21",
|
|
"original_id": "TASK-001"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Execution Delegation
|
|
|
|
After `.task/*.json` generation, execution is handled by `unified-execute-with-file`:
|
|
|
|
```bash
|
|
/codex:unified-execute-with-file PLAN="${sessionFolder}/.task/"
|
|
```
|
|
|
|
The execution engine provides:
|
|
- Pre-execution analysis (dependency validation, file conflicts, topological sort)
|
|
- Serial task execution with convergence verification
|
|
- Progress tracking via `execution.md` + `execution-events.md`
|
|
- Auto-commit per task (conventional commit format)
|
|
- Failure handling with retry/skip/abort options
|
|
|
|
**No inline execution logic in analyze-with-file** — single execution engine avoids duplication and ensures consistent behavior across all skill producers.
|