sinapse-ai 1.21.0 → 1.22.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.
Files changed (113) hide show
  1. package/.claude/rules/coderabbit-integration.md +6 -0
  2. package/.claude/rules/documentation-first-reference.md +146 -0
  3. package/.claude/rules/documentation-first.md +27 -119
  4. package/.claude/rules/mandatory-delegation-reference.md +93 -0
  5. package/.claude/rules/mandatory-delegation.md +29 -93
  6. package/.claude/rules/project-intelligence-reference.md +159 -0
  7. package/.claude/rules/project-intelligence.md +37 -155
  8. package/.claude/rules/safe-collaboration-reference.md +163 -0
  9. package/.claude/rules/safe-collaboration.md +32 -173
  10. package/.sinapse-ai/core/doctor/checks/index.js +1 -1
  11. package/.sinapse-ai/core/execution/build-orchestrator.js +4 -3
  12. package/.sinapse-ai/core/execution/subagent-dispatcher.js +2 -2
  13. package/.sinapse-ai/core/ideation/ideation-engine.js +2 -1
  14. package/.sinapse-ai/core/orchestration/cli-commands.js +13 -0
  15. package/.sinapse-ai/core/orchestration/doc-first-resolver.js +93 -2
  16. package/.sinapse-ai/core/orchestration/executors/epic-3-executor.js +15 -2
  17. package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +3 -1
  18. package/.sinapse-ai/core/orchestration/index.js +5 -0
  19. package/.sinapse-ai/core/orchestration/spec-complexity.js +141 -0
  20. package/.sinapse-ai/core-config.yaml +30 -0
  21. package/.sinapse-ai/data/entity-registry.yaml +46 -25
  22. package/.sinapse-ai/development/agents/architect.md +3 -15
  23. package/.sinapse-ai/development/agents/data-engineer.md +3 -15
  24. package/.sinapse-ai/development/agents/developer.md +3 -24
  25. package/.sinapse-ai/development/agents/devops.md +4 -25
  26. package/.sinapse-ai/development/agents/quality-gate.md +3 -25
  27. package/.sinapse-ai/development/knowledge-base/token-economy-guide.md +1 -1
  28. package/.sinapse-ai/development/tasks/resolve-github-issue.md +1 -1
  29. package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.1-COMPLETE.md +6 -2
  30. package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.2-SUMMARY.md +4 -1
  31. package/.sinapse-ai/install-manifest.yaml +44 -40
  32. package/.sinapse-ai/product/templates/story-tmpl.yaml +11 -6
  33. package/.sinapse-ai/quality/judge-calibration/README.md +75 -0
  34. package/.sinapse-ai/quality/judge-calibration/calibration-log.md +70 -0
  35. package/.sinapse-ai/quality/judge-calibration/golden-set.json +105 -0
  36. package/.sinapse-ai/quality/judge-calibration/scenarios.json +90 -0
  37. package/CHANGELOG.md +38 -8
  38. package/README.en.md +1 -1
  39. package/README.md +6 -6
  40. package/bin/sinapse-minimal.js +5 -4
  41. package/docs/community/README-community-snippet-core.md +1 -1
  42. package/docs/community/README-community-snippet-mcp.md +2 -2
  43. package/docs/framework/README.md +2 -2
  44. package/docs/framework/architecture-overview.md +2 -2
  45. package/docs/framework/core-architecture.md +1 -1
  46. package/docs/framework/feature-process.md +5 -5
  47. package/docs/framework/guiding-principles.md +1 -1
  48. package/docs/framework/roadmap.md +4 -4
  49. package/docs/framework/source-tree.md +1 -1
  50. package/docs/framework/versioning-and-releases.md +1 -1
  51. package/docs/getting-started.md +1 -1
  52. package/docs/guides/agent-selection-guide.md +1 -1
  53. package/docs/guides/agents/traces/README.md +1 -1
  54. package/docs/guides/config-migration-guide.md +1 -1
  55. package/docs/guides/development-setup.md +1 -1
  56. package/docs/guides/docker-mcp-setup.md +5 -5
  57. package/docs/guides/getting-started.md +1 -1
  58. package/docs/guides/git-workflow-guide.md +3 -3
  59. package/docs/guides/ide-integration.md +3 -3
  60. package/docs/guides/ide-sync-guide.md +1 -1
  61. package/docs/guides/mcp/desktop-commander.md +2 -2
  62. package/docs/guides/mcp/docker-gateway-tutorial.md +1 -1
  63. package/docs/guides/mcp-global-setup.md +3 -3
  64. package/docs/guides/memory-intelligence-system.md +10 -10
  65. package/docs/guides/meta-agent-commands.md +1 -1
  66. package/docs/guides/quality-gates.md +1 -1
  67. package/docs/guides/security-hardening.md +1 -1
  68. package/docs/guides/service-discovery.md +1 -1
  69. package/docs/guides/squad-examples/README.md +1 -1
  70. package/docs/guides/squads-guide.md +1 -1
  71. package/docs/guides/testing-guide.md +2 -2
  72. package/docs/guides/user-guide.md +22 -22
  73. package/docs/guides/workflows/BROWNFIELD-DISCOVERY-WORKFLOW.md +3 -3
  74. package/docs/guides/workflows/BROWNFIELD-SERVICE-WORKFLOW.md +1 -1
  75. package/docs/guides/workflows/GREENFIELD-UI-WORKFLOW.md +2 -2
  76. package/docs/guides/workflows/SPEC-PIPELINE-WORKFLOW.md +3 -3
  77. package/docs/guides/workflows/STORY-DEVELOPMENT-CYCLE-WORKFLOW.md +3 -3
  78. package/docs/guides/workflows/pro-developer-workflow.md +2 -2
  79. package/docs/guides/workflows-guide.md +1 -1
  80. package/docs/guides/workflows-overview.md +1 -1
  81. package/docs/installation/npx-install.md +1 -1
  82. package/docs/installation/uninstallation.md +1 -1
  83. package/docs/installation/v4-quick-start.md +1 -1
  84. package/docs/pt/guides/user-guide.md +18 -18
  85. package/docs/pt/security.md +2 -2
  86. package/docs/security/overview.md +2 -2
  87. package/docs/security/security-best-practices.md +1 -1
  88. package/docs/sinapse-agent-flows/architect-system.md +1 -1
  89. package/docs/sinapse-agent-flows/data-engineer-system.md +1 -1
  90. package/docs/sinapse-agent-flows/dev-system.md +1 -1
  91. package/docs/sinapse-agent-flows/devops-system.md +2 -2
  92. package/docs/sinapse-agent-flows/qa-system.md +1 -1
  93. package/docs/sinapse-agent-flows/sm-system.md +2 -2
  94. package/docs/sinapse-agent-flows/snps-orqx-system.md +4 -4
  95. package/docs/sinapse-agent-flows/squad-creator-system.md +1 -1
  96. package/docs/sinapse-workflows/README.md +2 -2
  97. package/docs/sinapse-workflows/brownfield-discovery-workflow.md +3 -3
  98. package/docs/sinapse-workflows/brownfield-service-workflow.md +3 -3
  99. package/docs/sinapse-workflows/greenfield-ui-workflow.md +2 -2
  100. package/docs/sinapse-workflows/spec-pipeline-workflow.md +3 -3
  101. package/docs/sinapse-workflows/story-development-cycle-workflow.md +3 -3
  102. package/docs/troubleshooting.md +1 -1
  103. package/package.json +5 -1
  104. package/scripts/calibrate-judge.js +134 -0
  105. package/scripts/validate-all.js +5 -0
  106. package/scripts/validate-constitution.js +58 -0
  107. package/scripts/validate-story-acs.js +174 -0
  108. package/scripts/validate-tool-descriptions.js +128 -0
  109. package/scripts/wave-gate.js +1 -1
  110. package/squads/claude-code-mastery/agents/project-integrator.md +3 -10
  111. package/squads/claude-code-mastery/knowledge-base/context-window-optimization.md +2 -2
  112. package/squads/claude-code-mastery/knowledge-base/memory-systems-reference.md +1 -1
  113. package/squads/squad-copy/knowledge-base/ai-copy-human-loop-canon.md +1 -1
