style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
Em dashes (—) and en dashes (–) had spread across comments, docs, tests, and a few UI strings, reading as AI-generated boilerplate rather than house style. Replaced each with punctuation matching its context: colon for explanatory clauses, comma for asides, plain hyphen for numeric/legal ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for paired-dash asides. messages/en.json and messages/sv.json were fixed by hand together to keep sv/en in sync. Left untouched where the dash is the functional subject rather than decorative punctuation: date-range-parser.ts's separator regex, charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the agent system-prompt files that already instruct against em dashes, and a golden iXBRL test fixture compared byte-for-byte. Also fixes two bugs surfaced along the way: an off-by-one in ApiKeysPanel's scope-label split (a leftover from an earlier partial pass), and a charset-repair test that had lost the literal en-dash it exists to verify. Regenerated the agent atom seed migration (skills:generate) since 27 SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes, with an explicit carve-out for the functional-dash cases above. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a5154ee884
commit
ec27228a8e
@@ -10,7 +10,7 @@ import { guardSandbox } from '@/lib/sandbox/guard'
|
||||
import { requireCapability } from '@/lib/entitlements/has-capability'
|
||||
import { CAPABILITY } from '@/lib/entitlements/keys'
|
||||
|
||||
// Make sure extensions are loaded — the chat loop dispatches against the
|
||||
// Make sure extensions are loaded: the chat loop dispatches against the
|
||||
// agent tool registry which is populated by the mcp-server extension at load.
|
||||
ensureInitialized()
|
||||
|
||||
@@ -62,7 +62,7 @@ const BodySchema = z.object({
|
||||
// POST /api/agent/invoke
|
||||
//
|
||||
// Streams NDJSON events from the chat loop. Each line is a JSON object whose
|
||||
// `kind` identifies the event type — see lib/agent/chat/run-turn.ts StreamEvent.
|
||||
// `kind` identifies the event type: see lib/agent/chat/run-turn.ts StreamEvent.
|
||||
//
|
||||
// Auth: the user must be a member of the resolved company.
|
||||
//
|
||||
@@ -72,7 +72,7 @@ export async function POST(request: Request) {
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
|
||||
// Generous per-user rate limit — bounds runaway Bedrock spend (loop-firing
|
||||
// Generous per-user rate limit: bounds runaway Bedrock spend (loop-firing
|
||||
// sessions). Fails open on infra error.
|
||||
const rate = await checkAgentRateLimit(supabase, user.id)
|
||||
if (!rate.ok) {
|
||||
@@ -108,7 +108,7 @@ export async function POST(request: Request) {
|
||||
.maybeSingle()
|
||||
if (!membership) return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
|
||||
|
||||
// No Anthropic Bedrock calls in the sandbox — the demo runs entirely on
|
||||
// No Anthropic Bedrock calls in the sandbox: the demo runs entirely on
|
||||
// seed data and the assistant is gated to a "look, don't touch" preview.
|
||||
const blocked = await guardSandbox(supabase, companyId)
|
||||
if (blocked) return blocked
|
||||
@@ -116,12 +116,12 @@ export async function POST(request: Request) {
|
||||
const capBlocked = await requireCapability(supabase, companyId, CAPABILITY.ai)
|
||||
if (capBlocked) return capBlocked
|
||||
|
||||
// onboarding.intake completion signal — once the user has actually
|
||||
// onboarding.intake completion signal: once the user has actually
|
||||
// engaged (typed a real reply, not the auto-fired greeting prompt that
|
||||
// mounts the chat), stamp intake_completed_at on the profile so re-entry
|
||||
// logic and opportunistic follow-up logic in other intents can tell the
|
||||
// intake happened. Idempotent: the IS NULL guard ensures we never
|
||||
// overwrite the first engagement timestamp. Best-effort — failure here
|
||||
// overwrite the first engagement timestamp. Best-effort: failure here
|
||||
// doesn't break the chat; the next user turn retries.
|
||||
if (
|
||||
body.intent_id === 'onboarding.intake' &&
|
||||
@@ -136,7 +136,7 @@ export async function POST(request: Request) {
|
||||
.eq('company_id', companyId)
|
||||
.is('intake_completed_at', null)
|
||||
} catch {
|
||||
// ignored — see comment above
|
||||
// ignored: see comment above
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ export async function POST(request: Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Stream — NDJSON events from the chat loop.
|
||||
// Stream: NDJSON events from the chat loop.
|
||||
const encoder = new TextEncoder()
|
||||
// Conversation id is set above; capture into a non-null local for the
|
||||
// streaming closure's first emission.
|
||||
|
||||
Reference in New Issue
Block a user