qualia-framework 5.4.0 → 5.5.0

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 CHANGED
@@ -53,7 +53,7 @@ Open Claude Code in any project directory.
53
53
  /qualia-polish # Design pass — flexible scope: component, route, app, redesign, critique, quick
54
54
  /qualia-ship # Deploy to production
55
55
  /qualia-handoff # Enforce the 4 mandatory handoff deliverables
56
- /qualia-report # Mandatory end-of-session report + ERP upload
56
+ /qualia-report # Mandatory shift report + ERP upload before clock-out
57
57
  ```
58
58
 
59
59
  ### The Road — auto mode
@@ -127,8 +127,8 @@ Every project has a `.planning/JOURNEY.md` — the North Star document that maps
127
127
  Project
128
128
  └─ Journey (all milestones defined upfront)
129
129
  └─ Milestone (a release — 2-5 total, Handoff is always last)
130
- └─ Phase (a feature-sized deliverable, 2-5 tasks)
131
- └─ Task (atomic unit, one commit, one verification contract)
130
+ └─ Phase (a feature-sized deliverable, 2-5 internal tasks)
131
+ └─ Task (framework-internal unit, one commit, one verification contract)
132
132
  ```
133
133
 
134
134
  **Hard rules:**
@@ -137,7 +137,7 @@ Project
137
137
  - Every non-Handoff milestone needs **≥ 2 phases** (enforced by `state.js close-milestone`).
138
138
  - Milestone numbering is contiguous.
139
139
 
140
- **Why it matters:** non-technical team members can follow the ladder from any entry point. `/qualia` and `/qualia-milestone` render JOURNEY.md as a visual ladder with current position highlighted.
140
+ **Why it matters:** non-technical team members can follow the ladder from any entry point. `/qualia` and `/qualia-milestone` render JOURNEY.md as a visual ladder with current position highlighted. In the ERP, the primary operational dates are project deadline, milestone deadline, and employee shift submission date; framework tasks stay internal to agent execution.
141
141
 
142
142
  ## What's Inside (v5.3.0)
143
143
 
package/agents/builder.md CHANGED
@@ -93,18 +93,26 @@ which is fine and means there is nothing to apply yet.
93
93
  - If the plan says "use library X" — use library X
94
94
  - If something in the plan seems wrong, flag it but still follow the plan
95
95
 
96
- ### 4. Self-Verify Your Work
96
+ ### 4. Self-Verify Your Work (Auto-Heal Loop)
97
97
 
98
- Before committing:
98
+ Before committing, run the checks below. If any fail, **fix and retry up to 2 times** before giving up. This is a tight self-heal loop — moving correctness checks here saves a verifier round.
99
99
 
100
- 1. Run every command in **Validation:** — they must pass
100
+ 1. Run every command in **Validation:** — they must pass.
101
101
  2. Mentally walk through each **Acceptance Criterion** — does the code actually produce that observable behavior?
