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
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * LLM-judge calibration harness (Story mesa2-llm-judge-calibration, AF-20260704 Mesa #2).
4
+ *
5
+ * The judge that decides "Done" is the @quality-gate agent: it emits free-form
6
+ * prose ending in `VERDICT: X`, and Epic6Executor._parseVerdict turns that prose
7
+ * into the binary verdict (APPROVED → Done). This harness calibrates that
8
+ * DETERMINISTIC seam against a human-labeled golden set:
9
+ *
10
+ * - It runs the REAL _parseVerdict (imported, never re-implemented) over each
11
+ * golden output and checks it agrees with the human-assigned verdict.
12
+ * - _parseVerdict is deterministic, so the gate is 100%: any disagreement means
13
+ * the parser regressed OR a golden label is wrong — both demand action.
14
+ *
15
+ * This does NOT calibrate the LLM's semantic judgment (non-deterministic, costly)
16
+ * — that is the documented LIVE procedure (feed the golden scenarios to the real
17
+ * @quality-gate and compare). See .sinapse-ai/quality/judge-calibration/README.md.
18
+ *
19
+ * `scoreCalibration` is pure so tests can drive it with any parse function.
20
+ *
21
+ * Exit 0 = full agreement · Exit 1 = one or more disagreements.
22
+ *
23
+ * @module scripts/calibrate-judge
24
+ */
25
+
26
+ 'use strict';
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+
31
+ const ROOT = path.resolve(__dirname, '..');
32
+ const GOLDEN_SET_PATH = path.join(
33
+ ROOT,
34
+ '.sinapse-ai/quality/judge-calibration/golden-set.json',
35
+ );
36
+
37
+ /**
38
+ * The REAL verdict-decision logic under calibration. `_parseVerdict` uses only
39
+ * its `output` argument and the module-level QAVerdict constants (no `this`), so
40
+ * it can be invoked detached via the prototype — using the exact production
41
+ * function, never a copy.
42
+ *
43
+ * @returns {(output: string) => string}
44
+ */
45
+ function loadRealParseVerdict() {
46
+ const Epic6Executor = require('../.sinapse-ai/core/orchestration/executors/epic-6-executor.js');
47
+ const fn = Epic6Executor.prototype._parseVerdict;
48
+ return (output) => fn.call(null, output);
49
+ }
50
+
51
+ /**
52
+ * Score a parse function against golden cases.
53
+ *
54
+ * @param {Array<{ id: string, output: string, expected: string }>} cases
55
+ * @param {(output: string) => string} parseFn
56
+ * @returns {{
57
+ * total: number,
58
+ * agreed: number,
59
+ * agreementRate: number,
60
+ * disagreements: Array<{ id: string, expected: string, predicted: string }>,
61
+ * confusion: Record<string, Record<string, number>>
62
+ * }}
63
+ */
64
+ function scoreCalibration(cases, parseFn) {
65
+ const disagreements = [];
66
+ const confusion = {};
67
+ let agreed = 0;
68
+
69
+ for (const c of cases) {
70
+ const predicted = parseFn(c.output);
71
+ confusion[c.expected] = confusion[c.expected] || {};
72
+ confusion[c.expected][predicted] = (confusion[c.expected][predicted] || 0) + 1;
73
+ if (predicted === c.expected) {
74
+ agreed += 1;
75
+ } else {
76
+ disagreements.push({ id: c.id, expected: c.expected, predicted });
77
+ }
78
+ }
79
+
80
+ const total = cases.length;
81
+ return {
82
+ total,
83
+ agreed,
84
+ agreementRate: total === 0 ? 1 : agreed / total,
85
+ disagreements,
86
+ confusion,
87
+ };
88
+ }
89
+
90
+ /** CLI entry point. */
91
+ function main() {
92
+ let golden;
93
+ try {
94
+ golden = JSON.parse(fs.readFileSync(GOLDEN_SET_PATH, 'utf8'));
95
+ } catch (err) {
96
+ console.error(`calibrate-judge: cannot read golden set at ${GOLDEN_SET_PATH}: ${err.message}`);
97
+ process.exit(1);
98
+ }
99
+
100
+ const cases = Array.isArray(golden.cases) ? golden.cases : [];
101
+ if (cases.length === 0) {
102
+ console.error('calibrate-judge: golden set has no cases.');
103
+ process.exit(1);
104
+ }
105
+
106
+ const parseFn = loadRealParseVerdict();
107
+ const result = scoreCalibration(cases, parseFn);
108
+
109
+ const pct = (result.agreementRate * 100).toFixed(1);
110
+ console.log(`judge calibration: ${result.agreed}/${result.total} agree with the human golden set (${pct}%).`);
111
+ console.log('confusion (expected → predicted):');
112
+ for (const expected of Object.keys(result.confusion)) {
113
+ const preds = result.confusion[expected];
114
+ const parts = Object.keys(preds).map((p) => `${p}:${preds[p]}`).join(', ');
115
+ console.log(` ${expected} → ${parts}`);
116
+ }
117
+
118
+ if (result.disagreements.length === 0) {
119
+ console.log('PASS — deterministic verdict extraction is calibrated to the human baseline.');
120
+ process.exit(0);
121
+ }
122
+
123
+ console.log('');
124
+ console.log(`FAIL — ${result.disagreements.length} case(s) disagree with the human label:`);
125
+ for (const d of result.disagreements) {
126
+ console.log(` ${d.id}: expected ${d.expected}, parser produced ${d.predicted}`);
127
+ }
128
+ console.log('\nEither _parseVerdict regressed or the golden label is wrong. Fix the code or the label — do not loosen the gate.');
129
+ process.exit(1);
130
+ }
131
+
132
+ if (require.main === module) main();
133
+
134
+ module.exports = { scoreCalibration, loadRealParseVerdict, GOLDEN_SET_PATH };
@@ -55,6 +55,11 @@ const GUARDS = [
55
55
  { name: 'squad-yaml', script: 'validate:squad-yaml' },
56
56
  { name: 'squad-orqx', script: 'validate:squad-orqx' },
57
57
  { name: 'agent-codenames', script: 'validate:agent-codenames' },
58
+ { name: 'tool-descriptions', script: 'validate:tool-descriptions' },
59
+ { name: 'constitution', script: 'validate:constitution' },
60
+ // ACs in Given/When/Then — WARN-only (exits 0 unless STORY_ACS_STRICT=1) and
61
+ // a no-op PASS in CI where docs/stories/ (gitignored) is absent.
62
+ { name: 'story-acs', script: 'validate:story-acs' },
58
63
  // Article IV traceability — WARN-only during calibration: the script itself
59
64
  // exits 0 on orphans unless ARTICLE_IV_STRICT=1 (see validate-article-iv.js).
60
65
  { name: 'article-iv', script: 'validate:article-iv' },
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lint guard: Constitution consistency across CLAUDE.md ⇄ AGENTS.md (+ source,
4
+ * install template, rules). Story rodada2-m5 (AF-20260704 Mesa #7).
5
+ *
6
+ * The Mesa item framed CLAUDE.md and AGENTS.md as "twins that drift" and asked
7
+ * to generate both from one source. Verification REFUTED that premise: the two
8
+ * files serve different surfaces (Claude Code vs Codex), share almost no verbatim
9
+ * body, and their only shared canon — the ecosystem counts and the Constitution
10
+ * article set — is already single-sourced. Counts are guarded by
11
+ * `validate:agents-md`; the article agreement is validated by the
12
+ * `constitution-consistency` doctor check.
13
+ *
14
+ * The real, narrow gap this guard closes: that doctor check ran only under
15
+ * `sinapse doctor` and the install matrix — NOT on the PR gate. So article drift
16
+ * between CLAUDE.md and AGENTS.md could merge unnoticed. This wraps the SAME
17
+ * existing check (no new logic, no twin-generator) so it runs on every push/PR.
18
+ *
19
+ * Exit 0 = consistent (PASS/WARN) · Exit 1 = FAIL (a consumer is missing a
20
+ * canonical article, or the source/rules are missing).
21
+ *
22
+ * @module scripts/validate-constitution
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ const path = require('path');
28
+
29
+ const check = require('../.sinapse-ai/core/doctor/checks/constitution-consistency');
30
+
31
+ async function main() {
32
+ const projectRoot = path.resolve(__dirname, '..');
33
+ let result;
34
+ try {
35
+ result = await check.run({ projectRoot });
36
+ } catch (err) {
37
+ // The check declares onError:'fail' — a thrown error is a real problem.
38
+ console.error(`FAIL — constitution-consistency threw: ${err.message}`);
39
+ process.exit(1);
40
+ }
41
+
42
+ const status = result.status || 'FAIL';
43
+ if (status === 'PASS') {
44
+ console.log(`OK — ${result.message}`);
45
+ process.exit(0);
46
+ }
47
+ if (status === 'WARN') {
48
+ // Minor divergence (≤2 issues) — surface it but do not block (matches the
49
+ // doctor severity gradation; Art. XI, avoid over-tightening the gate).
50
+ console.warn(`WARN — ${result.message}`);
51
+ process.exit(0);
52
+ }
53
+ console.error(`FAIL — ${result.message}`);
54
+ if (result.fixCommand) console.error(` fix: ${result.fixCommand}`);
55
+ process.exit(1);
56
+ }
57
+
58
+ main();
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Advisory guard: acceptance criteria in executable Given/When/Then form
4
+ * (Story mesa2-acs-gwt-guard, AF-20260704 Mesa #3).
5
+ *
6
+ * GWT is the documented "preferred" AC format (story-lifecycle.md), but stories
7
+ * historically copy free-form numbered lists from the epic. This guard flags ACs
8
+ * that are NOT in GWT so authors can tighten them — it is advisory by design:
9
+ *
10
+ * - Exit 0 always (WARN-only), mirroring validate-article-iv, UNLESS
11
+ * STORY_ACS_STRICT=1 is set and at least one non-GWT AC is found.
12
+ * - `docs/stories/` is gitignored (local, unversioned), so in CI there are
13
+ * typically no story files — the guard degrades gracefully to a PASS with
14
+ * "nothing to lint" instead of failing.
15
+ *
16
+ * The core is a pure function (`lintStoryAcs`) so tests can drive it with
17
+ * fixtures; the CLI wrapper walks the default story dir.
18
+ *
19
+ * @module scripts/validate-story-acs
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+
27
+ const ROOT = process.cwd();
28
+
29
+ /** Default lint target: local story files (gitignored — may be absent in CI). */
30
+ const DEFAULT_STORIES_DIR = 'docs/stories';
31
+
32
+ /** Heading that opens the acceptance-criteria section (case-insensitive). */
33
+ const AC_HEADING = /^#{1,6}\s+acceptance\s+criteria\b/i;
34
+
35
+ /** Any markdown heading — closes the AC section. */
36
+ const ANY_HEADING = /^#{1,6}\s+/;
37
+
38
+ /** A list item (bullet `-`/`*` with optional checkbox, or `N.` numbered). */
39
+ const LIST_ITEM = /^\s*(?:[-*]\s+(?:\[[ xX]\]\s+)?|\d+[.)]\s+)(.+)$/;
40
+
41
+ /**
42
+ * True when a single AC's text is in executable Given/When/Then form — it must
43
+ * mention all three keywords (order-agnostic, case-insensitive).
44
+ *
45
+ * @param {string} text
46
+ * @returns {boolean}
47
+ */
48
+ function isGwt(text) {
49
+ const t = text.toLowerCase();
50
+ return /\bgiven\b/.test(t) && /\bwhen\b/.test(t) && /\bthen\b/.test(t);
51
+ }
52
+
53
+ /**
54
+ * Extract the acceptance-criteria list items from a story's markdown body and
55
+ * classify each as GWT or not.
56
+ *
57
+ * @param {string} content - full markdown of a story file
58
+ * @returns {{ total: number, gwt: number, nonGwt: Array<{ text: string }> }}
59
+ */
60
+ function lintStoryAcs(content) {
61
+ const lines = String(content).split(/\r?\n/);
62
+ const items = [];
63
+
64
+ let inSection = false;
65
+ let current = null; // accumulates a multi-line AC item
66
+
67
+ const flush = () => {
68
+ if (current !== null) {
69
+ items.push(current.trim());
70
+ current = null;
71
+ }
72
+ };
73
+
74
+ for (const line of lines) {
75
+ if (!inSection) {
76
+ if (AC_HEADING.test(line)) inSection = true;
77
+ continue;
78
+ }
79
+ // A new heading ends the AC section.
80
+ if (ANY_HEADING.test(line)) {
81
+ flush();
82
+ break;
83
+ }
84
+ const m = line.match(LIST_ITEM);
85
+ if (m) {
86
+ flush();
87
+ current = m[1];
88
+ } else if (current !== null && line.trim() !== '') {
89
+ // continuation line of the current AC item
90
+ current += ' ' + line.trim();
91
+ } else if (current !== null && line.trim() === '') {
92
+ flush();
93
+ }
94
+ }
95
+ flush();
96
+
97
+ const nonGwt = items.filter((t) => !isGwt(t)).map((text) => ({ text }));
98
+ return { total: items.length, gwt: items.length - nonGwt.length, nonGwt };
99
+ }
100
+
101
+ /** Recursively collect `.md` files under a directory. */
102
+ function walkMarkdown(dir, out = []) {
103
+ let entries;
104
+ try {
105
+ entries = fs.readdirSync(dir, { withFileTypes: true });
106
+ } catch {
107
+ return out;
108
+ }
109
+ for (const e of entries) {
110
+ const p = path.join(dir, e.name);
111
+ if (e.isDirectory()) walkMarkdown(p, out);
112
+ else if (e.name.endsWith('.md')) out.push(p);
113
+ }
114
+ return out;
115
+ }
116
+
117
+ /** CLI entry point. */
118
+ function main() {
119
+ const strict = process.env.STORY_ACS_STRICT === '1';
120
+ const dir = path.join(ROOT, DEFAULT_STORIES_DIR);
121
+ const files = walkMarkdown(dir);
122
+
123
+ if (files.length === 0) {
124
+ console.log(
125
+ `story-acs: no story files under ${DEFAULT_STORIES_DIR}/ (gitignored) — nothing to lint. PASS.`,
126
+ );
127
+ process.exit(0);
128
+ }
129
+
130
+ let totalAcs = 0;
131
+ let totalNonGwt = 0;
132
+ const report = [];
133
+
134
+ for (const file of files) {
135
+ let content;
136
+ try {
137
+ content = fs.readFileSync(file, 'utf8');
138
+ } catch {
139
+ continue;
140
+ }
141
+ const { total, nonGwt } = lintStoryAcs(content);
142
+ if (total === 0) continue; // not an AC-bearing story
143
+ totalAcs += total;
144
+ if (nonGwt.length > 0) {
145
+ totalNonGwt += nonGwt.length;
146
+ report.push({ file: path.relative(ROOT, file), nonGwt });
147
+ }
148
+ }
149
+
150
+ if (totalNonGwt === 0) {
151
+ console.log(`story-acs: ${totalAcs} AC(s) across ${files.length} file(s), all GWT-shaped. PASS.`);
152
+ process.exit(0);
153
+ }
154
+
155
+ const level = strict ? 'FAIL' : 'WARN';
156
+ console.log(`story-acs [${level}]: ${totalNonGwt}/${totalAcs} AC(s) are not in Given/When/Then form:`);
157
+ for (const r of report) {
158
+ console.log(` ${r.file}`);
159
+ for (const { text } of r.nonGwt) {
160
+ const preview = text.length > 90 ? text.slice(0, 87) + '...' : text;
161
+ console.log(` - ${preview}`);
162
+ }
163
+ }
164
+ console.log(
165
+ strict
166
+ ? '\nSTORY_ACS_STRICT=1 → failing. Rewrite the ACs above as "Given <ctx>, When <action>, Then <outcome>."'
167
+ : '\nAdvisory only (exit 0). Prefer "Given <ctx>, When <action>, Then <outcome>." Set STORY_ACS_STRICT=1 to enforce.',
168
+ );
169
+ process.exit(strict ? 1 : 0);
170
+ }
171
+
172
+ if (require.main === module) main();
173
+
174
+ module.exports = { lintStoryAcs, isGwt };
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lint guard: tool/command descriptions (Story M2-mesa M3, AF-20260704 #9a).
4
+ *
5
+ * A command an agent exposes IS a tool, and its `description:` is the contract
6
+ * that drives selection (KIT-ai-engineering, Tool Use). A vague, empty, or
7
+ * placeholder description silently degrades routing. This guard enforces a
8
+ * minimal clarity contract on every `description:` field in the agent
9
+ * definitions, and is wired into `validate:all`.
10
+ *
11
+ * Exit 0 = all descriptions valid · Exit 1 = one or more violate the contract.
12
+ *
13
+ * The core is a pure function (`lintDescriptions`) so tests can drive it with
14
+ * fixtures; the CLI wrapper globs the default targets.
15
+ *
16
+ * @module scripts/validate-tool-descriptions
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+
24
+ const ROOT = process.cwd();
25
+
26
+ /** Default lint targets: the framework agent definitions (source of truth). */
27
+ const DEFAULT_TARGET_DIRS = ['.sinapse-ai/development/agents'];
28
+
29
+ /** Minimum characters for a meaningful description (smallest real one is 12). */
30
+ const MIN_LEN = 8;
31
+
32
+ /** Values that are placeholders, not real descriptions. */
33
+ const PLACEHOLDER = /^(todo|tbd|fixme|x{2,}|placeholder|custom|n\/?a|desc|description|\.\.\.|-+|\?+)$/i;
34
+
35
+ /**
36
+ * The WHOLE value is nothing but a template token — e.g. `{description}` or
37
+ * `<desc>`. Inline braces documenting command args (e.g. "Build story
38
+ * (*build {story-id})") are legitimate and must NOT be flagged.
39
+ */
40
+ const TEMPLATE_ONLY = /^[{<][^}>]*[}>]$/;
41
+
42
+ /** A YAML block-scalar indicator — the real text follows on indented lines. */
43
+ const BLOCK_SCALAR = /^[|>][+-]?\d*$/;
44
+
45
+ /** Recursively collect `.md` files under a directory. */
46
+ function walkMarkdown(dir, out = []) {
47
+ let entries;
48
+ try {
49
+ entries = fs.readdirSync(dir, { withFileTypes: true });
50
+ } catch {
51
+ return out;
52
+ }
53
+ for (const e of entries) {
54
+ const p = path.join(dir, e.name);
55
+ if (e.isDirectory()) walkMarkdown(p, out);
56
+ else if (e.name.toLowerCase().endsWith('.md')) out.push(p);
57
+ }
58
+ return out;
59
+ }
60
+
61
+ /** Strip a single layer of matching quotes from a YAML scalar. */
62
+ function unquote(s) {
63
+ const t = s.trim();
64
+ if ((t.startsWith("'") && t.endsWith("'")) || (t.startsWith('"') && t.endsWith('"'))) {
65
+ return t.slice(1, -1).trim();
66
+ }
67
+ return t;
68
+ }
69
+
70
+ /**
71
+ * Lint `description:` fields in the given files.
72
+ * @param {string[]} files
73
+ * @returns {Array<{file:string, line:number, value:string, reason:string}>}
74
+ */
75
+ function lintDescriptions(files) {
76
+ const violations = [];
77
+ for (const file of files) {
78
+ let content;
79
+ try {
80
+ content = fs.readFileSync(file, 'utf8');
81
+ } catch {
82
+ continue;
83
+ }
84
+ const lines = content.split(/\r?\n/);
85
+ lines.forEach((raw, i) => {
86
+ const m = raw.match(/^\s*description:\s*(.*)$/);
87
+ if (!m) return;
88
+ const rawValue = m[1].trim();
89
+ // Block scalars (`description: |`) carry the text on the following indented
90
+ // lines — treat as valid rather than flag the indicator itself.
91
+ if (BLOCK_SCALAR.test(rawValue)) return;
92
+ const value = unquote(rawValue);
93
+ let reason = null;
94
+ if (value === '') reason = 'descrição vazia';
95
+ else if (PLACEHOLDER.test(value)) reason = `placeholder ("${value}")`;
96
+ else if (TEMPLATE_ONLY.test(value)) reason = `template não preenchido ("${value}")`;
97
+ else if (value.length < MIN_LEN) reason = `curta demais (<${MIN_LEN} chars): "${value}"`;
98
+ if (reason) {
99
+ violations.push({ file: path.relative(ROOT, file), line: i + 1, value, reason });
100
+ }
101
+ });
102
+ }
103
+ return violations;
104
+ }
105
+
106
+ /** Resolve the files to lint: explicit args, or the default target dirs. */
107
+ function collectFiles(args) {
108
+ if (args.length) return args;
109
+ return DEFAULT_TARGET_DIRS.flatMap((d) => walkMarkdown(path.join(ROOT, d)));
110
+ }
111
+
112
+ function main() {
113
+ const files = collectFiles(process.argv.slice(2));
114
+ const violations = lintDescriptions(files);
115
+ if (violations.length === 0) {
116
+ console.log(`OK — tool/command descriptions valid (${files.length} files scanned).`);
117
+ process.exit(0);
118
+ }
119
+ console.error(`FAIL — ${violations.length} description(s) violate the clarity contract:`);
120
+ for (const v of violations) {
121
+ console.error(` ${v.file}:${v.line} — ${v.reason}`);
122
+ }
123
+ process.exit(1);
124
+ }
125
+
126
+ if (require.main === module) main();
127
+
128
+ module.exports = { lintDescriptions, unquote, walkMarkdown, MIN_LEN };
@@ -63,7 +63,7 @@ function scanWrittenFiles(dir, depth = 0) {
63
63
  if (EXCLUDED_DIRS.has(entry.name)) continue;
64
64
  out.push(
65
65
  ...scanWrittenFiles(path.join(dir, entry.name), depth + 1).map((f) =>
66
- path.join(entry.name, f)
66
+ path.join(entry.name, f),
67
67
  ),
68
68
  );
69
69
  continue;
@@ -651,6 +651,9 @@ dependencies:
651
651
 
652
652
  coderabbit_integration:
653
653
  enabled: true
654
+ # CodeRabbit mechanics (WSL execution, timeout, commands, report location) are
655
+ # single-sourced in .sinapse-ai/core-config.yaml + .claude/rules/coderabbit-integration.md.
656
+ # Only this agent's review focus/policy lives here — see Story rodada2-m6.
654
657
  focus: Integration patterns, configuration consistency, CLAUDE.md quality, hook coverage
655
658
 
656
659
  when_to_use:
@@ -659,16 +662,6 @@ dependencies:
659
662
  - Validating CI/CD workflow configurations
660
663
  - Checking settings.json deny/allow rules
661
664
 
662
- execution_guidelines: |
663
- CRITICAL: CodeRabbit CLI is installed in WSL, not Windows.
664
-
665
- **How to Execute:**
666
- 1. Use 'wsl bash -c' wrapper for all commands
667
- 2. Navigate to project directory in WSL path format (/mnt/c/...)
668
- 3. Use full path to coderabbit binary (~/.local/bin/coderabbit)
669
-
670
- **Timeout:** 15 minutes (900000ms) - CodeRabbit reviews take 7-30 min
671
-
672
665
  # =========================================================================
673
666
  # INTEGRATION ALGORITHM
674
667
  # =========================================================================
@@ -19,7 +19,7 @@ The context window is the scarcest resource in agentic systems. Every token has
19
19
  ### Claude Code Session Anatomy
20
20
 
21
21
  ```
22
- TOTAL WINDOW: ~200,000 tokens (Sonnet/Opus)
22
+ TOTAL WINDOW: ~200,000 tokens (example — current frontier windows reach 1M; see .claude/rules/token-economy.md)
23
23
  ├── System Prompt (static): ~2,000 tokens (1%) [CACHED]
24
24
  ├── CLAUDE.md hierarchy: 1-10,000 tokens (0.5-5%) [CACHED]
25
25
  ├── Rules files (loaded): 500-5,000 tokens (0.25-2.5%) [CACHED]
@@ -253,7 +253,7 @@ Parent system prompt (cached):
253
253
  For SINAPSE agents, recommended allocation:
254
254
 
255
255
  ```
256
- 200K token session:
256
+ 200K-window session (example — current frontier windows reach 1M):
257
257
  Agent persona (CLAUDE.md + rules): ~5K (2.5%)
258
258
  HOT memory (current task): ~20K (10%)
259
259
  WARM memory (retrieved context): ~30K (15%)
@@ -43,7 +43,7 @@ The context window is the scarcest resource in agentic systems. A well-designed
43
43
  ### Token Budget Management
44
44
 
45
45
  ```
46
- TOTAL WINDOW: 200,000 tokens (example)
46
+ TOTAL WINDOW: 200,000 tokens (example — current frontier windows reach 1M)
47
47
  |- System Prompt: ~2,000 tokens (1%)
48
48
  |- Agent Persona: ~1,500 tokens (0.75%)
49
49
  |- Memory Context: ~50,000 tokens (25%) ← MANAGED
@@ -195,7 +195,7 @@ Every AI-assisted copy deliverable MUST record:
195
195
 
196
196
  1. **Gate used** — which of the 4 gates (Trust / Light / Heavy / Scrap)
197
197
  2. **Prompt template(s) used** — from the library in §6
198
- 3. **Model used** — GPT-5, Claude Opus 4.6, Gemini 2.5 Pro, etc.
198
+ 3. **Model used** — e.g. GPT-5, Claude (Opus/Fable family), Gemini 2.5 Pro
199
199
  4. **Final edit depth** — rough % AI vs human in the shipped version
200
200
  5. **Conversion outcome** (if tracked) — linked to the attribution system
201
201