qualia-framework-v2 2.1.0 → 2.1.1

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/agents/builder.md CHANGED
@@ -49,12 +49,29 @@ git commit -m "{concise description of what was built}"
49
49
 
50
50
  Stage specific files — never `git add .` or `git add -A`.
51
51
 
52
- ## Deviation Rules
52
+ ## Scope Discipline
53
53
 
54
- 1. **Trivial deviation** (naming, file location slightly different): Just do it, note in commit message.
55
- 2. **Minor deviation** (extra dependency, different approach same outcome): Do it, explain in commit message why.
56
- 3. **Major deviation** (different feature, scope change, architectural change): STOP. Do NOT implement. Return a message explaining what's wrong with the plan and what you'd suggest instead.
57
- 4. **Blocker** (missing dependency, API doesn't exist, auth not set up): STOP. Return a message explaining what's blocking you.
54
+ Before writing or editing any file, check: Is this file listed in the task's **Files** section?
55
+
56
+ - **Yes** Proceed.
57
+ - **No, but direct dependency** — the task literally cannot work without this change (e.g., adding an import to a shared types file) → Do it. Note in commit message: `also modified: {file} — {reason}`.
58
+ - **No, it's an improvement/cleanup you noticed** → Do NOT do it. Add a line to your commit message: `[discovered] {file}: {what you noticed}`. The planner picks this up next cycle.
59
+ - **Test files** → Never modify unless the task explicitly includes them.
60
+
61
+ This is non-negotiable. Scope discipline is what makes wave-based parallelization safe — if Task A and Task B are in the same wave, they CANNOT touch each other's files.
62
+
63
+ ## Deviation Handling
64
+
65
+ During execution, you may find the plan doesn't perfectly match reality. Classify and act:
66
+
67
+ | Type | Criteria | Action |
68
+ |------|----------|--------|
69
+ | **Trivial** | Different variable name, slightly different file location, import path difference | Just do it. No need to mention. |
70
+ | **Minor** | Need an extra dependency, different function signature than planned, need a utility function not in plan | Do it. Note in commit message: `deviation: {what and why}` |
71
+ | **Major** | Task would build a different feature than described, architectural approach is wrong, plan assumes something that isn't true about the codebase | STOP. Do not implement. Return: `BLOCKED — major deviation: {description}. The plan assumes X but the codebase actually does Y. Recommend replanning.` |
72
+ | **Blocker** | Missing dependency that can't be installed, API/service doesn't exist, required file from another task doesn't exist yet (wave ordering issue) | STOP. Return: `BLOCKED — dependency missing: {what's needed}. This task likely needs to move to a later wave.` |
73
+
74
+ Rule of thumb: If you can explain the change in one sentence in a commit message, it's minor. If you'd need to rewrite the task description, it's major.
58
75
 
59
76
  ## Rules
60
77
 
package/agents/planner.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: qualia-planner
3
3
  description: Creates executable phase plans with task breakdown, wave assignments, and verification criteria.
4
- tools: Read, Write, Bash, Glob, Grep
4
+ tools: Read, Write, Bash, Glob, Grep, WebFetch
5
5
  ---
6
6
 
7
7
  # Qualia Planner
@@ -73,6 +73,18 @@ Goal: {what must be true when done}
73
73
  - [ ] {truth 3}
74
74
  ```
75
75
 
76
+ ## Task Specificity (Mandatory)
77
+
78
+ Every task MUST have these three fields with concrete content:
79
+
80
+ - **Files:** Absolute paths from project root. Not "the auth files" or "relevant components". Specific: `src/app/auth/login/page.tsx`, `src/lib/auth.ts`. If creating a file, state what it exports. If modifying, state what changes.
81
+ - **Action:** At least one concrete instruction — not just "implement auth". Reference specific functions, components, or patterns. "Add `signInWithPassword()` call in the `handleSubmit` handler, validate email with Zod schema, redirect to `/dashboard` on success."
82
+ - **Done when:** Testable, not fuzzy. Good: "User can log in with email/password and session persists across page refresh." Bad: "Auth works." Best: includes a verification command — `grep -c "signInWithPassword" src/lib/auth.ts` returns non-zero.
83
+
84
+ If a task involves a library or API you're unsure about, use WebFetch to check the current documentation before specifying the approach. Don't guess at APIs.
85
+
86
+ **Self-check:** Before returning the plan, verify every task has specific file paths, concrete actions, and testable done-when criteria. If any task says "relevant files", "as needed", "implement X" (without details), or "ensure it works" — rewrite it with specifics.
87
+
76
88
  ## Rules
