@ryuenn3123/agentic-senior-core 2.5.17 → 2.5.19

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.
@@ -2,6 +2,10 @@
2
2
 
3
3
  Use this checklist before promoting any release tag or package publish operation.
4
4
 
5
+ ## 0) Terminology Boundary (Compliance and Audit)
6
+ - Compliance and audit artifacts keep the canonical enterprise term: `Federated Governance`.
7
+ - Developer-facing aliases are allowed outside compliance artifacts when first mention includes the canonical term in parentheses.
8
+
5
9
  ## 1) Versioning and Changelog Integrity
6
10
  - `package.json` version is valid semantic version (`x.y.z`).
7
11
  - `CHANGELOG.md` has a matching release header for the package version.
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-04-18T02:40:52.883Z",
2
+ "generatedAt": "2026-04-18T02:58:09.480Z",
3
3
  "reportName": "memory-continuity-benchmark",
4
4
  "schemaVersion": "1.0.0",
5
5
  "passed": true,
package/.cursorrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.5.17
3
+ Generated by Agentic-Senior-Core CLI v2.5.19
4
4
  Timestamp: 2026-04-18T03:00:00.000Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/.windsurfrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.5.17
3
+ Generated by Agentic-Senior-Core CLI v2.5.19
4
4
  Timestamp: 2026-04-18T03:00:00.000Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
8
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
9
9
 
10
- **Production-grade rules engine for AI coding agents.**
10
+ **Production-grade Rules Engine (Governance Engine) for AI coding agents.**
11
11
  Works with Cursor, Windsurf, GitHub Copilot, Claude Code, Gemini, and other LLM-powered IDE workflows.
12
12
 
13
13
  </div>
@@ -103,6 +103,8 @@ Use `--dry-run` first to preview changes safely, then apply with `--yes`.
103
103
 
104
104
  Rule: on first mention in developer-facing docs, include canonical term in parentheses.
105
105
 
106
+ Full mapping reference: docs/terminology-mapping.md
107
+
106
108
  ---
107
109
 
108
110
  ## Reference Docs
@@ -115,6 +117,7 @@ Rule: on first mention in developer-facing docs, include canonical term in paren
115
117
  - V2 upgrade playbook: docs/v2-upgrade-playbook.md
116
118
  - Integration playbook: docs/integration-playbook.md
117
119
  - Benchmark and stack reference: docs/benchmark-reference.md
120
+ - Terminology mapping reference: docs/terminology-mapping.md
118
121
  - Product roadmap: docs/roadmap.md
119
122
 
120
123
  ---
@@ -502,6 +502,14 @@ async function askBlueprintSelection(promptMessage, selectableBlueprintFileNames
502
502
  return selectableBlueprintFileNames[selectedIndex] || selectableBlueprintFileNames[0] || null;
503
503
  }
504
504
 
505
+ function buildExistingProjectMajorConstraints() {
506
+ return [
507
+ 'Preserve existing project markers and avoid forced stack migration.',
508
+ 'Keep stack rule loading lazy and scoped to touched code.',
509
+ 'Explicit stack or blueprint overrides always win over auto-detection.',
510
+ ];
511
+ }
512
+
505
513
  export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
506
514
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
507
515
  const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
@@ -654,6 +662,64 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
654
662
  console.log(`\nSelected profile: ${selectedProfile.displayName}`);
655
663
  console.log(`This profile will block these review severities in CI: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}.`);
656
664
 