@@ -1,185 +1,44 @@
1
1
  # Safe Collaboration — Git Safety Net (NON-NEGOTIABLE)
2
2
 
3
3
  > **Applies to ALL agents, ALL projects using SINAPSE.**
4
- > Users are product builders, NOT git experts.
5
- > Agents MUST handle ALL git complexity automatically and safely.
4
+ > Users are product builders, NOT git experts. Agents handle ALL git complexity.
5
+ > This is the always-on CORE (the law). Operational detail (branch naming tables,
6
+ > step-by-step checklists, conflict matrices, communication templates) lives in
7
+ > `safe-collaboration-reference.md` and loads when you work on files.
6
8
 
7
9
  ## Golden Rule
8
10
 
9
11
  **Users focus on WHAT to build. Agents handle HOW to save and share it safely.**
10
-
11
- Users should NEVER need to:
12
- - Resolve merge conflicts manually
13
- - Decide which branch to use
14
- - Remember to pull before working
15
- - Worry about overwriting each other's code
16
- - Understand git rebase, cherry-pick, or force-push
17
-
18
- ## Automatic Safety Protocol (every session)
19
-
20
- ### 1. Session Start Auto-Sync (MANDATORY)
21
-
22
- Before ANY work begins in a session, the agent MUST:
23
-
24
- ```
25
- 1. git fetch origin
26
- 2. Check if local main is behind origin/main
27
- 3. If behind git pull origin main (fast-forward only)
28
- 4. If diverged STOP, inform user, resolve safely
29
- 5. Create work branch if not already on one
30
- 6. Verify branch protection is active on main
31
- ```
32
-
33
- **NEVER start work on `main` directly.** Always create a feature branch.
34
-
35
- ### 2. Branch Naming — Automatic
36
-
37
- The agent creates the branch. The user never needs to name it.
38
-
39
- | Who | Branch Pattern | Example |
40
- |-----|---------------|---------|
41
- | Caio's session | `caio/{type}/{short-desc}` | `caio/feat/installer-ux` |
42
- | Matheus's session | `soier/{type}/{short-desc}` | `soier/fix/agent-config` |
43
- | AI agent | `agent/{squad}/{agent-id}/{type}-{desc}` | `agent/core/pixel/feat-dark-mode` |
44
- | Unknown | `dev/{type}/{short-desc}` | `dev/feat/new-feature` |
45
-
46
- Types: `feat`, `fix`, `refactor`, `docs`, `chore`, `test`
47
-
48
- **User Detection (priority order):**
49
- 1. `git config user.name` -> lookup in mapping table (case-insensitive)
50
- 2. `$USERNAME` (Windows) or `$USER` (Unix) -> lookup in mapping table
51
- 3. Fallback: `dev/`
52
-
53
- **Mapping Table:**
54
-
55
- | git config / env var contains | Branch prefix |
56
- |-------------------------------|---------------|
57
- | caio (case-insensitive) | `caio/` |
58
- | matheus OR soier | `soier/` |
59
- | (anything else) | `dev/` |
60
-
61
- ### 3. Before Every Commit — Safety Checks (MANDATORY)
62
-
63
- ```
64
- 1. git status — verify only expected files changed
65
- 2. git diff --stat — show summary to user
66
- 3. SECRET SCAN — reject if ANY of these are staged:
67
- - .env files (except .env.example with placeholders)
68
- - Files containing API keys, tokens, passwords in plaintext
69
- - Private keys (RSA, SSH, PGP)
70
- - Database connection strings with credentials
71
- - Webhook URLs with embedded tokens
72
- 4. Commit with conventional message + story reference
73
- ```
74
-
75
- **If secrets detected → BLOCK commit, warn user, remove file from staging.**
76
-
77
- ### 4. Before Push — Conflict Prevention (MANDATORY)
78
-
79
- ```
80
- 1. git fetch origin main
81
- 2. git merge origin/main --no-edit (into feature branch)
82
- 3. If conflicts → AGENT resolves them (not the user)
83
- - For simple conflicts (whitespace, imports): auto-resolve
84
- - For complex conflicts: show both versions, ask user which to keep
85
- 4. Run tests after merge
86
- 5. Only then: git push origin {branch}
87
- ```
88
-
89
- ### 5. PR Creation — Automatic
90
-
91
- After push, the agent MUST:
92
- ```
93
- 1. gh pr create with clear title and description (uses PR template)
94
- 2. Auto-assign reviewer based on who is pushing:
95
- - Maintainer's PR → can merge directly (admin bypass)
96
- - Collaborator's PR → assign maintainer as reviewer (required approval)
97
- 3. Inform the user: "PR criado"
98
- ```
99
-
100
- ### 6. After PR Merge — Cleanup
101
-
102
- ```
103
- 1. git checkout main
104
- 2. git pull origin main
105
- 3. Delete local feature branch
106
- 4. Inform user: "Branch limpa, pronto para proximo trabalho"
107
- ```
108
-
109
- ## Conflict Resolution Rules
110
-
111
- | Scenario | Agent Action |
112
- |----------|-------------|
113
- | Same file, different sections | Auto-merge (git handles) |
114
- | Same file, same lines | Show diff, ask user which version to keep |
115
- | Package.json version conflict | Always take higher version |
116
- | Generated files (lock, build) | Regenerate after merge |
117
- | Story/doc files | Merge both contents (additive) |
118
-
119
- **NEVER use `--force` push. Use `--force-with-lease` ONLY as last resort with user confirmation.**
120
-
121
- ## Communication Protocol
122
-
123
- When working in parallel, agents MUST inform users about:
124
-
125
- | Event | Message |
126
- |-------|---------|
127
- | Session start | "Atualizando seu projeto... X mudancas novas do {outro}." |
128
- | Branch created | "Criada area segura para trabalhar: `caio/feat/xxx`" |
129
- | Pre-push conflict found | "{outro} mudou {file}. Resolvendo automaticamente..." |
130
- | Secret detected | "BLOQUEADO: encontrei {tipo} em {file}. Removendo antes de salvar." |
131
- | PR created | "Enviei para revisao. {outro} precisa aprovar no GitHub." |
132
- | PR merged by other | "{outro} aprovou suas mudancas. Atualizando seu projeto..." |
133
-
134
- ## Destructive Operations — BLOCKED BY DEFAULT
135
-
136
- These operations require EXPLICIT user confirmation before execution:
137
-
138
- | Operation | Risk | Confirmation Required |
139
- |-----------|------|----------------------|
140
- | `git push --force` / `--force-with-lease` | Overwrite remote history | YES + explain risk |
141
- | `git reset --hard` | Destroy local uncommitted work | YES + explain risk |
142
- | `git branch -D` | Delete branch with unmerged commits | YES + explain risk |
143
- | `git clean -f` | Delete untracked files permanently | YES + explain risk |
144
- | Delete remote branch | Affects other collaborators | YES |
12
+ Users NEVER resolve conflicts, pick branches, remember to pull, or touch rebase/force-push.
13
+
14
+ ## The Law (every session, every commit, every push)
15
+
16
+ 1. **Session start — auto-sync (MANDATORY):** `git fetch origin` → sync local with
17
+ origin (fast-forward; if diverged STOP and resolve safely) → create a work
18
+ branch. **NEVER start work on `main` directly.**
19
+ 2. **Auto-branch:** the agent creates and names the branch (`{user}/{type}/{desc}`);
20
+ the user never needs to.
21
+ 3. **Before every commit:** `git status` first; **SECRET SCAN — if any secret,
22
+ credential, key, or real `.env` is staged → BLOCK the commit**, warn, unstage.
23
+ 4. **Before push:** fetch + merge `origin/main` into the feature branch; the AGENT
24
+ resolves conflicts (simple auto; complex → show both versions, ask which to
25
+ keep); run tests after merging; only then push.
26
+ 5. **After push:** create the PR automatically with reviewer assignment; after
27
+ merge, clean up and re-sync.
28
+ 6. **Destructive operations are BLOCKED by default** (`--force`, `reset --hard`,
29
+ `branch -D`, `clean -f`, deleting remote branches): they require EXPLICIT user
30
+ confirmation plus a risk explanation. **NEVER `push --force`**;
31
+ `--force-with-lease` only as a last resort with user confirmation.
145
32
 