77
89
 
78
90
  1. **Plans complete within ~50% context.** More plans with smaller scope = consistent quality. 2-3 tasks per plan is ideal.
@@ -58,6 +58,32 @@ grep -c "TODO\|FIXME\|placeholder\|not implemented\|stub" {file}
58
58
  grep -r "import.*from.*{module}" {consumer_files}
59
59
  ```
60
60
 
61
+ ### Stub Detection (Level 2)
62
+
63
+ Red flags — these indicate placeholder/stub code:
64
+ ```bash
65
+ grep -c "TODO\|FIXME\|PLACEHOLDER\|not implemented\|coming soon" {file}
66
+ grep -c "return null\|return undefined\|return \[\]\|return \{\}" {file}
67
+ grep -c "throw new Error.*not implemented\|throw new Error.*todo" {file}
68
+ grep -c "console\.log.*only\|// stub\|// placeholder\|// temp" {file}
69
+
70
+ # Empty handlers:
71
+ grep -c "catch {}\|catch (e) {}\|catch (err) {}" {file}
72
+ grep -c "async.*=> {}\|() => {}" {file}
73
+ ```
74
+
75
+ If Level 2 finds more than 2 stub patterns in a single file, mark that criterion as **FAIL** regardless of other checks. Stubs are not implementations.
76
+
77
+ ### Wiring Check (Level 3)
78
+
79
+ ```bash
80
+ # Is the module actually imported somewhere?
81
+ grep -r "import.*from.*{module_name}" --include="*.ts" --include="*.tsx" | grep -v node_modules | grep -v ".planning"
82
+
83
+ # Are exported functions actually called?
84
+ grep -r "{function_name}" --include="*.ts" --include="*.tsx" | grep -v "export\|function\|const.*=" | grep -v node_modules
85
+ ```
86
+
61
87
  ### 3. Run Code Quality Checks
62
88
 
63
89
  ```bash
@@ -108,6 +134,20 @@ OR
108
134
  FAIL — {N} gaps found. Run `/qualia-plan {N} --gaps` to fix.