665
+ const detectionMajorConstraints = buildExistingProjectMajorConstraints();
666
+ const detectionTransparency = {
667
+ declaredAt: new Date().toISOString(),
668
+ declarationType: projectDetection.hasExistingProjectFiles ? 'existing-project' : 'fresh-project',
669
+ declarationShown: projectDetection.hasExistingProjectFiles,
670
+ detectionSummary: projectDetection.hasExistingProjectFiles
671
+ ? buildDetectionSummary(projectDetection)
672
+ : 'No existing project markers were detected.',
673
+ activeRulesSummary: {
674
+ canonicalSource: '.instructions.md',
675
+ compiledEntrypoints: ['.cursorrules', '.windsurfrules'],
676
+ stackLoadingMode: 'lazy',
677
+ selectedProfile: selectedProfileName,
678
+ selectedProfileDisplayName: selectedProfile.displayName,
679
+ blockingSeverities: selectedProfile.blockingSeverities,
680
+ ciGuardrailsEnabled: null,
681
+ },
682
+ majorConstraints: detectionMajorConstraints,
683
+ quickConfirmation: {
684
+ offered: false,
685
+ response: projectDetection.hasExistingProjectFiles ? 'pending' : 'not-applicable',
686
+ source: 'existing-project-detection',
687
+ },
688
+ decision: {
689
+ mode: projectDetection.hasExistingProjectFiles ? 'pending' : 'fresh-directory',
690
+ selectedStackFileName: null,
691
+ selectedBlueprintFileName: null,
692
+ },
693
+ };
694
+
695
+ if (projectDetection.hasExistingProjectFiles) {
696
+ console.log('\nExisting project detection transparency:');
697
+
698
+ if (projectDetection.recommendedStackFileName) {
699
+ const confidenceScoreLabel = Number(projectDetection.confidenceScore || 0).toFixed(2);
700
+ console.log(
701
+ `- Detected stack: ${toTitleCase(projectDetection.recommendedStackFileName)} (${projectDetection.confidenceLabel}, score ${confidenceScoreLabel})`
702
+ );
703
+
704
+ if (projectDetection.secondaryStackFileNames?.length) {
705
+ console.log(
706
+ `- Secondary stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}`
707
+ );
708
+ }
709
+ } else {
710
+ console.log('- Detected stack: unresolved (insufficient markers).');
711
+ }
712
+
713
+ console.log('- Active rules baseline: canonical .instructions.md -> compiled .cursorrules/.windsurfrules');
714
+ console.log(
715
+ `- Active review profile: ${selectedProfile.displayName} (blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)})`
716
+ );
717
+ console.log('- Major constraints:');
718
+ for (const majorConstraint of detectionMajorConstraints) {
719
+ console.log(` - ${majorConstraint}`);
720
+ }
721
+ }
722
+
657
723
  if (selectedProfilePack) {
658
724
  console.log(`Applying team profile pack: ${selectedProfilePack.displayName}.`);
659
725
  console.log(`Pack defaults: stack ${toTitleCase(selectedProfilePack.defaultStackFileName)}, blueprint ${toTitleCase(selectedProfilePack.defaultBlueprintFileName)}.`);
@@ -667,11 +733,15 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
667
733
  && !selectedStackFileNameFromOption
668
734
  && !selectedPreset?.stack
669
735
  && !selectedProfilePack?.defaultStackFileName;
736
+ const detectedBlueprintFileName = projectDetection.recommendedBlueprintFileName
737
+ || BLUEPRINT_RECOMMENDATIONS[projectDetection.recommendedStackFileName]
738
+ || null;
670
739
 
671
740
  let selectedManualStackFileName = null;
672
741
  let selectedManualBlueprintFileName = null;
673
742
  let selectedAdditionalStackFileNames = [];
674
743
  let selectedAdditionalBlueprintFileNames = [];
744
+ let detectedSetupWasApplied = false;
675
745
 
676
746
  let architectureRecommendation = null;
677
747
  let architectPreferenceState = await readArchitectPreferenceState();
@@ -684,11 +754,73 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
684
754
  && !selectedProfile.defaultStackFileName;
685
755
 
686
756
  if (shouldAutoApplyDetectedStack) {
687
- console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
688
- if (projectDetection.secondaryStackFileNames?.length) {
689
- console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
757
+ if (isInteractiveSession) {
758
+ detectionTransparency.quickConfirmation.offered = true;
759
+ console.log('\nQuick confirmation for existing project detection:');
760
+ console.log(`- Suggested stack: ${toTitleCase(projectDetection.recommendedStackFileName)}`);
761
+ if (detectedBlueprintFileName) {
762
+ console.log(`- Suggested blueprint: ${toTitleCase(detectedBlueprintFileName)}`);
763
+ }
764
+
765
+ const shouldUseDetectedSetup = await askYesNo(
766
+ 'Use detected setup for this existing project?',
767
+ userInterface,
768
+ true
769
+ );
770
+
771
+ if (shouldUseDetectedSetup) {
772
+ detectedSetupWasApplied = true;
773
+ detectionTransparency.quickConfirmation.response = 'confirmed-detected';
774
+ detectionTransparency.decision.mode = 'confirmed-detected';
775
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
776
+ if (projectDetection.secondaryStackFileNames?.length) {
777
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
778
+ }
779
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
780
+ } else {
781
+ const overrideStackFileName = await askStackSelection(
782
+ 'Override detected stack (quick selection):',
783
+ stackFileNames,
784
+ userInterface
785
+ );
786
+ const overrideBlueprintCandidates = filterBlueprintFileNamesByCandidates(
787
+ blueprintFileNames,
788
+ [BLUEPRINT_RECOMMENDATIONS[overrideStackFileName]].filter(Boolean)
789
+ );
790
+ const overrideBlueprintFileName = await askBlueprintSelection(
791
+ 'Override detected blueprint (quick selection):',
792
+ overrideBlueprintCandidates,
793
+ userInterface
794
+ );
795
+
796
+ selectedManualStackFileName = overrideStackFileName;
797
+ selectedManualBlueprintFileName = overrideBlueprintFileName;
798
+ selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
799
+ overrideStackFileName,
800
+ projectDetection.secondaryStackFileNames || []
801
+ );
802
+ detectionTransparency.quickConfirmation.response = 'overridden-detected';
803
+ detectionTransparency.decision.mode = 'overridden-detected';
804
+ console.log(
805
+ `Detection override applied: ${toTitleCase(overrideStackFileName)} + ${toTitleCase(overrideBlueprintFileName)}.`
806
+ );
807
+ }
808
+ } else {
809
+ detectedSetupWasApplied = true;
810
+ detectionTransparency.quickConfirmation.response = 'non-interactive-auto';
811
+ detectionTransparency.decision.mode = 'non-interactive-auto';
812
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
813
+ if (projectDetection.secondaryStackFileNames?.length) {
814
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
815
+ }
816
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
690
817
  }
691
- selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
818
+ } else if (projectDetection.hasExistingProjectFiles && projectDetection.recommendedStackFileName) {
819
+ detectionTransparency.quickConfirmation.response = 'explicit-selection-or-low-confidence';
820
+ detectionTransparency.decision.mode = 'explicit-selection-or-low-confidence';
821
+ } else if (!projectDetection.hasExistingProjectFiles) {
822
+ detectionTransparency.quickConfirmation.response = 'not-applicable';
823
+ detectionTransparency.decision.mode = 'fresh-directory';
692
824
  }
693
825
 
694
826
  if (shouldRunArchitectureRecommendation) {
@@ -805,10 +937,10 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
805
937
 
806
938
  const selectedResolvedStackFileName = selectedStackFileNameFromOption
807
939
  || selectedPreset?.stack
808
- || (shouldAutoApplyDetectedStack ? projectDetection.recommendedStackFileName : null)
940
+ || selectedManualStackFileName
941
+ || (detectedSetupWasApplied ? projectDetection.recommendedStackFileName : null)
809
942
  || selectedProfilePack?.defaultStackFileName
810
943
  || selectedProfile.defaultStackFileName
811
- || selectedManualStackFileName
812
944
  || stackFileNames[0];
813
945
 
814
946
  selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
@@ -816,9 +948,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
816
948
  selectedAdditionalStackFileNames
817
949
  );
818
950
 
819
- const recommendedBlueprintFileName = projectDetection.recommendedBlueprintFileName
820
- && shouldAutoApplyDetectedStack
821
- ? projectDetection.recommendedBlueprintFileName
951
+ const recommendedBlueprintFileName = detectedSetupWasApplied
952
+ && detectedBlueprintFileName
953
+ ? detectedBlueprintFileName
822
954
  : BLUEPRINT_RECOMMENDATIONS[selectedResolvedStackFileName] || null;
823
955
 
824
956
  if (!recommendedBlueprintFileName && !selectedBlueprintFileNameFromOption && !selectedProfile.defaultBlueprintFileName) {
@@ -864,6 +996,12 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
864
996
  : derivedAdditionalBlueprintFileNames
865
997
  );
866
998
 
999
+ detectionTransparency.decision.selectedStackFileName = selectedResolvedStackFileName;
1000
+ detectionTransparency.decision.selectedBlueprintFileName = selectedResolvedBlueprintFileName;
1001
+ detectionTransparency.decision.selectedAdditionalStackFileNames = selectedAdditionalStackFileNames;
1002
+ detectionTransparency.decision.selectedAdditionalBlueprintFileNames = selectedAdditionalBlueprintFileNames;
1003
+ detectionTransparency.decision.usedDetectedSetup = detectedSetupWasApplied;
1004
+
867
1005
  const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
868
1006
  selectedResolvedStackFileName,
869
1007
  selectedResolvedBlueprintFileName,
@@ -883,6 +1021,8 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
883
1021
  ? selectedProfile.defaultCi
884
1022
  : await askYesNo('Enable CI/CD quality checks (guardrails) and the LLM Judge policy?', userInterface, selectedProfile.defaultCi);
885
1023
 
1024
+ detectionTransparency.activeRulesSummary.ciGuardrailsEnabled = includeCiGuardrails;
1025
+
886
1026
  await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
887
1027
  includeMcpTemplate: shouldIncludeMcpTemplate,
888
1028
  });
