sinapse-ai 1.20.1 → 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 (122) 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/brownfield-progress.js +219 -0
  15. package/.sinapse-ai/core/orchestration/cli-commands.js +13 -0
  16. package/.sinapse-ai/core/orchestration/doc-first-resolver.js +96 -2
  17. package/.sinapse-ai/core/orchestration/executors/epic-3-executor.js +15 -2
  18. package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +3 -1
  19. package/.sinapse-ai/core/orchestration/greenfield-handler.js +97 -0
  20. package/.sinapse-ai/core/orchestration/index.js +5 -0
  21. package/.sinapse-ai/core/orchestration/spec-complexity.js +141 -0
  22. package/.sinapse-ai/core/orchestration/workflow-executor.js +17 -1
  23. package/.sinapse-ai/core-config.yaml +30 -0
  24. package/.sinapse-ai/data/entity-registry.yaml +81 -35
  25. package/.sinapse-ai/development/agents/architect.md +3 -15
  26. package/.sinapse-ai/development/agents/data-engineer.md +3 -15
  27. package/.sinapse-ai/development/agents/developer.md +3 -24
  28. package/.sinapse-ai/development/agents/devops.md +4 -25
  29. package/.sinapse-ai/development/agents/quality-gate.md +3 -25
  30. package/.sinapse-ai/development/knowledge-base/token-economy-guide.md +1 -1
  31. package/.sinapse-ai/development/tasks/execute-epic-plan.md +3 -0
  32. package/.sinapse-ai/development/tasks/resolve-github-issue.md +1 -1
  33. package/.sinapse-ai/development/workflows/brownfield-discovery.yaml +16 -0
  34. package/.sinapse-ai/development/workflows/epic-orchestration.yaml +11 -0
  35. package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.1-COMPLETE.md +6 -2
  36. package/.sinapse-ai/docs/standards/SINAPSE-LIVRO-DE-OURO-V2.2-SUMMARY.md +4 -1
  37. package/.sinapse-ai/install-manifest.yaml +58 -50
  38. package/.sinapse-ai/product/templates/story-tmpl.yaml +11 -6
  39. package/.sinapse-ai/quality/judge-calibration/README.md +75 -0
  40. package/.sinapse-ai/quality/judge-calibration/calibration-log.md +70 -0
  41. package/.sinapse-ai/quality/judge-calibration/golden-set.json +105 -0
  42. package/.sinapse-ai/quality/judge-calibration/scenarios.json +90 -0
  43. package/CHANGELOG.md +55 -10
  44. package/README.en.md +1 -1
  45. package/README.md +6 -6
  46. package/bin/sinapse-minimal.js +5 -4
  47. package/docs/community/README-community-snippet-core.md +1 -1
  48. package/docs/community/README-community-snippet-mcp.md +2 -2
  49. package/docs/framework/README.md +2 -2
  50. package/docs/framework/architecture-overview.md +2 -2
  51. package/docs/framework/core-architecture.md +1 -1
  52. package/docs/framework/feature-process.md +5 -5
  53. package/docs/framework/guiding-principles.md +1 -1
  54. package/docs/framework/roadmap.md +4 -4
  55. package/docs/framework/source-tree.md +1 -1
  56. package/docs/framework/versioning-and-releases.md +1 -1
  57. package/docs/getting-started.md +1 -1
  58. package/docs/guides/agent-selection-guide.md +1 -1
  59. package/docs/guides/agents/traces/README.md +1 -1
  60. package/docs/guides/config-migration-guide.md +1 -1
  61. package/docs/guides/development-setup.md +1 -1
  62. package/docs/guides/docker-mcp-setup.md +5 -5
  63. package/docs/guides/getting-started.md +1 -1
  64. package/docs/guides/git-workflow-guide.md +3 -3
  65. package/docs/guides/ide-integration.md +3 -3
  66. package/docs/guides/ide-sync-guide.md +1 -1
  67. package/docs/guides/mcp/desktop-commander.md +2 -2
  68. package/docs/guides/mcp/docker-gateway-tutorial.md +1 -1
  69. package/docs/guides/mcp-global-setup.md +3 -3
  70. package/docs/guides/memory-intelligence-system.md +10 -10
  71. package/docs/guides/meta-agent-commands.md +1 -1
  72. package/docs/guides/quality-gates.md +1 -1
  73. package/docs/guides/security-hardening.md +1 -1
  74. package/docs/guides/service-discovery.md +1 -1
  75. package/docs/guides/squad-examples/README.md +1 -1
  76. package/docs/guides/squads-guide.md +1 -1
  77. package/docs/guides/testing-guide.md +2 -2
  78. package/docs/guides/user-guide.md +22 -22
  79. package/docs/guides/workflows/BROWNFIELD-DISCOVERY-WORKFLOW.md +3 -3
  80. package/docs/guides/workflows/BROWNFIELD-SERVICE-WORKFLOW.md +1 -1
  81. package/docs/guides/workflows/GREENFIELD-UI-WORKFLOW.md +2 -2
  82. package/docs/guides/workflows/SPEC-PIPELINE-WORKFLOW.md +3 -3
  83. package/docs/guides/workflows/STORY-DEVELOPMENT-CYCLE-WORKFLOW.md +3 -3
  84. package/docs/guides/workflows/pro-developer-workflow.md +2 -2
  85. package/docs/guides/workflows-guide.md +1 -1
  86. package/docs/guides/workflows-overview.md +1 -1
  87. package/docs/installation/npx-install.md +1 -1
  88. package/docs/installation/uninstallation.md +1 -1
  89. package/docs/installation/v4-quick-start.md +1 -1
  90. package/docs/pt/guides/user-guide.md +18 -18
  91. package/docs/pt/security.md +2 -2
  92. package/docs/security/overview.md +2 -2
  93. package/docs/security/security-best-practices.md +1 -1
  94. package/docs/sinapse-agent-flows/architect-system.md +1 -1
  95. package/docs/sinapse-agent-flows/data-engineer-system.md +1 -1
  96. package/docs/sinapse-agent-flows/dev-system.md +1 -1
  97. package/docs/sinapse-agent-flows/devops-system.md +2 -2
  98. package/docs/sinapse-agent-flows/qa-system.md +1 -1
  99. package/docs/sinapse-agent-flows/sm-system.md +2 -2
  100. package/docs/sinapse-agent-flows/snps-orqx-system.md +4 -4
  101. package/docs/sinapse-agent-flows/squad-creator-system.md +1 -1
  102. package/docs/sinapse-workflows/README.md +2 -2
  103. package/docs/sinapse-workflows/brownfield-discovery-workflow.md +3 -3
  104. package/docs/sinapse-workflows/brownfield-service-workflow.md +3 -3
  105. package/docs/sinapse-workflows/greenfield-ui-workflow.md +2 -2
  106. package/docs/sinapse-workflows/spec-pipeline-workflow.md +3 -3
  107. package/docs/sinapse-workflows/story-development-cycle-workflow.md +3 -3
  108. package/docs/troubleshooting.md +1 -1
  109. package/package.json +7 -1
  110. package/scripts/calibrate-judge.js +134 -0
  111. package/scripts/eval-e2e.js +149 -0
  112. package/scripts/validate-all.js +8 -0
  113. package/scripts/validate-article-iv.js +289 -0
  114. package/scripts/validate-constitution.js +58 -0
  115. package/scripts/validate-evals.js +9 -2
  116. package/scripts/validate-story-acs.js +174 -0
  117. package/scripts/validate-tool-descriptions.js +128 -0
  118. package/scripts/wave-gate.js +207 -0
  119. package/squads/claude-code-mastery/agents/project-integrator.md +3 -10
  120. package/squads/claude-code-mastery/knowledge-base/context-window-optimization.md +2 -2
  121. package/squads/claude-code-mastery/knowledge-base/memory-systems-reference.md +1 -1
  122. 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
 
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Brownfield Discovery — deterministic progress + QA gate in code.
3
+ *
4
+ * Story onda3-s3-brownfield-progress-gate (AF-20260702 item 3.3).
5
+ *
6
+ * The 10 phases of brownfield-discovery.yaml are executed by agents (prose,
7
+ * orchestrate-then-handoff). What was missing — and what this module adds —
8
+ * is the DETERMINISTIC layer around that prose:
9
+ *
10
+ * 1. resolveBrownfieldProgress(): where the assessment actually stands,
11
+ * measured from artifacts ON DISK (not from what anyone claims), giving
12
+ * an exact resume point per phase.
13
+ * 2. evaluateQaGate() / recordRework(): the Phase 7 verdict (APPROVED /
14
+ * NEEDS WORK) parsed from docs/reviews/qa-review.md by code, with a
15
+ * persisted rework counter capped at MAX_REWORK — the NEEDS WORK loop
16
+ * escalates instead of spinning forever.
17
+ *
18
+ * Honesty contract: an unfilled template ("[APPROVED / NEEDS WORK]") is
19
+ * PENDING, not a verdict. Autonomous fan-out of phases 1-3 remains gated on
20
+ * a measured pilot (same pre-registered gate as epic waves — see the epic
21
+ * README of epic-onda3-estrutural); this module is the safe deterministic
22
+ * substrate either way.
23
+ *
24
+ * @module core/orchestration/brownfield-progress
25
+ */
26
+
27
+ 'use strict';
28
+
29
+ const fs = require('fs');
30
+ const path = require('path');
31
+
32
+ const { fileHasContent } = require('./doc-first-resolver');
33
+
34
+ const QA_REVIEW_RELPATH = path.join('docs', 'reviews', 'qa-review.md');
35
+ const STATE_RELPATH = path.join('.sinapse', 'workflow-state', 'brownfield-discovery.json');
36
+
37
+ /** Rework ceiling for the Phase 7 loop (NEEDS WORK → fix → re-review). */
38
+ const MAX_REWORK = 2;
39
+
40
+ /** Normalize a step's `creates` (string | string[]) into a string list. */
41
+ function listArtifacts(step) {
42
+ if (!step || !step.creates) return [];
43
+ const raw = Array.isArray(step.creates) ? step.creates : [step.creates];
44
+ return raw.filter((a) => typeof a === 'string' && a.trim().length > 0);
45
+ }
46
+
47
+ /** Glob-ish artifacts ("story-X.X-*.md") cannot be verified deterministically. */
48
+ function isCheckable(artifact) {
49
+ return !artifact.includes('*');
50
+ }
51
+
52
+ /**
53
+ * Resolve the real state of the brownfield discovery from disk.
54
+ *
55
+ * @param {string} projectRoot
56
+ * @param {Object} workflow - Parsed `workflow` node (needs `.sequence`)
57
+ * @returns {{phases: Array, nextPhase: ?number, complete: boolean}}
58
+ */
59
+ function resolveBrownfieldProgress(projectRoot, workflow) {
60
+ const sequence = (workflow && Array.isArray(workflow.sequence)) ? workflow.sequence : [];
61
+ const byPhase = new Map();
62
+
63
+ for (const step of sequence) {
64
+ if (!step || typeof step.phase !== 'number') continue;
65
+ if (!byPhase.has(step.phase)) {
66
+ byPhase.set(step.phase, { phase: step.phase, name: step.phase_name || null, steps: [] });
67
+ }
68
+ const artifacts = listArtifacts(step).map((artifact) => {
69
+ const checkable = isCheckable(artifact);
70
+ return {
71
+ path: artifact,
72
+ checkable,
73
+ exists: checkable ? fileHasContent(path.join(projectRoot, artifact)) : null,
74
+ };
75
+ });
76
+ byPhase.get(step.phase).steps.push({
77
+ id: step.step || step.id || null,
78
+ agent: step.agent || null,
79
+ conditional: Boolean(step.condition),
80
+ condition: step.condition || null,
81
+ artifacts,
82
+ });
83
+ }
84
+
85
+ const phases = [...byPhase.values()].sort((a, b) => a.phase - b.phase);
86
+
87
+ for (const phase of phases) {
88
+ // Required = checkable artifacts of unconditional steps. Conditional steps
89
+ // (e.g. project_has_database) never block completeness — but when their
90
+ // artifacts DO exist they are reported, so nothing done is invisible.
91
+ const required = phase.steps
92
+ .filter((s) => !s.conditional)
93
+ .flatMap((s) => s.artifacts.filter((a) => a.checkable));
94
+ const present = required.filter((a) => a.exists);
95
+ phase.requiredCount = required.length;
96
+ phase.presentCount = present.length;
97
+ if (required.length === 0) {
98
+ phase.status = 'unverifiable';
99
+ } else if (present.length === required.length) {
100
+ phase.status = 'complete';
101
+ } else if (present.length > 0) {
102
+ phase.status = 'partial';
103
+ } else {
104
+ phase.status = 'pending';
105
+ }
106
+ }
107
+
108
+ const firstIncomplete = phases.find(
109
+ (p) => p.status === 'pending' || p.status === 'partial',
110
+ );
111
+
112
+ return {
113
+ phases,
114
+ nextPhase: firstIncomplete ? firstIncomplete.phase : null,
115
+ complete: phases.length > 0 && !firstIncomplete,
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Parse the Phase 7 verdict out of qa-review.md content.
121
+ *
122
+ * @param {string} content
123
+ * @returns {'approved'|'needs_work'|'pending'|'malformed'}
124
+ */
125
+ function parseQaGateStatus(content) {
126
+ if (typeof content !== 'string') return 'malformed';
127
+ const m = content.match(/gate status:\s*(.*)$/im);
128
+ if (!m) return 'pending';
129
+ const value = m[1].trim();
130
+ const hasApproved = /approved/i.test(value);
131
+ const hasNeedsWork = /needs\s+work/i.test(value);
132
+ // The unfilled template is "[APPROVED / NEEDS WORK]" — both tokens present
133
+ // means the reviewer never picked. That is PENDING, never a verdict.
134
+ if (hasApproved && hasNeedsWork) return 'pending';
135
+ if (hasApproved) return 'approved';
136
+ if (hasNeedsWork) return 'needs_work';
137
+ return 'malformed';
138
+ }
139
+
140
+ function statePath(projectRoot) {
141
+ return path.join(projectRoot, STATE_RELPATH);
142
+ }
143
+
144
+ function readState(projectRoot) {
145
+ try {
146
+ const parsed = JSON.parse(fs.readFileSync(statePath(projectRoot), 'utf8'));
147
+ return { reworkCount: 0, ...parsed };
148
+ } catch {
149
+ return { reworkCount: 0 };
150
+ }
151
+ }
152
+
153
+ function writeState(projectRoot, state) {
154
+ const file = statePath(projectRoot);
155
+ fs.mkdirSync(path.dirname(file), { recursive: true });
156
+ fs.writeFileSync(file, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
157
+ }
158
+
159
+ /**
160
+ * Evaluate the Phase 7 QA gate deterministically (read-only — never mutates
161
+ * the rework counter; that is recordRework's job).
162
+ *
163
+ * @param {string} projectRoot
164
+ * @returns {{verdict: string, reworkCount: number, maxRework: number, escalate: boolean, reviewPath: string, reason?: string}}
165
+ */
166
+ function evaluateQaGate(projectRoot) {
167
+ const reviewPath = path.join(projectRoot, QA_REVIEW_RELPATH);
168
+ const state = readState(projectRoot);
169
+ const base = {
170
+ reworkCount: state.reworkCount,
171
+ maxRework: MAX_REWORK,
172
+ reviewPath: QA_REVIEW_RELPATH,
173
+ };
174
+
175
+ if (!fileHasContent(reviewPath)) {
176
+ return { ...base, verdict: 'pending', escalate: false, reason: 'qa-review.md ausente ou vazio' };
177
+ }
178
+
179
+ let content;
180
+ try {
181
+ content = fs.readFileSync(reviewPath, 'utf8');
182
+ } catch (error) {
183
+ return { ...base, verdict: 'malformed', escalate: false, reason: `qa-review.md ilegível: ${error.message}` };
184
+ }
185
+
186
+ const verdict = parseQaGateStatus(content);
187
+ const escalate = verdict === 'needs_work' && state.reworkCount >= MAX_REWORK;
188
+ return { ...base, verdict, escalate };
189
+ }
190
+
191
+ /**
192
+ * Record one NEEDS WORK → rework loop iteration. Call it when the flow
193
+ * returns to Phase 4 after a NEEDS WORK verdict. At MAX_REWORK the gate
194
+ * escalates instead of looping.
195
+ *
196
+ * @param {string} projectRoot
197
+ * @returns {{reworkCount: number, escalate: boolean}}
198
+ */
199
+ function recordRework(projectRoot) {
200
+ const state = readState(projectRoot);
201
+ state.reworkCount += 1;
202
+ state.lastReworkAt = new Date().toISOString();
203
+ writeState(projectRoot, state);
204
+ return { reworkCount: state.reworkCount, escalate: state.reworkCount >= MAX_REWORK };
205
+ }
206
+
207
+ /** Reset the rework counter (new assessment cycle). */
208
+ function resetQaGateState(projectRoot) {
209
+ writeState(projectRoot, { reworkCount: 0 });
210
+ }
211
+
212
+ module.exports = {
213
+ resolveBrownfieldProgress,
214
+ parseQaGateStatus,
215
+ evaluateQaGate,
216
+ recordRework,
217
+ resetQaGateState,
218
+ MAX_REWORK,
219
+ };
@@ -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,8 +403,14 @@ 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
321
412
  GREENFIELD_WORKFLOW_BY_TYPE,
413
+ // Onda3-S2 (AF-20260702 item 3.4): exported so artifact gates share ONE
414
+ // definition of "artifact exists and is non-empty" instead of forking it.
415
+ fileHasContent,
322
416
  };