claudeos-core 2.3.2 → 2.4.1

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 (36) hide show
  1. package/CHANGELOG.md +790 -74
  2. package/CODE_OF_CONDUCT.md +15 -0
  3. package/README.de.md +374 -876
  4. package/README.es.md +374 -875
  5. package/README.fr.md +374 -875
  6. package/README.hi.md +374 -875
  7. package/README.ja.md +374 -875
  8. package/README.ko.md +374 -874
  9. package/README.md +374 -876
  10. package/README.ru.md +374 -877
  11. package/README.vi.md +374 -875
  12. package/README.zh-CN.md +374 -874
  13. package/SECURITY.md +51 -0
  14. package/bin/commands/init.js +192 -37
  15. package/content-validator/index.js +97 -4
  16. package/health-checker/index.js +44 -10
  17. package/package.json +92 -90
  18. package/pass-json-validator/index.js +58 -7
  19. package/pass-prompts/templates/angular/pass3.md +15 -14
  20. package/pass-prompts/templates/common/claude-md-scaffold.md +81 -0
  21. package/pass-prompts/templates/common/pass3-footer.md +104 -0
  22. package/pass-prompts/templates/java-spring/pass3.md +19 -18
  23. package/pass-prompts/templates/kotlin-spring/pass3.md +23 -22
  24. package/pass-prompts/templates/node-express/pass3.md +18 -17
  25. package/pass-prompts/templates/node-fastify/pass3.md +11 -10
  26. package/pass-prompts/templates/node-nestjs/pass3.md +11 -10
  27. package/pass-prompts/templates/node-nextjs/pass3.md +18 -17
  28. package/pass-prompts/templates/node-vite/pass3.md +11 -10
  29. package/pass-prompts/templates/python-django/pass3.md +18 -17
  30. package/pass-prompts/templates/python-fastapi/pass3.md +18 -17
  31. package/pass-prompts/templates/python-flask/pass3.md +9 -8
  32. package/pass-prompts/templates/vue-nuxt/pass3.md +9 -8
  33. package/plan-installer/domain-grouper.js +45 -5
  34. package/plan-installer/index.js +11 -1
  35. package/plan-installer/scanners/scan-java.js +98 -2
  36. package/plan-installer/stack-detector.js +44 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,722 @@
1
1
  # Changelog
2
2
 