@@ -1044,6 +1184,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
1044
1184
  stateFile: isMemoryContinuityEnabled ? '.agent-context/state/memory-continuity.json' : null,
1045
1185
  },
1046
1186
  architectRecommendation: architectureRecommendation,
1187
+ detectionTransparency,
1047
1188
  });
1048
1189
 
1049
1190
  if (architectPreferenceUpdated && architectPreferenceState) {
@@ -24,7 +24,11 @@ import {
24
24
  copyGovernanceAssetsToTarget,
25
25
  } from '../utils.mjs';
26
26
 
27
- import { detectProjectContext } from '../detector.mjs';
27
+ import {
28
+ detectProjectContext,
29
+ buildDetectionSummary,
30
+ formatDetectionCandidates,
31
+ } from '../detector.mjs';
28
32
  import {
29
33
  buildCompiledRulesContent,
30
34
  writeSelectedPolicy,
@@ -76,6 +80,14 @@ export function parseUpgradeArguments(commandArguments) {
76
80
  return parsedUpgradeOptions;
77
81
  }
78
82
 
83
+ function buildExistingProjectMajorConstraints() {
84
+ return [
85
+ 'Preserve existing project markers and avoid forced stack migration.',
86
+ 'Keep stack rule loading lazy and scoped to touched code.',
87
+ 'Upgrade keeps prior onboarding choices unless user overrides them.',
88
+ ];
89
+ }
90
+
79
91
  export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
80
92
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
81
93
 
@@ -143,6 +155,56 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
143
155
  ? existingOnboardingReport.ciGuardrailsEnabled
144
156
  : true;
145
157
 
158
+ const detectionMajorConstraints = buildExistingProjectMajorConstraints();
159
+ const detectionTransparency = {
160
+ declaredAt: new Date().toISOString(),
161
+ declarationType: 'existing-project',
162
+ declarationShown: true,
163
+ detectionSummary: buildDetectionSummary(projectDetection),
164
+ activeRulesSummary: {
165
+ canonicalSource: '.instructions.md',
166
+ compiledEntrypoints: ['.cursorrules', '.windsurfrules'],
167
+ stackLoadingMode: 'lazy',
168
+ selectedProfile: selectedProfileName,
169
+ selectedProfileDisplayName: toTitleCase(selectedProfileName),
170
+ blockingSeverities: PROFILE_PRESETS[selectedProfileName]?.blockingSeverities || [],
171
+ ciGuardrailsEnabled: includeCiGuardrails,
172
+ },
173
+ majorConstraints: detectionMajorConstraints,
174
+ quickConfirmation: {
175
+ offered: false,
176
+ response: 'upgrade-auto',
177
+ source: 'upgrade-assistant',
178
+ },
179
+ decision: {
180
+ mode: 'upgrade-auto',
181
+ selectedStackFileName,
182
+ selectedBlueprintFileName,
183
+ },
184
+ };
185
+
186
+ console.log('\nExisting project detection transparency:');
187
+ if (projectDetection.recommendedStackFileName) {
188
+ const confidenceScoreLabel = Number(projectDetection.confidenceScore || 0).toFixed(2);
189
+ console.log(
190
+ `- Detected stack: ${toTitleCase(projectDetection.recommendedStackFileName)} (${projectDetection.confidenceLabel}, score ${confidenceScoreLabel})`
191
+ );
192
+ } else {
193
+ console.log('- Detected stack: unresolved (insufficient markers).');
194
+ }
195
+ console.log('- Active rules baseline: canonical .instructions.md -> compiled .cursorrules/.windsurfrules');
196
+ console.log(
197
+ `- Active review profile: ${toTitleCase(selectedProfileName)} (blocking severities: ${(
198
+ PROFILE_PRESETS[selectedProfileName]?.blockingSeverities || []
199
+ ).join(', ') || 'none'})`
200
+ );
201
+ console.log('- Top candidates:');
202
+ console.log(formatDetectionCandidates(projectDetection.rankedCandidates));
203
+ console.log('- Major constraints:');
204
+ for (const majorConstraint of detectionMajorConstraints) {
205
+ console.log(` - ${majorConstraint}`);
206
+ }
207
+
146
208
  const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
147
209
  selectedStackFileName,
148
210
  selectedBlueprintFileName,
@@ -249,6 +311,7 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
249
311
  compatibilityWarnings,
250
312
  runtimeEnvironment: existingOnboardingReport?.runtimeEnvironment || null,
251
313
  operationMode: 'upgrade',
314
+ detectionTransparency,
252
315
  });
