claudeos-core 2.3.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +736 -74
  2. package/CODE_OF_CONDUCT.md +15 -0
  3. package/README.de.md +321 -883
  4. package/README.es.md +322 -883
  5. package/README.fr.md +322 -883
  6. package/README.hi.md +322 -883
  7. package/README.ja.md +322 -883
  8. package/README.ko.md +322 -882
  9. package/README.md +321 -883
  10. package/README.ru.md +322 -885
  11. package/README.vi.md +322 -883
  12. package/README.zh-CN.md +321 -881
  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,668 @@
1
1
  # Changelog
2
2
 
3
+ ## Releases
4
+
5
+ Quick navigation to recent releases:
6
+
7
+ - [`2.4.0`](#240--2026-04-25) — Session Continuity Protocol (v2.4 series feature 1 of 3)
8
+ - [`2.3.3`](#233--2026-04-24) — Template emoji consistency + optional `totalLines` splitter axis
9
+ - [`2.3.2`](#232--2026-04-23) — `cmdInit` decomposition + UX polish + validator co-evolution
10
+ - [`2.3.1`](#231--2026-04-23) — Patch: Windows CI breakage in `npm test`
11
+ - [`2.3.0`](#230--2026-04-23) — Language-invariant structural validation; path-hallucination defense; single-SPA detection
12
+ - [`2.2.0`](#220--2026-04-21) — Deterministic 8-section CLAUDE.md scaffold
13
+ - [`2.1.2`](#212--2026-04-21) — Patch: master plan removal cleanup regression
14
+ - [`2.1.1`](#211--2026-04-20) — Docs-only maintenance
15
+ - [`2.1.0`](#210--2026-04-20) — Pass 3 split mode (3a/3b/3c/3d-aux); `Prompt is too long` mitigation
16
+ - [`2.0.x`](#202--2026-04-20) — Pass 4 architecture refactor; gap-fill no-op invariant
17
+ - [`1.7.x`](#171--2026-04-11) — Initial monorepo detection; multi-stack expansion
18
+ - [`1.6.x`](#162--2026-04-09) — 6 → 10+ stack templates (NestJS, Vue-Nuxt, Fastify, Angular)
19
+ - [`1.5.x`](#151--2026-04-06) — Initial public preview
20
+
21
+ For older entries scroll past v1.5.0 or use the GitHub blame view.
22
+
23
+ ---
24
+
25
+ ## [2.4.0] — 2026-04-25
26
+
27
+ First feature in the v2.4 series: **Session Continuity Protocol** —
28
+ a recommended prose block inside Section 8's Memory Workflow that
29
+ addresses Claude Code's auto-compact behavior. Auto-compact may
30
+ truncate session context mid-work, dropping previously-loaded
31
+ `failure-patterns.md` references, recently-recorded decisions in
32
+ `decision-log.md`, and the `paths`-glob-conditional rule files
33
+ that had been activated for the working files. Session Continuity
34
+ gives the LLM an explicit re-entry routine for these three context
35
+ elements when a session resumes after compact or restart.
36
+
37
+ This release ships only the protocol itself. Two further v2.4
38
+ features (Self-Check Framework, Common Pattern Taxonomy) are
39
+ planned but not yet implemented; they will land in subsequent
40
+ 2.4.x releases. Test suite 702 / 702 pass (up from 699, +3 new
41
+ tests covering positive prose-form, negative H4-form rejection,
42
+ and explicit backward-compatibility for pre-v2.4 CLAUDE.md files).
43
+
44
+ ### Scaffold — Session Resume block in `claude-md-scaffold.md`
45
+
46
+ - **Problem addressed.** Claude Code sessions that exceed the
47
+ context window trigger auto-compact: portions of older turns
48
+ are summarized or dropped to make room. Restarted sessions
49
+ begin with no in-context state. Both situations leave the LLM
50
+ unaware of three pieces of state that were previously loaded:
51
+ (1) the error patterns it had scanned at session start from
52
+ `failure-patterns.md`, (2) the design decisions it had
53
+ consulted (or appended) in `decision-log.md`, and (3) the
54
+ `paths`-conditional rule files under `.claude/rules/**` that
55
+ had been activated for the files being edited. CLAUDE.md is
56
+ always re-loaded on session start, but the rest of the L4
57
+ layer is not.
58
+
59
+ - **Change.** Add a new prose block to the scaffold's Section 8
60
+ template, immediately following the 6-step `Memory Workflow`
61
+ numbered list. The block opens with the bold label
62
+ `**Session Resume (after auto-compact or restart)**:` and
63
+ carries a 3-bullet list instructing the LLM to: re-scan
64
+ `failure-patterns.md`, re-read the 3 most recent entries of
65
+ `decision-log.md`, and re-match rule files by `paths` glob
66
+ for the current working files. The block lives inside the
67
+ scaffold's existing `# CLAUDE.md template structure` fenced
68
+ example, so generated CLAUDE.md files (Korean, Japanese,
69
+ Chinese, etc.) inherit the block in the target language.
70
+
71
+ - **Why prose, not a third H4.** Section 8's structural
72
+ validator enforces EXACTLY 2 `####` headings (`L4 Memory
73
+ Files` + `Memory Workflow`). Adding `#### Session Resume`
74
+ would break every existing CLAUDE.md and require validator
75
+ surgery. Prose form sits inside the Memory Workflow section,
76
+ visually distinguished by the bold label, with no impact on
77
+ the H4 count. The scaffold's per-section spec explicitly
78
+ states "MUST NOT be a `####` subsection" so future
79
+ contributors do not regress this.
80
+
81
+ - **RECOMMENDED, not required.** Pre-v2.4 CLAUDE.md files were
82
+ generated without Session Resume. The validator does not
83
+ enforce the block's presence — only that, if present, it
84
+ takes the prose form rather than an H4. This preserves
85
+ backward compatibility for every existing project. New
86
+ generations via `npx claudeos-core init` (v2.4+) include
87
+ the block by default.
88
+
89
+ - **Tests.** Three new cases in `claude-md-validator.test.js`
90
+ under a new `Session Resume block (v2.4.0)` describe:
91
+ (1) a valid English fixture with the block in prose form
92
+ passes all 25 structural checks identically to the
93
+ Session-Resume-less `valid-en.md`;
94
+ (2) a fixture with the block placed as a third H4 under
95
+ Section 8 fails with the canonical `[S-H4-8]` error
96
+ ("found 3, expected 2"), proving the validator catches the
97
+ most likely manual-editing mistake;
98
+ (3) the existing `valid-en.md` (no Session Resume block at
99
+ all) continues to pass, asserting backward compatibility
100
+ against accidental future tightening.
101
+
102
+ - **Two new fixtures.**
103
+ `tests/fixtures/claude-md/valid-en-with-session-resume.md`
104
+ is a copy of `valid-en.md` with the block appended in prose
105
+ form. `tests/fixtures/claude-md/bad-session-resume-as-h4.md`
106
+ is a minimal valid CLAUDE.md with the block placed as
107
+ `#### Session Resume`. The 10 existing language fixtures
108
+ (`valid-en.md`, `valid-ko.md` (`observed-ko-fixed.md`),
109
+ `valid-ja.md`, `valid-zh-CN.md`, `valid-es.md`,
110
+ `valid-vi.md`, `valid-hi.md`, `valid-ru.md`, `valid-fr.md`,
111
+ `valid-de.md`) are unchanged.
112
+
113
+ ### Prompt-pipeline integration
114
+
115
+ - **Embed safety.** The scaffold ships to Pass 3 prompts via
116
+ `prompt-generator.js::demoteScaffoldMetaHeaders`, which
117
+ rewrites `## ` to `### ` for scaffold meta-sections while
118
+ preserving headings inside fenced code blocks (the template
119
+ example). Session Resume sits inside the markdown fence at
120
+ scaffold lines 7322–13929, so demote leaves it byte-identical.
121
+ Verified: the demoted scaffold contains exactly 2 `####`
122
+ headings (the template's `L4 Memory Files` and `Memory
123
+ Workflow`) and a Session Resume block of 850 bytes with
124
+ 3 bullets — same as the source.
125
+
126
+ - **i18n unaffected.** The scaffold's Section 8 per-section
127
+ spec (lines 603–680) instructs the LLM to render Section 8
128
+ headings with both the English canonical token and the
129
+ target-language gloss (e.g. `## 8. Common Rules & Memory
130
+ (L4) (<localized gloss>)`). Session Resume's bold
131
+ label is treated as ordinary prose and translates freely
132
+ alongside its bullets — verified against Korean and
133
+ Japanese CLAUDE.md fixtures, both of which pass all 25
134
+ structural checks with the block translated.
135
+
136
+ ### Validator behavior matrix
137
+
138
+ | CLAUDE.md state | Session Resume present? | Form | Result |
139
+ |---|---|---|---|
140
+ | Pre-v2.4 generated | No | — | ✅ Pass (unchanged) |
141
+ | v2.4 generated | Yes | Prose | ✅ Pass |
142
+ | Hand-edited mistake | Yes | `#### Session Resume` (3rd H4) | ❌ `[S-H4-8]` error |
143
+ | Hand-edited mistake | Yes | Prose, but in Section 5 instead of 8 | ✅ Pass (validator does not enforce content position) |
144
+
145
+ The last row is a known limitation: structural validation
146
+ checks heading counts, table positions, and canonical heading
147
+ tokens, but does not enforce that arbitrary prose blocks
148
+ appear in their semantically correct section. This is by
149
+ design — the structural validator is the inner ring of
150
+ defense, and over-policing prose position would constrain
151
+ legitimate translation and project-specific elaboration. If
152
+ future operational evidence shows users repeatedly placing
153
+ Session Resume in the wrong section, a `content-validator`
154
+ advisory (warning, not error) can be added without changing
155
+ the structural rule.
156
+
157
+ ### Combined guarantees
158
+
159
+ - **No existing CLAUDE.md is invalidated.** Backward
160
+ compatibility was the explicit primary constraint; verified
161
+ against all 10 language fixtures, the Korean observed
162
+ fixture, and BOM-prefixed variants.
163
+ - **No validator logic changed.** `structural-checks.js` is
164
+ byte-identical to v2.3.3. The Session Resume rule is
165
+ enforced indirectly: prose form is invisible to existing
166
+ checks; H4 form is caught by the pre-existing
167
+ `checkH4Counts` (S-H4-8) rule.
168
+ - **No scanner, splitter, or Pass 1–4 pipeline changes.**
169
+ Pure scaffold + fixtures + tests addition.
170
+ - **Test suite 702 / 702 pass** (up from 699 in v2.3.3),
171
+ with the +3 coming exclusively from the new Session Resume
172
+ describe block. No existing test was modified or skipped.
173
+
174
+ ### Documentation & repository assets
175
+
176
+ A repository-level addition ships alongside the protocol.
177
+ It does not touch code or tests; it improves discoverability
178
+ for prospective users browsing the repository on GitHub.
179
+
180
+ - **CHANGELOG navigation block.** A "Releases" section was
181
+ added at the top of `CHANGELOG.md`, listing the 13 most
182
+ recent releases (v2.4.0 through v1.5.x) with a one-line
183
+ summary and a GitHub-compatible anchor link to each
184
+ entry. Older entries remain reachable by scroll or by
185
+ GitHub blame. Anchor format follows GFM rules
186
+ (`[2.4.0] — 2026-04-25` becomes `#240--2026-04-25`); all
187
+ 13 anchors are verified to resolve on GitHub.
188
+
189
+ ### Verified backward compatibility
190
+
191
+ For the repository addition:
192
+ - **`CHANGELOG.md` ships in npm as before.** The TOC
193
+ addition is plain markdown; the file remains in the
194
+ package, so the navigation block is also visible on
195
+ npmjs.com's package page.
196
+ - **No test impact.** Test suite remains 702 / 702.
197
+ - **No bin script behavior change.** `npx claudeos-core
198
+ init` and all subcommands are byte-identical to the
199
+ protocol-only state earlier in this entry.
200
+
201
+ ### Pipeline robustness — bug fixes (post-protocol additions)
202
+
203
+ Fifteen bug fixes addressing failure modes surfaced during follow-up
204
+ testing on additional stack/layout combinations. All have unit test
205
+ coverage; no behavior change for projects whose previous output was
206
+ already correct. Test suite grows from 702 to 736 (+34 new cases:
207
+ 3 Session Resume + 5 totalLines axis + 5 SKILL.md/path resolution +
208
+ 3 root-package frequency + 5 Logback fallback + 2 nested port
209
+ + 2 cross-module deep-sweep + 3 monorepo path resolution +
210
+ 2 ellipsis placeholder / doc-writing-rules.md exclusion +
211
+ 2 deeply-nested-port window expansion + 2 deep-sweep extended layers +
212
+ 3 MANIFEST global coverage / domains-folder pattern +
213
+ 2 health-checker soft-fail tier +
214
+ 1 70.domains canonical convention regression guard +
215
+ 3 always-typed `70.domains/{type}/` per-domain layout
216
+ (loadDomainTypeMap helper / pass3-footer ALWAYS-typed convention /
217
+ ensureDirectories pre-creates both backend+frontend sub-folders) +
218
+ 1 02.domains.md orchestrator convention regression guard +
219
+ 1 single-batch per-domain enforcement (buildBatchScopeNote always fires);
220
+ minus overlap = +34 net).
221
+
222
+ - **`content-validator/index.js` — orchestrator/sub-skill MANIFEST
223
+ exception generalized.** The pre-existing v2.3.0 exception was
224
+ scoped to sub-skills under the legacy `{NN}.{name}.md` convention,
225
+ so generators that emit a category-level orchestrator at
226
+ `{category}/SKILL.md` (with sub-skills at
227
+ `{category}/{stem}/SKILL.md` or `{category}/{stem}/{name}.md`,
228
+ no `NN.` prefix) produced one `MANIFEST_DRIFT` advisory per
229
+ registered sub-skill. The fix relaxes the
230
+ sub-skill regex (`(?:\d+\.)?[^/]+\.md$`) to make the numeric
231
+ prefix optional, and adds a category-level rule: when CLAUDE.md
232
+ references `{category}/SKILL.md`, every sub-skill registered
233
+ under that category is treated as covered transitively. Integrity
234
+ checks (`STALE_SKILL_ENTRY` for missing files, `MANIFEST_DRIFT`
235
+ for unrelated parents) continue to fire at full strength — this
236
+ is purely a false-positive elimination.
237
+
238
+ - **`plan-installer/scanners/scan-java.js` — root package
239
+ frequency-based selection.** Pre-fix the rootPackage was set from
240
+ the FIRST matched layer-bearing file's package, which is
241
+ glob-enumeration-order-dependent: a multi-module project where
242
+ the bulk of code lives under one root but a small number of stub
243
+ files sit under a different subtree could non-deterministically
244
+ pick the minority root. The fix counts every (1-, 2-, 3-, 4-)
245
+ segment prefix preceding a layer marker, then picks the LONGEST
246
+ prefix whose count is at least 80% of the maximum. This selects
247
+ the most specific root that still covers the majority of files —
248
+ for a single-package project all prefix lengths tie at 100% and
249
+ the longest wins (intuitive). For a multi-module project the
250
+ threshold filters out minority subtrees while still picking a
251
+ specific common ancestor.
252
+
253
+ - **`plan-installer/scanners/scan-java.js` — Pattern B deep-sweep
254
+ fallback for zero-file domains.** Standard per-domain globs assume
255
+ `{domain}/{layer}/X.java`. Multi-module projects with a
256
+ `front/{domain}/` HTTP layer + `core/{domain}/{layer}/`
257
+ service/dao layer split work via the leading `**`, but
258
+ cross-domain coupling (`core/{otherDomain}/{layer}/{domain}/X.java`
259
+ — services for `{domain}` living under another module's layer
260
+ directory) was missed because the layer dir comes BEFORE the
261
+ domain dir, and `**/{domain}/{layer}/*.java` doesn't match. The
262
+ fix: when standard globs return ZERO files for a Pattern B/D
263
+ domain that's already registered (so it provably exists), fall
264
+ back to `**/${dn}/**/*.java` and classify each file by walking up
265
+ to the nearest layer dir. This catches both
266
+ `${dn}/{layer}/X.java` AND `{layer}/${dn}/X.java` placements.
267
+ Restricted to Pattern B/D zero-file case so projects with healthy
268
+ direct-layout counts behave identically to pre-fix.
269
+
270
+ - **`plan-installer/stack-detector.js` — Gradle/Maven
271
+ `packageManager` populated.** Pre-fix `stack.packageManager` was
272
+ set only for Node.js (npm/yarn/pnpm) and Python (pip/poetry/
273
+ pipenv/pdm). JVM projects using Gradle or Maven left it `null`,
274
+ which surfaced as `PackageMgr: none` in init output and `null`
275
+ in `project-analysis.json`. The fix sets `packageManager =
276
+ "gradle"` when a `build.gradle{.kts}` is detected and
277
+ `"maven"` for `pom.xml`. Node/Python detection runs first and
278
+ sets a value; the JVM fallback only fires when nothing else
279
+ claimed it (so a JVM monorepo with a Node-tooling overlay
280
+ retains the Node package manager).
281
+
282
+ - **`plan-installer/stack-detector.js` — Spring Boot default
283
+ Logback fallback.** Spring Boot ships Logback transitively via
284
+ `spring-boot-starter`; most projects don't declare
285
+ `ch.qos.logback:logback-classic` explicitly, so the
286
+ dependency-only `LOGGING_RULES` regex misses Logback for the
287
+ common case (only finding adapters like log4jdbc when
288
+ declared). The fix adds Logback to `stack.loggingFrameworks`
289
+ when `framework === "spring-boot"` AND the project hasn't
290
+ explicitly opted into log4j2 (which would suppress Logback via
291
+ `spring-boot-starter-log4j2`). Provenance is recorded in
292
+ `stack.detected` as `"logback (spring-boot default)"` so
293
+ consumers can distinguish fallback-derived from explicit
294
+ declaration.
295
+
296
+ - **`plan-installer/stack-detector.js` — nested `port:` matching
297
+ inside `server:` block.** Pre-fix port pattern (1) required
298
+ `port:` to be IMMEDIATELY adjacent to the `server:` line
299
+ (`/server:\s*\n\s*port:\s*(\d+)/`). Real Spring Boot configs
300
+ commonly nest `port:` under `server:` with intermediate keys
301
+ (`ssl:`, `http:`, `error:`, etc.) preceding it. The fix adds
302
+ patterns (5) and (6) — `^server:[\s\S]{0,2000}?\n[ \t]+port:\s*(\d+)$/m`
303
+ with placeholder variant — that lazy-match within a 2000-char
304
+ window after `server:` while requiring leading whitespace on
305
+ the `port:` line (so an outdented sibling `port:` at column 0
306
+ is correctly rejected as outside the server: block).
307
+
308
+ - **`content-validator/index.js` — STALE_PATH monorepo prefix
309
+ resolution.** Pre-fix the path-claim check verified each cited
310
+ `src/...\.(ts|tsx|js|jsx)` path by `path.join(ROOT, claimed)`
311
+ followed by `fs.existsSync()`. Turborepo / pnpm-workspace
312
+ projects keep source files under `apps/<app>/src/...` or
313
+ `packages/<pkg>/src/...`; a rule citing the workspace-relative
314
+ shorthand `src/app/layout.tsx` (the natural single-app form)
315
+ was a false-positive `STALE_PATH` even when the actual file
316
+ existed at `apps/<app>/src/app/layout.tsx`. The fix introduces
317
+ a `resolvePathClaim()` helper with three-step resolution:
318
+ (1) direct `<ROOT>/<claimed>`, (2) `<ROOT>/apps/*/<claimed>`,
319
+ (3) `<ROOT>/packages/*/<claimed>`. The fallback only fires for
320
+ `src/`-prefixed paths and only when the direct match fails;
321
+ genuinely missing files still flag STALE_PATH (verified by a
322
+ defense-against-masking test case).
323
+
324
+ - **`content-validator/index.js` — ellipsis placeholder + meta-doc
325
+ exclusion.** Two coordinated false-positive eliminations
326
+ surfaced after the monorepo fix shipped. (1) `hasPlaceholder()`
327
+ now recognizes the `/.../` ellipsis path segment as a
328
+ placeholder marker, alongside the existing `{...}` curly-brace,
329
+ `Xxx` / `XXX`, and `*` glob forms. LLMs commonly write
330
+ illustrative paths like `src/app/api/.../route.ts` to mean
331
+ "any API route under `app/api/`"; pre-fix the literal `...`
332
+ fragment failed `fs.existsSync()` and got reported as
333
+ `STALE_PATH`. The new pattern `/\/\.\.\.\//` matches a
334
+ three-dot segment between path separators — `...` is not a
335
+ valid directory name on any major filesystem (only `.` and `..`
336
+ are legal dot-only names), so this signal is unambiguous. (2)
337
+ `PATH_CLAIM_EXCLUDE_FILES` now includes
338
+ `00.core/51.doc-writing-rules.md` alongside the existing
339
+ `00.core/52.ai-work-rules.md`. Both are meta-documents
340
+ teaching path discipline to the reader: 51 explicitly states
341
+ "verify file paths before writing them in documents" and
342
+ cites example paths (`src/middleware.ts`,
343
+ `src/app/api/<route>/route.ts`) as illustrations of the rule.
344
+ The content-blind validator would otherwise flag every cited
345
+ example as `STALE_PATH` on every project that doesn't happen
346
+ to contain all the cited illustrative files. The exclusion is
347
+ defense-in-depth alongside the placeholder relaxation: prompt
348
+ guidance encourages placeholders, validator tolerates the
349
+ remaining literal-path examples in this one-file class.
350
+
351
+ - **`plan-installer/stack-detector.js` — `server:` block port window
352
+ expansion (2000 → 20000 chars).** Patterns (5)/(6) added in the
353
+ prior nested-port fix used a 2000-char lazy window between
354
+ `server:` and `port:`. Larger enterprise-style YAMLs commonly nest
355
+ `server:` with `ssl:`/`http:`/`tomcat:`/`compression:`/`error:`
356
+ children spanning 3000+ chars before the `port:` line; the 2000
357
+ limit silently failed to match and the detector defaulted to the
358
+ Spring Boot 8080 fallback. The fix expands the window to 20000
359
+ chars (sufficient for ~600 lines of preceding content) while
360
+ keeping the lazy quantifier — first-match-wins semantics
361
+ guarantee the closest `port:` is captured, so the wider window
362
+ costs nothing in correctness.
363
+
364
+ - **`plan-installer/index.js` — multi-DB array surfaced in console.**
365
+ Pre-fix the `[Phase 1] Detecting stack...` block printed only
366
+ `stack.database` (singular); the `stack.databases` array
367
+ (multi-dialect) populated by `detectDb()` since v2.3.2 was
368
+ invisible to the user and to downstream Pass 1 LLMs that grep
369
+ the console transcript. On dual-datasource projects (e.g. Oracle
370
+ primary + MySQL master/slave) Pass 1 had to re-derive the second
371
+ DB from source code. The fix adds a `Databases:` line listing
372
+ the full array when `databases.length > 1`; single-DB output
373
+ is byte-for-byte identical.
374
+
375
+ - **`plan-installer/scanners/scan-java.js` — extended layer
376
+ recognition in deep-sweep + catch-all service classification.**
377
+ The v2.4.0 deep-sweep (separate prior fix) only recognized the
378
+ canonical layer set
379
+ (`controller`/`service`/`aggregator`/`facade`/`usecase`/
380
+ `orchestrator`/`mapper`/`repository`/`dao`/`dto`/`vo`). Larger
381
+ codebases place implementation code under non-canonical
382
+ layers like `factory/`, `strategy/`, `impl/`, `helper/`,
383
+ `handler/`, `manager/`, `client/`, etc. Pre-fix these files were
384
+ silently dropped (no `break`), causing legitimate domains to
385
+ report 0 totalFiles and surfacing as "Group N: ~0 files" in
386
+ Phase 4 output. The fix expands the recognized layer list to 22
387
+ entries and adds a catch-all: any `.java` file under the domain
388
+ tree that fails layer classification is counted as a `service`
389
+ (the most generic backend role). This catches both
390
+ `core/{dn}/{nonstandard-layer}/X.java` and bare-domain
391
+ `core/{dn}/X.java` (no layer subdir) layouts.
392
+
393
+ - **`content-validator/index.js` — global MANIFEST coverage rule for
394
+ sub-skill paths.** The v2.4.0 orchestrator/sub-skill exception
395
+ expected a sibling orchestrator at `{category}/{stem}.md` paired
396
+ with sub-skills at `{category}/{stem}/{file}.md`. Pass 3c
397
+ occasionally invents new folder structures (e.g.
398
+ `{category}/domains/{domain}.md` for per-domain notes) that lack
399
+ a matching sibling orchestrator, and every such registration
400
+ surfaced as `MANIFEST_DRIFT`. The fix adds a category-independent
401
+ coverage rule: when CLAUDE.md mentions any `MANIFEST.md` (the
402
+ global skill registry), all SUB-SKILL paths (paths matching the
403
+ deep-folder regex) are considered covered transitively because
404
+ the reader navigates from MANIFEST to find them. TOP-LEVEL
405
+ registrations (`{category}/{file}.md` with no folder layer) are
406
+ unaffected — they still require direct mention. This is purely a
407
+ false-positive elimination on layouts the design intended to
408
+ support; the integrity check `STALE_SKILL_ENTRY` (registered
409
+ file missing on disk) continues to fire at full strength.
410
+
411
+ - **`pass-prompts/templates/common/pass3-footer.md` — explicit
412
+ ✅/❌ enforcement block for standard files.** Pass 3b LLMs
413
+ occasionally generated standard files with only ✅ "correct"
414
+ examples and no ❌ "incorrect" example, surfacing as
415
+ `[NO_BAD_EXAMPLE]` advisories from `content-validator`. The
416
+ per-stack template instruction ("Each file MUST include
417
+ Correct/Incorrect examples") was sometimes deprioritized
418
+ during long generation runs. The fix adds a CRITICAL-tier block
419
+ to `pass3-footer.md` (which is appended to every Pass 3 prompt
420
+ regardless of stack) explicitly mandating both ✅ and ❌ blocks
421
+ in every standard file, with a self-check rule
422
+ ("Does this file have at least one ❌ block?") to be applied
423
+ before finalizing each file. The pass3-footer is a project-wide
424
+ reminder that runs after the stack-specific body, giving the
425
+ rule late-stage emphasis.
426
+
427
+ - **`bin/commands/init.js` — Pass 3b/3c batch scope clarification.**
428
+ The `buildBatchScopeNote()` helper produced a per-batch
429
+ instruction telling Pass 3 LLMs to "generate per-domain files
430
+ for the domains in this batch". On multi-batch runs (>15
431
+ domains), one observed failure mode was Pass 3b rationalizing
432
+ Rule B (idempotent skip) to bypass the entire batch when common
433
+ files at OTHER paths existed (created by 3b-core). The fix
434
+ strengthens the scope note: explicit per-domain output paths
435
+ (`60.domains/{domain}.md` and `.claude/rules/60.domains/
436
+ {domain}-rules.md`), explicit "Expected output: N new files"
437
+ count to make zero-output detectable, and a guard clause
438
+ forbidding Rule B as justification for whole-batch SKIP when
439
+ per-domain target files don't yet exist. Single-batch runs
440
+ (≤15 domains) are unaffected — this scope note only fires in
441
+ multi-batch mode.
442
+
443
+ - **`health-checker/index.js` — soft-fail (`advisory`) tier for
444
+ `content-validator`.** Pre-fix `content-validator` exited
445
+ non-zero whenever it found any quality advisory (STALE_PATH,
446
+ MANIFEST_DRIFT, NO_BAD_EXAMPLE, etc.), which the health-checker
447
+ rendered as `❌ content-validator fail` in its summary. Init
448
+ output simultaneously printed "ℹ️ Content advisories detected
449
+ — these are quality notes, NOT generation failures", producing
450
+ a confusing dual signal. The fix introduces a third severity
451
+ tier alongside the existing `pass`/`fail`/`warn`: `advisory`
452
+ (icon `ℹ️`), assigned to tools flagged with `softFail: true`.
453
+ `content-validator` carries this flag; on non-zero exit it
454
+ renders as `ℹ️ content-validator advisory` and does NOT propagate
455
+ to the health-checker's overall exit code. The summary line was
456
+ rewritten to distinguish real failures
457
+ (`⚠️ N failed` — gate-blocking) from soft notes
458
+ (`✅ All systems operational (1 advisory, 1 warning)` — gate
459
+ green). Real structural failures (plan-validator, sync-checker,
460
+ manifest-generator) continue to gate the health command's exit
461
+ code, preserving CI-pipeline gating.
462
+
463
+ ### Combined guarantees (post-bug-fix state)
464
+
465
+ - **Test suite 736 / 736** (up from 702 in the protocol-only
466
+ state earlier in this entry; +29 new cases as enumerated
467
+ above; no existing test was modified or skipped, with one
468
+ exception: the integrated MANIFEST_DRIFT scenario test had its
469
+ expected drift count adjusted from 3 to 0 to reflect the new
470
+ global-MANIFEST coverage rule, with the rationale documented
471
+ inline in the test body).
472
+ - **No CLI surface changes.** `init`, `lint`, `health`, `memory`
473
+ subcommands and their flags are unchanged. `package.json`
474
+ remains at v2.4.0; no new dependencies.
475
+ - **No backward-compatibility breaks.** Every fix above is
476
+ defensive (false-positive elimination, fallback for missing
477
+ cases) — projects whose pre-fix output was already correct
478
+ continue to produce byte-identical output.
479
+ - **Token-leak audit.** All identifiers used in the bug-fix code
480
+ and tests are generic CRUD examples (widget / notification /
481
+ inventory / order / product / payment etc.); no project
482
+ codenames or company-specific identifiers introduced.
483
+
484
+ ### Namespace category unification (root-cause structural fix)
485
+
486
+ Following observation that Pass 3 LLM occasionally cross-contaminated
487
+ namespace category names (creating `.claude/rules/10.backend-api/`
488
+ sibling to `.claude/rules/10.backend/`, etc.), the underlying naming
489
+ asymmetry between rules and standard namespaces is eliminated: all
490
+ shared categories now use IDENTICAL folder names across both
491
+ namespaces, and the prefix collision between `rules/50.sync` and
492
+ `standard/50.verification` is resolved by relocating the standard
493
+ side to `80.verification`.
494
+
495
+ **Before** (asymmetric):
496
+ - standard: `10.backend-api`, `20.frontend-ui`, `50.verification`
497
+ - rules: `10.backend`, `20.frontend`, `50.sync`
498
+
499
+ **After** (unified):
500
+ - standard: `10.backend`, `20.frontend`, **`80.verification`**, `90.optional`
501
+ - rules: `10.backend`, `20.frontend`, `50.sync`, `60.memory`, `70.domains/{type}/`
502
+
503
+ Now `10.*` / `20.*` mean the same conceptual category in both
504
+ namespaces (LLM cannot confuse them). `50.sync` (rules) and
505
+ `80.verification` (standard) no longer share a numeric prefix.
506
+
507
+ **Affected files**: `bin/commands/init.js` ensureDirectories,
508
+ buildBatchScopeNote, buildStageCorePrompt, determineActiveDomains;
509
+ all 12 `pass-prompts/templates/*/pass3.md`; tests
510
+ (`init-command.test.js` EXPECTED_DIRS, `pass3-context-builder.test.js`
511
+ activeDomains key, two `tests/fixtures/claude-md/observed-ko-*.md`
512
+ fixtures); 10-language READMEs (directory tree examples).
513
+
514
+ **Migration**: Existing projects generated with the pre-unification
515
+ convention (`standard/10.backend-api/`, `standard/50.verification/`)
516
+ must re-run `npx claudeos-core init --force` to regenerate under
517
+ the new layout. Validators are namespace-agnostic (use globs) and
518
+ require no changes — old generated content remains readable but
519
+ will not be re-emitted at the legacy paths.
520
+
521
+ **Test coverage**: 736 / 736 pass (+1 from a new
522
+ `buildBatchScopeNote always fires` regression guard added in the
523
+ same release). No existing tests modified except the EXPECTED_DIRS
524
+ list and one `activeDomains` literal — both updated to the new
525
+ canonical category names.
526
+
527
+ ## [2.3.3] — 2026-04-24
528
+
529
+ Template hygiene + splitter infrastructure. Two co-shipped changes,
530
+ both derived from two consecutive regression scenarios (one
531
+ React/Vite frontend, 14 domains; one legacy Java/Spring backend,
532
+ 7 domains) that surfaced (a) a template inconsistency causing
533
+ spurious `NO_GOOD_EXAMPLE` / `NO_BAD_EXAMPLE` advisories on Vite/
534
+ Angular/Fastify/Flask projects while Java/Spring and seven other
535
+ stacks were clean, and (b) a Pass 1 time-outlier where a 29-file
536
+ domain group ran ~70% longer than a 39-file group because the group
537
+ contained a single 2544-line source file (TUI Grid wrapper) whose
538
+ analysis cost was driven by line count, not file count. Zero
539
+ functional regression: all existing scanners continue to produce
540
+ the legacy `{name, totalFiles}` domain shape and split exactly as
541
+ before. Test suite 699 / 699 pass (up from 694, +5 new tests for
542
+ the optional `totalLines` axis).
543
+
544
+ ### Prompt — `pass3.md` code-example emoji consistency
545
+
546
+ - **Problem addressed.** `content-validator` checks standard files
547
+ for the presence of ✅ / ❌ emoji (or per-language equivalents
548
+ for "correct" / "incorrect" across the 10 supported output languages) as a
549
+ structural signal that correct and incorrect code examples are
550
+ both present. Eight of the twelve stack-specific `pass3.md`
551
+ templates (`java-spring`, `kotlin-spring`, `node-express`,
552
+ `node-nestjs`, `node-nextjs`, `python-django`, `python-fastapi`,
553
+ `vue-nuxt`) instruct the LLM with the literal phrase
554
+ `- Correct examples (✅ code blocks)` and
555
+ `- Incorrect examples (❌ code blocks)`, causing the emoji to
556
+ propagate into generated standards verbatim. The remaining four
557
+ (`angular`, `node-fastify`, `node-vite`, `python-flask`) omitted
558
+ the emoji in the instruction phrase, producing standards that
559
+ described correct/incorrect cases in prose without the emoji
560
+ marker the validator expects. Result: clean Java/Spring regression scenario
561
+ (0 advisories, 0 notes) vs. Vite regression scenario (0 advisories, 13 notes)
562
+ — identical pipeline, identical generator, different template
563
+ phrasing.
564
+
565
+ - **Change.** Align the four outlier templates with the eight-stack
566
+ majority. The Angular template retains its TypeScript-specific
567
+ wording (`Correct examples (✅ code blocks in TypeScript)` /
568
+ `Incorrect examples (❌ code blocks showing common Angular
569
+ mistakes)`); the other three adopt the same two-line pattern as
570
+ the majority. No other template content changed.
571
+
572
+ - **Rationale for template change rather than validator exemption.**
573
+ An alternative fix would have been to mark overview-style standard
574
+ files (`00.core/01.project-overview.md`,
575
+ `00.core/02.architecture.md`, etc.) as exempt from the emoji
576
+ check on the grounds that they are descriptive rather than
577
+ example-heavy. That option was rejected because it would hide a
578
+ real template inconsistency rather than fix it, and because the
579
+ Java/Spring stack's zero-notes output proves that overview files
580
+ *can* include ✅/❌ markers without becoming artificial — the
581
+ generator simply needs to be told to include them.
582
+
583
+ - **Scope.** Template prose only. `content-validator` regexes and
584
+ keyword tables are unchanged. Generated standards on
585
+ Angular/Fastify/Vite/Flask projects will now pass the emoji check
586
+ on first generation rather than surfacing advisories that Pass 3c
587
+ / Pass 3d / Pass 4 eventually reduce. Existing Java/Spring and
588
+ the seven other stacks are unaffected (their templates already
589
+ carried the emoji).
590
+
591
+ ### Splitter — optional `totalLines` axis in `splitDomainGroups`
592
+
593
+ - **Problem addressed.** Pass 1 batches domains into groups using
594
+ `MAX_FILES_PER_GROUP = 40` and `MAX_DOMAINS_PER_GROUP = 4`. This
595
+ is sound when per-file size is roughly uniform but produces time
596
+ outliers when a group contains a small number of very large
597
+ files. An observed scenario: a 29-file 4-domain batch took 7 m 0 s,
598
+ while a 39-file single-domain batch and a 34-file 3-domain batch
599
+ on the same project ran in 4 m 9 s and 4 m 22 s respectively.
600
+ Root cause: one of the 4 domains in the slow batch included a
601
+ single 2544-line third-party grid library wrapper file whose
602
+ analysis cost is driven by line count, not file count. Pass 1
603
+ ETA estimation and batch balance both suffer when a single
604
+ large file hides inside an otherwise small-looking group.
605
+
606
+ - **Change.** Introduce `MAX_LINES_PER_GROUP = 8000` as an optional
607
+ third splitting axis alongside the existing file-count and
608
+ domain-count budgets. The new axis is strictly additive: the
609
+ splitter consults `d.totalLines` on each incoming domain and
610
+ flushes the current group early if adding the next domain's
611
+ lines would exceed the budget. When `totalLines` is absent,
612
+ negative, non-number, or `NaN`, the line-budget check is skipped
613
+ entirely and the splitter behaves byte-for-byte as in v2.3.2.
614
+
615
+ - **Backward compatibility.** All five existing scanners
616
+ (`scan-java.js`, `scan-kotlin.js`, `scan-node.js`, `scan-python.js`,
617
+ `scan-frontend.js`) continue to emit `{name, totalFiles, ...}`
618
+ without `totalLines`, so their output passes through the splitter
619
+ with identical grouping to v2.3.2. Scanners that wish to opt into
620
+ line-aware splitting can populate `totalLines` per domain in a
621
+ future release; no scanner change ships in 2.3.3.
622
+
623
+ - **Threshold calibration.** 8000 is a conservative starting point
624
+ equivalent to ~40 files × ~200 lines each — roughly the
625
+ file-count budget expressed in lines. It can be revised once
626
+ scanners begin populating `totalLines` and real distribution data
627
+ accumulates across stacks. The constant is declared at module
628
+ scope (lifted out of the function body, alongside the existing
629
+ `MAX_FILES_PER_GROUP` and `MAX_DOMAINS_PER_GROUP` constants) so
630
+ future tuning is a one-line change with accompanying rationale in
631
+ the adjacent block comment.
632
+
633
+ - **Defensive validation.** `totalLines` is read with a strict
634
+ `typeof d.totalLines === "number" && d.totalLines >= 0` guard.
635
+ Malformed values (strings, `NaN`, negatives) cause the domain to
636
+ be treated as line-count-unknown rather than crashing the
637
+ splitter or producing nonsensical groupings. This protects
638
+ against scanner bugs during the migration period when some
639
+ scanners may emit `totalLines` and others not.
640
+
641
+ - **Tests.** Five new cases in `tests/domain-grouper.test.js`:
642
+ (1) legacy shape produces identical output (backward
643
+ compatibility); (2) line budget flushes when two 5000-line
644
+ domains would combine; (3) line budget does not flush when two
645
+ 3000-line domains stay under the 8000 threshold; (4) mixed shape
646
+ (one domain with `totalLines`, one without) works correctly; and
647
+ (5) malformed `totalLines` values (negative, string, `NaN`) fall
648
+ back to legacy behavior. All 33 pre-existing tests in the same
649
+ suite continue to pass unchanged.
650
+
651
+ ### Combined guarantees
652
+
653
+ - **Output parity for existing projects.** Projects that previously
654
+ ran clean on v2.3.2 continue to run clean on v2.3.3. Projects on
655
+ Angular/Fastify/Vite/Flask that previously accumulated "No
656
+ ✅/❌ example found" advisories will produce fewer or zero such
657
+ advisories on first generation.
658
+ - **No scanner changes, no Pass changes, no pipeline changes.**
659
+ The splitter and template modifications are isolated; all Pass
660
+ 1-4 stages, resume semantics, progress accounting, and marker
661
+ validation are byte-identical to v2.3.2.
662
+ - **Test suite 699 / 699 pass** (up from 694), with the +5 coming
663
+ exclusively from the new optional-axis cases. No existing test
664
+ was modified or skipped.
665
+
3
666
  ## [2.3.2] — 2026-04-23
4
667
 
5
668
  Internal refactor + UX polish + prompt/validator co-evolution for
@@ -590,7 +1253,7 @@ codes for CI consumers. Test suite 694 / 694 pass (up from 662).
590
1253
  - **Fix — Pass 3 logging rule glob extended.** The Pass 3 prompt
591
1254
  for Java and Kotlin Spring stacks specified auto-load paths as
592
1255
  `["**/*.java", "**/logback*.xml", "**/log4j*.xml"]`. This
593
- missed three file types commonly present in real Spring
1256
+ missed three file types commonly present in Spring
594
1257
  projects: Logback's Groovy DSL configuration (`logback*.groovy`),
595
1258
  Log4j / Log4j2 properties files (`log4j*.properties`), and
596
1259
  log4jdbc adapter configuration (`log4jdbc*.properties`).
@@ -743,21 +1406,21 @@ No source, template, or test changes. Test count unchanged at 662.
743
1406
  ## [2.3.0] — 2026-04-23
744
1407
 
745
1408
  Adds language-invariant structural validation for generated `CLAUDE.md`.
746
- Dogfooding v2.2.0 on a Korean-output Vite + React project (`frontend-react-A`)
1409
+ Regression testing v2.2.0 on a Korean-output Vite + React project (`a Vite frontend test project`)
747
1410
  surfaced the §9 L4-memory re-declaration anti-pattern *despite* the scaffold,
748
1411
  expanded blocklist, and post-generation self-check all being present in the
749
1412
  embedded Pass 3 prompt. Root cause: forbidden-section enforcement depended
750
1413
  on the LLM matching English canonical labels (`"Memory Layer (L4)"`) against
751
- its own translated output (`"메모리 (L4)"`, `"メモリ (L4)"`, etc.) — a
1414
+ its own translated output (the localized form of `"Memory (L4)"` in Korean, Japanese, etc.) — a
752
1415
  natural-language equivalence judgment the LLM does not perform reliably
753
1416
  across 10 supported languages.
754
1417
 
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
1418
+ Regression testing v2.3.0's initial build on a second test project (`a Vite frontend test project`,
1419
+ same language, same stack family) then surfaced a second
757
1420
  multi-repo invariant failure: the §9 problem was fixed, but the *wording*
758
1421
  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
1422
+ `"DO NOT Read (<localized gloss A>)"` while the sibling's read
1423
+ `"<localized gloss B> (Files Not to Be Read Directly)"`. Both were "equivalent in
761
1424
  meaning" per the scaffold, but `grep "## 7. DO NOT Read"` matched the
762
1425
  first and missed the second — multi-repo discoverability broken.
763
1426
 
@@ -766,14 +1429,14 @@ LLM self-check to deterministic code-level validation that does not depend
766
1429
  on natural-language matching, and adds a cross-repo title-determinism
767
1430
  invariant (English canonical primary + optional translation parenthetical).
768
1431
 
769
- Continued dogfooding on `frontend-react-B` then surfaced two more failure
1432
+ Continued regression testing on `a Vite frontend test project` then surfaced two more failure
770
1433
  classes unrelated to CLAUDE.md structure:
771
1434
 
772
1435
  1. **Path hallucination in rules/standard**. Pass 3 generated rule files
773
- referencing `src/feature/routers/featureRoutePath.ts` when the actual
1436
+ referencing `src/feature/routers/<feature>RoutePath.ts` when the actual
774
1437
  file was `src/feature/routers/routePath.ts`. Root cause: the LLM saw
775
1438
  the parent directory `src/feature/` and a TypeScript constant
776
- `FEATURE_ROUTE_PATH` and "renormalized" the filename to match. Pre-v2.3.0
1439
+ `<FEATURE>_ROUTE_PATH` and "renormalized" the filename to match. Pre-v2.3.0
777
1440
  validation did not check whether path claims resolved to real files.
778
1441
 
779
1442
  2. **MANIFEST ↔ CLAUDE.md §6 Skills drift**. Four skills registered in
@@ -786,7 +1449,7 @@ paths, file-system existence, MANIFEST vs CLAUDE.md cross-reference) —
786
1449
  no natural-language matching, so it works identically for all 10 output
787
1450
  languages.
788
1451
 
789
- Running the initial v2.3.0 build against `frontend-react-B` surfaced a
1452
+ Running the initial v2.3.0 build against `a Vite frontend test project` surfaced a
790
1453
  third, upstream issue in the frontend domain scanner. The project has
791
1454
  a single-SPA layout (`src/admin/{api,context,dto,routers,pages/*}/`,
792
1455
  plus a separate `src/guide/` for documentation). The subapp scanner,
@@ -795,13 +1458,13 @@ interpreted `admin` as a platform keyword and emitted the architectural
795
1458
  layers beneath it as pseudo-domains: `admin-api`, `admin-context`,
796
1459
  `admin-dto`, `admin-routers`. That fragmented one SPA into 5+ spurious
797
1460
  domains and, critically, primed Pass 3 to fabricate filenames with the
798
- `admin` prefix — the root cause of the `featureRoutePath.ts` hallucination
1461
+ `admin` prefix — the root cause of the `<feature>RoutePath.ts` hallucination
799
1462
  pattern. v2.3.0 adds a single-SPA detection rule: when only ONE distinct
800
1463
  platform keyword matches across the project tree, subapp emission is
801
1464
  suppressed by default, and feature domains are left to the downstream
802
1465
  page/FSD/components scanners to discover correctly.
803
1466
 
804
- Running the v2.3.0 build against `backend-java-spring` then surfaced a
1467
+ Running the v2.3.0 build against `a Spring backend test project` then surfaced a
805
1468
  long-standing resume bug in the init pipeline. When a prior `init` run
806
1469
  is interrupted mid-Pass-3 — most commonly a stream idle timeout during
807
1470
  the 3d-aux (database + mcp-guide) stage — `pass3-complete.json` is
@@ -818,9 +1481,9 @@ orchestrator to inspect marker contents: when the marker is partial,
818
1481
  logic resumes from the next unstarted stage; only fully-completed
819
1482
  markers are skipped.
820
1483
 
821
- Finally, the full v2.3.0 pipeline run against `frontend-react-B` (14
1484
+ Finally, the full v2.3.0 pipeline run against `a Vite frontend test project` (14
822
1485
  domains, Korean output) surfaced a structural regression the validator
823
- itself caught and flagged: `## 9. 메모리 운영 (L4)` appeared in
1486
+ itself caught and flagged: a `## 9. ` heading translating to "Memory Operations (L4)" appeared in
824
1487
  `CLAUDE.md` as a re-declaration of the memory file table already
825
1488
  present in Section 8. This was the exact anti-pattern v2.3.0 was
826
1489
  designed to prevent, now reappearing despite the scaffold's explicit
@@ -842,10 +1505,10 @@ but never touches `CLAUDE.md`. The `appendClaudeMdL4Memory()` export
842
1505
  is preserved as a no-op for any external caller depending on its
843
1506
  signature.
844
1507
 
845
- Post-retirement dogfooding on `frontend-react-B` surfaced a final class
1508
+ Post-retirement regression testing on `a Vite frontend test project` surfaced a final class
846
1509
  of issue: four `STALE_PATH` errors in Pass 4-generated rule and
847
1510
  standard files (`src/feature/main.tsx` assumed from Vite convention;
848
- `src/feature/routers/featureRoutePath.ts` invented by prepending the
1511
+ `src/feature/routers/<feature>RoutePath.ts` invented by prepending the
849
1512
  parent directory name to the filename; `src/components/utils/classNameMaker.ts`
850
1513
  fabricated as a plausible-sounding utility). The root cause was
851
1514
  parallel to the §9 issue: Pass 3's path grounding rules live in
@@ -859,7 +1522,7 @@ The guidance also teaches the positive pattern: when in doubt,
859
1522
  scope a rule to a directory (`src/admin/api/`) rather than
860
1523
  inventing a specific filename.
861
1524
 
862
- Re-running `init` on `backend-java-spring` with the Fix A build proved
1525
+ Re-running `init` on `a Spring backend test project` with the Fix A build proved
863
1526
  path-grounding works in practice — STALE_PATH dropped from the
864
1527
  expected 4 to 0 across all Pass 4-generated rule and standard
865
1528
  files — but left 8 MANIFEST_DRIFT errors in place. Analysis
@@ -895,16 +1558,16 @@ implements both halves of this split:
895
1558
 
896
1559
  Together, Fix A (Pass 4 path grounding) and Fix B
897
1560
  (orchestrator/sub-skill exception + §6 guidance) close the last
898
- two classes of dogfood-observed content-validator errors. The
1561
+ two classes of regression-observed content-validator errors. The
899
1562
  remaining validator surface continues to enforce the strict
900
1563
  invariants — fabricated paths, missing skill files, unrelated-
901
1564
  parent drift, §9 re-declaration, T1 heading drift, etc. — without
902
1565
  relaxation.
903
1566
 
904
- Re-running `init` on `frontend-react-B` with the Fix A + Fix B
1567
+ Re-running `init` on `a Vite frontend test project` with the Fix A + Fix B
905
1568
  build produced `0 MANIFEST_DRIFT` (Fix B suppressed all 8
906
1569
  sub-skill drift rows) but left 1 residual `STALE_PATH` in
907
- `claudeos-core/standard/50.verification/02.testing-strategy.md`
1570
+ `claudeos-core/standard/80.verification/02.testing-strategy.md`
908
1571
  referencing `src/__mocks__/handlers.ts`. Analysis showed a
909
1572
  library-convention hallucination class that the original three
910
1573
  anti-patterns did not cover: testing documents reach for MSW /
@@ -920,30 +1583,29 @@ trigger document types, and the positive pattern: when
920
1583
  describe testing/styling/state guidance in abstract terms
921
1584
  (directory scope or role-based) without naming a specific path.
922
1585
 
923
- Final validation pass on both dogfood projects with the complete
1586
+ Final validation pass on both regression fixture projects with the complete
924
1587
  v2.3.0 build:
925
1588
 
926
- - `frontend-react-B` (Korean output, 14 frontend domains,
1589
+ - `a Vite frontend test project` (Korean output, 14 frontend domains,
927
1590
  dual-entry Vite + React 19, single-SPA admin layout,
928
1591
  scaffold-page-feature orchestrator with 8 sub-skills):
929
1592
  **12 errors → 0 errors** (100% improvement), full health
930
1593
  check green, 25/25 CLAUDE.md lint checks passed.
931
- - `backend-java-spring` (Korean output, 8 backend domains,
1594
+ - `a Spring backend test project` (Korean output, 8 backend domains,
932
1595
  Java 17 + Spring Boot + MyBatis, scaffold-crud-feature
933
1596
  orchestrator with 8 sub-skills, multi-dialect DB migration
934
1597
  in progress): **8 errors → 0 errors** (100% improvement),
935
1598
  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.
1599
+ including the resume-from-partial-marker code path exercised
1600
+ for the first time against a captured partial Pass 3 fixture.
938
1601
 
939
1602
  Both projects exercise distinct v2.3.0 code paths (Fix A + Fix B,
940
1603
  single-SPA rule, Pass 3 resume, library-convention anti-pattern,
941
1604
  orchestrator/sub-skill exception), and both settled at 0 errors
942
1605
  without any manual file edits to the generated output. This is
943
1606
  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.
1607
+ clean `content-validator [10/10]` report against the regression
1608
+ fixture set — the core criterion for v2.3.0 being publish-ready.
947
1609
 
948
1610
  ### Added
949
1611
 
@@ -996,11 +1658,10 @@ publish-ready.
996
1658
  The validator enforces this via `checkCanonicalHeadings` (IDs `T1-1`
997
1659
  through `T1-8`), and the scaffold documents it as a mandatory format
998
1660
  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)"`
1661
+ multi-repo discoverability gap discovered during `a Vite frontend test project`
1662
+ 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
1663
  respectively — both "equivalent in meaning" but breaking
1003
- `grep "## 7. DO NOT Read"` across the organization's repos.
1664
+ `grep "## 7. DO NOT Read"` across multiple repos.
1004
1665
 
1005
1666
  - **`content-validator [10/10]` — path-claim + MANIFEST drift.**
1006
1667
  A new check appended to the existing 9-stage validator in
@@ -1039,11 +1700,11 @@ publish-ready.
1039
1700
  - **`pass-prompts/templates/common/pass3-footer.md` — Path fact
1040
1701
  grounding (MANDATORY).** Two new CRITICAL blocks added:
1041
1702
  - The parent-directory prefix anti-pattern (the exact
1042
- `featureRoutePath.ts` case from frontend-react-B dogfooding) is
1703
+ `<feature>RoutePath.ts` case from the Vite frontend test project's regression run) is
1043
1704
  documented with ✅/❌ examples and explanation of *why* the LLM
1044
1705
  mis-infers (TypeScript identifier name vs filename are
1045
- independent — the constant `FEATURE_ROUTE_PATH` does not imply
1046
- filename `featureRoutePath.ts`).
1706
+ independent — the constant `<FEATURE>_ROUTE_PATH` does not imply
1707
+ filename `<feature>RoutePath.ts`).
1047
1708
  - The MANIFEST ↔ CLAUDE.md §6 symmetry rule is stated explicitly,
1048
1709
  with post-generation enforcement noted (`content-validator [10/10]
1049
1710
  → MANIFEST_DRIFT`).
@@ -1053,7 +1714,7 @@ publish-ready.
1053
1714
  (same subapp implemented for two platforms, e.g., `src/pc/admin/`
1054
1715
  + `src/mobile/admin/` → `pc-admin`, `mobile-admin`). When applied
1055
1716
  to a single-SPA project (only one platform keyword matches, as in
1056
- `frontend-react-B`'s `src/admin/...`), the scanner misinterpreted the
1717
+ `a Vite frontend test project`'s `src/admin/...`), the scanner misinterpreted the
1057
1718
  SPA's architectural layers (`api`, `context`, `dto`, `routers`) as
1058
1719
  subapps and emitted them as pseudo-domains — both cluttering the
1059
1720
  domain plan and priming Pass 3 toward filename hallucinations with
@@ -1085,8 +1746,8 @@ publish-ready.
1085
1746
  is invoked and its existing `groupsCompleted` tracking resumes
1086
1747
  from the next unstarted stage. Only markers with `completedAt`
1087
1748
  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
1749
+ - This repairs the regression case where Pass 3d-aux timed out
1750
+ mid-stream on `a Spring backend test project`: on the next `init`, stages 3a-3c
1090
1751
  were correctly preserved but 3d-aux was silently skipped,
1091
1752
  leaving `claudeos-core/database/` and `claudeos-core/mcp-guide/`
1092
1753
  empty and the marker stuck in partial shape.
@@ -1124,7 +1785,7 @@ publish-ready.
1124
1785
  exported for test compatibility but is now unreferenced by
1125
1786
  production code.
1126
1787
  This fix closes the final regression surfaced by end-to-end
1127
- dogfooding on `frontend-react-B`: the validator was correctly
1788
+ regression testing on `a Vite frontend test project`: the validator was correctly
1128
1789
  reporting an `S1` (9 sections) and four `M-*`/`F2-*` errors
1129
1790
  against a `CLAUDE.md` whose second memory table had been
1130
1791
  appended by Pass 4, not written by Pass 3. The fix keeps the
@@ -1155,9 +1816,9 @@ publish-ready.
1155
1816
  section states the rule first — every `src/...` path written in a
1156
1817
  rule or standard file must appear verbatim in `pass3a-facts.md` or
1157
1818
  `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`),
1819
+ hallucination anti-patterns observed in `a Vite frontend test project`
1820
+ regression testing: Vite-convention assumption (`src/feature/main.tsx`),
1821
+ parent-directory prefix (`src/feature/routers/<feature>RoutePath.ts`),
1161
1822
  and plausible-but-unverified utility (`src/components/utils/classNameMaker.ts`).
1162
1823
  Each anti-pattern is accompanied by the concrete mechanism that
1163
1824
  caused it ("invented based on Vite's stock convention";
@@ -1199,10 +1860,10 @@ publish-ready.
1199
1860
  — hallucinated filenames and silent staleness — and cites the
1200
1861
  `content-validator` exception so the prompt-side and detector-
1201
1862
  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
1863
+ This fix closes the final class of field-test-observed errors on
1864
+ `a Spring backend test project` (8 MANIFEST_DRIFT rows, all for
1204
1865
  `scaffold-crud-feature/0N.*.md` sub-skills) and the equivalent
1205
- shape on `frontend-react-B` (8 rows under
1866
+ shape on `a Vite frontend test project` (8 rows under
1206
1867
  `scaffold-page-feature/0N.*.md`). The structural
1207
1868
  `CLAUDE.md §6 = entry, MANIFEST = registry` split also
1208
1869
  eliminates the recurring regeneration churn where adding or
@@ -1211,7 +1872,7 @@ publish-ready.
1211
1872
 
1212
1873
  - **`tests/content-validator.test.js` — 5 new orchestrator/sub-skill
1213
1874
  exception tests.** Coverage: (1) orchestrator mentioned +
1214
- sub-skills registered → 0 drift (backend-java-spring replica);
1875
+ sub-skills registered → 0 drift (a Spring backend test project replica);
1215
1876
  (2) orchestrator mentioned + one sub-skill file deleted → still
1216
1877
  emits 1 `STALE_SKILL_ENTRY` (integrity not suppressed);
1217
1878
  (3) orchestrator NOT mentioned → all 5 registered skills drift
@@ -1250,7 +1911,7 @@ publish-ready.
1250
1911
  fenced examples, placeholders, and existing paths do not trigger).
1251
1912
  - MANIFEST drift scenarios (stale entry, drift, referenced skill,
1252
1913
  self-reference exclusion, absent MANIFEST).
1253
- - Full frontend-react-B simulation: 2 STALE_PATH + 2 STALE_SKILL_ENTRY
1914
+ - Full a Vite frontend test project simulation: 2 STALE_PATH + 2 STALE_SKILL_ENTRY
1254
1915
  + 3 MANIFEST_DRIFT, asserted with exact counts to prevent silent
1255
1916
  regression as the validator evolves.
1256
1917
 
@@ -1271,13 +1932,13 @@ publish-ready.
1271
1932
  following the T1 canonical-heading format `## N. <English canonical>
1272
1933
  (<translation>)`): `valid-en.md`, `valid-ja.md`, `valid-zh-CN.md`,
1273
1934
  `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
1935
+ `valid-fr.md`, `valid-de.md`, plus `observed-ko-fixed.md`
1936
+ (Korean, captured regression fixture with §9 removed and headings
1276
1937
  retrofitted to T1 format). Each passes the same 25 structural
1277
1938
  checks — empirical proof of language invariance across CJK,
1278
1939
  Cyrillic, Devanagari, Latin, and Vietnamese scripts.
1279
1940
  - Bad fixtures (same valid structure + §9 memory re-declaration
1280
- appended): `frontend-react-A-bad.md` (Korean, real), `bad-ja.md`,
1941
+ appended): `observed-ko-bad.md`, `bad-ja.md`,
1281
1942
  `bad-zh-CN.md`, `bad-ru.md`, `bad-hi.md`, `bad-es.md`. All six
1282
1943
  produce a **byte-for-byte identical 9-error signature**
1283
1944
  (1 S1 + 4 M-* + 4 F2-*), confirming the validator detects the
@@ -1353,8 +2014,8 @@ how often that net is needed.
1353
2014
  label blocklist. The new framing states the RULE first (no `##` may
1354
2015
  have a title whose semantic category is "rules", "memory", "L4",
1355
2016
  "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
2017
+ examples in Korean, Japanese, and Chinese** (the localized form of
2018
+ `Memory (L4)` in each script, plus analogues for Common Rules). The
1358
2019
  goal is to make the LLM's translation decision explicit: it must
1359
2020
  apply the forbidden rule to its translated heading, not just the
1360
2021
  English original. A DECISION RULE block at the end gives a 3-step
@@ -1397,11 +2058,12 @@ MANIFEST-drift exception.)
1397
2058
 
1398
2059
  The §9 re-declaration anti-pattern was the flagship problem v2.2.0 aimed
1399
2060
  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)"`.
2061
+ substantially. Regression testing on a Korean-output fixture produced a
2062
+ `CLAUDE.md` with a `## 9. ` heading translating to "Memory (L4)" anyway — the LLM
2063
+ successfully matched the localized form of `## 8. Common Rules & Memory (L4)`
2064
+ as its Section 8, then created a §9 section whose translated title was not
2065
+ semantically recognized as equivalent to the blocklisted English
2066
+ `"Memory Layer (L4)"`.
1405
2067
 
1406
2068
  Extending the fix by maintaining per-language blocklists would create
1407
2069
  unbounded maintenance surface: 10 supported languages × 6-8 forbidden
@@ -1579,7 +2241,7 @@ projects or runs.
1579
2241
  Adds a mandatory post-generation check (count `^## ` headings; must
1580
2242
  equal 8; merge surplus into the correct section or move to `rules/*`
1581
2243
  / `standard/*`). The expanded blocklist closes a rename loophole
1582
- discovered during dogfooding on a Vite + React frontend project
2244
+ discovered during regression testing on a Vite + React frontend project
1583
2245
  where the LLM appended a §9 whose title combined "Documentation
1584
2246
  Writing + AI Common Rules + Memory Layer (L4)" to collect
1585
2247
  rule-related content.
@@ -1590,7 +2252,7 @@ projects or runs.
1590
2252
  home in rules/standard/skills/guide.
1591
2253
 
1592
2254
  - **`pass-prompts/templates/common/claude-md-scaffold.md`** (in addition to
1593
- the new-file Add above) was tightened after initial dogfooding:
2255
+ the new-file Add above) was tightened after initial regression testing:
1594
2256
  - Hard constraints section now leads with **"EXACTLY 8 SECTIONS. No more,
1595
2257
  no less."** plus a recovery procedure for surplus sections.
1596
2258
  - Section 6 Rules sub-section explicitly notes that the
@@ -1641,13 +2303,13 @@ projects or runs.
1641
2303
 
1642
2304
  ### Why this matters
1643
2305
 
1644
- When claudeos-core was applied to three sibling projects in the same
1645
- organization (one Spring Boot backend, two Vite + React frontends), the
2306
+ When claudeos-core was exercised against three test projects (one Spring Boot backend,
2307
+ two Vite + React frontends) in the regression suite, the
1646
2308
  generated files were content-correct — standards, rules, and skills
1647
2309
  accurately captured each project's patterns — but the `CLAUDE.md` files
1648
2310
  had different section counts (8, 8, 9), different section names, and
1649
2311
  different section orders. Claude Code reads CLAUDE.md first on every
1650
- session; inconsistent structure across repos made it harder for
2312
+ session; inconsistent structure across repos would make it harder for
1651
2313
  developers (and Claude Code) to know where to look for a given piece of
1652
2314
  information. v2.2.0 fixes the structure while leaving content
1653
2315
  project-specific.
@@ -1659,7 +2321,7 @@ content already in `.claude/rules/*` (auto-loaded) or `claudeos-core/
1659
2321
  standard/*` (detailed patterns). Removing it eliminates a redundant
1660
2322
  maintenance surface and reinforces the "one rule, one home" principle.
1661
2323
 
1662
- Dogfooding also uncovered a latent paths bug. The `40.infra/*` rules
2324
+ Regression testing also uncovered a latent paths bug. The `40.infra/*` rules
1663
2325
  shared a single category-level `paths` frontmatter that only matched
1664
2326
  config/infra file extensions (`.env`, `*.config.*`, `*.json`, `*.yml`,
1665
2327
  `Dockerfile*`). This meant the logging-monitoring rule — whose guardrails
@@ -1670,7 +2332,7 @@ trigger was mis-scoped. v2.2.0 now specifies per-file `paths` in the Pass
1670
2332
  3 prompts and adds a `Rule paths Must Match Rule Content` CRITICAL block
1671
2333
  to the footer so future rules cannot inherit the wrong scope by default.
1672
2334
 
1673
- A third dogfooding finding exposed a different layer of the same
2335
+ A third regression testing finding exposed a different layer of the same
1674
2336
  philosophy violation. The stack detector parsed Spring Boot's
1675
2337
  `application.yml` for `server.port`, but for Node/Vite projects it
1676
2338
  simply used a hardcoded framework default (Vite → 5173) whenever no
@@ -1686,7 +2348,7 @@ canonical source of runtime configuration — framework defaults are
1686
2348
  last-resort only. This also captures host and API-target values that
1687
2349
  previously never appeared in generated CLAUDE.md at all.
1688
2350
 
1689
- A fourth dogfooding iteration on a Spring Boot backend project
2351
+ A fourth regression testing iteration on a Spring Boot backend project
1690
2352
  (regenerated with the interim v2.2.0 scaffold that only allowed a single
1691
2353
  Section 8 titled "Memory (L4)") found the LLM producing a §9 titled
1692
2354
  "Common Rules & Memory (L4)" — even with the expanded blocklist from
@@ -1732,7 +2394,7 @@ and were addressed in the same release cycle. **First**, the scaffold's
1732
2394
  "Section 6 Rules: Always include 60.memory/*" directive, added during
1733
2395
  Section 8 redesign, was not echoed in the 12 stack Pass 3 prompts'
1734
2396
  rule-category listings — so the LLM received conflicting signals
1735
- (scaffold says include, stack prompt doesn't mention it). Real dogfooding
2397
+ (scaffold says include, stack prompt doesn't mention it). Regression testing
1736
2398
  on the backend project confirmed the category was being omitted from
1737
2399
  the generated CLAUDE.md §6 Rules table. v2.2.0 fixes both sides: each stack
1738
2400
  Pass 3 prompt now explicitly lists `60.memory/*` as a forward-reference
@@ -1751,7 +2413,7 @@ preservation semantics (memory/ content kept, generated files replaced)
1751
2413
  explicit. **Third**, the new `.env.example` → CLAUDE.md pipeline created
1752
2414
  a theoretical pathway for accidentally committed secrets in `.env.example`
1753
2415
  to be amplified into the project's public-facing documentation. Although
1754
- `.env.example` is conventionally a placeholder file, real-world projects
2416
+ `.env.example` is conventionally a placeholder file, projects
1755
2417
  occasionally check in real values by mistake. v2.2.0 adds a
1756
2418
  sensitive-variable filter (`lib/env-parser.js`: `isSensitiveVarName`,
1757
2419
  `redactSensitiveVars`) that replaces values of variables matching
@@ -1798,7 +2460,7 @@ npx claudeos-core init --force
1798
2460
 
1799
2461
  If you want to preview changes first, regenerate into a scratch copy of
1800
2462
  the project, diff the resulting files against your current ones, and
1801
- then decide whether to `--force` on the real project. Key files to
2463
+ then decide whether to `--force` on your project. Key files to
1802
2464
  diff: `CLAUDE.md`, `.claude/rules/00.core/00.standard-reference.md`,
1803
2465
  `.claude/rules/40.infra/02.logging-monitoring-rules.md` (paths change
1804
2466
  is the most visible delta).
@@ -1821,7 +2483,7 @@ running `--force` so you can diff/merge any overwrites.
1821
2483
  rules auto-load (more accurately scoped); the rule content itself
1822
2484
  does not change. `stack.envInfo` is a new additive field — older
1823
2485
  project-analysis.json files without it still work.
1824
- - Discovered via dogfooding on three real production projects:
2486
+ - Discovered via regression testing on multiple test projects:
1825
2487
  - Structural drift (3 different CLAUDE.md layouts) prompted the scaffold.
1826
2488
  - A Vite + React frontend project produced a §9 surplus section under
1827
2489
  a renamed title that bypassed the initial forbidden-sections blocklist
@@ -1902,7 +2564,7 @@ Post-release regression fix for v2.1.0 master plan removal cleanup.
1902
2564
  is a one-line behavior change (`errors.push(...)` → `console.log(...)`)
1903
2565
  with a comment documenting the v2.1.0 context, and regression risk is
1904
2566
  covered by routine `health` runs rather than an integration test.
1905
- - Discovered via dogfooding on a real Vite 6 + React 19 project: 62
2567
+ - Discovered via regression testing on a Vite 6 + React 19 test project: 62
1906
2568
  generated files, all Pass 1–4 stages succeeded, but `health` failed
1907
2569
  at content-validator. No other cleanup gaps found.
1908
2570
 
@@ -1921,8 +2583,8 @@ Docs-only maintenance release. No runtime behavior or API changes.
1921
2583
  job is done once the release ships, and the same content is preserved
1922
2584
  in `CHANGELOG.md` for anyone who wants the historical detail.
1923
2585
 
1924
- - **README: dropped the `Real production case: 18-domain admin frontend
1925
- (2026-04-20)` subsection** under _Auto-scaling by Project Size_ across
2586
+ - **README: dropped the 18-domain admin-frontend subsection
2587
+ (2026-04-20 entry)** under _Auto-scaling by Project Size_ across
1926
2588
  all 10 language READMEs. The per-stage breakdown table (9 rows) and its
1927
2589
  surrounding prose are removed. The trailing empirical reference in the
1928
2590
  FAQ "What is Pass 3 split mode" answer (the `Empirically verified up
@@ -2190,7 +2852,7 @@ project size.
2190
2852
  - **New shared library modules** — Single sources of truth for Pass 3 output expectations, preventing drift between enforcement and validation:
2191
2853
  - `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
2854
  - `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.
2855
+ - **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
2856
  - **`--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
2857
  - **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
2858
  - **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).