146
33
  ## Anti-Patterns (FORBIDDEN)
147
34
 
148
- - Letting user work on `main` directly
149
- - Pushing to `main` without PR (branch protection enforces this)
150
- - Ignoring `git fetch` at session start
151
- - Letting conflicts accumulate (merge frequently)
152
- - Using `git push --force` without explicit user confirmation
153
- - Assuming the other person isn't working on the same area
154
- - Committing without checking `git status` first
35
+ - Letting the user work on `main` directly, or pushing to `main` without a PR
36
+ - Skipping `git fetch` at session start; letting conflicts accumulate
37
+ - Committing without checking `git status`; committing secrets or credentials
155
38
  - Skipping tests after resolving conflicts
156
- - Committing files containing secrets or credentials
157
- - Running destructive git operations without user confirmation
158
-
159
- ## For Projects Using SINAPSE (not just sinapse-ai repo)
160
-
161
- These same rules apply to ANY project where SINAPSE agents operate:
162
- 1. Auto-branch before work
163
- 2. Auto-sync before starting
164
- 3. Secret scan before every commit
165
- 4. Auto-resolve simple conflicts
166
- 5. Auto-PR with reviewer assignment
167
- 6. User never touches git directly
168
-
169
- ## User Cheat Sheet (the ONLY things users do manually)
170
-
171
- ```
172
- ! git push origin main ← when agent can't push (hook block)
173
- ! npm publish ← when publishing to NPM
174
- ```
175
-
176
- Everything else: **ask the agent to do it.**
177
-
178
- ## PR Quality Standards
179
-
180
- | Metric | Target | Warning |
181
- |--------|--------|---------|
182
- | PR size | < 200 lines | > 400 lines |
183
- | PR cycle time | < 1 day | > 3 days |
39
+ - Running destructive git operations without explicit user confirmation
40
+ - Assuming the other person isn't working on the same area
184
41
 