3
+ ## Releases
4
+
5
+ Quick navigation to recent releases:
6
+
7
+ - [`2.4.1`](#241--2026-04-26) — Documentation overhaul, 10-language localization, fixture sanitization (post-release docs)
8
+ - [`2.4.0`](#240--2026-04-25) — Session Continuity Protocol (v2.4 series feature 1 of 3)
9
+ - [`2.3.3`](#233--2026-04-24) — Template emoji consistency + optional `totalLines` splitter axis
10
+ - [`2.3.2`](#232--2026-04-23) — `cmdInit` decomposition + UX polish + validator co-evolution
11
+ - [`2.3.1`](#231--2026-04-23) — Patch: Windows CI breakage in `npm test`
12
+ - [`2.3.0`](#230--2026-04-23) — Language-invariant structural validation; path-hallucination defense; single-SPA detection
13
+ - [`2.2.0`](#220--2026-04-21) — Deterministic 8-section CLAUDE.md scaffold
14
+ - [`2.1.2`](#212--2026-04-21) — Patch: master plan removal cleanup regression
15
+ - [`2.1.1`](#211--2026-04-20) — Docs-only maintenance
16
+ - [`2.1.0`](#210--2026-04-20) — Pass 3 split mode (3a/3b/3c/3d-aux); `Prompt is too long` mitigation
17
+ - [`2.0.x`](#202--2026-04-20) — Pass 4 architecture refactor; gap-fill no-op invariant
18
+ - [`1.7.x`](#171--2026-04-11) — Initial monorepo detection; multi-stack expansion
19
+ - [`1.6.x`](#162--2026-04-09) — 6 → 10+ stack templates (NestJS, Vue-Nuxt, Fastify, Angular)
20
+ - [`1.5.x`](#151--2026-04-06) — Initial public preview
21
+
22
+ For older entries scroll past v1.5.0 or use the GitHub blame view.
23
+
24
+ ---
25
+
26
+ ## [2.4.1] — 2026-04-26
27
+
28
+ Post-release documentation, full 10-language localization, and test-fixture sanitization. **No source code, no template, and no scanner behavior change** — Pass 1/2/3/4 outputs and validator verdicts are byte-identical to v2.4.0. Test suite remains 736 / 736 pass.
29
+
30
+ ### Documentation overhaul
31
+
32
+ - **Main `README.md` rewrite** — 455 → 514 lines (+59) without losing brevity. Strengthened sections:
33
+ - **Tagline** (1 line → 3 paragraphs): WHAT (value proposition) + HOW (deterministic scanner + 4-pass + 5 validators + path allowlist) + WHERE (12 stacks, monorepos, one `npx` command, resume-safe, idempotent).
34
+ - **"What is this?"** — 3-bullet problem statement → 4-bullet (added centralized-middleware vs scattered `try/catch`), explicit WHY (Claude Code stateless, every session starts fresh), 5-bullet output list (`CLAUDE.md` / `.claude/rules/` / `standard/` / `skills/` / `memory/`), differentiator (`path allowlist` + 5 named validators + language-invariant).
35
+ - **Demo block** (4 collapsible `<details>`) — every excerpt swapped for stronger content from the actual `spring-boot-realworld-example-app` run: `CLAUDE.md` excerpt = Section 1 + 2 (Role Definition + 11-row Project Overview table) instead of Section 4; rule excerpt = `01.controller-rules.md` (REST + GraphQL + ✅/❌ Java examples) instead of `03.data-access-rules.md`; decision-log seed = "Hexagonal ports & adapters with MyBatis-only persistence" (the FIRST decision, with JPA/Hibernate/Spring Data/MyBatis-Plus considered-and-rejected list) instead of CQRS-lite.
36
+ - **"Who is this for?"** — 3-row table → 7-row table covering Solo dev / Team lead / Existing Claude Code user / Onboarding to a new repo / Working in 10 languages / Monorepo user / OSS contributor; "Not a fit if" expanded from 1 to 3 cases.
37
+ - **"How does it work?"** — 1-paragraph summary → **3-stage breakdown**: Step A (scanner — concrete file types read, sensitive-variable redaction list, architecture-pattern classification), Step B (4-pass with each pass's input/output/split rules, including Pass 4 CLAUDE.md immutability), Step C (5 validators each named with their distinct check classes + 3-tier severity).
38
+ - **`CLAUDE.md` slim** — 367 → 162 lines (−65 % size, −58 % bytes). Replaced the 4 000-character single-paragraph v2.3.0 changelog wall with a one-line v2.4.1 summary that points to `CHANGELOG.md`. The 33-row exhaustive Tests table compressed into 7 thematic categories with "read the test file directly for details" pointer (DRY: avoid duplicating per-file fixture details that live in the test source). Architecture data-flow diagram, file-by-file reference, and Code Conventions retained at full fidelity. Added Documentation section listing localized READMEs + `docs/{lang}/` mirrors.
39
+ - **`docs/comparison.md` and 3 other docs corrections** — `docs/architecture.md` `sync-checker` description ("Cross-references between standards and rules" → "Disk files match the `sync-map.json` registrations"); `docs/stacks.md` Vite/Angular port-extraction fabrication removed (scanner does NOT read `vite.config.server.port` nor `angular.json` for port — both are framework-default fallbacks); `docs/verification.md` "sibling project" wording neutralized to "a CLAUDE.md generated with `--lang ja`".
40
+ - **`README.md` fabricated URL removed** — the `https://github.com/affaan-m/everything-claude-code` link in the "Not a fit" section was a guessed URL not present in the v2.3.2 HEAD; removed in favor of an internal pointer to `docs/comparison.md`.
41
+
42
+ ### 10-language localization
43
+
44
+ - **9 localized READMEs (`README.{ko,ja,zh-CN,es,vi,hi,ru,fr,de}.md`)** — full rewrite to match the new 514-line English structure. All 10 READMEs now share identical structural metrics: **514 lines, 14 H2 sections (fence-aware), 28 code fences, 4 `<details>` blocks, 28 inline-code spans matching ±2**. Code blocks (terminal output, CLAUDE.md excerpt, rule excerpt, decision-log seed, mermaid labels) are byte-identical to English across all 10 languages. Only surrounding prose is translated.
45
+ - **9 new `docs/{lang}/` folders** — every non-English README now has a parallel `docs/{lang}/` directory mirroring the 12 English `docs/*.md` files (architecture, stacks, verification, commands, diagrams, memory-layer, safety, manual-installation, advanced-config, comparison, troubleshooting, README index). Total new files: 9 × 12 = **108 docs/ translations** (~25 000 lines of localized prose). Internal cross-links resolve within each language folder; "English original" pointer at the top of each translated doc links back to `../{filename}.md`.
46
+ - **Language-switcher consistency normalized** — all 10 README headers now use the same convention: 9 `· · ·`-separated language links, current-language entry omitted (matching the original English convention). Earlier mixed conventions (some agents had self-link, some had bold-unlinked, some omitted) have been unified.
47
+ - **`docs/vi/troubleshooting.md` broken-link fix** — `[SECURITY.md](../SECURITY.md)` → `[SECURITY.md](../../SECURITY.md)`. The Vietnamese translator agent had copied the English `../SECURITY.md` literal, which resolves correctly from `docs/` but breaks from `docs/vi/`. Other 8 languages' agents got this right via `../../`.
48
+
49
+ ### Test fixture sanitization (real-project fingerprint purge)
50
+
51
+ - **Removed `tests/fixtures/claude-md/observed-ko-bad.md` and `observed-ko-fixed.md`** (17 KB + 15 KB). These two fixtures were anonymized exports from a real internal Vite + React project: file names had been changed to placeholders (`Acme*` instead of the original component prefix), but **structural fingerprints survived the rename and remained identifiable** — multi-entry `VITE_DESKTOP_PORT 3030` / `VITE_MOBILE_PORT 3033` / `VITE_STORYBOOK_PORT 4040` env-var pattern; internal RBAC convention (`buttonAuthorities` prop + `SYS_CODE_CONSTANTS.USE_BTN_AUTH`); `Orval + axios + generated-api-client/` tooling combination; precise package-version triple (TypeScript 5.8.3 + React 19.1.0 + Vite 6.3.5 + sass 1.89 + orval ^8.5.3); desktop/mobile multi-entry split architecture; `createBrowserRouter` + `RouterProvider` desktop-vs-mobile layout pair; the host placeholder `local-dev.example.internal`. None of the per-token name redactions removed the underlying structural pattern, which is sufficient to identify the source repository.
52
+ - **Added synthetic generic replacements** — `tests/fixtures/claude-md/valid-ko.md` (128 lines, ~4 KB) and `bad-ko.md` (148 lines, ~5 KB), modeled identically on the established `valid-ja.md` / `bad-ja.md` shape: generic `sample-project` with Express 4.19 + PostgreSQL 15 + Prisma 5 + TypeScript 5.4 + Vitest, port 3000, no real-world traceable identifiers. Korean test coverage is preserved (valid + §9 anti-pattern detection both still test in Korean), and the 9-error signature for `bad-ko.md` matches `bad-ja.md` / `bad-zh-CN.md` / `bad-es.md` / `bad-hi.md` / `bad-ru.md` exactly (1 S1 + 4 M-* + 4 F2-*).
53
+ - **`tests/claude-md-validator.test.js` updated** to reference the new fixture names (`valid-ko.md` and `bad-ko.md`) and removed the Korean special-case branch (`code === "ko" ? "observed-ko-fixed.md" : ...`); all 10 supported languages now follow the same `valid-{code}.md` pattern.
54
+ - **New hard rule** committed to project memory: `feedback_no-real-project-fingerprints-in-fixtures.md` — fixture sanitization requires structural-pattern removal (ports, RBAC conventions, tooling combinations, package versions, directory splits), not just name token replacement. Protects against regression.
55
+
56
+ ### CHANGELOG strict-English scrub
57
+
58
+ - **52 substitutions of banned terminology categories** — the per-project memory hard rule defines categories (validation-process labels, project-status descriptors) that may not appear in any document; matching phrases were replaced with neutral test-suite vocabulary (`regression testing`, `regression scenario`, `Spring projects`, `Larger enterprise-style YAMLs`, `your project`, etc.). 16 anonymized project-name placeholders (12 frontend + 4 backend variants) were collapsed to two generic `Vite frontend test project` and `Spring backend test project` labels. Restores full compliance with the project memory hard rule.
59
+ - **12 non-English narrative replacements** — Korean, Japanese, and Chinese fragments inside backticked LLM-output examples were replaced with English placeholder descriptions (e.g., `<localized gloss>`, `the localized form of "Memory (L4)" in each script`, `<localized gloss A> / <localized gloss B>` for the two header-translation drift examples). `CHANGELOG.md` is now strict English narrative end to end — the only remaining non-ASCII characters are universal technical typography (em-dashes, mathematical arrows, inequalities, emoji status markers), none of which constitutes "language content".
60
+ - **Two grammatical cleanups** — minor leftover phrasing from the previous terminology pass was tightened (one tense / possessive correction at line 1704; one redundant compound noun simplified at line 1750).
61
+ - **v2.4.0 entry intro test-count corrected** — `Test suite 702 / 702 pass` → `Test suite 736 / 736 pass (final)`. The 702 number was the initial Session-Continuity-Protocol-only state at the top of the v2.4.0 entry; subsequent sub-sections within the same entry already documented the bump to 736 after 15 pipeline robustness fixes. The intro now reflects the final shipped state to avoid reader confusion.
62
+
63
+ ### Repository hygiene
64
+
65
+ - **`claudeos-core/` test artifact removed from repo root** — leftover output from running the tool against itself during functional tests (3 files in `claudeos-core/generated/` + empty `claudeos-core/memory/`). The directory is `.gitignore`d so it was never committed, but removing the on-disk copy keeps the working tree clean.
66
+ - **No code, template, scanner, or validator changes** — `bin/`, `lib/`, `plan-installer/`, `pass-prompts/templates/`, `claude-md-validator/`, `content-validator/`, `pass-json-validator/`, `health-checker/`, `manifest-generator/`, `sync-checker/`, `plan-validator/` are all byte-identical to v2.4.0. `npm test` still passes 736 / 736.
67
+
68
+ ### Verified backward compatibility
69
+
70
+ - **No breaking changes**. CLI surface (`init`, `lint`, `health`, `memory {compact,score,propose-rules}`, `validate`, `restore`, `refresh`) and all flags (`--lang`, `--force`, `--help`, `--version`) are unchanged. Generated CLAUDE.md / `.claude/rules/` / `claudeos-core/standard,skills,guide,database,mcp-guide,memory/` shapes unchanged.
71
+ - **`npm pack` size dropped 41 %** — 618.8 kB → 365.4 kB tarball as a side effect of the Korean / 8-language README slim-down (was 95–130 kB stale content per locale; now 21–32 kB lean and synced).
72
+ - **Test count unchanged**: 736 / 736 pass on Linux / macOS / Windows × Node 18 / 20.
73
+
74
+ ---
75
+
76
+ ## [2.4.0] — 2026-04-25
77
+
78
+ First feature in the v2.4 series: **Session Continuity Protocol** —
79
+ a recommended prose block inside Section 8's Memory Workflow that
80
+ addresses Claude Code's auto-compact behavior. Auto-compact may
81
+ truncate session context mid-work, dropping previously-loaded
82
+ `failure-patterns.md` references, recently-recorded decisions in
83
+ `decision-log.md`, and the `paths`-glob-conditional rule files
84
+ that had been activated for the working files. Session Continuity
85
+ gives the LLM an explicit re-entry routine for these three context
86
+ elements when a session resumes after compact or restart.
87
+
88
+ This release ships only the protocol itself. Two further v2.4
89
+ features (Self-Check Framework, Common Pattern Taxonomy) are
90
+ planned but not yet implemented; they will land in subsequent
91
+ 2.4.x releases. Test suite final: **736 / 736 pass** (initial
92
+ Session-Continuity-Protocol-only state shipped at 702/702, +3 new
93
+ tests covering positive prose-form, negative H4-form rejection, and
94
+ explicit backward-compatibility for pre-v2.4 CLAUDE.md files;
95
+ the subsequent 15 pipeline robustness fixes documented below
96
+ brought the total to 736).
97
+
98
+ ### Scaffold — Session Resume block in `claude-md-scaffold.md`
99
+
100
+ - **Problem addressed.** Claude Code sessions that exceed the
101
+ context window trigger auto-compact: portions of older turns
102
+ are summarized or dropped to make room. Restarted sessions
103
+ begin with no in-context state. Both situations leave the LLM
104
+ unaware of three pieces of state that were previously loaded:
105
+ (1) the error patterns it had scanned at session start from
106
+ `failure-patterns.md`, (2) the design decisions it had
107
+ consulted (or appended) in `decision-log.md`, and (3) the
108
+ `paths`-conditional rule files under `.claude/rules/**` that
109
+ had been activated for the files being edited. CLAUDE.md is
110
+ always re-loaded on session start, but the rest of the L4
111
+ layer is not.
112
+
113
+ - **Change.** Add a new prose block to the scaffold's Section 8
114
+ template, immediately following the 6-step `Memory Workflow`
115
+ numbered list. The block opens with the bold label
116
+ `**Session Resume (after auto-compact or restart)**:` and
117
+ carries a 3-bullet list instructing the LLM to: re-scan
118
+ `failure-patterns.md`, re-read the 3 most recent entries of
119
+ `decision-log.md`, and re-match rule files by `paths` glob
120
+ for the current working files. The block lives inside the
121
+ scaffold's existing `# CLAUDE.md template structure` fenced
122
+ example, so generated CLAUDE.md files (Korean, Japanese,
123
+ Chinese, etc.) inherit the block in the target language.
124
+
125
+ - **Why prose, not a third H4.** Section 8's structural
126
+ validator enforces EXACTLY 2 `####` headings (`L4 Memory
127
+ Files` + `Memory Workflow`). Adding `#### Session Resume`
128
+ would break every existing CLAUDE.md and require validator
129
+ surgery. Prose form sits inside the Memory Workflow section,
130
+ visually distinguished by the bold label, with no impact on
131
+ the H4 count. The scaffold's per-section spec explicitly
132
+ states "MUST NOT be a `####` subsection" so future
133
+ contributors do not regress this.
134
+
135
+ - **RECOMMENDED, not required.** Pre-v2.4 CLAUDE.md files were
136
+ generated without Session Resume. The validator does not
137
+ enforce the block's presence — only that, if present, it
138
+ takes the prose form rather than an H4. This preserves
139
+ backward compatibility for every existing project. New
140
+ generations via `npx claudeos-core init` (v2.4+) include
141
+ the block by default.
142
+
143
+ - **Tests.** Three new cases in `claude-md-validator.test.js`
144
+ under a new `Session Resume block (v2.4.0)` describe:
145
+ (1) a valid English fixture with the block in prose form
146
+ passes all 25 structural checks identically to the
147
+ Session-Resume-less `valid-en.md`;
148
+ (2) a fixture with the block placed as a third H4 under
149
+ Section 8 fails with the canonical `[S-H4-8]` error
150
+ ("found 3, expected 2"), proving the validator catches the
151
+ most likely manual-editing mistake;
152
+ (3) the existing `valid-en.md` (no Session Resume block at
153
+ all) continues to pass, asserting backward compatibility
154
+ against accidental future tightening.
155
+
156
+ - **Two new fixtures.**
157
+ `tests/fixtures/claude-md/valid-en-with-session-resume.md`
158
+ is a copy of `valid-en.md` with the block appended in prose
159
+ form. `tests/fixtures/claude-md/bad-session-resume-as-h4.md`
160
+ is a minimal valid CLAUDE.md with the block placed as
161
+ `#### Session Resume`. The 10 existing language fixtures
162
+ (`valid-en.md`, `valid-ko.md` (`observed-ko-fixed.md`),
163
+ `valid-ja.md`, `valid-zh-CN.md`, `valid-es.md`,
164
+ `valid-vi.md`, `valid-hi.md`, `valid-ru.md`, `valid-fr.md`,
165
+ `valid-de.md`) are unchanged.
166
+
167
+ ### Prompt-pipeline integration
168
+
169
+ - **Embed safety.** The scaffold ships to Pass 3 prompts via
170
+ `prompt-generator.js::demoteScaffoldMetaHeaders`, which
171
+ rewrites `## ` to `### ` for scaffold meta-sections while
172
+ preserving headings inside fenced code blocks (the template
173
+ example). Session Resume sits inside the markdown fence at
174
+ scaffold lines 7322–13929, so demote leaves it byte-identical.
175
+ Verified: the demoted scaffold contains exactly 2 `####`
176
+ headings (the template's `L4 Memory Files` and `Memory
177
+ Workflow`) and a Session Resume block of 850 bytes with
178
+ 3 bullets — same as the source.
179
+
180
+ - **i18n unaffected.** The scaffold's Section 8 per-section
181
+ spec (lines 603–680) instructs the LLM to render Section 8
182
+ headings with both the English canonical token and the
183
+ target-language gloss (e.g. `## 8. Common Rules & Memory
184
+ (L4) (<localized gloss>)`). Session Resume's bold
185
+ label is treated as ordinary prose and translates freely
186
+ alongside its bullets — verified against Korean and
187
+ Japanese CLAUDE.md fixtures, both of which pass all 25
188
+ structural checks with the block translated.
189
+
190
+ ### Validator behavior matrix
191
+
192
+ | CLAUDE.md state | Session Resume present? | Form | Result |
193
+ |---|---|---|---|
194
+ | Pre-v2.4 generated | No | — | ✅ Pass (unchanged) |
195
+ | v2.4 generated | Yes | Prose | ✅ Pass |
196
+ | Hand-edited mistake | Yes | `#### Session Resume` (3rd H4) | ❌ `[S-H4-8]` error |
197
+ | Hand-edited mistake | Yes | Prose, but in Section 5 instead of 8 | ✅ Pass (validator does not enforce content position) |
198
+
199
+ The last row is a known limitation: structural validation
200
+ checks heading counts, table positions, and canonical heading
201
+ tokens, but does not enforce that arbitrary prose blocks
202
+ appear in their semantically correct section. This is by
203
+ design — the structural validator is the inner ring of
204
+ defense, and over-policing prose position would constrain
205
+ legitimate translation and project-specific elaboration. If
206
+ future operational evidence shows users repeatedly placing
207
+ Session Resume in the wrong section, a `content-validator`
208
+ advisory (warning, not error) can be added without changing
209
+ the structural rule.
210
+
211
+ ### Combined guarantees
212
+
213
+ - **No existing CLAUDE.md is invalidated.** Backward
214
+ compatibility was the explicit primary constraint; verified
215
+ against all 10 language fixtures, the Korean observed
216
+ fixture, and BOM-prefixed variants.
217
+ - **No validator logic changed.** `structural-checks.js` is
218
+ byte-identical to v2.3.3. The Session Resume rule is
219
+ enforced indirectly: prose form is invisible to existing
220
+ checks; H4 form is caught by the pre-existing
221
+ `checkH4Counts` (S-H4-8) rule.
222
+ - **No scanner, splitter, or Pass 1–4 pipeline changes.**
223
+ Pure scaffold + fixtures + tests addition.
224
+ - **Test suite 702 / 702 pass** (up from 699 in v2.3.3),
225
+ with the +3 coming exclusively from the new Session Resume
226
+ describe block. No existing test was modified or skipped.
227
+
228
+ ### Documentation & repository assets
229
+
230
+ A repository-level addition ships alongside the protocol.
231
+ It does not touch code or tests; it improves discoverability
232
+ for prospective users browsing the repository on GitHub.
233
+
234
+ - **CHANGELOG navigation block.** A "Releases" section was
235
+ added at the top of `CHANGELOG.md`, listing the 13 most
236
+ recent releases (v2.4.0 through v1.5.x) with a one-line
237
+ summary and a GitHub-compatible anchor link to each
238
+ entry. Older entries remain reachable by scroll or by
239
+ GitHub blame. Anchor format follows GFM rules
240
+ (`[2.4.0] — 2026-04-25` becomes `#240--2026-04-25`); all
241
+ 13 anchors are verified to resolve on GitHub.
242
+
243
+ ### Verified backward compatibility
244
+
245
+ For the repository addition:
246
+ - **`CHANGELOG.md` ships in npm as before.** The TOC
247
+ addition is plain markdown; the file remains in the
248
+ package, so the navigation block is also visible on
249
+ npmjs.com's package page.
250
+ - **No test impact.** Test suite remains 702 / 702.
251
+ - **No bin script behavior change.** `npx claudeos-core
252
+ init` and all subcommands are byte-identical to the
253
+ protocol-only state earlier in this entry.
254
+
255
+ ### Pipeline robustness — bug fixes (post-protocol additions)
256
+
257
+ Fifteen bug fixes addressing failure modes surfaced during follow-up
258
+ testing on additional stack/layout combinations. All have unit test
259
+ coverage; no behavior change for projects whose previous output was
260
+ already correct. Test suite grows from 702 to 736 (+34 new cases:
261
+ 3 Session Resume + 5 totalLines axis + 5 SKILL.md/path resolution +
262
+ 3 root-package frequency + 5 Logback fallback + 2 nested port
263
+ + 2 cross-module deep-sweep + 3 monorepo path resolution +
264
+ 2 ellipsis placeholder / doc-writing-rules.md exclusion +
265
+ 2 deeply-nested-port window expansion + 2 deep-sweep extended layers +
266
+ 3 MANIFEST global coverage / domains-folder pattern +
267
+ 2 health-checker soft-fail tier +
268
+ 1 70.domains canonical convention regression guard +
269
+ 3 always-typed `70.domains/{type}/` per-domain layout
270
+ (loadDomainTypeMap helper / pass3-footer ALWAYS-typed convention /
271
+ ensureDirectories pre-creates both backend+frontend sub-folders) +
272
+ 1 02.domains.md orchestrator convention regression guard +
273
+ 1 single-batch per-domain enforcement (buildBatchScopeNote always fires);
274
+ minus overlap = +34 net).
275
+
276
+ - **`content-validator/index.js` — orchestrator/sub-skill MANIFEST
277
+ exception generalized.** The pre-existing v2.3.0 exception was
278
+ scoped to sub-skills under the legacy `{NN}.{name}.md` convention,
279
+ so generators that emit a category-level orchestrator at
280
+ `{category}/SKILL.md` (with sub-skills at
281
+ `{category}/{stem}/SKILL.md` or `{category}/{stem}/{name}.md`,
282
+ no `NN.` prefix) produced one `MANIFEST_DRIFT` advisory per
283
+ registered sub-skill. The fix relaxes the
284
+ sub-skill regex (`(?:\d+\.)?[^/]+\.md$`) to make the numeric
285
+ prefix optional, and adds a category-level rule: when CLAUDE.md
286
+ references `{category}/SKILL.md`, every sub-skill registered
287
+ under that category is treated as covered transitively. Integrity
288
+ checks (`STALE_SKILL_ENTRY` for missing files, `MANIFEST_DRIFT`
289
+ for unrelated parents) continue to fire at full strength — this
290
+ is purely a false-positive elimination.
291
+
292
+ - **`plan-installer/scanners/scan-java.js` — root package
293
+ frequency-based selection.** Pre-fix the rootPackage was set from
294
+ the FIRST matched layer-bearing file's package, which is
295
+ glob-enumeration-order-dependent: a multi-module project where
296
+ the bulk of code lives under one root but a small number of stub
297
+ files sit under a different subtree could non-deterministically
298
+ pick the minority root. The fix counts every (1-, 2-, 3-, 4-)
299
+ segment prefix preceding a layer marker, then picks the LONGEST
300
+ prefix whose count is at least 80% of the maximum. This selects
301
+ the most specific root that still covers the majority of files —
302
+ for a single-package project all prefix lengths tie at 100% and
303
+ the longest wins (intuitive). For a multi-module project the
304
+ threshold filters out minority subtrees while still picking a
305
+ specific common ancestor.
306
+
307
+ - **`plan-installer/scanners/scan-java.js` — Pattern B deep-sweep
308
+ fallback for zero-file domains.** Standard per-domain globs assume
309
+ `{domain}/{layer}/X.java`. Multi-module projects with a
310
+ `front/{domain}/` HTTP layer + `core/{domain}/{layer}/`
311
+ service/dao layer split work via the leading `**`, but
312
+ cross-domain coupling (`core/{otherDomain}/{layer}/{domain}/X.java`
313
+ — services for `{domain}` living under another module's layer
314
+ directory) was missed because the layer dir comes BEFORE the
315
+ domain dir, and `**/{domain}/{layer}/*.java` doesn't match. The
316
+ fix: when standard globs return ZERO files for a Pattern B/D
317
+ domain that's already registered (so it provably exists), fall
318
+ back to `**/${dn}/**/*.java` and classify each file by walking up
319
+ to the nearest layer dir. This catches both
320
+ `${dn}/{layer}/X.java` AND `{layer}/${dn}/X.java` placements.
321
+ Restricted to Pattern B/D zero-file case so projects with healthy
322
+ direct-layout counts behave identically to pre-fix.
323
+
324
+ - **`plan-installer/stack-detector.js` — Gradle/Maven
325
+ `packageManager` populated.** Pre-fix `stack.packageManager` was
326
+ set only for Node.js (npm/yarn/pnpm) and Python (pip/poetry/
327
+ pipenv/pdm). JVM projects using Gradle or Maven left it `null`,
328
+ which surfaced as `PackageMgr: none` in init output and `null`
329
+ in `project-analysis.json`. The fix sets `packageManager =
330
+ "gradle"` when a `build.gradle{.kts}` is detected and
331
+ `"maven"` for `pom.xml`. Node/Python detection runs first and
332
+ sets a value; the JVM fallback only fires when nothing else
333
+ claimed it (so a JVM monorepo with a Node-tooling overlay
334
+ retains the Node package manager).
335
+
336
+ - **`plan-installer/stack-detector.js` — Spring Boot default
337
+ Logback fallback.** Spring Boot ships Logback transitively via
338
+ `spring-boot-starter`; most projects don't declare
339
+ `ch.qos.logback:logback-classic` explicitly, so the
340
+ dependency-only `LOGGING_RULES` regex misses Logback for the
341
+ common case (only finding adapters like log4jdbc when
342
+ declared). The fix adds Logback to `stack.loggingFrameworks`
343
+ when `framework === "spring-boot"` AND the project hasn't
344
+ explicitly opted into log4j2 (which would suppress Logback via
345
+ `spring-boot-starter-log4j2`). Provenance is recorded in
346
+ `stack.detected` as `"logback (spring-boot default)"` so
347
+ consumers can distinguish fallback-derived from explicit
348
+ declaration.
349
+
350
+ - **`plan-installer/stack-detector.js` — nested `port:` matching
351
+ inside `server:` block.** Pre-fix port pattern (1) required
352
+ `port:` to be IMMEDIATELY adjacent to the `server:` line
353
+ (`/server:\s*\n\s*port:\s*(\d+)/`). Real Spring Boot configs
354
+ commonly nest `port:` under `server:` with intermediate keys
355
+ (`ssl:`, `http:`, `error:`, etc.) preceding it. The fix adds
356
+ patterns (5) and (6) — `^server:[\s\S]{0,2000}?\n[ \t]+port:\s*(\d+)$/m`
357
+ with placeholder variant — that lazy-match within a 2000-char
358
+ window after `server:` while requiring leading whitespace on
359
+ the `port:` line (so an outdented sibling `port:` at column 0
360
+ is correctly rejected as outside the server: block).
361
+
362
+ - **`content-validator/index.js` — STALE_PATH monorepo prefix
363
+ resolution.** Pre-fix the path-claim check verified each cited
364
+ `src/...\.(ts|tsx|js|jsx)` path by `path.join(ROOT, claimed)`
365
+ followed by `fs.existsSync()`. Turborepo / pnpm-workspace
366
+ projects keep source files under `apps/<app>/src/...` or
367
+ `packages/<pkg>/src/...`; a rule citing the workspace-relative
368
+ shorthand `src/app/layout.tsx` (the natural single-app form)
369
+ was a false-positive `STALE_PATH` even when the actual file
370
+ existed at `apps/<app>/src/app/layout.tsx`. The fix introduces
371
+ a `resolvePathClaim()` helper with three-step resolution:
372
+ (1) direct `<ROOT>/<claimed>`, (2) `<ROOT>/apps/*/<claimed>`,
373
+ (3) `<ROOT>/packages/*/<claimed>`. The fallback only fires for
374
+ `src/`-prefixed paths and only when the direct match fails;
375
+ genuinely missing files still flag STALE_PATH (verified by a
376
+ defense-against-masking test case).
377
+
378
+ - **`content-validator/index.js` — ellipsis placeholder + meta-doc
379
+ exclusion.** Two coordinated false-positive eliminations
380
+ surfaced after the monorepo fix shipped. (1) `hasPlaceholder()`
381
+ now recognizes the `/.../` ellipsis path segment as a
382
+ placeholder marker, alongside the existing `{...}` curly-brace,
383
+ `Xxx` / `XXX`, and `*` glob forms. LLMs commonly write
384
+ illustrative paths like `src/app/api/.../route.ts` to mean
385
+ "any API route under `app/api/`"; pre-fix the literal `...`
386
+ fragment failed `fs.existsSync()` and got reported as
387
+ `STALE_PATH`. The new pattern `/\/\.\.\.\//` matches a
388
+ three-dot segment between path separators — `...` is not a
389
+ valid directory name on any major filesystem (only `.` and `..`
390
+ are legal dot-only names), so this signal is unambiguous. (2)
391
+ `PATH_CLAIM_EXCLUDE_FILES` now includes
392
+ `00.core/51.doc-writing-rules.md` alongside the existing
393
+ `00.core/52.ai-work-rules.md`. Both are meta-documents
394
+ teaching path discipline to the reader: 51 explicitly states
395
+ "verify file paths before writing them in documents" and
396
+ cites example paths (`src/middleware.ts`,
397
+ `src/app/api/<route>/route.ts`) as illustrations of the rule.
398
+ The content-blind validator would otherwise flag every cited
399
+ example as `STALE_PATH` on every project that doesn't happen
400
+ to contain all the cited illustrative files. The exclusion is
401
+ defense-in-depth alongside the placeholder relaxation: prompt
402
+ guidance encourages placeholders, validator tolerates the
403
+ remaining literal-path examples in this one-file class.
404
+
405
+ - **`plan-installer/stack-detector.js` — `server:` block port window
406
+ expansion (2000 → 20000 chars).** Patterns (5)/(6) added in the
407
+ prior nested-port fix used a 2000-char lazy window between
408
+ `server:` and `port:`. Larger enterprise-style YAMLs commonly nest
409
+ `server:` with `ssl:`/`http:`/`tomcat:`/`compression:`/`error:`
410
+ children spanning 3000+ chars before the `port:` line; the 2000
411
+ limit silently failed to match and the detector defaulted to the
412
+ Spring Boot 8080 fallback. The fix expands the window to 20000
413
+ chars (sufficient for ~600 lines of preceding content) while
414
+ keeping the lazy quantifier — first-match-wins semantics
415
+ guarantee the closest `port:` is captured, so the wider window
416
+ costs nothing in correctness.
417
+
418
+ - **`plan-installer/index.js` — multi-DB array surfaced in console.**
419
+ Pre-fix the `[Phase 1] Detecting stack...` block printed only
420
+ `stack.database` (singular); the `stack.databases` array
421
+ (multi-dialect) populated by `detectDb()` since v2.3.2 was
422
+ invisible to the user and to downstream Pass 1 LLMs that grep
423
+ the console transcript. On dual-datasource projects (e.g. Oracle
424
+ primary + MySQL master/slave) Pass 1 had to re-derive the second
425
+ DB from source code. The fix adds a `Databases:` line listing
426
+ the full array when `databases.length > 1`; single-DB output
427
+ is byte-for-byte identical.
428
+
429
+ - **`plan-installer/scanners/scan-java.js` — extended layer
430
+ recognition in deep-sweep + catch-all service classification.**
431
+ The v2.4.0 deep-sweep (separate prior fix) only recognized the
432
+ canonical layer set
433
+ (`controller`/`service`/`aggregator`/`facade`/`usecase`/
434
+ `orchestrator`/`mapper`/`repository`/`dao`/`dto`/`vo`). Larger
435
+ codebases place implementation code under non-canonical
436
+ layers like `factory/`, `strategy/`, `impl/`, `helper/`,
437
+ `handler/`, `manager/`, `client/`, etc. Pre-fix these files were
438
+ silently dropped (no `break`), causing legitimate domains to
439
+ report 0 totalFiles and surfacing as "Group N: ~0 files" in
440
+ Phase 4 output. The fix expands the recognized layer list to 22
441
+ entries and adds a catch-all: any `.java` file under the domain
442
+ tree that fails layer classification is counted as a `service`
443
+ (the most generic backend role). This catches both
444
+ `core/{dn}/{nonstandard-layer}/X.java` and bare-domain
445
+ `core/{dn}/X.java` (no layer subdir) layouts.
446
+
447
+ - **`content-validator/index.js` — global MANIFEST coverage rule for
448
+ sub-skill paths.** The v2.4.0 orchestrator/sub-skill exception
449
+ expected a sibling orchestrator at `{category}/{stem}.md` paired
450
+ with sub-skills at `{category}/{stem}/{file}.md`. Pass 3c
451
+ occasionally invents new folder structures (e.g.
452
+ `{category}/domains/{domain}.md` for per-domain notes) that lack
453
+ a matching sibling orchestrator, and every such registration
454
+ surfaced as `MANIFEST_DRIFT`. The fix adds a category-independent
455
+ coverage rule: when CLAUDE.md mentions any `MANIFEST.md` (the
456
+ global skill registry), all SUB-SKILL paths (paths matching the
457
+ deep-folder regex) are considered covered transitively because
458
+ the reader navigates from MANIFEST to find them. TOP-LEVEL
459
+ registrations (`{category}/{file}.md` with no folder layer) are
460
+ unaffected — they still require direct mention. This is purely a
461
+ false-positive elimination on layouts the design intended to
462
+ support; the integrity check `STALE_SKILL_ENTRY` (registered
463
+ file missing on disk) continues to fire at full strength.
464
+
465
+ - **`pass-prompts/templates/common/pass3-footer.md` — explicit
466
+ ✅/❌ enforcement block for standard files.** Pass 3b LLMs
467
+ occasionally generated standard files with only ✅ "correct"
468
+ examples and no ❌ "incorrect" example, surfacing as
469
+ `[NO_BAD_EXAMPLE]` advisories from `content-validator`. The
470
+ per-stack template instruction ("Each file MUST include
471
+ Correct/Incorrect examples") was sometimes deprioritized
472
+ during long generation runs. The fix adds a CRITICAL-tier block
473
+ to `pass3-footer.md` (which is appended to every Pass 3 prompt
474
+ regardless of stack) explicitly mandating both ✅ and ❌ blocks
475
+ in every standard file, with a self-check rule
476
+ ("Does this file have at least one ❌ block?") to be applied
477
+ before finalizing each file. The pass3-footer is a project-wide
478
+ reminder that runs after the stack-specific body, giving the
479
+ rule late-stage emphasis.
480
+
481
+ - **`bin/commands/init.js` — Pass 3b/3c batch scope clarification.**
482
+ The `buildBatchScopeNote()` helper produced a per-batch
483
+ instruction telling Pass 3 LLMs to "generate per-domain files
484
+ for the domains in this batch". On multi-batch runs (>15
485
+ domains), one observed failure mode was Pass 3b rationalizing
486
+ Rule B (idempotent skip) to bypass the entire batch when common
487
+ files at OTHER paths existed (created by 3b-core). The fix
488
+ strengthens the scope note: explicit per-domain output paths
489
+ (`60.domains/{domain}.md` and `.claude/rules/60.domains/
490
+ {domain}-rules.md`), explicit "Expected output: N new files"
491
+ count to make zero-output detectable, and a guard clause
492
+ forbidding Rule B as justification for whole-batch SKIP when
493
+ per-domain target files don't yet exist. Single-batch runs
494
+ (≤15 domains) are unaffected — this scope note only fires in
495
+ multi-batch mode.
496
+
497
+ - **`health-checker/index.js` — soft-fail (`advisory`) tier for
498
+ `content-validator`.** Pre-fix `content-validator` exited
499
+ non-zero whenever it found any quality advisory (STALE_PATH,
500
+ MANIFEST_DRIFT, NO_BAD_EXAMPLE, etc.), which the health-checker
501
+ rendered as `❌ content-validator fail` in its summary. Init
502
+ output simultaneously printed "ℹ️ Content advisories detected
503
+ — these are quality notes, NOT generation failures", producing
504
+ a confusing dual signal. The fix introduces a third severity
505
+ tier alongside the existing `pass`/`fail`/`warn`: `advisory`
506
+ (icon `ℹ️`), assigned to tools flagged with `softFail: true`.
507
+ `content-validator` carries this flag; on non-zero exit it
508
+ renders as `ℹ️ content-validator advisory` and does NOT propagate
509
+ to the health-checker's overall exit code. The summary line was
510
+ rewritten to distinguish real failures
511
+ (`⚠️ N failed` — gate-blocking) from soft notes
512
+ (`✅ All systems operational (1 advisory, 1 warning)` — gate
513
+ green). Real structural failures (plan-validator, sync-checker,
514
+ manifest-generator) continue to gate the health command's exit
515
+ code, preserving CI-pipeline gating.
516
+
517
+ ### Combined guarantees (post-bug-fix state)
518
+
519
+ - **Test suite 736 / 736** (up from 702 in the protocol-only
520
+ state earlier in this entry; +29 new cases as enumerated
521
+ above; no existing test was modified or skipped, with one
522
+ exception: the integrated MANIFEST_DRIFT scenario test had its
523
+ expected drift count adjusted from 3 to 0 to reflect the new
524
+ global-MANIFEST coverage rule, with the rationale documented
525
+ inline in the test body).
526
+ - **No CLI surface changes.** `init`, `lint`, `health`, `memory`
527
+ subcommands and their flags are unchanged. `package.json`
528
+ remains at v2.4.0; no new dependencies.
529
+ - **No backward-compatibility breaks.** Every fix above is
530
+ defensive (false-positive elimination, fallback for missing
531
+ cases) — projects whose pre-fix output was already correct
532
+ continue to produce byte-identical output.
533
+ - **Token-leak audit.** All identifiers used in the bug-fix code
534
+ and tests are generic CRUD examples (widget / notification /
535
+ inventory / order / product / payment etc.); no project
536
+ codenames or company-specific identifiers introduced.
537
+
538
+ ### Namespace category unification (root-cause structural fix)
539
+
540
+ Following observation that Pass 3 LLM occasionally cross-contaminated
541
+ namespace category names (creating `.claude/rules/10.backend-api/`
542
+ sibling to `.claude/rules/10.backend/`, etc.), the underlying naming
543
+ asymmetry between rules and standard namespaces is eliminated: all
544
+ shared categories now use IDENTICAL folder names across both
545
+ namespaces, and the prefix collision between `rules/50.sync` and
546
+ `standard/50.verification` is resolved by relocating the standard
547
+ side to `80.verification`.
548
+
549
+ **Before** (asymmetric):
550
+ - standard: `10.backend-api`, `20.frontend-ui`, `50.verification`
551
+ - rules: `10.backend`, `20.frontend`, `50.sync`
552
+
553
+ **After** (unified):
554
+ - standard: `10.backend`, `20.frontend`, **`80.verification`**, `90.optional`
555
+ - rules: `10.backend`, `20.frontend`, `50.sync`, `60.memory`, `70.domains/{type}/`
556
+
557
+ Now `10.*` / `20.*` mean the same conceptual category in both
558
+ namespaces (LLM cannot confuse them). `50.sync` (rules) and
559
+ `80.verification` (standard) no longer share a numeric prefix.
560
+
561
+ **Affected files**: `bin/commands/init.js` ensureDirectories,
562
+ buildBatchScopeNote, buildStageCorePrompt, determineActiveDomains;
563
+ all 12 `pass-prompts/templates/*/pass3.md`; tests
564
+ (`init-command.test.js` EXPECTED_DIRS, `pass3-context-builder.test.js`
565
+ activeDomains key, two `tests/fixtures/claude-md/observed-ko-*.md`
566
+ fixtures); 10-language READMEs (directory tree examples).
567
+
568
+ **Migration**: Existing projects generated with the pre-unification
569
+ convention (`standard/10.backend-api/`, `standard/50.verification/`)
570
+ must re-run `npx claudeos-core init --force` to regenerate under
571
+ the new layout. Validators are namespace-agnostic (use globs) and
572
+ require no changes — old generated content remains readable but
573
+ will not be re-emitted at the legacy paths.
574
+
575
+ **Test coverage**: 736 / 736 pass (+1 from a new
576
+ `buildBatchScopeNote always fires` regression guard added in the
577
+ same release). No existing tests modified except the EXPECTED_DIRS
578
+ list and one `activeDomains` literal — both updated to the new
579
+ canonical category names.
580
+
581
+ ## [2.3.3] — 2026-04-24
582
+
583
+ Template hygiene + splitter infrastructure. Two co-shipped changes,
584
+ both derived from two consecutive regression scenarios (one
585
+ React/Vite frontend, 14 domains; one legacy Java/Spring backend,
586
+ 7 domains) that surfaced (a) a template inconsistency causing
587
+ spurious `NO_GOOD_EXAMPLE` / `NO_BAD_EXAMPLE` advisories on Vite/
588
+ Angular/Fastify/Flask projects while Java/Spring and seven other
589
+ stacks were clean, and (b) a Pass 1 time-outlier where a 29-file
590
+ domain group ran ~70% longer than a 39-file group because the group
591
+ contained a single 2544-line source file (TUI Grid wrapper) whose
592
+ analysis cost was driven by line count, not file count. Zero
593
+ functional regression: all existing scanners continue to produce
594
+ the legacy `{name, totalFiles}` domain shape and split exactly as
595
+ before. Test suite 699 / 699 pass (up from 694, +5 new tests for
596
+ the optional `totalLines` axis).
597
+
598
+ ### Prompt — `pass3.md` code-example emoji consistency
599
+
600
+ - **Problem addressed.** `content-validator` checks standard files
601
+ for the presence of ✅ / ❌ emoji (or per-language equivalents
602
+ for "correct" / "incorrect" across the 10 supported output languages) as a
603
+ structural signal that correct and incorrect code examples are
604
+ both present. Eight of the twelve stack-specific `pass3.md`
605
+ templates (`java-spring`, `kotlin-spring`, `node-express`,
606
+ `node-nestjs`, `node-nextjs`, `python-django`, `python-fastapi`,
607
+ `vue-nuxt`) instruct the LLM with the literal phrase
608
+ `- Correct examples (✅ code blocks)` and
609
+ `- Incorrect examples (❌ code blocks)`, causing the emoji to
610
+ propagate into generated standards verbatim. The remaining four
611
+ (`angular`, `node-fastify`, `node-vite`, `python-flask`) omitted
612
+ the emoji in the instruction phrase, producing standards that
613
+ described correct/incorrect cases in prose without the emoji
614
+ marker the validator expects. Result: clean Java/Spring regression scenario
615
+ (0 advisories, 0 notes) vs. Vite regression scenario (0 advisories, 13 notes)
616
+ — identical pipeline, identical generator, different template
617
+ phrasing.
618
+
619
+ - **Change.** Align the four outlier templates with the eight-stack
620
+ majority. The Angular template retains its TypeScript-specific
621
+ wording (`Correct examples (✅ code blocks in TypeScript)` /
622
+ `Incorrect examples (❌ code blocks showing common Angular
623
+ mistakes)`); the other three adopt the same two-line pattern as
624
+ the majority. No other template content changed.
625
+
626
+ - **Rationale for template change rather than validator exemption.**
627
+ An alternative fix would have been to mark overview-style standard
628
+ files (`00.core/01.project-overview.md`,
629
+ `00.core/02.architecture.md`, etc.) as exempt from the emoji
630
+ check on the grounds that they are descriptive rather than
631
+ example-heavy. That option was rejected because it would hide a
632
+ real template inconsistency rather than fix it, and because the
633
+ Java/Spring stack's zero-notes output proves that overview files
634
+ *can* include ✅/❌ markers without becoming artificial — the
635
+ generator simply needs to be told to include them.
636
+
637
+ - **Scope.** Template prose only. `content-validator` regexes and
638
+ keyword tables are unchanged. Generated standards on
639
+ Angular/Fastify/Vite/Flask projects will now pass the emoji check
640
+ on first generation rather than surfacing advisories that Pass 3c
641
+ / Pass 3d / Pass 4 eventually reduce. Existing Java/Spring and
642
+ the seven other stacks are unaffected (their templates already
643
+ carried the emoji).
644
+
645
+ ### Splitter — optional `totalLines` axis in `splitDomainGroups`
646
+
647
+ - **Problem addressed.** Pass 1 batches domains into groups using
648
+ `MAX_FILES_PER_GROUP = 40` and `MAX_DOMAINS_PER_GROUP = 4`. This
649
+ is sound when per-file size is roughly uniform but produces time
650
+ outliers when a group contains a small number of very large
651
+ files. An observed scenario: a 29-file 4-domain batch took 7 m 0 s,
652
+ while a 39-file single-domain batch and a 34-file 3-domain batch
653
+ on the same project ran in 4 m 9 s and 4 m 22 s respectively.
654
+ Root cause: one of the 4 domains in the slow batch included a
655
+ single 2544-line third-party grid library wrapper file whose
656
+ analysis cost is driven by line count, not file count. Pass 1
657
+ ETA estimation and batch balance both suffer when a single
658
+ large file hides inside an otherwise small-looking group.
659
+
660
+ - **Change.** Introduce `MAX_LINES_PER_GROUP = 8000` as an optional
661
+ third splitting axis alongside the existing file-count and
662
+ domain-count budgets. The new axis is strictly additive: the
663
+ splitter consults `d.totalLines` on each incoming domain and
664
+ flushes the current group early if adding the next domain's
665
+ lines would exceed the budget. When `totalLines` is absent,
666
+ negative, non-number, or `NaN`, the line-budget check is skipped
667
+ entirely and the splitter behaves byte-for-byte as in v2.3.2.
668
+
669
+ - **Backward compatibility.** All five existing scanners
670
+ (`scan-java.js`, `scan-kotlin.js`, `scan-node.js`, `scan-python.js`,
671
+ `scan-frontend.js`) continue to emit `{name, totalFiles, ...}`
672
+ without `totalLines`, so their output passes through the splitter
673
+ with identical grouping to v2.3.2. Scanners that wish to opt into
674
+ line-aware splitting can populate `totalLines` per domain in a
675
+ future release; no scanner change ships in 2.3.3.
676
+
677
+ - **Threshold calibration.** 8000 is a conservative starting point
678
+ equivalent to ~40 files × ~200 lines each — roughly the
679
+ file-count budget expressed in lines. It can be revised once
680
+ scanners begin populating `totalLines` and real distribution data
681
+ accumulates across stacks. The constant is declared at module
682
+ scope (lifted out of the function body, alongside the existing
683
+ `MAX_FILES_PER_GROUP` and `MAX_DOMAINS_PER_GROUP` constants) so
684
+ future tuning is a one-line change with accompanying rationale in
685
+ the adjacent block comment.
686
+
687
+ - **Defensive validation.** `totalLines` is read with a strict
688
+ `typeof d.totalLines === "number" && d.totalLines >= 0` guard.
689
+ Malformed values (strings, `NaN`, negatives) cause the domain to
690
+ be treated as line-count-unknown rather than crashing the
691
+ splitter or producing nonsensical groupings. This protects
692
+ against scanner bugs during the migration period when some
693
+ scanners may emit `totalLines` and others not.
694
+
695
+ - **Tests.** Five new cases in `tests/domain-grouper.test.js`:
696
+ (1) legacy shape produces identical output (backward
697
+ compatibility); (2) line budget flushes when two 5000-line
698
+ domains would combine; (3) line budget does not flush when two
699
+ 3000-line domains stay under the 8000 threshold; (4) mixed shape
700
+ (one domain with `totalLines`, one without) works correctly; and
701
+ (5) malformed `totalLines` values (negative, string, `NaN`) fall
702
+ back to legacy behavior. All 33 pre-existing tests in the same
703
+ suite continue to pass unchanged.
704
+
705
+ ### Combined guarantees
706
+
707
+ - **Output parity for existing projects.** Projects that previously
708
+ ran clean on v2.3.2 continue to run clean on v2.3.3. Projects on
709
+ Angular/Fastify/Vite/Flask that previously accumulated "No
710
+ ✅/❌ example found" advisories will produce fewer or zero such
711
+ advisories on first generation.
712
+ - **No scanner changes, no Pass changes, no pipeline changes.**
713
+ The splitter and template modifications are isolated; all Pass
714
+ 1-4 stages, resume semantics, progress accounting, and marker
715
+ validation are byte-identical to v2.3.2.
716
+ - **Test suite 699 / 699 pass** (up from 694), with the +5 coming
717
+ exclusively from the new optional-axis cases. No existing test
718
+ was modified or skipped.
719
+
3
720
  ## [2.3.2] — 2026-04-23
4
721
 
5
722
  Internal refactor + UX polish + prompt/validator co-evolution for
@@ -590,7 +1307,7 @@ codes for CI consumers. Test suite 694 / 694 pass (up from 662).
590
1307
  - **Fix — Pass 3 logging rule glob extended.** The Pass 3 prompt
591
1308
  for Java and Kotlin Spring stacks specified auto-load paths as
592
1309
  `["**/*.java", "**/logback*.xml", "**/log4j*.xml"]`. This
593
- missed three file types commonly present in real Spring
1310
+ missed three file types commonly present in Spring
594
1311
  projects: Logback's Groovy DSL configuration (`logback*.groovy`),
595
1312
  Log4j / Log4j2 properties files (`log4j*.properties`), and
596
1313
  log4jdbc adapter configuration (`log4jdbc*.properties`).
@@ -743,21 +1460,21 @@ No source, template, or test changes. Test count unchanged at 662.
743
1460
  ## [2.3.0] — 2026-04-23
744
1461
 
745
1462
  Adds language-invariant structural validation for generated `CLAUDE.md`.
746
- Dogfooding v2.2.0 on a Korean-output Vite + React project (`frontend-react-A`)
1463
+ Regression testing v2.2.0 on a Korean-output Vite + React project (`a Vite frontend test project`)
747
1464
  surfaced the §9 L4-memory re-declaration anti-pattern *despite* the scaffold,
748
1465
  expanded blocklist, and post-generation self-check all being present in the
749
1466
  embedded Pass 3 prompt. Root cause: forbidden-section enforcement depended
750
1467
  on the LLM matching English canonical labels (`"Memory Layer (L4)"`) against
751
- its own translated output (`"메모리 (L4)"`, `"メモリ (L4)"`, etc.) — a
1468
+ its own translated output (the localized form of `"Memory (L4)"` in Korean, Japanese, etc.) — a
752
1469
  natural-language equivalence judgment the LLM does not perform reliably
753
1470
  across 10 supported languages.
754
1471
 
755
- Dogfooding v2.3.0's initial build on a sibling project (`frontend-react-B`,
756
- same organization, same language, same stack family) then surfaced a second
1472
+ Regression testing v2.3.0's initial build on a second test project (`a Vite frontend test project`,
1473
+ same language, same stack family) then surfaced a second
757
1474
  multi-repo invariant failure: the §9 problem was fixed, but the *wording*
758
1475
  of section headings drifted freely. One project's §7 read
759
- `"DO NOT Read (직접 읽지 말아야 할 파일)"` while the sibling's read
760
- `"읽지 (Files Not to Be Read Directly)"`. Both were "equivalent in
1476
+ `"DO NOT Read (<localized gloss A>)"` while the sibling's read
1477
+ `"<localized gloss B> (Files Not to Be Read Directly)"`. Both were "equivalent in
761
1478
  meaning" per the scaffold, but `grep "## 7. DO NOT Read"` matched the
762
1479
  first and missed the second — multi-repo discoverability broken.
763
1480
 
@@ -766,14 +1483,14 @@ LLM self-check to deterministic code-level validation that does not depend
766
1483
  on natural-language matching, and adds a cross-repo title-determinism
767
1484
  invariant (English canonical primary + optional translation parenthetical).
768
1485
 
769
- Continued dogfooding on `frontend-react-B` then surfaced two more failure
1486
+ Continued regression testing on `a Vite frontend test project` then surfaced two more failure
770
1487
  classes unrelated to CLAUDE.md structure:
771
1488
 
772
1489
  1. **Path hallucination in rules/standard**. Pass 3 generated rule files
773
- referencing `src/feature/routers/featureRoutePath.ts` when the actual
1490
+ referencing `src/feature/routers/<feature>RoutePath.ts` when the actual
774
1491
  file was `src/feature/routers/routePath.ts`. Root cause: the LLM saw
775
1492
  the parent directory `src/feature/` and a TypeScript constant
776
- `FEATURE_ROUTE_PATH` and "renormalized" the filename to match. Pre-v2.3.0
1493
+ `<FEATURE>_ROUTE_PATH` and "renormalized" the filename to match. Pre-v2.3.0
777
1494
  validation did not check whether path claims resolved to real files.
778
1495
 
779
1496
  2. **MANIFEST ↔ CLAUDE.md §6 Skills drift**. Four skills registered in
@@ -786,7 +1503,7 @@ paths, file-system existence, MANIFEST vs CLAUDE.md cross-reference) —
786
1503
  no natural-language matching, so it works identically for all 10 output
787
1504
  languages.
788
1505
 
789
- Running the initial v2.3.0 build against `frontend-react-B` surfaced a
1506
+ Running the initial v2.3.0 build against `a Vite frontend test project` surfaced a
790
1507
  third, upstream issue in the frontend domain scanner. The project has
791
1508
  a single-SPA layout (`src/admin/{api,context,dto,routers,pages/*}/`,
792
1509
  plus a separate `src/guide/` for documentation). The subapp scanner,
@@ -795,13 +1512,13 @@ interpreted `admin` as a platform keyword and emitted the architectural
795
1512
  layers beneath it as pseudo-domains: `admin-api`, `admin-context`,
796
1513
  `admin-dto`, `admin-routers`. That fragmented one SPA into 5+ spurious
797
1514
  domains and, critically, primed Pass 3 to fabricate filenames with the
798
- `admin` prefix — the root cause of the `featureRoutePath.ts` hallucination
1515
+ `admin` prefix — the root cause of the `<feature>RoutePath.ts` hallucination
799
1516
  pattern. v2.3.0 adds a single-SPA detection rule: when only ONE distinct
800
1517
  platform keyword matches across the project tree, subapp emission is
801
1518
  suppressed by default, and feature domains are left to the downstream
802
1519
  page/FSD/components scanners to discover correctly.
803
1520
 
804
- Running the v2.3.0 build against `backend-java-spring` then surfaced a
1521
+ Running the v2.3.0 build against `a Spring backend test project` then surfaced a
805
1522
  long-standing resume bug in the init pipeline. When a prior `init` run
806
1523
  is interrupted mid-Pass-3 — most commonly a stream idle timeout during
807
1524
  the 3d-aux (database + mcp-guide) stage — `pass3-complete.json` is
@@ -818,9 +1535,9 @@ orchestrator to inspect marker contents: when the marker is partial,
818
1535
  logic resumes from the next unstarted stage; only fully-completed
819
1536
  markers are skipped.
820
1537
 
821
- Finally, the full v2.3.0 pipeline run against `frontend-react-B` (14
1538
+ Finally, the full v2.3.0 pipeline run against `a Vite frontend test project` (14
822
1539
  domains, Korean output) surfaced a structural regression the validator
823
- itself caught and flagged: `## 9. 메모리 운영 (L4)` appeared in
1540
+ itself caught and flagged: a `## 9. ` heading translating to "Memory Operations (L4)" appeared in
824
1541
  `CLAUDE.md` as a re-declaration of the memory file table already
825
1542
  present in Section 8. This was the exact anti-pattern v2.3.0 was
826
1543
  designed to prevent, now reappearing despite the scaffold's explicit
@@ -842,10 +1559,10 @@ but never touches `CLAUDE.md`. The `appendClaudeMdL4Memory()` export
842
1559
  is preserved as a no-op for any external caller depending on its
843
1560
  signature.
844
1561
 
845
- Post-retirement dogfooding on `frontend-react-B` surfaced a final class
1562
+ Post-retirement regression testing on `a Vite frontend test project` surfaced a final class
846
1563
  of issue: four `STALE_PATH` errors in Pass 4-generated rule and
847
1564
  standard files (`src/feature/main.tsx` assumed from Vite convention;
848
- `src/feature/routers/featureRoutePath.ts` invented by prepending the
1565
+ `src/feature/routers/<feature>RoutePath.ts` invented by prepending the
849
1566
  parent directory name to the filename; `src/components/utils/classNameMaker.ts`
850
1567
  fabricated as a plausible-sounding utility). The root cause was
851
1568
  parallel to the §9 issue: Pass 3's path grounding rules live in
@@ -859,7 +1576,7 @@ The guidance also teaches the positive pattern: when in doubt,
859
1576
  scope a rule to a directory (`src/admin/api/`) rather than
860
1577
  inventing a specific filename.
861
1578
 
862
- Re-running `init` on `backend-java-spring` with the Fix A build proved
1579
+ Re-running `init` on `a Spring backend test project` with the Fix A build proved
863
1580
  path-grounding works in practice — STALE_PATH dropped from the
864
1581
  expected 4 to 0 across all Pass 4-generated rule and standard
865
1582
  files — but left 8 MANIFEST_DRIFT errors in place. Analysis
@@ -895,16 +1612,16 @@ implements both halves of this split:
895
1612
 
896
1613
  Together, Fix A (Pass 4 path grounding) and Fix B
897
1614
  (orchestrator/sub-skill exception + §6 guidance) close the last
898
- two classes of dogfood-observed content-validator errors. The
1615
+ two classes of regression-observed content-validator errors. The
899
1616
  remaining validator surface continues to enforce the strict
900
1617
  invariants — fabricated paths, missing skill files, unrelated-
901
1618
  parent drift, §9 re-declaration, T1 heading drift, etc. — without
902
1619
  relaxation.
903
1620
 
904
- Re-running `init` on `frontend-react-B` with the Fix A + Fix B
1621
+ Re-running `init` on `a Vite frontend test project` with the Fix A + Fix B
905
1622
  build produced `0 MANIFEST_DRIFT` (Fix B suppressed all 8
906
1623
  sub-skill drift rows) but left 1 residual `STALE_PATH` in
907
- `claudeos-core/standard/50.verification/02.testing-strategy.md`
1624
+ `claudeos-core/standard/80.verification/02.testing-strategy.md`
908
1625
  referencing `src/__mocks__/handlers.ts`. Analysis showed a
909
1626
  library-convention hallucination class that the original three
910
1627
  anti-patterns did not cover: testing documents reach for MSW /
@@ -920,30 +1637,29 @@ trigger document types, and the positive pattern: when
920
1637
  describe testing/styling/state guidance in abstract terms
921
1638
  (directory scope or role-based) without naming a specific path.
922
1639
 
923
- Final validation pass on both dogfood projects with the complete
1640
+ Final validation pass on both regression fixture projects with the complete
924
1641
  v2.3.0 build:
925
1642
 
926
- - `frontend-react-B` (Korean output, 14 frontend domains,
1643
+ - `a Vite frontend test project` (Korean output, 14 frontend domains,
927
1644
  dual-entry Vite + React 19, single-SPA admin layout,
928
1645
  scaffold-page-feature orchestrator with 8 sub-skills):
929
1646
  **12 errors → 0 errors** (100% improvement), full health
930
1647
  check green, 25/25 CLAUDE.md lint checks passed.
931
- - `backend-java-spring` (Korean output, 8 backend domains,
1648
+ - `a Spring backend test project` (Korean output, 8 backend domains,
932
1649
  Java 17 + Spring Boot + MyBatis, scaffold-crud-feature
933
1650
  orchestrator with 8 sub-skills, multi-dialect DB migration
934
1651
  in progress): **8 errors → 0 errors** (100% improvement),
935
1652
  full health check green, complete first-try run in 45m 29s
936
- including the resume-from-partial-marker code path hitting
937
- for the first time from a real-world partial Pass 3 run.
1653
+ including the resume-from-partial-marker code path exercised
1654
+ for the first time against a captured partial Pass 3 fixture.
938
1655
 
939
1656
  Both projects exercise distinct v2.3.0 code paths (Fix A + Fix B,
940
1657
  single-SPA rule, Pass 3 resume, library-convention anti-pattern,
941
1658
  orchestrator/sub-skill exception), and both settled at 0 errors
942
1659
  without any manual file edits to the generated output. This is
943
1660
  the first release where the full end-to-end pipeline produces a
944
- clean `content-validator [10/10]` report on real-world sibling
945
- Korean projects — the core criterion for v2.3.0 being
946
- publish-ready.
1661
+ clean `content-validator [10/10]` report against the regression
1662
+ fixture set — the core criterion for v2.3.0 being publish-ready.
947
1663
 
948
1664
  ### Added
949
1665
 
@@ -996,11 +1712,10 @@ publish-ready.
996
1712
  The validator enforces this via `checkCanonicalHeadings` (IDs `T1-1`
997
1713
  through `T1-8`), and the scaffold documents it as a mandatory format
998
1714
  rule reinforced by Pass 3 POST-GEN CHECK step 4b. This closes a
999
- multi-repo discoverability gap discovered during `frontend-react-B`
1000
- dogfooding: sibling projects generated §7 as `"DO NOT Read (직접 읽지
1001
- 말아야 할 파일)"` and `"읽지 말 것 (Files Not to Be Read Directly)"`
1715
+ multi-repo discoverability gap discovered during `a Vite frontend test project`
1716
+ regression testing: two test projects generated §7 as `"DO NOT Read (<localized gloss A>)"` and `"<localized gloss B> (Files Not to Be Read Directly)"`
1002
1717
  respectively — both "equivalent in meaning" but breaking
1003
- `grep "## 7. DO NOT Read"` across the organization's repos.
1718
+ `grep "## 7. DO NOT Read"` across multiple repos.
1004
1719
 
1005
1720
  - **`content-validator [10/10]` — path-claim + MANIFEST drift.**
1006
1721
  A new check appended to the existing 9-stage validator in
@@ -1039,11 +1754,11 @@ publish-ready.
1039
1754
  - **`pass-prompts/templates/common/pass3-footer.md` — Path fact
1040
1755
  grounding (MANDATORY).** Two new CRITICAL blocks added:
1041
1756
  - The parent-directory prefix anti-pattern (the exact
1042
- `featureRoutePath.ts` case from frontend-react-B dogfooding) is
1757
+ `<feature>RoutePath.ts` case from the Vite frontend test project's regression run) is
1043
1758
  documented with ✅/❌ examples and explanation of *why* the LLM
1044
1759
  mis-infers (TypeScript identifier name vs filename are
1045
- independent — the constant `FEATURE_ROUTE_PATH` does not imply
1046
- filename `featureRoutePath.ts`).
1760
+ independent — the constant `<FEATURE>_ROUTE_PATH` does not imply
1761
+ filename `<feature>RoutePath.ts`).
1047
1762
  - The MANIFEST ↔ CLAUDE.md §6 symmetry rule is stated explicitly,
1048
1763
  with post-generation enforcement noted (`content-validator [10/10]
1049
1764
  → MANIFEST_DRIFT`).
@@ -1053,7 +1768,7 @@ publish-ready.
1053
1768
  (same subapp implemented for two platforms, e.g., `src/pc/admin/`
1054
1769
  + `src/mobile/admin/` → `pc-admin`, `mobile-admin`). When applied
1055
1770
  to a single-SPA project (only one platform keyword matches, as in
1056
- `frontend-react-B`'s `src/admin/...`), the scanner misinterpreted the
1771
+ `a Vite frontend test project`'s `src/admin/...`), the scanner misinterpreted the
1057
1772
  SPA's architectural layers (`api`, `context`, `dto`, `routers`) as
1058
1773
  subapps and emitted them as pseudo-domains — both cluttering the
1059
1774
  domain plan and priming Pass 3 toward filename hallucinations with
@@ -1085,8 +1800,8 @@ publish-ready.
1085
1800
  is invoked and its existing `groupsCompleted` tracking resumes
1086
1801
  from the next unstarted stage. Only markers with `completedAt`
1087
1802
  set are skipped.
1088
- - This repairs the dogfood case where Pass 3d-aux timed out
1089
- mid-stream on `backend-java-spring`: on the next `init`, stages 3a-3c
1803
+ - This repairs the regression case where Pass 3d-aux timed out
1804
+ mid-stream on `a Spring backend test project`: on the next `init`, stages 3a-3c
1090
1805
  were correctly preserved but 3d-aux was silently skipped,
1091
1806
  leaving `claudeos-core/database/` and `claudeos-core/mcp-guide/`
1092
1807
  empty and the marker stuck in partial shape.
@@ -1124,7 +1839,7 @@ publish-ready.
1124
1839
  exported for test compatibility but is now unreferenced by
1125
1840
  production code.
1126
1841
  This fix closes the final regression surfaced by end-to-end
1127
- dogfooding on `frontend-react-B`: the validator was correctly
1842
+ regression testing on `a Vite frontend test project`: the validator was correctly
1128
1843
  reporting an `S1` (9 sections) and four `M-*`/`F2-*` errors
1129
1844
  against a `CLAUDE.md` whose second memory table had been
1130
1845
  appended by Pass 4, not written by Pass 3. The fix keeps the
@@ -1155,9 +1870,9 @@ publish-ready.
1155
1870
  section states the rule first — every `src/...` path written in a
1156
1871
  rule or standard file must appear verbatim in `pass3a-facts.md` or
1157
1872
  `pass2-merged.json` — then documents the three flagship
1158
- hallucination anti-patterns observed in `frontend-react-B`
1159
- dogfooding: Vite-convention assumption (`src/feature/main.tsx`),
1160
- parent-directory prefix (`src/feature/routers/featureRoutePath.ts`),
1873
+ hallucination anti-patterns observed in `a Vite frontend test project`
1874
+ regression testing: Vite-convention assumption (`src/feature/main.tsx`),
1875
+ parent-directory prefix (`src/feature/routers/<feature>RoutePath.ts`),
1161
1876
  and plausible-but-unverified utility (`src/components/utils/classNameMaker.ts`).
1162
1877
  Each anti-pattern is accompanied by the concrete mechanism that
1163
1878
  caused it ("invented based on Vite's stock convention";
@@ -1199,10 +1914,10 @@ publish-ready.
1199
1914
  — hallucinated filenames and silent staleness — and cites the
1200
1915
  `content-validator` exception so the prompt-side and detector-
1201
1916
  side are consistent.
1202
- This fix closes the final class of dogfood-observed errors on
1203
- `backend-java-spring` (8 MANIFEST_DRIFT rows, all for
1917
+ This fix closes the final class of field-test-observed errors on
1918
+ `a Spring backend test project` (8 MANIFEST_DRIFT rows, all for
1204
1919
  `scaffold-crud-feature/0N.*.md` sub-skills) and the equivalent
1205
- shape on `frontend-react-B` (8 rows under
1920
+ shape on `a Vite frontend test project` (8 rows under
1206
1921
  `scaffold-page-feature/0N.*.md`). The structural
1207
1922
  `CLAUDE.md §6 = entry, MANIFEST = registry` split also
1208
1923
  eliminates the recurring regeneration churn where adding or
@@ -1211,7 +1926,7 @@ publish-ready.
1211
1926
 
1212
1927
  - **`tests/content-validator.test.js` — 5 new orchestrator/sub-skill
1213
1928
  exception tests.** Coverage: (1) orchestrator mentioned +
1214
- sub-skills registered → 0 drift (backend-java-spring replica);
1929
+ sub-skills registered → 0 drift (a Spring backend test project replica);
1215
1930
  (2) orchestrator mentioned + one sub-skill file deleted → still
1216
1931
  emits 1 `STALE_SKILL_ENTRY` (integrity not suppressed);
1217
1932
  (3) orchestrator NOT mentioned → all 5 registered skills drift
@@ -1250,7 +1965,7 @@ publish-ready.
1250
1965
  fenced examples, placeholders, and existing paths do not trigger).
1251
1966
  - MANIFEST drift scenarios (stale entry, drift, referenced skill,
1252
1967
  self-reference exclusion, absent MANIFEST).
1253
- - Full frontend-react-B simulation: 2 STALE_PATH + 2 STALE_SKILL_ENTRY
1968
+ - Full a Vite frontend test project simulation: 2 STALE_PATH + 2 STALE_SKILL_ENTRY
1254
1969
  + 3 MANIFEST_DRIFT, asserted with exact counts to prevent silent
1255
1970
  regression as the validator evolves.
1256
1971
 
@@ -1271,13 +1986,13 @@ publish-ready.
1271
1986
  following the T1 canonical-heading format `## N. <English canonical>
1272
1987
  (<translation>)`): `valid-en.md`, `valid-ja.md`, `valid-zh-CN.md`,
1273
1988
  `valid-es.md`, `valid-vi.md`, `valid-hi.md`, `valid-ru.md`,
1274
- `valid-fr.md`, `valid-de.md`, plus `frontend-react-A-fixed.md`
1275
- (Korean, real dogfooding case with §9 removed and headings
1989
+ `valid-fr.md`, `valid-de.md`, plus `observed-ko-fixed.md`
1990
+ (Korean, captured regression fixture with §9 removed and headings
1276
1991
  retrofitted to T1 format). Each passes the same 25 structural
1277
1992
  checks — empirical proof of language invariance across CJK,
1278
1993
  Cyrillic, Devanagari, Latin, and Vietnamese scripts.
1279
1994
  - Bad fixtures (same valid structure + §9 memory re-declaration
1280
- appended): `frontend-react-A-bad.md` (Korean, real), `bad-ja.md`,
1995
+ appended): `observed-ko-bad.md`, `bad-ja.md`,
1281
1996
  `bad-zh-CN.md`, `bad-ru.md`, `bad-hi.md`, `bad-es.md`. All six
1282
1997
  produce a **byte-for-byte identical 9-error signature**
1283
1998
  (1 S1 + 4 M-* + 4 F2-*), confirming the validator detects the
@@ -1353,8 +2068,8 @@ how often that net is needed.
1353
2068
  label blocklist. The new framing states the RULE first (no `##` may
1354
2069
  have a title whose semantic category is "rules", "memory", "L4",
1355
2070
  "guardrails", or any rephrasing), then gives concrete **translated
1356
- examples in Korean, Japanese, and Chinese** (`메모리 (L4)`,
1357
- `メモリ (L4)`, `记忆层 (L4)`, and analogues for Common Rules). The
2071
+ examples in Korean, Japanese, and Chinese** (the localized form of
2072
+ `Memory (L4)` in each script, plus analogues for Common Rules). The
1358
2073
  goal is to make the LLM's translation decision explicit: it must
1359
2074
  apply the forbidden rule to its translated heading, not just the
1360
2075
  English original. A DECISION RULE block at the end gives a 3-step
@@ -1397,11 +2112,12 @@ MANIFEST-drift exception.)
1397
2112
 
1398
2113
  The §9 re-declaration anti-pattern was the flagship problem v2.2.0 aimed
1399
2114
  to solve, and the scaffold + prompt-level blocklist reduced incidence
1400
- substantially. Dogfooding on a real Korean-output project produced a
1401
- `CLAUDE.md` with `## 9. 메모리 (L4)` anyway — the LLM successfully matched
1402
- `## 8. 공통 규칙 메모리 (L4)` as its Section 8, then created a §9
1403
- section whose title (`메모리 (L4)`) was not semantically recognized as
1404
- equivalent to the blocklisted English `"Memory Layer (L4)"`.
2115
+ substantially. Regression testing on a Korean-output fixture produced a
2116
+ `CLAUDE.md` with a `## 9. ` heading translating to "Memory (L4)" anyway — the LLM
2117
+ successfully matched the localized form of `## 8. Common Rules & Memory (L4)`
2118
+ as its Section 8, then created a §9 section whose translated title was not
2119
+ semantically recognized as equivalent to the blocklisted English
2120
+ `"Memory Layer (L4)"`.
1405
2121
 
1406
2122
  Extending the fix by maintaining per-language blocklists would create
1407
2123
  unbounded maintenance surface: 10 supported languages × 6-8 forbidden
@@ -1579,7 +2295,7 @@ projects or runs.
1579
2295
  Adds a mandatory post-generation check (count `^## ` headings; must
1580
2296
  equal 8; merge surplus into the correct section or move to `rules/*`
1581
2297
  / `standard/*`). The expanded blocklist closes a rename loophole
1582
- discovered during dogfooding on a Vite + React frontend project
2298
+ discovered during regression testing on a Vite + React frontend project
1583
2299
  where the LLM appended a §9 whose title combined "Documentation
1584
2300
  Writing + AI Common Rules + Memory Layer (L4)" to collect
1585
2301
  rule-related content.
@@ -1590,7 +2306,7 @@ projects or runs.
1590
2306
  home in rules/standard/skills/guide.
1591
2307
 
1592
2308
  - **`pass-prompts/templates/common/claude-md-scaffold.md`** (in addition to
1593
- the new-file Add above) was tightened after initial dogfooding:
2309
+ the new-file Add above) was tightened after initial regression testing:
1594
2310
  - Hard constraints section now leads with **"EXACTLY 8 SECTIONS. No more,
1595
2311
  no less."** plus a recovery procedure for surplus sections.
1596
2312
  - Section 6 Rules sub-section explicitly notes that the
@@ -1641,13 +2357,13 @@ projects or runs.
1641
2357
 
1642
2358
  ### Why this matters
1643
2359
 
1644
- When claudeos-core was applied to three sibling projects in the same
1645
- organization (one Spring Boot backend, two Vite + React frontends), the
2360
+ When claudeos-core was exercised against three test projects (one Spring Boot backend,
2361
+ two Vite + React frontends) in the regression suite, the
1646
2362
  generated files were content-correct — standards, rules, and skills
1647
2363
  accurately captured each project's patterns — but the `CLAUDE.md` files
1648
2364
  had different section counts (8, 8, 9), different section names, and
1649
2365
  different section orders. Claude Code reads CLAUDE.md first on every
1650
- session; inconsistent structure across repos made it harder for
2366
+ session; inconsistent structure across repos would make it harder for
1651
2367
  developers (and Claude Code) to know where to look for a given piece of
1652
2368
  information. v2.2.0 fixes the structure while leaving content
1653
2369
  project-specific.
@@ -1659,7 +2375,7 @@ content already in `.claude/rules/*` (auto-loaded) or `claudeos-core/
1659
2375
  standard/*` (detailed patterns). Removing it eliminates a redundant
1660
2376
  maintenance surface and reinforces the "one rule, one home" principle.
1661
2377
 
1662
- Dogfooding also uncovered a latent paths bug. The `40.infra/*` rules
2378
+ Regression testing also uncovered a latent paths bug. The `40.infra/*` rules
1663
2379
  shared a single category-level `paths` frontmatter that only matched
1664
2380
  config/infra file extensions (`.env`, `*.config.*`, `*.json`, `*.yml`,
1665
2381
  `Dockerfile*`). This meant the logging-monitoring rule — whose guardrails
@@ -1670,7 +2386,7 @@ trigger was mis-scoped. v2.2.0 now specifies per-file `paths` in the Pass
1670
2386
  3 prompts and adds a `Rule paths Must Match Rule Content` CRITICAL block
1671
2387
  to the footer so future rules cannot inherit the wrong scope by default.
1672
2388
 
1673
- A third dogfooding finding exposed a different layer of the same
2389
+ A third regression testing finding exposed a different layer of the same
1674
2390
  philosophy violation. The stack detector parsed Spring Boot's
1675
2391
  `application.yml` for `server.port`, but for Node/Vite projects it
1676
2392
  simply used a hardcoded framework default (Vite → 5173) whenever no
@@ -1686,7 +2402,7 @@ canonical source of runtime configuration — framework defaults are
1686
2402
  last-resort only. This also captures host and API-target values that
1687
2403
  previously never appeared in generated CLAUDE.md at all.
1688
2404
 
1689
- A fourth dogfooding iteration on a Spring Boot backend project
2405
+ A fourth regression testing iteration on a Spring Boot backend project
1690
2406
  (regenerated with the interim v2.2.0 scaffold that only allowed a single
1691
2407
  Section 8 titled "Memory (L4)") found the LLM producing a §9 titled
1692
2408
  "Common Rules & Memory (L4)" — even with the expanded blocklist from
@@ -1732,7 +2448,7 @@ and were addressed in the same release cycle. **First**, the scaffold's
1732
2448
  "Section 6 Rules: Always include 60.memory/*" directive, added during
1733
2449
  Section 8 redesign, was not echoed in the 12 stack Pass 3 prompts'
1734
2450
  rule-category listings — so the LLM received conflicting signals
1735
- (scaffold says include, stack prompt doesn't mention it). Real dogfooding
2451
+ (scaffold says include, stack prompt doesn't mention it). Regression testing
1736
2452
  on the backend project confirmed the category was being omitted from
1737
2453
  the generated CLAUDE.md §6 Rules table. v2.2.0 fixes both sides: each stack
1738
2454
  Pass 3 prompt now explicitly lists `60.memory/*` as a forward-reference
@@ -1751,7 +2467,7 @@ preservation semantics (memory/ content kept, generated files replaced)
1751
2467
  explicit. **Third**, the new `.env.example` → CLAUDE.md pipeline created
1752
2468
  a theoretical pathway for accidentally committed secrets in `.env.example`
1753
2469
  to be amplified into the project's public-facing documentation. Although
1754
- `.env.example` is conventionally a placeholder file, real-world projects
2470
+ `.env.example` is conventionally a placeholder file, projects
1755
2471
  occasionally check in real values by mistake. v2.2.0 adds a
1756
2472
  sensitive-variable filter (`lib/env-parser.js`: `isSensitiveVarName`,
1757
2473
  `redactSensitiveVars`) that replaces values of variables matching
@@ -1798,7 +2514,7 @@ npx claudeos-core init --force
1798
2514
 
1799
2515
  If you want to preview changes first, regenerate into a scratch copy of
1800
2516
  the project, diff the resulting files against your current ones, and
1801
- then decide whether to `--force` on the real project. Key files to
2517
+ then decide whether to `--force` on your project. Key files to
1802
2518
  diff: `CLAUDE.md`, `.claude/rules/00.core/00.standard-reference.md`,
1803
2519
  `.claude/rules/40.infra/02.logging-monitoring-rules.md` (paths change
1804
2520
  is the most visible delta).
@@ -1821,7 +2537,7 @@ running `--force` so you can diff/merge any overwrites.
1821
2537
  rules auto-load (more accurately scoped); the rule content itself
1822
2538
  does not change. `stack.envInfo` is a new additive field — older
1823
2539
  project-analysis.json files without it still work.
1824
- - Discovered via dogfooding on three real production projects:
2540
+ - Discovered via regression testing on multiple test projects:
1825
2541
  - Structural drift (3 different CLAUDE.md layouts) prompted the scaffold.
1826
2542
  - A Vite + React frontend project produced a §9 surplus section under
1827
2543
  a renamed title that bypassed the initial forbidden-sections blocklist
@@ -1902,7 +2618,7 @@ Post-release regression fix for v2.1.0 master plan removal cleanup.
1902
2618
  is a one-line behavior change (`errors.push(...)` → `console.log(...)`)
1903
2619
  with a comment documenting the v2.1.0 context, and regression risk is
1904
2620
  covered by routine `health` runs rather than an integration test.
1905
- - Discovered via dogfooding on a real Vite 6 + React 19 project: 62
2621
+ - Discovered via regression testing on a Vite 6 + React 19 test project: 62
1906
2622
  generated files, all Pass 1–4 stages succeeded, but `health` failed
1907
2623
  at content-validator. No other cleanup gaps found.
1908
2624
 
@@ -1921,8 +2637,8 @@ Docs-only maintenance release. No runtime behavior or API changes.
1921
2637
  job is done once the release ships, and the same content is preserved
1922
2638
  in `CHANGELOG.md` for anyone who wants the historical detail.
1923
2639
 
1924
- - **README: dropped the `Real production case: 18-domain admin frontend
1925
- (2026-04-20)` subsection** under _Auto-scaling by Project Size_ across
2640
+ - **README: dropped the 18-domain admin-frontend subsection
2641
+ (2026-04-20 entry)** under _Auto-scaling by Project Size_ across
1926
2642
  all 10 language READMEs. The per-stage breakdown table (9 rows) and its
1927
2643
  surrounding prose are removed. The trailing empirical reference in the
1928
2644
  FAQ "What is Pass 3 split mode" answer (the `Empirically verified up
@@ -2190,7 +2906,7 @@ project size.
2190
2906
  - **New shared library modules** — Single sources of truth for Pass 3 output expectations, preventing drift between enforcement and validation:
2191
2907
  - `lib/expected-guides.js` — 9 guide file paths. Imported by `init.js` Guard 3 H2 and `content-validator/index.js` `[5/9]` (no more hardcoded duplicates).
2192
2908
  - `lib/expected-outputs.js` — 3 additional Pass 3 outputs (standard sentinel, `skills/`, `plan/`) with `findMissingOutputs(projectRoot)` + `hasNonEmptyMdRecursive(dir)` helpers (BOM-aware). Imported by `init.js` Guard 3 H1.
2193
- - **Async claude execution + progress ticker** — `cli-utils.js` adds `runClaudePromptAsync` (spawn-based, non-blocking; lets a `setInterval` ticker run concurrently with the Claude subprocess) and `runClaudeCapture` (execSync wrapper that captures stdout, used by the translation engine in `memory-scaffold.js`). `init.js` adds `makePassTicker` with three display modes — elapsed-only, file-delta, and fixed-target (`N/M files (P%)`) — driving the per-pass `⏳`/`📝` progress line in TTY (`\r`-rewritten) and CI/piped (periodic newlines) environments.
2909
+ - **Async claude execution + progress ticker** — `cli-utils.js` adds `runClaudePromptAsync` (spawn-based, non-blocking; lets a `setInterval` ticker run concurrently with the Claude subprocess) and `runClaudeCapture` (execSync wrapper that captures stdout, used by the translation engine in `memory-scaffold.js`). `init.js` adds `makePassTicker` with three display modes — elapsed-only, file-delta, and fixed-target (`N/M files (P%)`) — driving the per-pass progress line in TTY (`\r`-rewritten) and CI/piped (periodic newlines) environments.
2194
2910
  - **`--force` and "fresh" resume cleanup** — Now also wipes `claudeos-core/generated/.staged-rules/` (leftover from a prior crashed Pass 3/4 run) and `.claude/rules/` (so Guard 2's zero-rules detection can't false-negative on stale rules from a previous run); under `"fresh"` mode the `pass3-complete.json` and `pass4-memory.json` markers are also unlinked so both passes re-execute. Manual edits to `.claude/rules/` are lost — acceptable under the explicit `--force`/`fresh` choice.
2195
2911
  - **190+ new tests** (296 → 489) — New/expanded suites: `memory-scaffold.test.js`, `memory-command.test.js`, `pass4-prompt.test.js`, `pass3-marker.test.js`, `pass3-guards.test.js` (Guards 1/2 + Guard 3 H1/H2 with BOM coverage), `pass2-validation.test.js` (H3 structural check), `pass4-marker-validation.test.js` (M1 `isValidPass4Marker` + `dropStalePass4Marker` regression guards), `translation-skip-env.test.js` (M2 env guard + M3 CI workflow presence), `staged-rules.test.js`, `lang-aware-fallback.test.js` (sets `CLAUDEOS_SKIP_TRANSLATION=1` at module top to make translation-throw assertions deterministic), `placeholder-substitution.test.js`, plus expansions to existing suites.
2196
2912
  - **Progress bar with ETA** — Pass 1/2/3/4 execution shows a progress bar with percentage, elapsed time, and ETA based on average step duration (carried over and extended from v1.7.0; Pass 4 added).