109
135
  ```
110
136
 
137
+ ## Scoring
138
+
139
+ Each success criterion from the plan gets a verdict:
140
+
141
+ - **PASS** — All 3 levels check out. File exists, has real implementation (not stubs), and is imported/used by the system.
142
+ - **PARTIAL** — File exists and has real code, but isn't fully wired (e.g., component exists but isn't rendered in any page, API route exists but no client calls it). This is NOT a pass.
143
+ - **FAIL** — File missing, is a stub, or has 0 connections to the rest of the codebase.
144
+
145
+ Phase verdict:
146
+ - **ALL PASS** → Phase verified. Update STATE.md status to "verified".
147
+ - **ANY PARTIAL or FAIL** → Phase has gaps. List each gap with: what's wrong, what file, what's needed. Suggest `/qualia-plan {N} --gaps`.
148
+
149
+ Never round up. A PARTIAL is not a PASS. The goal of verification is to catch the work that LOOKS done but ISN'T.
150
+
111
151
  ## Rules
112
152
 
113
153
  1. **Never trust summaries.** Always grep the code yourself.
@@ -4,6 +4,11 @@
4
4
  BRANCH=$(git branch --show-current 2>/dev/null)
5
5
  ROLE=$(grep -m1 "^## Role:" ~/.claude/CLAUDE.md 2>/dev/null | sed 's/^## Role: *//')
6
6
 
7
+ if [ -z "$ROLE" ]; then
8
+ echo "BLOCKED: Cannot determine role — ~/.claude/CLAUDE.md missing or malformed. Defaulting to deny."
9
+ exit 1
10
+ fi
11
+
7
12
  if [[ "$BRANCH" == "main" || "$BRANCH" == "master" ]]; then
8
13
  if [[ "$ROLE" != "OWNER" ]]; then
9
14
  echo "BLOCKED: Employees cannot push to $BRANCH. Create a feature branch first."
package/hooks/pre-push.sh CHANGED
@@ -12,8 +12,12 @@ if [ -f "$STATE" ] && [ -f "$TRACKING" ]; then
12
12
  NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
13
13
 
14
14
  # Update tracking.json with current values
15
- if command -v python3 &>/dev/null; then
16
- python3 -c "
15
+ if ! command -v python3 &>/dev/null; then
16
+ echo "WARNING: python3 not found — tracking.json not updated" >&2
17
+ exit 0
18
+ fi
19
+
20
+ if ! python3 -c "
17
21
  import json
18
22
  with open('$TRACKING', 'r') as f:
19
23
  t = json.load(f)
@@ -23,7 +27,9 @@ t['last_commit'] = '${LAST_COMMIT}'
23
27
  t['last_updated'] = '${NOW}'
24
28
  with open('$TRACKING', 'w') as f:
25
29
  json.dump(t, f, indent=2)
26
- " 2>/dev/null
27
- git add "$TRACKING" 2>/dev/null
30
+ " 2>/tmp/qualia-push-err.txt; then
31
+ echo "WARNING: Failed to update tracking.json — $(cat /tmp/qualia-push-err.txt)" >&2
32
+ exit 0
28
33
  fi
34
+ git add "$TRACKING" 2>/dev/null
29
35
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualia-framework-v2",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
5
5
  "bin": {
6
6
  "qualia-framework-v2": "./bin/cli.js"
@@ -22,6 +22,9 @@
22
22
  "url": "https://github.com/qualia-solutions/qualia-framework-v2"
23
23
  },
24
24
  "homepage": "https://github.com/qualia-solutions/qualia-framework-v2#readme",
25
+ "scripts": {
26
+ "test": "bash tests/hooks.test.sh"
27
+ },
25
28
  "files": [
26
29
  "bin/",
27
30
  "agents/",
@@ -29,6 +32,7 @@
29
32
  "rules/",
30
33
  "skills/",
31
34
  "templates/",
35
+ "tests/",
32
36
  "CLAUDE.md",
33
37
  "guide.md",
34
38
  "statusline.sh"
@@ -22,7 +22,13 @@ echo "---VERIFICATIONS---"
22
22
  ls .planning/phase-*-verification.md 2>/dev/null || echo "NO_VERIFICATIONS"
23
23
  ```
24
24
 
25
- ### 2. Route
25
+ ### Task Routing (size-based)
26
+
27
+ - Single file change, config tweak, typo fix, bug with known cause → `/qualia-quick`
28
+ - One feature, 1-5 files, clear scope, under 2 hours → `/qualia-task`
29
+ - Multi-feature, 5+ files, needs architecture decisions, or part of a roadmap phase → `/qualia-plan`
30
+
31
+ ### 2. Route (state-based)
26
32
 
27
33
  | Condition | Command |
28
34
  |-----------|---------|
@@ -82,3 +82,16 @@ Update tracking.json: status → "planned"
82
82
  ```
83
83
  → Run: /qualia-build {N}
84
84
  ```
85
+
86
+ ### Gap Closure Mode (`--gaps`)
87
+
88
+ When invoked as `/qualia-plan {N} --gaps`, the planner is in gap-closure mode:
89
+
90
+ 1. Read `.planning/phase-{N}-verification.md` — extract ONLY the FAIL items
91
+ 2. For each FAIL item, create a targeted fix task:
92
+ - **Files:** The specific files that failed verification
93
+ - **Action:** The specific fix needed (not "fix auth" — "add session persistence check in `src/lib/auth.ts` signIn function")
94
+ - **Done when:** The exact verification criterion that previously failed, restated
95
+ 3. Do NOT re-plan passing items. Do NOT add new features. Gap plans are surgical.
96
+ 4. Write to `.planning/phase-{N}-gaps-plan.md` (separate from original plan)
97
+ 5. All gap tasks are Wave 1 (parallel) unless they share files
@@ -5,7 +5,7 @@ description: "Fast path for small tasks — bug fixes, tweaks, hot fixes. Skips
5
5
 