253
316
 
254
317
  console.log('\nUpgrade complete.');
@@ -56,6 +56,7 @@ export async function writeOnboardingReport({
56
56
  tokenOptimization = undefined,
57
57
  memoryContinuity = undefined,
58
58
  architectRecommendation = null,
59
+ detectionTransparency = null,
59
60
  }) {
60
61
  const onboardingReportPath = path.join(targetDirectoryPath, '.agent-context', 'state', 'onboarding-report.json');
61
62
  const resolvedTokenOptimization = typeof tokenOptimization === 'undefined'
@@ -110,6 +111,7 @@ export async function writeOnboardingReport({
110
111
  detectionReasoning: projectDetection.detectionReasoning,
111
112
  rankedCandidates: projectDetection.rankedCandidates,
112
113
  evidence: projectDetection.evidence,
114
+ detectionTransparency: detectionTransparency || null,
113
115
  },
114
116
  };
115
117
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.5.17",
3
+ "version": "2.5.19",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -100,6 +100,86 @@ const REQUIRED_TERMINOLOGY_ROW_PATTERNS = [
100
100
  ];
101
101
  const REQUIRED_TERMINOLOGY_RULE_SNIPPET =
102
102
  'Rule: on first mention in developer-facing docs, include canonical term in parentheses.';
103
+ const TERMINOLOGY_REFERENCE_DOCUMENT_PATH = 'docs/terminology-mapping.md';
104
+ const REQUIRED_DEVELOPER_FIRST_MENTION_PATTERNS = [
105
+ {
106
+ path: 'README.md',
107
+ label: 'Rules Engine first mention includes Governance Engine',
108
+ pattern: /Rules Engine\s*\(Governance Engine\)/u,
109
+ },
110
+ {
111
+ path: 'docs/deep-dive.md',
112
+ label: 'Dynamic Rules Engine first mention includes Governance Engine',
113
+ pattern: /Dynamic Rules Engine\s*\(Governance Engine\)/u,
114
+ },
115
+ {
116
+ path: 'docs/faq.md',
117
+ label: 'Quality Checks first mention includes Guardrails',
118
+ pattern: /Quality Checks\s*\(Guardrails\)/u,
119
+ },
120
+ {
121
+ path: '.agent-context/prompts/init-project.md',
122
+ label: 'Init prompt first mention includes Federated Governance baseline',
123
+ pattern: /rules operations context\s*\(Federated Governance baseline\)/iu,
124
+ },
125
+ {
126
+ path: 'lib/cli/commands/init.mjs',
127
+ label: 'Init command wording includes Federated Governance baseline',
128
+ pattern: /rules operations\s+(assets|pack)[^\n]*\(Federated Governance baseline\)/iu,
129
+ },
130
+ {
131
+ path: 'lib/cli/commands/upgrade.mjs',
132
+ label: 'Upgrade command wording includes Federated Governance baseline',
133
+ pattern: /rules operations upgrade assistant\s*\(Federated Governance baseline\)/iu,
134
+ },
135
+ {
136
+ path: 'lib/cli/utils.mjs',
137
+ label: 'CLI help wording includes quality checks and guardrails',
138
+ pattern: /quality checks\s*\(guardrails\)/iu,
139
+ },
140
+ ];
141
+ const COMPLIANCE_TERMINOLOGY_BOUNDARY_PATHS = [
142
+ '.agent-context/review-checklists/security-audit.md',
143
+ '.agent-context/review-checklists/performance-audit.md',
144
+ '.agent-context/review-checklists/release-operations.md',
145
+ 'scripts/release-gate.mjs',
146
+ 'scripts/forbidden-content-check.mjs',
147
+ ];
148
+ const COMPLIANCE_ALIAS_TERMS = [
149
+ 'Federated Rules Operations',
150
+ ];
151
+ const REQUIRED_COMPLIANCE_CANONICAL_SNIPPETS = [
152
+ {
153
+ path: '.agent-context/review-checklists/release-operations.md',
154
+ snippet: 'Federated Governance',
155
+ label: 'release operations checklist keeps canonical term Federated Governance',
156
+ },
157
+ ];
158
+ const REQUIRED_DETECTION_TRANSPARENCY_SNIPPETS = [
159
+ {
160
+ path: 'lib/cli/commands/init.mjs',
161
+ snippets: [
162
+ 'Existing project detection transparency:',
163
+ 'Use detected setup for this existing project?',
164
+ 'detectionTransparency',
165
+ ],
166
+ },
167
+ {
168
+ path: 'lib/cli/commands/upgrade.mjs',
169
+ snippets: [
170
+ 'Existing project detection transparency:',
171
+ 'formatDetectionCandidates(projectDetection.rankedCandidates)',
172
+ 'detectionTransparency',
173
+ ],
174
+ },
175
+ {
176
+ path: 'lib/cli/compiler.mjs',
177
+ snippets: [
178
+ 'detectionTransparency = null',
179
+ 'detectionTransparency: detectionTransparency || null',
180
+ ],
181
+ },
182
+ ];
103
183
 
104
184
  const validationResult = {
105
185
  passed: 0,
@@ -212,6 +292,7 @@ async function validateRequiredFiles() {
212
292
  'CHANGELOG.md',
213
293
  'docs/faq.md',
214
294
  'docs/deep-dive.md',
295
+ 'docs/terminology-mapping.md',
215
296
  'docs/v1.7-execution-playbook.md',
216
297
  'docs/v1.7-issue-breakdown.md',
217
298
  'docs/v1.8-operations-playbook.md',
@@ -750,6 +831,40 @@ async function validateDocumentationFlow() {
750
831
  async function validateTerminologyMapping() {
751
832
  console.log('\nChecking terminology mapping consistency...');
752
833
 
834
+ const terminologyReferenceDocumentPath = join(ROOT_DIR, TERMINOLOGY_REFERENCE_DOCUMENT_PATH);
835
+
836
+ if (!(await fileExists(terminologyReferenceDocumentPath))) {
837
+ fail(`Missing terminology reference document: ${TERMINOLOGY_REFERENCE_DOCUMENT_PATH}`);
838
+ } else {
839
+ const terminologyReferenceContent = await readTextFile(terminologyReferenceDocumentPath);
840
+
841
+ if (terminologyReferenceContent.includes('Dual-Term Mapping')) {
842
+ pass(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} includes Dual-Term Mapping section`);
843
+ } else {
844
+ fail(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} must include Dual-Term Mapping section`);
845
+ }
846
+
847
+ for (const terminologyRowRule of REQUIRED_TERMINOLOGY_ROW_PATTERNS) {
848
+ if (terminologyRowRule.pattern.test(terminologyReferenceContent)) {
849
+ pass(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} includes mapping row: ${terminologyRowRule.label}`);
850
+ } else {
851
+ fail(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} is missing mapping row: ${terminologyRowRule.label}`);
852
+ }
853
+ }
854
+
855
+ if (terminologyReferenceContent.includes('first mention must include canonical term in parentheses')) {
856
+ pass(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} defines first-mention canonical term rule`);
857
+ } else {
858
+ fail(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} must define first-mention canonical term rule`);
859
+ }
860
+
861
+ if (terminologyReferenceContent.includes('Compliance and audit artifacts must keep canonical enterprise terminology')) {
862
+ pass(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} defines compliance terminology boundary`);
863
+ } else {
864
+ fail(`${TERMINOLOGY_REFERENCE_DOCUMENT_PATH} must define compliance terminology boundary`);
865
+ }
866
+ }
867
+
753
868
  for (const terminologyReferencePath of TERMINOLOGY_REFERENCE_PATHS) {
754
869
  const absoluteReferencePath = join(ROOT_DIR, terminologyReferencePath);
755
870
 
@@ -779,6 +894,84 @@ async function validateTerminologyMapping() {
779
894
  } else {
780
895
  fail(`${terminologyReferencePath} must include first-mention canonical term rule`);
781
896
  }
897
+
898
+ if (referenceContent.includes(TERMINOLOGY_REFERENCE_DOCUMENT_PATH)) {
899
+ pass(`${terminologyReferencePath} links to ${TERMINOLOGY_REFERENCE_DOCUMENT_PATH}`);
900
+ } else {
901
+ fail(`${terminologyReferencePath} must link to ${TERMINOLOGY_REFERENCE_DOCUMENT_PATH}`);
902
+ }
903
+ }
904
+
905
+ for (const firstMentionRule of REQUIRED_DEVELOPER_FIRST_MENTION_PATTERNS) {
906
+ const absoluteFirstMentionPath = join(ROOT_DIR, firstMentionRule.path);
907
+
908
+ if (!(await fileExists(absoluteFirstMentionPath))) {
909
+ fail(`Missing developer-facing first-mention source: ${firstMentionRule.path}`);
910
+ continue;
911
+ }
912
+
913
+ const firstMentionContent = await readTextFile(absoluteFirstMentionPath);
914
+ if (firstMentionRule.pattern.test(firstMentionContent)) {
915
+ pass(`${firstMentionRule.path} keeps first-mention rule: ${firstMentionRule.label}`);
916
+ } else {
917
+ fail(`${firstMentionRule.path} must keep first-mention rule: ${firstMentionRule.label}`);
918
+ }
919
+ }
920
+
921
+ for (const compliancePath of COMPLIANCE_TERMINOLOGY_BOUNDARY_PATHS) {
922
+ const absoluteCompliancePath = join(ROOT_DIR, compliancePath);
923
+
924
+ if (!(await fileExists(absoluteCompliancePath))) {
925
+ fail(`Missing compliance/audit artifact for terminology boundary: ${compliancePath}`);
926
+ continue;
927
+ }
928
+
929
+ const complianceContent = await readTextFile(absoluteCompliancePath);
930
+ for (const aliasTerm of COMPLIANCE_ALIAS_TERMS) {
931
+ if (complianceContent.includes(aliasTerm)) {
932
+ fail(`${compliancePath} must not use developer-facing alias in compliance context: ${aliasTerm}`);
933
+ } else {
934
+ pass(`${compliancePath} keeps canonical terminology boundary for alias: ${aliasTerm}`);
935
+ }
936
+ }
937
+ }
938
+
939
+ for (const complianceRule of REQUIRED_COMPLIANCE_CANONICAL_SNIPPETS) {
940
+ const absoluteComplianceRulePath = join(ROOT_DIR, complianceRule.path);
941
+
942
+ if (!(await fileExists(absoluteComplianceRulePath))) {
943
+ fail(`Missing compliance canonical source: ${complianceRule.path}`);
944
+ continue;
945
+ }
946
+
947
+ const complianceRuleContent = await readTextFile(absoluteComplianceRulePath);
948
+ if (complianceRuleContent.includes(complianceRule.snippet)) {
949
+ pass(`${complianceRule.path} keeps canonical terminology rule: ${complianceRule.label}`);
950
+ } else {
951
+ fail(`${complianceRule.path} must keep canonical terminology rule: ${complianceRule.label}`);
952
+ }
953
+ }
954
+ }
955
+
956
+ async function validateDetectionTransparencyCoverage() {
957
+ console.log('\nChecking existing-project detection transparency coverage...');
958
+
959
+ for (const transparencyRule of REQUIRED_DETECTION_TRANSPARENCY_SNIPPETS) {
960
+ const absoluteTransparencyPath = join(ROOT_DIR, transparencyRule.path);
961
+
962
+ if (!(await fileExists(absoluteTransparencyPath))) {
963
+ fail(`Missing detection transparency source: ${transparencyRule.path}`);
964
+ continue;
965
+ }
966
+
967
+ const transparencyContent = await readTextFile(absoluteTransparencyPath);
968
+ for (const requiredSnippet of transparencyRule.snippets) {
969
+ if (transparencyContent.includes(requiredSnippet)) {
970
+ pass(`${transparencyRule.path} includes detection transparency snippet: ${requiredSnippet}`);
971
+ } else {
972
+ fail(`${transparencyRule.path} is missing detection transparency snippet: ${requiredSnippet}`);
973
+ }
974
+ }
782
975
  }
783
976
  }
784
977
 
@@ -1031,6 +1224,7 @@ async function main() {
1031
1224
  await validateVersionConsistency();
1032
1225
  await validateDocumentationFlow();
1033
1226
  await validateTerminologyMapping();
1227
+ await validateDetectionTransparencyCoverage();
1034
1228
  await validateMcpConfiguration();
1035
1229
  await validateHumanWritingGovernance();
1036
1230
  await validateInstructionAdapters();