@ryuenn3123/agentic-senior-core 4.4.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/agentic-senior-core/plugin.json +3 -0
- package/.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md +131 -0
- package/.agents/plugins/agentic-senior-core/skills/asc/SKILL.md +16 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-audit/SKILL.md +28 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-refactor/SKILL.md +35 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-review/SKILL.md +54 -0
- package/.agents/rules/agentic-senior-core.md +131 -0
- package/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +17 -0
- package/.clinerules/agentic-senior-core.md +94 -0
- package/.codex-plugin/plugin.json +24 -0
- package/.cursor/rules/agentic-senior-core.mdc +99 -0
- package/.devin-plugin/plugin.json +13 -0
- package/.github/copilot-instructions.md +94 -0
- package/.github/plugin/marketplace.json +20 -0
- package/.github/plugin/plugin.json +16 -0
- package/.kiro/steering/agentic-senior-core.md +94 -0
- package/.openclaw/skills/asc/SKILL.md +23 -0
- package/.openclaw/skills/asc-audit/SKILL.md +28 -0
- package/.openclaw/skills/asc-review/SKILL.md +54 -0
- package/.opencode/plugins/agentic-senior-core.mjs +31 -0
- package/.windsurf/rules/agentic-senior-core.md +94 -0
- package/AGENTS.md +126 -127
- package/CONTRIBUTING.md +93 -63
- package/README.md +190 -110
- package/__init__.py +61 -0
- package/bin/agentic-senior-core.js +42 -41
- package/commands/asc-audit.md +1 -0
- package/commands/asc-audit.toml +2 -0
- package/commands/asc-help.md +9 -0
- package/commands/asc-help.toml +2 -0
- package/commands/asc-refactor.md +1 -0
- package/commands/asc-refactor.toml +2 -0
- package/commands/asc-review.md +1 -0
- package/commands/asc-review.toml +2 -0
- package/gemini-extension.json +10 -0
- package/hooks/copilot-hooks.json +21 -0
- package/hooks/hooks.json +31 -0
- package/hooks/session-start.js +36 -0
- package/hooks/subagent-start.js +38 -0
- package/lib/cli/commands/adapter.mjs +109 -0
- package/lib/cli/commands/clean.mjs +63 -0
- package/lib/cli/commands/status.mjs +94 -0
- package/package.json +43 -60
- package/plugin.yaml +16 -0
- package/scripts/uninstall.js +38 -0
- package/skills/asc/SKILL.md +16 -0
- package/skills/asc-audit/SKILL.md +28 -0
- package/skills/asc-refactor/SKILL.md +35 -0
- package/skills/asc-review/SKILL.md +54 -0
- package/.agent-context/policies/llm-judge-threshold.json +0 -29
- package/.agent-context/prompts/bootstrap-design.md +0 -63
- package/.agent-context/prompts/compact-natural-mode.md +0 -100
- package/.agent-context/prompts/init-project.md +0 -60
- package/.agent-context/prompts/refactor.md +0 -38
- package/.agent-context/prompts/review-code.md +0 -31
- package/.agent-context/review-checklists/architecture-review.md +0 -57
- package/.agent-context/review-checklists/pr-checklist.md +0 -134
- package/.agent-context/rules/api-docs.md +0 -24
- package/.agent-context/rules/api-versioning.md +0 -16
- package/.agent-context/rules/architecture.md +0 -38
- package/.agent-context/rules/background-jobs.md +0 -17
- package/.agent-context/rules/config-and-flags.md +0 -16
- package/.agent-context/rules/database-design.md +0 -18
- package/.agent-context/rules/docker-runtime.md +0 -17
- package/.agent-context/rules/error-handling.md +0 -16
- package/.agent-context/rules/event-driven.md +0 -16
- package/.agent-context/rules/frontend-architecture.md +0 -54
- package/.agent-context/rules/microservices.md +0 -16
- package/.agent-context/rules/migrations.md +0 -16
- package/.agent-context/rules/observability.md +0 -16
- package/.agent-context/rules/performance.md +0 -16
- package/.agent-context/rules/realtime.md +0 -16
- package/.agent-context/rules/resilience.md +0 -18
- package/.agent-context/rules/security.md +0 -18
- package/.agent-context/rules/testing.md +0 -16
- package/.agent-context/state/README.md +0 -25
- package/.agent-context/state/architecture-map.md +0 -40
- package/.agent-context/state/benchmark-comparison-schema.json +0 -181
- package/.agent-context/state/benchmark-reproducibility.json +0 -87
- package/.agent-context/state/benchmark-thresholds.json +0 -10
- package/.agent-context/state/benchmark-writer-judge-config.json +0 -58
- package/.agent-context/state/dependency-map.md +0 -41
- package/.agent-context/state/memory-adapter-contract.json +0 -52
- package/.agent-context/state/memory-schema-v1.json +0 -88
- package/GEMINI.md +0 -1
- package/benchmarks/README.md +0 -60
- package/benchmarks/compact-natural-mode/fixtures.mjs +0 -359
- package/benchmarks/compact-natural-mode/scorer.mjs +0 -331
- package/benchmarks/runtime-token-saver/fixtures.mjs +0 -836
- package/lib/cli/adaptive-context/catalog.mjs +0 -394
- package/lib/cli/adaptive-context/file-signals.mjs +0 -100
- package/lib/cli/adaptive-context/implications.mjs +0 -44
- package/lib/cli/adaptive-context.mjs +0 -151
- package/lib/cli/audits/typography-palette-anti-repeat/color-utils.mjs +0 -156
- package/lib/cli/audits/typography-palette-anti-repeat/file-scanner.mjs +0 -103
- package/lib/cli/audits/typography-palette-anti-repeat/typography-utils.mjs +0 -70
- package/lib/cli/backup.mjs +0 -210
- package/lib/cli/commands/context.mjs +0 -140
- package/lib/cli/commands/init/project-context.mjs +0 -60
- package/lib/cli/commands/init/runtime-environment.mjs +0 -59
- package/lib/cli/commands/init/setup-decisions.mjs +0 -83
- package/lib/cli/commands/init.mjs +0 -654
- package/lib/cli/commands/launch.mjs +0 -76
- package/lib/cli/commands/optimize.mjs +0 -284
- package/lib/cli/commands/rollback.mjs +0 -64
- package/lib/cli/commands/upgrade/token-optimization-state.mjs +0 -51
- package/lib/cli/commands/upgrade.mjs +0 -451
- package/lib/cli/compiler.mjs +0 -187
- package/lib/cli/constants.mjs +0 -136
- package/lib/cli/detector/constants.mjs +0 -135
- package/lib/cli/detector/design-evidence/collector.mjs +0 -256
- package/lib/cli/detector/design-evidence/constants.mjs +0 -39
- package/lib/cli/detector/design-evidence/file-traversal.mjs +0 -83
- package/lib/cli/detector/design-evidence/structured-attribute-evidence.mjs +0 -117
- package/lib/cli/detector/design-evidence/summary.mjs +0 -109
- package/lib/cli/detector/design-evidence/utility-helpers.mjs +0 -122
- package/lib/cli/detector/design-evidence.mjs +0 -25
- package/lib/cli/detector/stack-detection.mjs +0 -243
- package/lib/cli/detector/ui-signals.mjs +0 -150
- package/lib/cli/detector/workspace-scan.mjs +0 -177
- package/lib/cli/detector.mjs +0 -23
- package/lib/cli/init-detection-flow.mjs +0 -48
- package/lib/cli/init-options.mjs +0 -237
- package/lib/cli/init-selection.mjs +0 -29
- package/lib/cli/memory-continuity.mjs +0 -537
- package/lib/cli/preflight.mjs +0 -76
- package/lib/cli/project-scaffolder/constants.mjs +0 -69
- package/lib/cli/project-scaffolder/discovery.mjs +0 -272
- package/lib/cli/project-scaffolder/prompt-builders.mjs +0 -171
- package/lib/cli/project-scaffolder/storage.mjs +0 -144
- package/lib/cli/project-scaffolder/ui-scope-detection.mjs +0 -36
- package/lib/cli/project-scaffolder.mjs +0 -29
- package/lib/cli/rollback.mjs +0 -66
- package/lib/cli/token-optimization.mjs +0 -401
- package/lib/cli/utils/filesystem.mjs +0 -81
- package/lib/cli/utils/managed-surface.mjs +0 -280
- package/lib/cli/utils/prompting.mjs +0 -44
- package/lib/cli/utils.mjs +0 -479
- package/mcp.json +0 -134
- package/scripts/adaptive-context/fixtures.mjs +0 -183
- package/scripts/adaptive-context-benchmark.mjs +0 -9
- package/scripts/ascx-runtime-token-saver-benchmark.mjs +0 -9
- package/scripts/benchmark-evidence-bundle.mjs +0 -645
- package/scripts/benchmark-gate.mjs +0 -121
- package/scripts/benchmark-intelligence.mjs +0 -33
- package/scripts/benchmark-writer-judge-matrix.mjs +0 -379
- package/scripts/build-release-benchmark-bundle.mjs +0 -202
- package/scripts/bump-version.mjs +0 -103
- package/scripts/clean-local-artifacts.mjs +0 -78
- package/scripts/compact-natural-mode-benchmark.mjs +0 -9
- package/scripts/context-triggered-audit.mjs +0 -391
- package/scripts/detection-benchmark.mjs +0 -127
- package/scripts/docs-quality-drift-report.mjs +0 -358
- package/scripts/documentation-boundary-audit.mjs +0 -305
- package/scripts/explain-on-demand-audit.mjs +0 -427
- package/scripts/forbidden-content-check.mjs +0 -123
- package/scripts/frontend-usability-audit.mjs +0 -243
- package/scripts/generate-sbom.mjs +0 -61
- package/scripts/governance-weekly-report.mjs +0 -466
- package/scripts/llm-judge/checklist-loader.mjs +0 -45
- package/scripts/llm-judge/constants.mjs +0 -66
- package/scripts/llm-judge/diff-collection.mjs +0 -74
- package/scripts/llm-judge/prompting.mjs +0 -78
- package/scripts/llm-judge/providers.mjs +0 -111
- package/scripts/llm-judge/verdict.mjs +0 -134
- package/scripts/llm-judge.mjs +0 -200
- package/scripts/memory-continuity-benchmark.mjs +0 -322
- package/scripts/quality-trend-report.mjs +0 -289
- package/scripts/release-gate/audit-checks.mjs +0 -441
- package/scripts/release-gate/constants.mjs +0 -53
- package/scripts/release-gate/runtime.mjs +0 -63
- package/scripts/release-gate/static-checks.mjs +0 -182
- package/scripts/release-gate.mjs +0 -42
- package/scripts/rules-guardian-audit.mjs +0 -580
- package/scripts/single-source-lazy-loading-audit.mjs +0 -449
- package/scripts/sync-thin-adapters.mjs +0 -72
- package/scripts/token-optimization-benchmark.mjs +0 -252
- package/scripts/ui-design-judge/constants.mjs +0 -13
- package/scripts/ui-design-judge/design-execution-summary.mjs +0 -81
- package/scripts/ui-design-judge/git-input.mjs +0 -134
- package/scripts/ui-design-judge/prompting.mjs +0 -52
- package/scripts/ui-design-judge/providers.mjs +0 -102
- package/scripts/ui-design-judge/reporting.mjs +0 -183
- package/scripts/ui-design-judge/rubric-calibration.mjs +0 -214
- package/scripts/ui-design-judge/rubric-goldset.json +0 -188
- package/scripts/ui-design-judge.mjs +0 -319
- package/scripts/ui-rubric-calibration.mjs +0 -35
- package/scripts/validate/audits/cache-layer-contract.mjs +0 -230
- package/scripts/validate/audits/caching-scope-hygiene.mjs +0 -235
- package/scripts/validate/audits/file-size.mjs +0 -158
- package/scripts/validate/audits/reflection-citations.mjs +0 -130
- package/scripts/validate/audits/release-bundle.mjs +0 -135
- package/scripts/validate/audits/rule-id-uniqueness.mjs +0 -278
- package/scripts/validate/config.mjs +0 -501
- package/scripts/validate/coverage-checks.mjs +0 -446
- package/scripts/validate/file-structure.mjs +0 -158
- package/scripts/validate/markdown-content.mjs +0 -109
- package/scripts/validate/project-metadata.mjs +0 -166
- package/scripts/validate/utils.mjs +0 -52
- package/scripts/validate.mjs +0 -267
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* docs-quality-drift-report.mjs
|
|
5
|
-
*
|
|
6
|
-
* Generates a machine-readable documentation quality drift artifact.
|
|
7
|
-
* Tracks plain-language readability signals and trend deltas over time.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
-
import fs from 'node:fs/promises';
|
|
12
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
13
|
-
import { fileURLToPath } from 'node:url';
|
|
14
|
-
|
|
15
|
-
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
16
|
-
const SCRIPT_DIR = dirname(SCRIPT_FILE_PATH);
|
|
17
|
-
const REPOSITORY_ROOT = resolve(SCRIPT_DIR, '..');
|
|
18
|
-
const REPORT_PATH = join(REPOSITORY_ROOT, '.agent-context', 'state', 'docs-quality-drift-report.json');
|
|
19
|
-
const ARGUMENT_FLAGS = new Set(process.argv.slice(2));
|
|
20
|
-
const isStdoutOnlyMode = ARGUMENT_FLAGS.has('--stdout-only');
|
|
21
|
-
const HISTORY_LIMIT = 52;
|
|
22
|
-
const LONG_SENTENCE_WORD_THRESHOLD = 28;
|
|
23
|
-
|
|
24
|
-
const MONITORED_STATIC_FILE_PATHS = [
|
|
25
|
-
'README.md',
|
|
26
|
-
'CHANGELOG.md',
|
|
27
|
-
'AGENTS.md',
|
|
28
|
-
'CLAUDE.md',
|
|
29
|
-
'GEMINI.md',
|
|
30
|
-
'docs/deep-analysis-and-roadmap-backlog.md',
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const MONITORED_DIRECTORY_PATHS = [
|
|
34
|
-
'docs',
|
|
35
|
-
'.agent-context/prompts',
|
|
36
|
-
'.agent-context/review-checklists',
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
const FORBIDDEN_BUZZWORDS = [
|
|
40
|
-
'delve',
|
|
41
|
-
'leverage',
|
|
42
|
-
'robust',
|
|
43
|
-
'utilize',
|
|
44
|
-
'seamless',
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
function normalizeLineEndings(content) {
|
|
48
|
-
return content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function extractWordCount(content) {
|
|
52
|
-
const words = content.match(/[A-Za-z0-9']+/g) || [];
|
|
53
|
-
return words.length;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function extractSentenceWordCounts(content) {
|
|
57
|
-
const sentenceFragments = content
|
|
58
|
-
.split(/[.!?]+/u)
|
|
59
|
-
.map((fragment) => fragment.trim())
|
|
60
|
-
.filter((fragment) => fragment.length > 0);
|
|
61
|
-
|
|
62
|
-
const sentenceWordCounts = [];
|
|
63
|
-
for (const sentenceFragment of sentenceFragments) {
|
|
64
|
-
const sentenceWordCount = extractWordCount(sentenceFragment);
|
|
65
|
-
if (sentenceWordCount > 0) {
|
|
66
|
-
sentenceWordCounts.push(sentenceWordCount);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return sentenceWordCounts;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function countEmoji(content) {
|
|
74
|
-
const emojiMatches = content.match(/[\p{Extended_Pictographic}]/gu) || [];
|
|
75
|
-
return emojiMatches.length;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function countForbiddenBuzzwords(content) {
|
|
79
|
-
const buzzwordCounts = {};
|
|
80
|
-
|
|
81
|
-
for (const forbiddenBuzzword of FORBIDDEN_BUZZWORDS) {
|
|
82
|
-
const buzzwordRegex = new RegExp(`\\b${forbiddenBuzzword}\\b`, 'gi');
|
|
83
|
-
const matchCount = (content.match(buzzwordRegex) || []).length;
|
|
84
|
-
buzzwordCounts[forbiddenBuzzword] = matchCount;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return buzzwordCounts;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function collectMarkdownFiles(directoryPath) {
|
|
91
|
-
const markdownFilePaths = [];
|
|
92
|
-
|
|
93
|
-
async function walk(currentDirectoryPath) {
|
|
94
|
-
if (!existsSync(currentDirectoryPath)) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const directoryEntries = await fs.readdir(currentDirectoryPath, { withFileTypes: true });
|
|
99
|
-
|
|
100
|
-
for (const directoryEntry of directoryEntries) {
|
|
101
|
-
if (directoryEntry.name === 'node_modules' || directoryEntry.name === '.git' || directoryEntry.name === '.benchmarks') {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const entryPath = join(currentDirectoryPath, directoryEntry.name);
|
|
106
|
-
|
|
107
|
-
if (directoryEntry.isDirectory()) {
|
|
108
|
-
await walk(entryPath);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (directoryEntry.isFile() && directoryEntry.name.toLowerCase().endsWith('.md')) {
|
|
113
|
-
markdownFilePaths.push(entryPath);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
await walk(directoryPath);
|
|
119
|
-
return markdownFilePaths;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async function collectMonitoredFiles() {
|
|
123
|
-
const collectedFilePathSet = new Set();
|
|
124
|
-
|
|
125
|
-
for (const relativeFilePath of MONITORED_STATIC_FILE_PATHS) {
|
|
126
|
-
const absoluteFilePath = join(REPOSITORY_ROOT, relativeFilePath);
|
|
127
|
-
if (existsSync(absoluteFilePath)) {
|
|
128
|
-
collectedFilePathSet.add(absoluteFilePath);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
for (const relativeDirectoryPath of MONITORED_DIRECTORY_PATHS) {
|
|
133
|
-
const absoluteDirectoryPath = join(REPOSITORY_ROOT, relativeDirectoryPath);
|
|
134
|
-
const markdownFiles = await collectMarkdownFiles(absoluteDirectoryPath);
|
|
135
|
-
|
|
136
|
-
for (const markdownFilePath of markdownFiles) {
|
|
137
|
-
collectedFilePathSet.add(markdownFilePath);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return Array.from(collectedFilePathSet).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function readJsonOrNull(filePath) {
|
|
145
|
-
if (!existsSync(filePath)) {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
151
|
-
} catch {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function clamp(value, minimum, maximum) {
|
|
157
|
-
return Math.max(minimum, Math.min(maximum, value));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function buildQualityScore(metrics) {
|
|
161
|
-
const longSentencePenalty = metrics.longSentenceRatePercent * 0.4;
|
|
162
|
-
const buzzwordPenalty = metrics.totalForbiddenBuzzwordHits * 1.5;
|
|
163
|
-
const emojiPenalty = metrics.emojiCount * 5;
|
|
164
|
-
const averageSentencePenalty = metrics.averageWordsPerSentence > 24
|
|
165
|
-
? (metrics.averageWordsPerSentence - 24) * 1.2
|
|
166
|
-
: 0;
|
|
167
|
-
|
|
168
|
-
const rawScore = 100 - longSentencePenalty - buzzwordPenalty - emojiPenalty - averageSentencePenalty;
|
|
169
|
-
return Number(clamp(rawScore, 0, 100).toFixed(2));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function summarizeTrend(currentSummary, previousSummary) {
|
|
173
|
-
if (!previousSummary) {
|
|
174
|
-
return {
|
|
175
|
-
hasBaseline: false,
|
|
176
|
-
trend: 'baseline-created',
|
|
177
|
-
deltaQualityScore: null,
|
|
178
|
-
deltaLongSentenceRatePercent: null,
|
|
179
|
-
deltaForbiddenBuzzwordHits: null,
|
|
180
|
-
deltaEmojiCount: null,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const deltaQualityScore = Number((currentSummary.qualityScore - previousSummary.qualityScore).toFixed(2));
|
|
185
|
-
const deltaLongSentenceRatePercent = Number((currentSummary.longSentenceRatePercent - previousSummary.longSentenceRatePercent).toFixed(2));
|
|
186
|
-
const deltaForbiddenBuzzwordHits = currentSummary.totalForbiddenBuzzwordHits - previousSummary.totalForbiddenBuzzwordHits;
|
|
187
|
-
const deltaEmojiCount = currentSummary.emojiCount - previousSummary.emojiCount;
|
|
188
|
-
|
|
189
|
-
let trend = 'stable';
|
|
190
|
-
if (deltaQualityScore >= 1 && deltaLongSentenceRatePercent <= 0 && deltaForbiddenBuzzwordHits <= 0 && deltaEmojiCount <= 0) {
|
|
191
|
-
trend = 'improving';
|
|
192
|
-
} else if (deltaQualityScore <= -1 || deltaLongSentenceRatePercent > 0 || deltaForbiddenBuzzwordHits > 0 || deltaEmojiCount > 0) {
|
|
193
|
-
trend = 'regressing';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
hasBaseline: true,
|
|
198
|
-
trend,
|
|
199
|
-
deltaQualityScore,
|
|
200
|
-
deltaLongSentenceRatePercent,
|
|
201
|
-
deltaForbiddenBuzzwordHits,
|
|
202
|
-
deltaEmojiCount,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function buildHistoryEntry(report) {
|
|
207
|
-
return {
|
|
208
|
-
generatedAt: report.generatedAt,
|
|
209
|
-
qualityScore: report.summary.qualityScore,
|
|
210
|
-
documentCount: report.summary.documentCount,
|
|
211
|
-
averageWordsPerSentence: report.summary.averageWordsPerSentence,
|
|
212
|
-
longSentenceRatePercent: report.summary.longSentenceRatePercent,
|
|
213
|
-
totalForbiddenBuzzwordHits: report.summary.totalForbiddenBuzzwordHits,
|
|
214
|
-
emojiCount: report.summary.emojiCount,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function mergeHistory(previousReport, currentHistoryEntry) {
|
|
219
|
-
const existingHistory = Array.isArray(previousReport?.history) ? previousReport.history : [];
|
|
220
|
-
const mergedHistory = [...existingHistory, currentHistoryEntry];
|
|
221
|
-
|
|
222
|
-
if (mergedHistory.length <= HISTORY_LIMIT) {
|
|
223
|
-
return mergedHistory;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return mergedHistory.slice(mergedHistory.length - HISTORY_LIMIT);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function runDocsQualityDriftReport() {
|
|
230
|
-
const monitoredFilePaths = await collectMonitoredFiles();
|
|
231
|
-
|
|
232
|
-
const fileSummaries = [];
|
|
233
|
-
let totalLineCount = 0;
|
|
234
|
-
let totalWordCount = 0;
|
|
235
|
-
let totalSentenceCount = 0;
|
|
236
|
-
let totalLongSentenceCount = 0;
|
|
237
|
-
let totalEmojiCount = 0;
|
|
238
|
-
const forbiddenBuzzwordTotals = Object.fromEntries(FORBIDDEN_BUZZWORDS.map((word) => [word, 0]));
|
|
239
|
-
|
|
240
|
-
for (const monitoredFilePath of monitoredFilePaths) {
|
|
241
|
-
const rawContent = await fs.readFile(monitoredFilePath, 'utf8');
|
|
242
|
-
const normalizedContent = normalizeLineEndings(rawContent);
|
|
243
|
-
|
|
244
|
-
const lineCount = normalizedContent.length === 0 ? 0 : normalizedContent.split('\n').length;
|
|
245
|
-
const wordCount = extractWordCount(normalizedContent);
|
|
246
|
-
const sentenceWordCounts = extractSentenceWordCounts(normalizedContent);
|
|
247
|
-
const sentenceCount = sentenceWordCounts.length;
|
|
248
|
-
const longSentenceCount = sentenceWordCounts.filter((sentenceWordCount) => sentenceWordCount > LONG_SENTENCE_WORD_THRESHOLD).length;
|
|
249
|
-
const emojiCount = countEmoji(normalizedContent);
|
|
250
|
-
const forbiddenBuzzwordCounts = countForbiddenBuzzwords(normalizedContent);
|
|
251
|
-
|
|
252
|
-
totalLineCount += lineCount;
|
|
253
|
-
totalWordCount += wordCount;
|
|
254
|
-
totalSentenceCount += sentenceCount;
|
|
255
|
-
totalLongSentenceCount += longSentenceCount;
|
|
256
|
-
totalEmojiCount += emojiCount;
|
|
257
|
-
|
|
258
|
-
for (const forbiddenBuzzword of FORBIDDEN_BUZZWORDS) {
|
|
259
|
-
forbiddenBuzzwordTotals[forbiddenBuzzword] += forbiddenBuzzwordCounts[forbiddenBuzzword];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
fileSummaries.push({
|
|
263
|
-
filePath: relative(REPOSITORY_ROOT, monitoredFilePath).replace(/\\/g, '/'),
|
|
264
|
-
lineCount,
|
|
265
|
-
wordCount,
|
|
266
|
-
sentenceCount,
|
|
267
|
-
longSentenceCount,
|
|
268
|
-
emojiCount,
|
|
269
|
-
forbiddenBuzzwordCounts,
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const averageWordsPerSentence = totalSentenceCount === 0
|
|
274
|
-
? 0
|
|
275
|
-
: Number((totalWordCount / totalSentenceCount).toFixed(2));
|
|
276
|
-
const longSentenceRatePercent = totalSentenceCount === 0
|
|
277
|
-
? 0
|
|
278
|
-
: Number(((totalLongSentenceCount / totalSentenceCount) * 100).toFixed(2));
|
|
279
|
-
const totalForbiddenBuzzwordHits = FORBIDDEN_BUZZWORDS.reduce(
|
|
280
|
-
(sum, forbiddenBuzzword) => sum + forbiddenBuzzwordTotals[forbiddenBuzzword],
|
|
281
|
-
0
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
const summary = {
|
|
285
|
-
documentCount: monitoredFilePaths.length,
|
|
286
|
-
totalLineCount,
|
|
287
|
-
totalWordCount,
|
|
288
|
-
totalSentenceCount,
|
|
289
|
-
averageWordsPerSentence,
|
|
290
|
-
longSentenceCount: totalLongSentenceCount,
|
|
291
|
-
longSentenceRatePercent,
|
|
292
|
-
emojiCount: totalEmojiCount,
|
|
293
|
-
forbiddenBuzzwordTotals,
|
|
294
|
-
totalForbiddenBuzzwordHits,
|
|
295
|
-
qualityScore: 0,
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
summary.qualityScore = buildQualityScore(summary);
|
|
299
|
-
|
|
300
|
-
const previousReport = readJsonOrNull(REPORT_PATH);
|
|
301
|
-
const previousSummary = previousReport?.summary || null;
|
|
302
|
-
const trend = summarizeTrend(summary, previousSummary);
|
|
303
|
-
|
|
304
|
-
const sortedBuzzwordBreakdown = Object.entries(forbiddenBuzzwordTotals)
|
|
305
|
-
.map(([term, hits]) => ({ term, hits }))
|
|
306
|
-
.sort((firstEntry, secondEntry) => secondEntry.hits - firstEntry.hits);
|
|
307
|
-
|
|
308
|
-
const docsQualityDriftReportSnapshot = {
|
|
309
|
-
generatedAt: new Date().toISOString(),
|
|
310
|
-
reportName: 'docs-quality-drift-report',
|
|
311
|
-
passed: summary.emojiCount === 0,
|
|
312
|
-
methodology: {
|
|
313
|
-
monitoredStaticFiles: MONITORED_STATIC_FILE_PATHS,
|
|
314
|
-
monitoredDirectories: MONITORED_DIRECTORY_PATHS,
|
|
315
|
-
forbiddenBuzzwords: FORBIDDEN_BUZZWORDS,
|
|
316
|
-
longSentenceWordThreshold: LONG_SENTENCE_WORD_THRESHOLD,
|
|
317
|
-
},
|
|
318
|
-
summary,
|
|
319
|
-
trend,
|
|
320
|
-
buzzwordBreakdown: sortedBuzzwordBreakdown,
|
|
321
|
-
topLongSentenceRiskFiles: fileSummaries
|
|
322
|
-
.map((fileSummary) => ({
|
|
323
|
-
filePath: fileSummary.filePath,
|
|
324
|
-
longSentenceCount: fileSummary.longSentenceCount,
|
|
325
|
-
}))
|
|
326
|
-
.filter((fileSummary) => fileSummary.longSentenceCount > 0)
|
|
327
|
-
.sort((firstFile, secondFile) => secondFile.longSentenceCount - firstFile.longSentenceCount)
|
|
328
|
-
.slice(0, 10),
|
|
329
|
-
fileSummaries,
|
|
330
|
-
artifact: {
|
|
331
|
-
path: REPORT_PATH,
|
|
332
|
-
writeMode: isStdoutOnlyMode ? 'stdout-only' : 'stdout-and-file',
|
|
333
|
-
},
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
const history = mergeHistory(previousReport, buildHistoryEntry(docsQualityDriftReportSnapshot));
|
|
337
|
-
const docsQualityDriftReport = {
|
|
338
|
-
...docsQualityDriftReportSnapshot,
|
|
339
|
-
history,
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
if (!isStdoutOnlyMode) {
|
|
343
|
-
await fs.mkdir(dirname(REPORT_PATH), { recursive: true });
|
|
344
|
-
await fs.writeFile(REPORT_PATH, JSON.stringify(docsQualityDriftReport, null, 2) + '\n', 'utf8');
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return docsQualityDriftReport;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
runDocsQualityDriftReport()
|
|
351
|
-
.then((docsQualityDriftReport) => {
|
|
352
|
-
console.log(JSON.stringify(docsQualityDriftReport, null, 2));
|
|
353
|
-
})
|
|
354
|
-
.catch((docsQualityError) => {
|
|
355
|
-
const errorMessage = docsQualityError instanceof Error ? docsQualityError.message : String(docsQualityError);
|
|
356
|
-
console.error(`Docs quality drift report failed: ${errorMessage}`);
|
|
357
|
-
process.exit(1);
|
|
358
|
-
});
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* documentation-boundary-audit.mjs
|
|
5
|
-
*
|
|
6
|
-
* Enforces documentation sync only on changed scope boundaries.
|
|
7
|
-
* If public surface, API contract, or database structure files change,
|
|
8
|
-
* matching documentation updates must be present in the same change scope.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { execFileSync } from 'node:child_process';
|
|
12
|
-
import { dirname, resolve } from 'node:path';
|
|
13
|
-
import { fileURLToPath } from 'node:url';
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = dirname(__filename);
|
|
17
|
-
const REPOSITORY_ROOT = resolve(__dirname, '..');
|
|
18
|
-
const DOCUMENTATION_BOUNDARY_AUDIT_REPORT_VERSION = '2.1.0';
|
|
19
|
-
const AUTO_DOCS_SYNC_SCOPE_PHASE = 'phase-1';
|
|
20
|
-
const AUTO_DOCS_SYNC_SCOPE_BOUNDARIES = [
|
|
21
|
-
'public-surface',
|
|
22
|
-
'api-contract',
|
|
23
|
-
'database-structure',
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const CORE_DOCUMENTATION_FILES = new Set(['README.md', 'CHANGELOG.md']);
|
|
27
|
-
|
|
28
|
-
const BOUNDARY_RULES = [
|
|
29
|
-
{
|
|
30
|
-
boundaryName: 'public-surface',
|
|
31
|
-
requirement: 'Public surface changes must update README.md, CHANGELOG.md, or docs/* in the same scope.',
|
|
32
|
-
requiredDocumentationUpdates: [
|
|
33
|
-
'README.md',
|
|
34
|
-
'CHANGELOG.md',
|
|
35
|
-
'docs/architecture-decision-record.md',
|
|
36
|
-
'docs/flow-overview.md',
|
|
37
|
-
],
|
|
38
|
-
trigger(filePath) {
|
|
39
|
-
return /^(bin\/|lib\/|scripts\/)/.test(filePath) && !isDocumentationFilePath(filePath);
|
|
40
|
-
},
|
|
41
|
-
docsMatcher(filePath) {
|
|
42
|
-
return filePath === 'README.md' || filePath === 'CHANGELOG.md' || filePath.startsWith('docs/');
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
boundaryName: 'api-contract',
|
|
47
|
-
requirement: 'API endpoint or contract changes must update API/OpenAPI documentation in the same scope.',
|
|
48
|
-
requiredDocumentationUpdates: [
|
|
49
|
-
'docs/api-contract.md',
|
|
50
|
-
'docs/flow-overview.md',
|
|
51
|
-
'.agent-context/rules/api-docs.md',
|
|
52
|
-
'README.md',
|
|
53
|
-
],
|
|
54
|
-
trigger(filePath) {
|
|
55
|
-
return !isDocumentationFilePath(filePath)
|
|
56
|
-
&& (
|
|
57
|
-
/(api|openapi|controller|route|endpoint)/i.test(filePath)
|
|
58
|
-
|| /api[-_/]?contract/i.test(filePath)
|
|
59
|
-
);
|
|
60
|
-
},
|
|
61
|
-
docsMatcher(filePath) {
|
|
62
|
-
return filePath === '.agent-context/rules/api-docs.md'
|
|
63
|
-
|| /^(docs\/.*(api|contract|openapi))/i.test(filePath)
|
|
64
|
-
|| filePath === 'README.md';
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
boundaryName: 'database-structure',
|
|
69
|
-
requirement: 'Database structure changes must update schema or migration documentation in the same scope.',
|
|
70
|
-
requiredDocumentationUpdates: [
|
|
71
|
-
'docs/database-schema.md',
|
|
72
|
-
'docs/flow-overview.md',
|
|
73
|
-
'.agent-context/rules/database-design.md',
|
|
74
|
-
'README.md',
|
|
75
|
-
],
|
|
76
|
-
trigger(filePath) {
|
|
77
|
-
// Path-based exclusion: design-contract JSON shape lives under
|
|
78
|
-
// lib/cli/project-scaffolder/. Files like research-dossier-migration.mjs
|
|
79
|
-
// describe agent-prompt JSON contract migrations, not database schema
|
|
80
|
-
// or persistent-store migrations, so they must not trigger this boundary
|
|
81
|
-
// even when the filename contains the words "schema" or "migration".
|
|
82
|
-
// Tests for those design-contract migrations are excluded for the same
|
|
83
|
-
// reason.
|
|
84
|
-
if (filePath.startsWith('lib/cli/project-scaffolder/')) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
if (filePath.startsWith('tests/') && /research-dossier|design-contract/i.test(filePath)) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
return !isDocumentationFilePath(filePath)
|
|
91
|
-
&& /(database|schema|migration|repository|sql|prisma|typeorm|knex)/i.test(filePath);
|
|
92
|
-
},
|
|
93
|
-
docsMatcher(filePath) {
|
|
94
|
-
return filePath === '.agent-context/rules/database-design.md'
|
|
95
|
-
|| /^(docs\/.*(database|schema|migration))/i.test(filePath)
|
|
96
|
-
|| filePath === 'README.md';
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
];
|
|
100
|
-
|
|
101
|
-
function normalizeFilePath(filePath) {
|
|
102
|
-
return filePath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function parseGitFileList(rawOutput) {
|
|
106
|
-
if (typeof rawOutput !== 'string' || rawOutput.trim().length === 0) {
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return rawOutput
|
|
111
|
-
.split(/\r?\n/)
|
|
112
|
-
.map((filePath) => filePath.trim())
|
|
113
|
-
.filter((filePath) => filePath.length > 0)
|
|
114
|
-
.map(normalizeFilePath);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function runGitFileQuery(commandArguments) {
|
|
118
|
-
try {
|
|
119
|
-
const rawOutput = execFileSync('git', commandArguments, {
|
|
120
|
-
cwd: REPOSITORY_ROOT,
|
|
121
|
-
encoding: 'utf8',
|
|
122
|
-
maxBuffer: 1024 * 1024,
|
|
123
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
return parseGitFileList(rawOutput);
|
|
127
|
-
} catch {
|
|
128
|
-
return [];
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function uniqueSorted(filePaths) {
|
|
133
|
-
return Array.from(new Set(filePaths)).sort((leftPath, rightPath) => leftPath.localeCompare(rightPath));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function collectChangedFiles() {
|
|
137
|
-
const workingTreeFiles = runGitFileQuery(['diff', '--name-only']);
|
|
138
|
-
const stagedFiles = runGitFileQuery(['diff', '--name-only', '--cached']);
|
|
139
|
-
const workingScopeFiles = uniqueSorted([...workingTreeFiles, ...stagedFiles]);
|
|
140
|
-
|
|
141
|
-
if (workingScopeFiles.length > 0) {
|
|
142
|
-
return {
|
|
143
|
-
source: 'working-tree-and-index',
|
|
144
|
-
files: workingScopeFiles,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const latestCommitRangeFiles = runGitFileQuery(['diff', '--name-only', 'HEAD~1..HEAD']);
|
|
149
|
-
if (latestCommitRangeFiles.length > 0) {
|
|
150
|
-
return {
|
|
151
|
-
source: 'latest-commit-range',
|
|
152
|
-
files: uniqueSorted(latestCommitRangeFiles),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const headCommitFiles = runGitFileQuery(['show', '--pretty=format:', '--name-only', 'HEAD']);
|
|
157
|
-
if (headCommitFiles.length > 0) {
|
|
158
|
-
return {
|
|
159
|
-
source: 'head-commit',
|
|
160
|
-
files: uniqueSorted(headCommitFiles),
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
source: 'none',
|
|
166
|
-
files: [],
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function isDocumentationFilePath(filePath) {
|
|
171
|
-
return CORE_DOCUMENTATION_FILES.has(filePath)
|
|
172
|
-
|| filePath.startsWith('docs/')
|
|
173
|
-
|| filePath.startsWith('.agent-context/review-checklists/')
|
|
174
|
-
|| filePath === '.agent-context/rules/api-docs.md'
|
|
175
|
-
|| filePath === '.agent-context/rules/database-design.md';
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function evaluateBoundary(boundaryRule, changedFiles, changedDocumentationFiles) {
|
|
179
|
-
const boundaryChangedFiles = changedFiles.filter((filePath) => boundaryRule.trigger(filePath));
|
|
180
|
-
const expectedDocumentationPaths = Array.isArray(boundaryRule.requiredDocumentationUpdates)
|
|
181
|
-
? boundaryRule.requiredDocumentationUpdates
|
|
182
|
-
: [];
|
|
183
|
-
|
|
184
|
-
if (boundaryChangedFiles.length === 0) {
|
|
185
|
-
return {
|
|
186
|
-
boundaryName: boundaryRule.boundaryName,
|
|
187
|
-
requirement: boundaryRule.requirement,
|
|
188
|
-
triggered: false,
|
|
189
|
-
passed: true,
|
|
190
|
-
changedFiles: [],
|
|
191
|
-
documentationFiles: [],
|
|
192
|
-
expectedDocumentationPaths,
|
|
193
|
-
missingDocumentationUpdates: false,
|
|
194
|
-
requiredActions: [],
|
|
195
|
-
details: 'Boundary not triggered by changed scope.',
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const matchingDocumentationFiles = changedDocumentationFiles.filter((filePath) => boundaryRule.docsMatcher(filePath));
|
|
200
|
-
const boundaryPassed = matchingDocumentationFiles.length > 0;
|
|
201
|
-
const requiredActions = boundaryPassed
|
|
202
|
-
? []
|
|
203
|
-
: [
|
|
204
|
-
`Update one or more boundary docs: ${expectedDocumentationPaths.join(', ')}`,
|
|
205
|
-
'Re-run scripts/documentation-boundary-audit.mjs before merge.',
|
|
206
|
-
];
|
|
207
|
-
|
|
208
|
-
const details = boundaryPassed
|
|
209
|
-
? `Boundary triggered and synchronized with documentation updates: ${matchingDocumentationFiles.join(', ')}`
|
|
210
|
-
: 'Boundary triggered without required documentation updates.';
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
boundaryName: boundaryRule.boundaryName,
|
|
214
|
-
requirement: boundaryRule.requirement,
|
|
215
|
-
triggered: true,
|
|
216
|
-
passed: boundaryPassed,
|
|
217
|
-
changedFiles: boundaryChangedFiles,
|
|
218
|
-
documentationFiles: matchingDocumentationFiles,
|
|
219
|
-
expectedDocumentationPaths,
|
|
220
|
-
missingDocumentationUpdates: !boundaryPassed,
|
|
221
|
-
requiredActions,
|
|
222
|
-
details,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function runDocumentationBoundaryAudit() {
|
|
227
|
-
const changedScope = collectChangedFiles();
|
|
228
|
-
const changedFiles = changedScope.files;
|
|
229
|
-
const changedDocumentationFiles = changedFiles.filter(isDocumentationFilePath);
|
|
230
|
-
|
|
231
|
-
const boundaryResults = BOUNDARY_RULES.map((boundaryRule) => (
|
|
232
|
-
evaluateBoundary(boundaryRule, changedFiles, changedDocumentationFiles)
|
|
233
|
-
));
|
|
234
|
-
|
|
235
|
-
const violations = boundaryResults
|
|
236
|
-
.filter((boundaryResult) => boundaryResult.triggered && !boundaryResult.passed)
|
|
237
|
-
.map((boundaryResult) => ({
|
|
238
|
-
boundaryName: boundaryResult.boundaryName,
|
|
239
|
-
requirement: boundaryResult.requirement,
|
|
240
|
-
changedFiles: boundaryResult.changedFiles,
|
|
241
|
-
expectedDocumentationPaths: boundaryResult.expectedDocumentationPaths,
|
|
242
|
-
requiredActions: boundaryResult.requiredActions,
|
|
243
|
-
diagnosticCode: `BOUNDARY_${boundaryResult.boundaryName.toUpperCase().replace(/-/g, '_')}_DOCS_SYNC_REQUIRED`,
|
|
244
|
-
}));
|
|
245
|
-
|
|
246
|
-
const failures = violations.map((violation) => {
|
|
247
|
-
const affectedFiles = violation.changedFiles.join(', ');
|
|
248
|
-
return `${violation.boundaryName}: ${violation.requirement} Changed files: ${affectedFiles}`;
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
const reportPayload = {
|
|
252
|
-
generatedAt: new Date().toISOString(),
|
|
253
|
-
reportVersion: DOCUMENTATION_BOUNDARY_AUDIT_REPORT_VERSION,
|
|
254
|
-
auditName: 'documentation-boundary-audit',
|
|
255
|
-
source: changedScope.source,
|
|
256
|
-
changedFileCount: changedFiles.length,
|
|
257
|
-
changedFiles,
|
|
258
|
-
boundaryResults,
|
|
259
|
-
violations,
|
|
260
|
-
passed: failures.length === 0,
|
|
261
|
-
failureCount: failures.length,
|
|
262
|
-
failures,
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const triggeredBoundaryResults = boundaryResults.filter((boundaryResult) => boundaryResult.triggered);
|
|
266
|
-
const passedTriggeredBoundaryResults = triggeredBoundaryResults.filter((boundaryResult) => boundaryResult.passed);
|
|
267
|
-
const scopeMatchedDocumentationFiles = uniqueSorted(
|
|
268
|
-
triggeredBoundaryResults.flatMap((boundaryResult) => boundaryResult.documentationFiles),
|
|
269
|
-
);
|
|
270
|
-
const scopeMatchedDocumentationFileSet = new Set(scopeMatchedDocumentationFiles);
|
|
271
|
-
const outOfScopeDocumentationFiles = changedDocumentationFiles.filter(
|
|
272
|
-
(filePath) => !scopeMatchedDocumentationFileSet.has(filePath),
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
const precisionNumerator = scopeMatchedDocumentationFiles.length;
|
|
276
|
-
const precisionDenominator = changedDocumentationFiles.length;
|
|
277
|
-
const recallNumerator = passedTriggeredBoundaryResults.length;
|
|
278
|
-
const recallDenominator = triggeredBoundaryResults.length;
|
|
279
|
-
|
|
280
|
-
const precision = precisionDenominator > 0 ? precisionNumerator / precisionDenominator : 1;
|
|
281
|
-
const recall = recallDenominator > 0 ? recallNumerator / recallDenominator : 1;
|
|
282
|
-
|
|
283
|
-
reportPayload.autoDocsSyncScope = {
|
|
284
|
-
phase: AUTO_DOCS_SYNC_SCOPE_PHASE,
|
|
285
|
-
bounded: true,
|
|
286
|
-
explicitBoundaries: AUTO_DOCS_SYNC_SCOPE_BOUNDARIES,
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
reportPayload.rolloutMetrics = {
|
|
290
|
-
measuredAt: reportPayload.generatedAt,
|
|
291
|
-
precision,
|
|
292
|
-
recall,
|
|
293
|
-
precisionNumerator,
|
|
294
|
-
precisionDenominator,
|
|
295
|
-
recallNumerator,
|
|
296
|
-
recallDenominator,
|
|
297
|
-
scopeMatchedDocumentationFiles,
|
|
298
|
-
outOfScopeDocumentationFiles,
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
console.log(JSON.stringify(reportPayload, null, 2));
|
|
302
|
-
process.exit(reportPayload.passed ? 0 : 1);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
runDocumentationBoundaryAudit();
|