6
6
  # /qualia-quick — Quick Task
7
7
 
8
- For tasks under 30 minutes that don't need full phase planning. Bug fixes, small features, tweaks.
8
+ For tasks under 1 hour that don't need full phase planning. Single file changes, bug fixes, config tweaks, typo fixes.
9
9
 
10
10
  ## Process
11
11
 
@@ -12,7 +12,7 @@ Build one thing properly. Fresh builder context, atomic commit, but no phase pla
12
12
  `/qualia-task {description}` — build it directly
13
13
 
14
14
  ## When to Use
15
- - Too big for a quick fix, too small for a full phase
15
+ - One feature, 1-5 files, clear scope, 1-3 hours of work
16
16
  - Adding a single feature, component, API route, or integration
17
17
  - Refactoring one module
18
18
  - Building something specific someone asked for
@@ -29,12 +29,12 @@ Then use AskUserQuestion:
29
29
  question: "How complex is this task?"
30
30
  header: "Scope"
31
31
  options:
32
- - label: "Small (30min-1hr)"
32
+ - label: "Small (1-2hrs)"
33
33
  description: "Single file or component, straightforward implementation"
34
- - label: "Medium (1-3hrs)"
34
+ - label: "Medium (2-3hrs)"
35
35
  description: "Multiple files, some integration work, needs testing"
36
36
  - label: "Large (3hrs+)"
