fix(v0.18.2.fork.1): allow underscore in slug-prefix rules
Phase 6 deploy uncovered: chezmoi-managed prefixes like `dot_claude/` are legitimate slugs (chezmoi convention maps `~/.claude/` → `dot_claude/` in source tree). The original validator rejected underscores, which blocked the Phase 4 source taxonomy mid-way: $ gbrain sources update claude-config --slug-prefix 'dot_claude/,claude' Invalid slug-prefix rule "dot_claude/". Must be lowercase a-z, 0-9, '-', '/', optionally ending in '*'. Reject: underscores, ... Underscore is now first-class. Updated regex + comment + test (flipped the "reject underscore" case to "accept underscore" with chezmoi example). Discovered during Phase 6 deploy: blocked at E3 step 4 of 5 (`gbrain sources update claude-config --slug-prefix 'dot_claude/,claude'`). First 3 commands had succeeded. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,17 +47,23 @@ function validateSourceId(id: string): void {
|
||||
// - Single-level glob: 'wedding-planning/*' (cosmetic; same as literal)
|
||||
//
|
||||
// Rules:
|
||||
// - Allowed chars: lowercase a-z, 0-9, '-' (hyphen), '/' (slash)
|
||||
// - Allowed chars: lowercase a-z, 0-9, '-' (hyphen), '_' (underscore), '/' (slash)
|
||||
// - Optional single trailing '*' (no other position)
|
||||
// - Length 1..64 (excluding the trailing '*')
|
||||
// - Reject underscores ('_'), uppercase, whitespace, mid-string '*',
|
||||
// multi-level globs ('**'), any other punctuation
|
||||
// - Reject uppercase, whitespace, mid-string '*', multi-level globs
|
||||
// ('**'), any other punctuation
|
||||
//
|
||||
// Why fail-fast at write time: a typo'd rule (`memory_dashboard/`) writes
|
||||
// successfully into config_jsonb but never matches anything at routing
|
||||
// time — the put_page silently falls to brain-default. Catching at
|
||||
// CLI-write moment surfaces "this is a typo" before bad data lands.
|
||||
const SLUG_PREFIX_RULE_RE = /^[a-z0-9](?:[a-z0-9-/]{0,62}[a-z0-9-/])?\*?$/;
|
||||
// Why fail-fast at write time: a typo'd rule writes successfully into
|
||||
// config_jsonb but never matches anything at routing time — the put_page
|
||||
// silently falls to brain-default. Catching at CLI-write moment surfaces
|
||||
// the typo before bad data lands.
|
||||
//
|
||||
// Underscore note (v0.18.2.fork.1 Phase 6 fix): chezmoi-managed prefixes
|
||||
// like `dot_claude/` are legitimate slugs — chezmoi conventionally maps
|
||||
// `~/.claude/` → `dot_claude/` in source. Earlier draft of this validator
|
||||
// rejected underscores, which broke Phase 4 source taxonomy. Underscore
|
||||
// is now first-class.
|
||||
const SLUG_PREFIX_RULE_RE = /^[a-z0-9_](?:[a-z0-9_\-/]{0,62}[a-z0-9_\-/])?\*?$/;
|
||||
function validateSlugPrefix(rule: string): void {
|
||||
if (!rule || rule.length === 0) {
|
||||
throw new Error('Empty slug-prefix rule. Each --slug-prefix entry must be a non-empty string.');
|
||||
|
||||
@@ -106,8 +106,10 @@ describe('Prefix grammar validator (Issue #6 — fail-fast at write time)', () =
|
||||
if (hint) expect(msg).toContain(hint);
|
||||
};
|
||||
|
||||
test('reject underscore', async () => {
|
||||
await expectReject('memory_dashboard/', 'Invalid slug-prefix');
|
||||
test('accept underscore (chezmoi-style prefixes like dot_claude/)', async () => {
|
||||
await runSources(engine, ['add', 'test-accept-under', '--slug-prefix', 'dot_claude/,foo_bar/']);
|
||||
const cfg = await readConfig('test-accept-under');
|
||||
expect(cfg.slug_prefix_rules).toEqual(['dot_claude/', 'foo_bar/']);
|
||||
});
|
||||
test('reject uppercase', async () => {
|
||||
await expectReject('MemoryDashboard/', 'Invalid slug-prefix');
|
||||
|
||||
Reference in New Issue
Block a user