102
- 3. Run `npx tsc --noEmit` if you touched TypeScript files
103
- 4. **If you touched any `.tsx/.jsx/.css/.scss/.html` file: run `node bin/slop-detect.mjs {touched paths}`. Exit 1 (critical findings) BLOCKS the commit.** Fix the findings (apply the rewrite recipe in the script's output), re-run, repeat until exit 0.
104
- 5. No `// TODO`, no placeholder text, no stub functions
105
- 6. Imports are wired — not just declared but actually used
102
+ 3. Run `npx tsc --noEmit` if you touched TypeScript files. On failure, capture the first 50 lines of error output, fix the offending file(s), re-run. Cap at 2 retries.
103
+ 4. **If you touched any `.tsx/.jsx/.css/.scss/.html` file: run `node bin/slop-detect.mjs {touched paths}`. Exit 1 (critical findings) BLOCKS the commit.** Fix the findings (apply the rewrite recipe in the script's output), re-run, repeat until exit 0 (also capped at 2 retries before BLOCKED).
104
+ 5. No `// TODO`, no placeholder text, no stub functions.
105
+ 6. Imports are wired — not just declared but actually used.
106
106
 
107
- If any Validation command fails, slop-detect returns 1, or any AC is not met, fix before committing. Do not commit and hope the verifier catches it.
107
+ **Auto-heal protocol:**
108
+
109
+ ```
110
+ attempt 1: run validation → fix what failed → run again
111
+ attempt 2: run validation → fix what failed → run again
112
+ attempt 3: if still failing, return BLOCKED — do not commit broken code
113
+ ```
114
+
115
+ If any Validation command fails after 2 retries, slop-detect returns 1 after 2 retries, or any AC is not met after a fix attempt, return `BLOCKED — {validation failure}: {first 20 lines of last error output}`. Do not commit and hope the verifier catches it.
108
116
 
109
117
  ### 5. Commit
110
118
  One atomic commit per task:
@@ -115,6 +123,15 @@ git commit -m "{concise description of what was built}"
115
123
 
116
124
  Stage specific files — never `git add .` or `git add -A`.
117
125
 
126
+ ## Scope Reduction Prohibition
127
+
128
+ The plan was written with the full spec in mind. Don't simplify it. If a task says "validate with Zod schema X covering 6 fields" don't ship 3 fields. If it says "redirect on success" don't ship a console.log placeholder.
129
+
130
+ **Banned phrases in code, comments, and commit messages:**
131
+ `v1`, `// for now`, `// TODO: wire this up later`, `// hardcoded for now`, `// stub`, `// placeholder`, `// minimal version`, `// will improve later`, `mock for now` (in production code paths).
132
+
133
+ If you cannot deliver the full spec because a dependency is genuinely missing, return `BLOCKED — dependency missing: {what}` per the deviation table. Do NOT ship a watered-down version with a TODO note.
134
+
118
135
  ## Scope Discipline
119
136
 
120
137
  Before writing or editing any file, check: Is this file listed in the task's **Files** section?
@@ -132,6 +132,54 @@ Every frontend task MUST include a `**Design:**` field with:
132
132
 
133
133
  Non-frontend tasks (backend, migrations, API routes without UI) MUST NOT have a `**Design:**` field. Warn but don't fail if one is mistakenly added.
134
134
 
135
+ ### Rule 11: Requirement Coverage (when ROADMAP.md lists REQ-IDs)
136
+
137
+ If `.planning/ROADMAP.md` exists and the current phase's section lists `Requirements covered:` with `REQ-ID`s (format `[A-Z]+-\d+`, e.g. `AUTH-01`, `BILLING-03`), every REQ-ID must be covered by at least one task. Coverage = the task's `**Why:**`, `**Acceptance Criteria:**`, or `**Action:**` field references the REQ-ID, OR the task's content directly implements that requirement (read the requirement description from `.planning/REQUIREMENTS.md` and confirm).
138
+
139
+ **FAIL if:**
140
+ - A REQ-ID listed for the current phase appears nowhere in the plan.
141
+ - A task claims a REQ-ID but its Action/AC obviously doesn't implement it.
142
+
143
+ **How to detect:**
144
+ ```bash
145
+ # Extract REQ-IDs for this phase from ROADMAP.md
146
+ awk '/^### Phase {N}:/,/^---|^### Phase/' .planning/ROADMAP.md | grep -oE '[A-Z]+-[0-9]+' | sort -u
147
+ # Check each appears in the plan
148
+ grep -oE '[A-Z]+-[0-9]+' .planning/phase-{N}-plan.md | sort -u
149
+ ```
150
+
151
+ The set difference (REQ-IDs in roadmap minus REQ-IDs in plan) must be empty.
152
+
153
+ If a REQ-ID is missing from the plan, REVISE: "REQ AUTH-03 is in scope for this phase per ROADMAP.md but no task implements it." Plan-wide, not task-specific.
154
+
155
+ ### Rule 9: Decision Coverage (when phase-context.md exists)
156
+
157
+ If `.planning/phase-{N}-context.md` exists with a `## Locked Decisions` section, every `D-NN` row must be covered by at least one task. Coverage = the task references the ID in its `**Why:**` or `**Action:**` field, OR the task's Action implements the decision content directly (read the task and confirm).
158
+
159
+ **FAIL if:**
160
+ - A `D-NN` row exists in phase-context.md but no task in the plan references it or implements it.
161
+ - A row from `## Deferred Ideas` is being implemented by a task (deferred = explicitly out-of-scope).
162
+
163
+ **How to detect:**
164
+ ```bash
165
+ grep -E '^\| D-[0-9]+' .planning/phase-{N}-context.md # extract decision IDs
166
+ grep -E 'D-[0-9]+' .planning/phase-{N}-plan.md # check IDs appear in plan
167
+ ```
168
+
169
+ If a decision ID appears in phase-context.md but not the plan, REVISE: "D-03 is locked but no task implements it." Plus the deferred check: if a task's Action matches a Deferred-Ideas row, REVISE.
170
+
171
+ ### Rule 10: Scope Reduction Detection
172
+
173
+ LLMs systematically simplify specs. Scan the plan for banned phrases that signal scope reduction:
174
+
175
+ ```bash
176
+ grep -niE '\b(v1|v2|simplified version|static for now|hardcoded for now|placeholder|basic version|minimal implementation|will be wired later|dynamic in future phase|skip for now|stub|mock for now|we can improve this later|quick win for now)\b' .planning/phase-{N}-plan.md
177
+ ```
178
+
179
+ **FAIL if:** any match. Quote the offending line in the issue. The planner must rewrite the task to deliver the actual thing, OR explicitly justify the split using one of the three legitimate reasons (context cost > 50%, missing info, dependency conflict).
180
+
181
+ Exception: `v1` / `v2` is fine when referring to the project's actual versioning (e.g., `migrate to API v2`). Distinguish by context.
182
+
135
183
  ### Rule 8: Validation commands test behavior, not just existence
136
184
 
137
185
  Each task's `**Validation:**` list must contain at least one `grep-match` or `command-exit` check — a command that proves the code DOES something. A task whose ONLY validation is `test -f {file}` will pass even if the file contains only `// TODO`.
@@ -152,7 +200,7 @@ Each task's `**Validation:**` list must contain at least one `grep-match` or `co
152
200
 
153
201
  ## Tool Budget
154
202
 
155
- Read the plan file once. Grep the codebase only to validate Rule 7 (locked decisions). Do NOT speculatively check whether files listed in the plan already exist — that's the builder's job. Max 10 tool calls per invocation.
203
+ Read the plan file once. Read `.planning/phase-{N}-context.md` once if it exists (Rules 7 + 9). Read `.planning/ROADMAP.md` once if it exists (Rules 4 + 11). Grep the plan for scope-reduction phrases (Rule 10), decision IDs (Rule 9), and REQ-IDs (Rule 11). Do NOT speculatively check whether files listed in the plan already exist — that's the builder's job. Max 14 tool calls per invocation.
156
204
 
157
205
  ## Output Format
158
206
 
@@ -215,6 +263,6 @@ Before returning, self-check:
215
263
  - [ ] Every issue has a specific task reference
216
264
  - [ ] Every issue has a concrete fix instruction
217
265
  - [ ] No issue is "make it better" or "be more specific" without saying how
218
- - [ ] If plan passes, you actually verified all 7 rules (not just 1-2)
266
+ - [ ] If plan passes, you actually verified all 11 rules (not just 1-2)
219
267
 
220
268
  Don't pass a plan you didn't fully check. Don't fail a plan for style preferences.
package/agents/planner.md CHANGED
@@ -212,12 +212,36 @@ When a phase involves frontend work (pages, components, layouts, UI):
212
212
  - Include responsive: "works on 375px mobile and 1440px desktop"
213
213
  4. **Reference `@.planning/DESIGN.md`** in the Context field of every frontend task so builders read it before coding
214
214
 
215
+ ## Scope Reduction Prohibition
216
+
217
+ LLMs systematically simplify specs. You will not. If a locked decision or success criterion says X, the plan delivers X — not a watered-down version that "we can extend later."
218
+
219
+ **Banned phrases in task Action / Acceptance Criteria / Why fields:**
220
+ `v1`, `v2`, `simplified version`, `static for now`, `hardcoded for now`, `placeholder`, `basic version`, `minimal implementation`, `will be wired later`, `dynamic in future phase`, `skip for now`, `stub`, `mock for now`, `we can improve this later`, `quick win for now`.
221
+
222
+ **The only legitimate reasons to split scope across phases:**
223
+ 1. Implementing it would force a single task above ~50% builder context.
224
+ 2. Required information genuinely does not exist (data shape unknown, external API not yet specified).
225
+ 3. A dependency is owned by a future phase and the wave-graph cannot resolve it.
226
+
227
+ If none of these apply, deliver the full spec. A self-check before returning the plan: grep your draft for the banned phrases. If you find one, rewrite the task to deliver the actual thing.
228
+
229
+ ## Decision Coverage Audit
230
+
231
+ If `.planning/phase-{N}-context.md` exists with a `## Locked Decisions` section, every decision row carries an ID (e.g., `D-01`, `D-02`). Before returning the plan, confirm:
232
+
233
+ - Every `D-XX` is covered by at least one task whose Action implements it. Reference the ID in that task's Why or Action (e.g., `Why: D-03 requires session tokens stored database-side, not in JWT`).
234
+ - No `Deferred Ideas` row appears in any task. Deferred = out-of-scope for this phase.
235
+ - `Discretion` items are the planner's call — no audit needed.
236
+
237
+ If a locked decision has no covering task, add one. If you genuinely cannot, the phase scope is wrong and the plan-checker will block — STOP and surface the gap to the user.
238
+
215
239
  ## Rules
216
240
 
217
241
  1. **Plans complete within ~50% context.** More plans with smaller scope = consistent quality. 2-3 tasks per plan is ideal.
218
242
  2. **Tasks are atomic.** Each task = one commit. If a task touches 10+ files, split it.
219
243
  3. **"Done when" must be testable.** Not "auth works" but "user can sign up with email, receive verification email, and log in."
220
- 4. **Honor locked decisions.** If PROJECT.md says "use library X" — the plan uses library X.
244
+ 4. **Honor locked decisions.** If PROJECT.md or phase-context.md says "use library X" — the plan uses library X.
221
245
  5. **No enterprise patterns.** No RACI, no stakeholder management, no sprint ceremonies. One person + Claude.
222
246
  6. **Context references are explicit.** Use `@filepath` so the builder knows exactly what to read.
223
247
 
package/bin/install.js CHANGED
@@ -894,7 +894,7 @@ Client-specific preferences, design choices, and requirements. Loaded by \`/qual
894
894
  tips: [
895
895
  "⬢ Lost? Type /qualia for the next step",
896
896
  "⬢ Small fix? Use /qualia-quick to skip planning",
897
- "⬢ End of day? /qualia-report before you clock out",
897
+ "⬢ End of day? /qualia-report submits your shift before clock-out",
898
898
  "⬢ Context isolation: every task gets a fresh AI brain",
899
899
  "⬢ The verifier doesn't trust claims — it greps the code",
900
900
  "⬢ Plans are prompts — the plan IS what the builder reads",
@@ -1105,7 +1105,7 @@ function printSummary({ member, target, claudeInstalled }) {
1105
1105
  console.log("");
1106
1106
  console.log(` ${DIM}New project?${RESET} ${TEAL}/qualia-new${RESET}`);
1107
1107
  console.log(` ${DIM}Quick fix?${RESET} ${TEAL}/qualia-quick${RESET}`);
1108
- console.log(` ${DIM}End of day?${RESET} ${TEAL}/qualia-report${RESET} ${DIM}(mandatory)${RESET}`);
1108
+ console.log(` ${DIM}End of day?${RESET} ${TEAL}/qualia-report${RESET} ${DIM}(shift submission)${RESET}`);
1109
1109
  console.log(` ${DIM}Stuck?${RESET} ${TEAL}/qualia${RESET}`);
1110
1110
  console.log("");
1111
1111
  console.log(` ${DIM2}${RULE}${RESET}`);
@@ -21,6 +21,28 @@ const CHECK_TYPES = new Set([
21
21
  "file-exists", "grep-match", "command-exit", "behavioral",
22
22
  ]);
23
23
 
24
+ // Scope-reduction detection — phrases that signal an LLM has watered down the
25
+ // spec. The plan-checker agent does the same scan on the markdown plan; this
26
+ // function does it on the JSON contract's free-text fields (action +
27
+ // acceptance_criteria) so both paths catch the same failure mode.
28
+ const SCOPE_REDUCTION_PHRASES = [
29
+ /\bv1\b/i, /\bv2\b/i, /simplified version/i, /static for now/i,
30
+ /hardcoded for now/i, /\bplaceholder\b/i, /basic version/i,
31
+ /minimal implementation/i, /will be wired later/i,
32
+ /dynamic in future phase/i, /skip for now/i, /\bstub\b/i,
33
+ /mock for now/i, /we can improve this later/i, /quick win for now/i,
34
+ ];
35
+
36
+ function findScopeReductionPhrases(text) {
37
+ if (typeof text !== "string") return [];
38
+ const hits = [];
39
+ for (const re of SCOPE_REDUCTION_PHRASES) {
40
+ const m = text.match(re);
41
+ if (m) hits.push(m[0]);
42
+ }
43
+ return hits;
44
+ }
45
+
24
46
  function isStringArray(v) {
25
47
  return Array.isArray(v) && v.every((x) => typeof x === "string");
26
48
  }
@@ -98,7 +120,15 @@ function validateTask(task, idx, allIds) {
98
120
  errs.push(`${where}.acceptance_criteria: must be a non-empty string[]`);
99
121
  }
100
122
  if (typeof task.action !== "string") errs.push(`${where}.action: required string`);
101
- else if (task.action.length > 500) errs.push(`${where}.action: must be ≤ 500 characters (got ${task.action.length})`);
123
+ else {
124
+ if (task.action.length > 500) errs.push(`${where}.action: must be ≤ 500 characters (got ${task.action.length})`);
125
+ const actionHits = findScopeReductionPhrases(task.action);
126
+ if (actionHits.length) errs.push(`${where}.action: scope-reduction phrase(s) detected: ${actionHits.join(", ")} — rewrite to deliver the actual spec, or split via locked-decision channel`);
127
+ }
128
+ for (let i = 0; i < (task.acceptance_criteria || []).length; i++) {
129
+ const acHits = findScopeReductionPhrases(task.acceptance_criteria[i]);
130
+ if (acHits.length) errs.push(`${where}.acceptance_criteria[${i}]: scope-reduction phrase(s) detected: ${acHits.join(", ")}`);
131
+ }
102
132
  if (!isStringArray(task.context_files || [])) errs.push(`${where}.context_files: must be string[]`);
103
133
  if (!Array.isArray(task.verification) || task.verification.length === 0) {
104
134
  errs.push(`${where}.verification: must be a non-empty array`);
@@ -217,4 +247,5 @@ module.exports = {
217
247
  parseSafely,
218
248
  hashPlan,
219
249
  checkDrift,
250
+ findScopeReductionPhrases,
220
251
  };
@@ -2,6 +2,17 @@
2
2
 
3
3
  The Qualia Framework optionally uploads session reports to the company ERP at `https://portal.qualiasolutions.net`. This document specifies the API shape.
4
4
 
5
+ ## Operating Model
6
+
7
+ The ERP treats `/qualia-report` as an employee shift submission, not proof that an assigned task was finished. Employees clock out after their fixed daily hours and submit what happened during the shift: shipped work, partial progress, blockers, investigation, meetings, or no-code work.
8
+
9
+ Primary ERP planning dates are:
10
+ - Project deadline
11
+ - Milestone deadline
12
+ - Employee submission date from the uploaded report
13
+
14
+ Phase and task counters remain framework telemetry. They help agents plan/build/verify, but they should not become the ERP's primary navigation, deadline model, or employee-performance label.
15
+
5
16
  ## Configuration
6
17
 
7
18
  Stored in `~/.claude/.qualia-config.json`:
package/guide.md CHANGED
@@ -109,7 +109,7 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
109
109
  ## Session Start / End
110
110
 
111
111
  **Start:** Claude loads your project context automatically. The router banner shows your journey position ("M2 of 4 · P2 of 3").
112
- **End:** Run `/qualia-report` — this is mandatory before clock-out. The report is committed to git and (if ERP is enabled) uploaded to https://portal.qualiasolutions.net.
112
+ **End:** Run `/qualia-report` — this is the mandatory clock-out submission. It reports what happened during the work shift, even if the work is unfinished. The report is committed to git and (if ERP is enabled) uploaded to https://portal.qualiasolutions.net.
113
113
 
114
114
  ## How It Works (you don't need to know this, but if curious)
115
115
 
@@ -120,7 +120,7 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
120
120
  - **Story-file plans:** Every task has Why / Acceptance Criteria / Depends on / Validation inline — the plan IS the brief.
121
121
  - **Wave execution:** Independent tasks run in parallel. Dependent tasks wait.
122
122
  - **Milestone-boundary pauses:** In `--auto` mode, the framework pauses only at real decision points. Everything else runs on rails.
123
- - **tracking.json:** Updated on every push. The ERP reads it automatically. Includes `milestone_name` + `milestones[]` so the ERP renders a proper tree instead of a flat list.
123
+ - **tracking.json:** Updated on every push. The ERP reads it automatically. Includes `milestone_name` + `milestones[]` so the ERP can show project and milestone progress without exposing framework tasks as the main employee workflow.
124
124
 
125
125
  ## Quick Reference
126
126
 
@@ -134,4 +134,4 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
134
134
  | Finished the last phase of a milestone | `/qualia-milestone` |
135
135
  | About to ship | `/qualia-ship` |
136
136
  | Client is ready to take over | `/qualia-handoff` |
137
- | End of workday | `/qualia-report` (mandatory) |
137
+ | End of workday / clock-out | `/qualia-report` (mandatory shift submission) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualia-framework",
3
- "version": "5.4.0",
3
+ "version": "5.5.0",
4
4
  "description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
5
5
  "bin": {
6
6
  "qualia-framework": "./bin/cli.js"
@@ -67,10 +67,24 @@ Wait for response. Then:
67
67
  - Write an ADR in `.planning/decisions/ADR-{NNNN}-{slug}.md` ONLY when the decision is hard-to-reverse, surprising-without-context, AND involves real trade-offs (use the template — keep it scarce)
68
68
  - Drill deeper if the answer opens new branches
69
69
 
70
- ### 4. Build the locked-decisions list
70
+ ### 4. Build the locked-decisions list (with IDs — machine-parseable downstream)
71
71
 
72
- For each resolved decision, capture: choice (what) / rationale (why) / source (who/when).
73
- Also track: **Discretion items** (planner decides) / **Deferred ideas** (NOT this phase) / **Risk flags** (watch during build) / **Open questions** (still unresolved).
72
+ For each resolved decision, capture as a row with a stable ID `D-NN` (zero-padded, sequential within the phase). The planner's Decision Coverage Audit checks every `D-NN` is implemented; the plan-checker BLOCKS if any is missing.
73
+
74
+ **Locked Decision row format:**
75
+
76
+ | ID | Decision | Rationale | Source |
77
+ |----|----------|-----------|--------|
78
+ | D-01 | Use Supabase RLS for authorization, not middleware | Compliance requires database-level checks | discuss session 2026-05-09 |
79
+ | D-02 | Store session tokens server-side, not in JWT | OWASP guidance + revocation requirement | ADR-0007 |
80
+
81
+ Also track:
82
+ - **Discretion items** — planner decides based on best practice (no IDs needed).
83
+ - **Deferred ideas** — explicitly NOT this phase. The plan-checker will REVISE if any of these appears in a task.
84
+ - **Risk flags** — watch during build (no IDs).
85
+ - **Open questions** — still unresolved. Cannot lock until resolved.
86
+
87
+ When you reference a decision later (in commit messages, task Why fields, ADRs), use its ID — `D-03` is shorter than the full decision text and cross-checkable.
74
88
 
75
89
  ### 5. Decision gate
76
90
 
@@ -9,9 +9,11 @@ allowed-tools:
9
9
  - AskUserQuestion
10
10
  ---
11
11
 
12
- # /qualia-report — Daily Clock-Out Report
12
+ # /qualia-report — Daily Shift Report
13
13
 
14
- The end-of-day flow. Generates a report, commits it, pushes, uploads to the ERP, and tells the employee they can stop. Designed so Hasan and Moayad never get stuck on it.
14
+ The end-of-day clock-out flow. Generates a shift report, commits it, pushes, uploads to the ERP, and tells the employee they can stop. Designed so Hasan and Moayad never get stuck on it.
15
+
16
+ This is not a task-completion ceremony. The report records what happened during the employee's fixed work shift: shipped work, partial progress, blockers, investigation, meetings, or no-code work. A valid report can say "not finished yet" as long as it clearly explains the shift outcome and next step.
15
17
 
16
18
  ## Flags
17
19
  - `/qualia-report` — normal flow (generate, commit, push, upload to ERP)
@@ -60,18 +62,18 @@ None. ← or list 1–N actual blockers (NOT "had to read docs" — that's nor
60
62
  2. ...
61
63
  ```
62
64
 
63
- **If `COUNT == 0`** — ask the employee gracefully (don't force a fake report):
65
+ **If `COUNT == 0`** — ask the employee gracefully (don't force a fake report or fake completed task):
64
66
 
65
67
  Use `AskUserQuestion`:
66
68
  - header: "Empty day?"
67
- - question: "No commits in the last 8 hours. What did you do today?"
69
+ - question: "No commits in the last 8 hours. What happened during your shift?"
68
70
  - options:
69
71
  - "Investigation / research only"
70
72
  - "Meetings / calls (no code)"
71
73
  - "Blocked — tell me on what"
72
74
  - "Time off / partial day"
73
75
 
74
- Capture the answer as the report body. Empty days are still valid clock-outs — the ERP needs to see them.
76
+ Capture the answer as the report body. Empty days and unfinished work are still valid clock-outs — the ERP needs a truthful employee submission date and shift summary.
75
77
 
76
78
  ### Step 3 — Write report file
77
79
 
@@ -139,7 +141,7 @@ fi
139
141
 
140
142
  node ~/.claude/bin/qualia-ui.js divider
141
143
  node ~/.claude/bin/qualia-ui.js ok "Report $CLIENT_REPORT_ID complete."
142
- node ~/.claude/bin/qualia-ui.js info "You can clock out now. See you tomorrow."
144
+ node ~/.claude/bin/qualia-ui.js info "Shift report submitted. You can clock out now."
143
145
  ```
144
146
 
145
147
  ## Common errors (read this when something goes wrong)
@@ -18,14 +18,15 @@ A unit of work inside a milestone. 2–5 tasks. Ends in a verification gate.
18
18
  **Avoid:** epic, story, ticket, sprint.
19
19
 
20
20
  ### Task
21
- A single commit-sized unit with one verification contract.
22
- **Avoid:** subtask, chore, todo.
21
+ A framework-internal execution unit: one commit-sized work item with one verification contract.
22
+ **Avoid:** using "task" as an ERP assignment or employee performance label unless the product domain explicitly needs it.
23
23
 
24
24
  ## Relationships
25
25
  - Project holds many Milestones
26
26
  - Milestone holds many Phases
27
27
  - Phase holds many Tasks
28
28
  - Task carries one Verification Contract
29
+ - ERP tracks project deadlines, milestone deadlines, and employee shift submissions; framework tasks stay internal.
29
30
  - {{add domain-specific relationships, e.g. "Customer holds many Orders"}}
30
31
 
31
32
  ## Flagged ambiguities
@@ -479,7 +479,7 @@
479
479
  <li><span class="rule-icon">1</span> Feature branches by default &mdash; OWNER overrides must be explicit</li>
480
480
  <li><span class="rule-icon">2</span> Read before write &mdash; understand files before editing</li>
481
481
  <li><span class="rule-icon">3</span> MVP first &mdash; build what's asked, nothing extra</li>
482
- <li><span class="rule-icon">4</span> /qualia-report before clock-out &mdash; mandatory, enforced by ERP</li>
482
+ <li><span class="rule-icon">4</span> /qualia-report before clock-out &mdash; mandatory shift submission in ERP</li>
483
483
  <li><span class="rule-icon">5</span> Secrets through approved flows &mdash; use set-erp-key or ask Fawzi</li>
484
484
  <li><span class="rule-icon">6</span> Stuck 30+ minutes? Ask Fawzi</li>
485
485
  </ul>
@@ -13,11 +13,12 @@ Captured during `/qualia-discuss {N}` — decisions, trade-offs, and constraints
13
13
 
14
14
  ## Locked Decisions
15
15
 
16
- Non-negotiable choices. Planner must honor these exactly.
16
+ Non-negotiable choices. Planner must honor these exactly. Every row has a stable ID (`D-NN`) — the planner's Decision Coverage Audit checks each is implemented; the plan-checker BLOCKS if any is missing.
17
17
 
18
- | Decision | Rationale | Source |
19
- |----------|-----------|--------|
20
- | {e.g., "Use Supabase RLS for authorization, not middleware"} | {e.g., "Client compliance requires database-level checks"} | {who/when} |
18
+ | ID | Decision | Rationale | Source |
19
+ |----|----------|-----------|--------|
20
+ | D-01 | {e.g., "Use Supabase RLS for authorization, not middleware"} | {e.g., "Client compliance requires database-level checks"} | {who/when} |
21
+ | D-02 | {next decision} | {rationale} | {source} |
21
22
 
22
23
  ## Discretion (Planner Chooses)
23
24
 
package/tests/bin.test.sh CHANGED
@@ -1583,6 +1583,36 @@ else
1583
1583
  fail_case "package.json version not 5.x" "got=$PKG_V"
1584
1584
  fi
1585
1585
 
1586
+ echo ""
1587
+ echo "--- ERP shift-report contract ---"
1588
+
1589
+ # 144. qualia-report describes clock-out as truthful shift submission, not task completion
1590
+ if grep -qi "daily shift report" "$TMP/.claude/skills/qualia-report/SKILL.md" \
1591
+ && grep -qi "not a task-completion ceremony" "$TMP/.claude/skills/qualia-report/SKILL.md" \
1592
+ && grep -qi "What happened during your shift" "$TMP/.claude/skills/qualia-report/SKILL.md"; then
1593
+ pass "qualia-report frames clock-out as shift submission, not task completion"
1594
+ else
1595
+ fail_case "qualia-report missing shift-submission contract"
1596
+ fi
1597
+
1598
+ # 145. ERP contract documents the date model: project, milestone, employee submission
1599
+ if grep -q "Project deadline" "$FRAMEWORK_DIR/docs/erp-contract.md" \
1600
+ && grep -q "Milestone deadline" "$FRAMEWORK_DIR/docs/erp-contract.md" \
1601
+ && grep -q "Employee submission date" "$FRAMEWORK_DIR/docs/erp-contract.md" \
1602
+ && grep -q "Phase and task counters remain framework telemetry" "$FRAMEWORK_DIR/docs/erp-contract.md"; then
1603
+ pass "ERP contract documents project/milestone/submission date model"
1604
+ else
1605
+ fail_case "ERP contract missing date-model clarification"
1606
+ fi
1607
+
1608
+ # 146. Project glossary keeps framework tasks internal to agent execution
1609
+ if grep -q "framework-internal execution unit" "$FRAMEWORK_DIR/templates/CONTEXT.md" \
1610
+ && grep -q "ERP tracks project deadlines, milestone deadlines, and employee shift submissions" "$FRAMEWORK_DIR/templates/CONTEXT.md"; then
1611
+ pass "CONTEXT template distinguishes internal tasks from ERP workflow"
1612
+ else
1613
+ fail_case "CONTEXT template missing framework-task vs ERP-workflow distinction"
1614
+ fi
1615
+
1586
1616
  echo ""
1587
1617
  echo "=== Results: $PASS passed, $FAIL failed ==="
1588
1618
  [ "$FAIL" -eq 0 ] && exit 0 || exit 1
package/tests/lib.test.sh CHANGED
@@ -57,6 +57,27 @@ console.log(errs.length > 0 ? "REJECTED" : "ACCEPTED");
57
57
  ')
58
58
  [ "$OUT" = "REJECTED" ] && ok "rejects malformed contract" || fail "malformed accepted"
59
59
 
60
+ OUT=$($NODE -e '
61
+ const pc = require("'"$PC"'");
62
+ const slop = {
63
+ version: 1, phase: 1, goal: "x", why: "y",
64
+ generated_at: "t", generated_by: "planner", source_plan_hash: "h",
65
+ success_criteria: ["sc"],
66
+ tasks: [{
67
+ id: "T1", title: "t", wave: 1, depends_on: [],
68
+ files_modify: [], files_create: [], files_delete: [],
69
+ acceptance_criteria: ["minimal implementation of login"],
70
+ action: "Add hardcoded for now placeholder, will be wired later",
71
+ context_files: [],
72
+ verification: [{ type: "file-exists", path: "a.ts" }]
73
+ }]
74
+ };
75
+ const errs = pc.validate(slop);
76
+ const hits = errs.filter(e => /scope-reduction/.test(e));
77
+ console.log(hits.length >= 2 ? "DETECTED" : "MISSED:" + errs.join(";"));
78
+ ')
79
+ [ "$OUT" = "DETECTED" ] && ok "detects scope-reduction phrases in action + acceptance_criteria" || fail "scope-reduction missed: $OUT"
80
+
60
81
  OUT=$($NODE -e '
61
82
  const pc = require("'"$PC"'");
62
83
  const c = {