37
- description: "Significant feature, multiple components, consider /qualia-plan instead"
37
+ description: "Significant feature, multiple components use /qualia-plan instead"
38
38
  ```
39
39
 
40
40
  If "Large" — suggest `/qualia-plan` instead. Ask if they want to proceed anyway.
@@ -0,0 +1,144 @@
1
+ #!/bin/bash
2
+ # Qualia Framework v2 — Hook Tests
3
+ # Run: bash tests/hooks.test.sh
4
+
5
+ PASS=0
6
+ FAIL=0
7
+ HOOKS_DIR="$(dirname "$0")/../hooks"
8
+
9
+ assert_exit() {
10
+ local name="$1" expected="$2" actual="$3"
11
+ if [ "$expected" = "$actual" ]; then
12
+ echo " ✓ $name"
13
+ PASS=$((PASS + 1))
14
+ else
15
+ echo " ✗ $name (expected exit $expected, got $actual)"
16
+ FAIL=$((FAIL + 1))
17
+ fi
18
+ }
19
+
20
+ echo "=== Hook Tests ==="
21
+ echo ""
22
+
23
+ # --- block-env-edit.sh ---
24
+ echo "block-env-edit:"
25
+
26
+ echo '{"tool_input":{"file_path":".env.local"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
27
+ assert_exit "blocks .env.local" 2 $?
28
+
29
+ echo '{"tool_input":{"file_path":".env.production"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
30
+ assert_exit "blocks .env.production" 2 $?
31
+
32
+ echo '{"tool_input":{"file_path":".env"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
33
+ assert_exit "blocks .env" 2 $?
34
+
35
+ echo '{"tool_input":{"file_path":"src/app.tsx"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
36
+ assert_exit "allows src/app.tsx" 0 $?
37
+
38
+ echo '{"tool_input":{"file_path":"components/Footer.tsx"}}' | bash "$HOOKS_DIR/block-env-edit.sh" > /dev/null 2>&1
39
+ assert_exit "allows components/Footer.tsx" 0 $?
40
+
41
+ # --- migration-guard.sh ---
42
+ echo ""
43
+ echo "migration-guard:"
44
+
45
+ echo '{"tool_input":{"file_path":"migrations/001.sql","content":"DROP TABLE users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
46
+ assert_exit "blocks DROP TABLE without IF EXISTS" 2 $?
47
+
48
+ echo '{"tool_input":{"file_path":"migrations/001.sql","content":"DROP TABLE IF EXISTS old_users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
49
+ assert_exit "allows DROP TABLE IF EXISTS" 0 $?
50
+
51
+ echo '{"tool_input":{"file_path":"migrations/002.sql","content":"DELETE FROM users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
52
+ assert_exit "blocks DELETE without WHERE" 2 $?
53
+
54
+ echo '{"tool_input":{"file_path":"migrations/003.sql","content":"TRUNCATE TABLE sessions;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
55
+ assert_exit "blocks TRUNCATE" 2 $?
56
+
57
+ echo '{"tool_input":{"file_path":"migrations/004.sql","content":"CREATE TABLE users (id uuid);"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
58
+ assert_exit "blocks CREATE TABLE without RLS" 2 $?
59
+
60
+ echo '{"tool_input":{"file_path":"migrations/005.sql","content":"ALTER TABLE users ADD COLUMN email text;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
61
+ assert_exit "allows safe ALTER TABLE" 0 $?
62
+
63
+ echo '{"tool_input":{"file_path":"src/app.tsx","content":"DROP TABLE users;"}}' | bash "$HOOKS_DIR/migration-guard.sh" > /dev/null 2>&1
64
+ assert_exit "skips non-migration files" 0 $?
65
+
66
+ # --- branch-guard.sh ---
67
+ echo ""
68
+ echo "branch-guard:"
69
+
70
+ if [ -f "$HOOKS_DIR/branch-guard.sh" ]; then
71
+ echo " ✓ branch-guard.sh exists"
72
+ PASS=$((PASS + 1))
73
+ else
74
+ echo " ✗ branch-guard.sh missing"
75
+ FAIL=$((FAIL + 1))
76
+ fi
77
+
78
+ if grep -q 'ROLE' "$HOOKS_DIR/branch-guard.sh"; then
79
+ echo " ✓ checks ROLE variable"
80
+ PASS=$((PASS + 1))
81
+ else
82
+ echo " ✗ missing ROLE check"
83
+ FAIL=$((FAIL + 1))
84
+ fi
85
+
86
+ if grep -q 'z "$ROLE"' "$HOOKS_DIR/branch-guard.sh"; then
87
+ echo " ✓ defaults to deny on missing ROLE"
88
+ PASS=$((PASS + 1))
89
+ else
90
+ echo " ✗ missing empty-ROLE deny"
91
+ FAIL=$((FAIL + 1))
92
+ fi
93
+
94
+ # --- pre-push.sh ---
95
+ echo ""
96
+ echo "pre-push:"
97
+
98
+ if grep -q 'command -v python3' "$HOOKS_DIR/pre-push.sh"; then
99
+ echo " ✓ checks for python3 availability"
100
+ PASS=$((PASS + 1))
101
+ else
102
+ echo " ✗ missing python3 check"
103
+ FAIL=$((FAIL + 1))
104
+ fi
105
+
106
+ if grep -q 'qualia-push-err' "$HOOKS_DIR/pre-push.sh"; then
107
+ echo " ✓ captures python3 errors"
108
+ PASS=$((PASS + 1))
109
+ else
110
+ echo " ✗ missing python3 error capture"
111
+ FAIL=$((FAIL + 1))
112
+ fi
113
+
114
+ # --- pre-deploy-gate.sh ---
115
+ echo ""
116
+ echo "pre-deploy-gate:"
117
+
118
+ if [ -f "$HOOKS_DIR/pre-deploy-gate.sh" ]; then
119
+ echo " ✓ pre-deploy-gate.sh exists"
120
+ PASS=$((PASS + 1))
121
+ else
122
+ echo " ✗ pre-deploy-gate.sh missing"
123
+ FAIL=$((FAIL + 1))
124
+ fi
125
+
126
+ if grep -q 'tsc --noEmit' "$HOOKS_DIR/pre-deploy-gate.sh"; then
127
+ echo " ✓ runs TypeScript check"
128
+ PASS=$((PASS + 1))
129
+ else
130
+ echo " ✗ missing TypeScript check"
131
+ FAIL=$((FAIL + 1))
132
+ fi
133
+
134
+ if grep -q 'service_role' "$HOOKS_DIR/pre-deploy-gate.sh"; then
135
+ echo " ✓ checks for service_role leaks"
136
+ PASS=$((PASS + 1))
137
+ else
138
+ echo " ✗ missing service_role check"
139
+ FAIL=$((FAIL + 1))
140
+ fi
141
+
142
+ echo ""
143
+ echo "=== Results: $PASS passed, $FAIL failed ==="
144
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1