185
- **DORA Targets (Elite):** Deploy multiple/day, lead time < 1 day, failure rate < 4%, recovery < 1 hour.
42
+ > **Detail (loads on file work):** branch naming + user-detection tables, per-phase
43
+ > checklists, conflict-resolution matrix, communication protocol messages, PR
44
+ > quality/DORA targets, user cheat sheet — see `safe-collaboration-reference.md`.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Doctor Check Registry
3
3
  *
4
- * Exports all 15 check modules in execution order.
4
+ * Exports all 16 default check modules (plus 1 deep-only) in execution order.
5
5
  *
6
6
  * @module sinapse-ai/doctor/checks
7
7
  * @story INS-4.1, INS-4.8
@@ -87,9 +87,10 @@ const DEFAULT_CONFIG = {
87
87
  globalTimeout: 45 * 60 * 1000, // 45 minutes
88
88
  subtaskTimeout: 10 * 60 * 1000, // 10 minutes per subtask
89
89
 
90
- // Epic 10: Parallel Execution
91
- parallelMode: false, // Enable wave-based parallel execution
92
- maxParallel: 4, // Max concurrent tasks per wave
90
+ // NOTE: dead `parallelMode`/`maxParallel` flags lived here (Epic 10) never
91
+ // read by this orchestrator (waves were measured and rejected; see
92
+ // docs/epics/epic-orchestration-consolidation/KNOWN-LIMITATIONS.md). Removed
93
+ // with `useSubagentDispatch` rationale below (AF-20260704 Lote B).
93
94
  // NOTE: a dead `useSubagentDispatch` flag lived here — it was never read.
94
95
  // Agent routing happens one level up: epic-4 delegates to this BuildOrchestrator,
95
96
  // which builds via executeSubtaskWithClaude. Removed to kill the false affordance
@@ -262,8 +262,8 @@ class SubagentDispatcher extends EventEmitter {
262
262
  return this.agentMapping[task.type.toLowerCase()];
263
263
  }
264
264
 
265
- // F2: if the task names a real agent id directly (any of the 189 squad/
266
- // framework personas), honor it instead of inferring a generic one.
265
+ // F2: if the task names a real agent id directly (any squad/framework
266
+ // persona known to the resolver), honor it instead of inferring a generic one.
267
267
  if (this.agentResolver && task.name && this.agentResolver.has(task.name)) {
268
268
  return `@${this.agentResolver.resolve(task.name).id}`;
269
269
  }
@@ -2,7 +2,8 @@
2
2
  * Ideation Engine
3
3
  * Story 11.1 - Enhanced Capabilities
4
4
  *
5
- * AI-powered analysis for codebase improvements.
5
+ * Heuristic static analysis for codebase improvements (pure-Node scanners: grep,
6
+ * line counts, npm audit, madge — no LLM calls).
6
7
  * Suggests optimizations for performance, security, code quality, and UX.
7
8
  */
8
9
 
@@ -73,6 +73,14 @@ async function orchestrate(storyId, options = {}) {
73
73
  console.log(chalk.cyan.bold(` 🚀 SINAPSE Orchestrator: ${storyId}`));
74
74
  console.log(chalk.cyan('═══════════════════════════════════════════════════════════\n'));
75
75
 
76
+ // Measured-scope guard (AF-20260704 Lote B): the help text already states the
77
+ // 1-story-per-run limit, but nothing said it at runtime — where it matters.
78
+ console.log(
79
+ chalk.dim(
80
+ 'Scope: 1 story per run — multi-story chaining is not supported (see KNOWN-LIMITATIONS.md).\n',
81
+ ),
82
+ );
83
+
76
84
  if (options.phaseLimit) {
77
85
  console.log(
78
86
  chalk.yellow(
@@ -107,6 +115,11 @@ async function orchestrate(storyId, options = {}) {
107
115
  // Start from specific epic (AC5)
108
116
  if (options.epic) {
109
117
  console.log(chalk.yellow(`Starting from Epic ${options.epic}...`));
118
+ console.log(
119
+ chalk.yellow(
120
+ '⚠️ --epic resumes THIS story from the given epic — it does not chain multiple stories.',
121
+ ),
122
+ );
110
123
  result = await orchestrator.resumeFromEpic(options.epic);
111
124
  } else {
112
125
  console.log(chalk.green('Starting full pipeline...'));
@@ -198,6 +198,66 @@ function storyStatusIsReady(file) {
198
198
  return VALID_STORY_STATUSES.includes(status);
199
199
  }
200
200
 
201
+ // ═══════════════════════════════════════════════════════════════════════════════════
202
+ // SPEC SUBSTANCE (AF-20260704 M2)
203
+ // ═══════════════════════════════════════════════════════════════════════════════════
204
+ // A story can be `Ready` yet empty. The status gate alone lets a substanceless
205
+ // story unlock implementation, which violates No Invention (Art. IV). These checks
206
+ // verify the story actually carries the required sections + at least one acceptance
207
+ // criterion, and flag missing traceability as a (non-blocking) concern.
208
+
209
+ const STORY_SECTION_PATTERNS = Object.freeze({
210
+ acceptanceCriteria: /^#{1,4}\s*(acceptance criteria|crit[eé]rios? de aceita)/im,
211
+ scope: /^#{1,4}\s*(scope|escopo)/im,
212
+ description: /^#{1,4}\s*(description|descri[cç][aã]o)/im,
213
+ });
214
+ /** A markdown checkbox item with real content. */
215
+ const AC_CHECKBOX = /^\s*[-*]\s*\[[ xX]\]\s+\S/m;
216
+ /** A Given/When/Then triple (executable AC form). */
217
+ const AC_GWT = /given[\s\S]{0,120}when[\s\S]{0,120}then/i;
218
+ /** Signals that the story traces to evidence/requirement (No Invention). */
219
+ const AC_TRACEABILITY = /(evid[eê]ncia|\bFR-\d|\bNFR-\d|\bCON-\d|\bAC\d|\bepic\b|\bstory\b|audit)/i;
220
+
221
+ /**
222
+ * Inspect a story file for substance (required sections + ≥1 acceptance criterion).
223
+ * Never throws — a read error degrades open (warn-and-proceed), so a filesystem
224
+ * hiccup can never block development (circuit-breaker principle).
225
+ * @param {string} file
226
+ * @returns {{ok:boolean, missingSections:string[], hasAcItem:boolean, hasTraceability:boolean, degraded?:boolean}}
227
+ */
228
+ function storyHasSubstance(file) {
229
+ let content;
230
+ try {
231
+ content = fs.readFileSync(file, 'utf8');
232
+ } catch {
233
+ return { ok: true, missingSections: [], hasAcItem: true, hasTraceability: true, degraded: true };
234
+ }
235
+ const missingSections = [];
236
+ if (!STORY_SECTION_PATTERNS.description.test(content)) missingSections.push('Descrição/Description');
237
+ if (!STORY_SECTION_PATTERNS.acceptanceCriteria.test(content)) missingSections.push('Acceptance Criteria');
238
+ if (!STORY_SECTION_PATTERNS.scope.test(content)) missingSections.push('Escopo/Scope');
239
+ const hasAcItem = AC_CHECKBOX.test(content) || AC_GWT.test(content);
240
+ const hasTraceability = AC_TRACEABILITY.test(content);
241
+ const ok = missingSections.length === 0 && hasAcItem;
242
+ return { ok, missingSections, hasAcItem, hasTraceability };
243
+ }
244
+
245
+ /**
246
+ * Substance verdict across a project's Ready stories. A project satisfies the
247
+ * substance gate when AT LEAST ONE Ready story is substantive (mirrors how
248
+ * `hasReadyStory` treats "some Ready story exists"). Returns the best verdict.
249
+ * @param {string} projectRoot
250
+ */
251
+ function readyStorySubstance(projectRoot) {
252
+ const dir = path.join(projectRoot, 'docs', 'stories');
253
+ const readyFiles = walkMarkdown(dir).filter((f) => storyStatusIsReady(f));
254
+ if (readyFiles.length === 0) {
255
+ return { ok: false, missingSections: [], hasAcItem: false, hasTraceability: false, noReadyStory: true };
256
+ }
257
+ const verdicts = readyFiles.map(storyHasSubstance);
258
+ return verdicts.find((v) => v.ok) || verdicts[0];
259
+ }
260
+
201
261
  // ═══════════════════════════════════════════════════════════════════════════════════
202
262
  // MAIN RESOLVER
203
263
  // ═══════════════════════════════════════════════════════════════════════════════════
@@ -237,17 +297,37 @@ function resolveDocFirstState(opts = {}) {
237
297
  const prd = hasPrd(projectRoot);
238
298
  const epic = hasEpic(projectRoot);
239
299
  const readyStory = hasReadyStory(projectRoot);
300
+ // M2: a Ready story must also carry substance (sections + ≥1 AC). Evaluated
301
+ // only when a Ready story exists, so this never changes the "no story" message.
302
+ const substance = readyStory
303
+ ? readyStorySubstance(projectRoot)
304
+ : { ok: false, missingSections: [], hasAcItem: false, hasTraceability: false };
240
305
 
241
306
  // Light types ride on an existing project: the minimal gate is "a Ready story"
242
307
  // (the existing story-gate). Full projects additionally need PRD + epic.
243
308
  const missing = [];
244
- if (!readyStory) missing.push('story (status >= Ready)');
309
+ if (!readyStory) {
310
+ missing.push('story (status >= Ready)');
311
+ } else if (!substance.ok) {
312
+ // Block: a Ready story without required sections / any AC is not implementable.
313
+ const lack = substance.missingSections.length
314
+ ? substance.missingSections.join(', ')
315
+ : 'nenhum acceptance criterion';
316
+ missing.push(`story substance (falta: ${lack})`);
317
+ }
245
318
  if (!isLightType) {
246
319
  if (!prd) missing.push('PRD (docs/prd.md)');
247
320
  if (!epic) missing.push('epic (docs/epics/)');
248
321
  }
249
322
  const satisfied = missing.length === 0;
250
323
 
324
+ // Non-blocking concerns (Art. IV No Invention): a substantive story that lacks
325
+ // any traceability signal to evidence/requirement is flagged, not blocked.
326
+ const concerns = [];
327
+ if (readyStory && substance.ok && !substance.hasTraceability) {
328
+ concerns.push('story sem rastreabilidade explícita (Art. IV) — cite evidência/requisito/AC');
329
+ }
330
+
251
331
  return {
252
332
  brief,
253
333
  projectType,
@@ -255,7 +335,15 @@ function resolveDocFirstState(opts = {}) {
255
335
  isLightType,
256
336
  workflow,
257
337
  artifacts,
258
- gate: { prd, epic, readyStory, satisfied, missing },
338
+ gate: {
339
+ prd,
340
+ epic,
341
+ readyStory,
342
+ substance: substance.ok,
343
+ satisfied,
344
+ missing,
345
+ concerns,
346
+ },
259
347
  maturity: assessProjectMaturity(projectRoot),
260
348
  };
261
349
  }
@@ -315,6 +403,9 @@ module.exports = {
315
403
  classifyProjectType,
316
404
  resolveDocFirstState,
317
405
  assessProjectMaturity,
406
+ // M2 (AF-20260704): spec substance checks, exported for reuse + testing.
407
+ storyHasSubstance,
408
+ readyStorySubstance,
318
409
  REQUIRED_ARTIFACTS_BY_WORKFLOW,
319
410
  TYPE_KEYWORDS,
320
411
  // re-exported for callers that want the raw map
@@ -14,6 +14,7 @@
14
14
  const fs = require('fs-extra');
15
15
  const path = require('path');
16
16
  const EpicExecutor = require('./epic-executor');
17
+ const { classifyComplexity } = require('../spec-complexity');
17
18
 
18
19
  /**
19
20
  * Spec Pipeline phases
@@ -131,14 +132,26 @@ class Epic3Executor extends EpicExecutor {
131
132
  this._addArtifact('spec', specPath);
132
133
 
133
134
  // Collect complexity and requirements from phases
134
- const complexity = phaseResults['assess-complexity']?.complexity || 'STANDARD';
135
+ const assess = phaseResults['assess-complexity'] || {};
136
+ const complexity = assess.complexity || 'STANDARD';
135
137
  const requirements = phaseResults['gather-requirements']?.requirements || [];
136
138
 
139
+ // M4 (AF-20260704 #9b): turn the COMPLEX≥16 rule from prose into a
140
+ // deterministic classification. Prefer the numeric dimension score when the
141
+ // assess phase provides one; otherwise fall back to the level string.
142
+ const classification = classifyComplexity(
143
+ typeof assess.score === 'number' ? assess.score : assess.dimensions || complexity,
144
+ );
145
+
137
146
  // Honesty invariant (epic: orchestration-consolidation, F0a):
138
147
  // if the spec was auto-stubbed (no real agent ran), report STUB, not success.
139
148
  const specResult = {
140
149
  specPath,
141
- complexity,
150
+ complexity: classification.level,
151
+ complexityScore: classification.score,
152
+ requiresRevisionCycle: classification.requiresRevisionCycle,
153
+ requiresFullSpecPipeline: classification.requiresFullSpecPipeline,
154
+ specPipelinePhases: classification.phases,
142
155
  requirements,
143
156
  phases: Object.keys(phaseResults),
144
157
  };
@@ -193,12 +193,14 @@ class Epic4Executor extends EpicExecutor {
193
193
  async _executeViaBuildOrchestrator(storyId, context) {
194
194
  try {
195
195
  const { BuildOrchestrator } = require('../../execution/build-orchestrator');
196
+ // buildOptions is passed once, via build() — which already merges it over
197
+ // the constructor config ({...this.config, ...options}). Passing it in both
198
+ // places (AF-20260704 Lote B) was redundant, not wrong.
196
199
  const builder = new BuildOrchestrator({
197
200
  rootPath: this.projectRoot,
198
201
  useWorktree: false,
199
202
  autoMerge: false,
200
203
  runQA: false,
201
- ...(context.buildOptions || {}),
202
204
  });
203
205
  return await builder.build(storyId, context.buildOptions || {});
204
206
  } catch (err) {
@@ -158,6 +158,8 @@ const {
158
158
 
159
159
  module.exports = {
160
160
  // Main orchestrators
161
+ // @deprecated WorkflowOrchestrator has no internal consumers (AF-20260704);
162
+ // kept exported because the barrel is public package API. Prefer MasterOrchestrator.
161
163
  WorkflowOrchestrator,
162
164
  MasterOrchestrator, // Epic 0: ADE Master Orchestrator
163
165
 
@@ -290,6 +292,9 @@ module.exports = {
290
292
  STALE_SNAPSHOT_DAYS,
291
293
 
292
294
  // Story 12.4: Epic Context Accumulator (Projeto Bob)
295
+ // @deprecated EpicContextAccumulator has no internal consumers (AF-20260704;
296
+ // multi-story orchestration was measured and rejected — see KNOWN-LIMITATIONS.md).
297
+ // Kept exported because the barrel is public package API.
293
298
  EpicContextAccumulator,
294
299
  createEpicContextAccumulator,
295
300
  CompressionLevel,
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Spec-Pipeline Complexity — deterministic threshold + phase plan.
3
+ *
4
+ * The COMPLEX≥16 rule lived only in prose (`workflow-execution.md` §3,
5
+ * `documentation-first.md` complexity gate): "score ≥16 → COMPLEX → run the full
6
+ * Spec Pipeline (6 phases + revision cycle) FIRST". Nothing in code enforced the
7
+ * threshold or derived the phase plan from it, so the assessment was advisory.
8
+ *
9
+ * This module turns the threshold and the per-level phase plan into deterministic,
10
+ * tested code (Story rodada2-m4, AF-20260704 #9b). It does NOT invent HOW the five
11
+ * dimensions are scored — those values come from the `assess-complexity` phase; it
12
+ * only encodes the mapping score → level → required phases, canonically defined in
13
+ * `workflow-execution.md`.
14
+ *
15
+ * @module core/orchestration/spec-complexity
16
+ */
17
+
18
+ 'use strict';
19
+
20
+ /** The five complexity dimensions, each scored 1-5 (min 5, max 25). */
21
+ const DIMENSIONS = Object.freeze(['scope', 'integration', 'infrastructure', 'knowledge', 'risk']);
22
+
23
+ /**
24
+ * Canonical thresholds (`workflow-execution.md` §3):
25
+ * score <= 8 → SIMPLE
26
+ * 9..15 → STANDARD
27
+ * score >= 16 → COMPLEX
28
+ */
29
+ const THRESHOLDS = Object.freeze({ SIMPLE_MAX: 8, COMPLEX_MIN: 16 });
30
+
31
+ const LEVELS = Object.freeze({ SIMPLE: 'SIMPLE', STANDARD: 'STANDARD', COMPLEX: 'COMPLEX' });
32
+
33
+ /**
34
+ * Phase plans per level (`workflow-execution.md` §3 table):
35
+ * SIMPLE → gather → spec → critique (3)
36
+ * STANDARD → gather → assess → research → spec → critique → plan (6)
37
+ * COMPLEX → the 6 phases + a revision cycle (6 + revision)
38
+ */
39
+ const PHASES_BY_LEVEL = Object.freeze({
40
+ SIMPLE: Object.freeze(['gather-requirements', 'write-spec', 'critique']),
41
+ STANDARD: Object.freeze([
42
+ 'gather-requirements',
43
+ 'assess-complexity',
44
+ 'research-dependencies',
45
+ 'write-spec',
46
+ 'critique',
47
+ 'plan',
48
+ ]),
49
+ COMPLEX: Object.freeze([
50
+ 'gather-requirements',
51
+ 'assess-complexity',
52
+ 'research-dependencies',
53
+ 'write-spec',
54
+ 'critique',
55
+ 'plan',
56
+ ]),
57
+ });
58
+
59
+ /**
60
+ * Map a numeric complexity score to its level. Deterministic; no side effects.
61
+ * @param {number} score - Sum of the five dimensions (nominally 5..25).
62
+ * @returns {'SIMPLE'|'STANDARD'|'COMPLEX'}
63
+ */
64
+ function scoreToLevel(score) {
65
+ const n = Number(score);
66
+ if (!Number.isFinite(n)) return LEVELS.STANDARD; // conservative default
67
+ if (n <= THRESHOLDS.SIMPLE_MAX) return LEVELS.SIMPLE;
68
+ if (n >= THRESHOLDS.COMPLEX_MIN) return LEVELS.COMPLEX;
69
+ return LEVELS.STANDARD;
70
+ }
71
+
72
+ /** Normalize a level-ish input (a level string, in any case) to a canonical level. */
73
+ function normalizeLevel(level) {
74
+ const u = String(level || '').trim().toUpperCase();
75
+ return LEVELS[u] || null;
76
+ }
77
+
78
+ /**
79
+ * Sum an object of dimension → score (1-5). Missing dimensions count as 0.
80
+ * @param {Record<string, number>} dimensions
81
+ * @returns {number}
82
+ */
83
+ function sumDimensions(dimensions) {
84
+ if (!dimensions || typeof dimensions !== 'object') return NaN;
85
+ return DIMENSIONS.reduce((total, d) => {
86
+ const v = Number(dimensions[d]);
87
+ return total + (Number.isFinite(v) ? v : 0);
88
+ }, 0);
89
+ }
90
+
91
+ /**
92
+ * Classify complexity from either a numeric score, a dimensions object, or an
93
+ * already-decided level string. Returns the deterministic plan.
94
+ *
95
+ * @param {number|string|Record<string, number>} input
96
+ * @returns {{
97
+ * level: 'SIMPLE'|'STANDARD'|'COMPLEX',
98
+ * score: number|null,
99
+ * phases: string[],
100
+ * requiresRevisionCycle: boolean,
101
+ * requiresFullSpecPipeline: boolean
102
+ * }}
103
+ */
104
+ function classifyComplexity(input) {
105
+ let level;
106
+ let score = null;
107
+
108
+ if (typeof input === 'number') {
109
+ score = input;
110
+ level = scoreToLevel(input);
111
+ } else if (typeof input === 'string') {
112
+ level = normalizeLevel(input) || LEVELS.STANDARD;
113
+ } else if (input && typeof input === 'object') {
114
+ const s = sumDimensions(input);
115
+ score = Number.isFinite(s) ? s : null;
116
+ level = Number.isFinite(s) ? scoreToLevel(s) : LEVELS.STANDARD;
117
+ } else {
118
+ level = LEVELS.STANDARD; // conservative default when nothing usable is given
119
+ }
120
+
121
+ return {
122
+ level,
123
+ score,
124
+ phases: [...PHASES_BY_LEVEL[level]],
125
+ // COMPLEX is the only level that adds the revision cycle.
126
+ requiresRevisionCycle: level === LEVELS.COMPLEX,
127
+ // SIMPLE runs the trimmed 3-phase pipeline; STANDARD/COMPLEX run the full one.
128
+ requiresFullSpecPipeline: level !== LEVELS.SIMPLE,
129
+ };
130
+ }
131
+
132
+ module.exports = {
133
+ DIMENSIONS,
134
+ THRESHOLDS,
135
+ LEVELS,
136
+ PHASES_BY_LEVEL,
137
+ scoreToLevel,
138
+ normalizeLevel,
139
+ sumDimensions,
140
+ classifyComplexity,
141
+ };