← all branches

paused/slug-budget-24

needs attention
2c88a05 · fullpre-PRreviewed 2026-08-11 18:49 UTC3H · 7M · 11L · 14I
The branch
Purpose
Raises the CDK preview-branch slug budget from 17 to 24 descriptive chars so feature branches with conventional type prefixes (feat/, fix/, etc.) get the full budget for the meaningful part of their name.
Goal
Eliminate premature CDK-preview skips caused by prefix overhead, while maintaining the 64-char AWS resource name limit via a token abbreviation pass and a synth-time enforcement aspect.
Sub-goals
  • SG-1: Raise MAX_BRANCH_NAME_LEN 17→24 and strip type prefix in boundedBranchSlug (naming.ts + preview-provision.yml)
  • SG-2: Add BRANCH_TOKEN_ABBREV + BRANCH_EXACT_ABBREV abbreviation pass for branched physical names
  • SG-3: Add BranchNameLengthAspect — synth-time guard that fails the build for over-budget new resource names
  • SG-4: Add audit-resource-name-lengths.mjs — developer tool for inspecting name budgets from cdk.out
  • SG-5: Update the platform twin (metrics-explore-core.ts) to match new boundedBranchSlug semantics
  • SG-6: Update IAM wildcards in vercel-service-user.stack.ts for both helioscope and helio (abbreviated) spellings
  • SG-7: Doc sweep — CLAUDE.md, infra/cdk/CLAUDE.md, deploy-cdk, branch-provisioning, loop-autofix, cfe-pipeline, infrastructure rules
The changes (whole branch)
What
naming.ts: MAX_BRANCH_NAME_LEN=24 (exported), BRANCH_TOKEN_ABBREV + BRANCH_EXACT_ABBREV maps, abbreviateForBranch(), type-prefix stripping in boundedBranchSlug. resourceName/s3BucketName apply abbreviation when branched. New BranchNameLengthAspect and audit script. Platform twin updated. GHA slug gate updated (descriptive part). IAM policy gains abbreviated helio ARNs.
Why
The previous 17-char hard cap counted type prefixes (feat/fix/etc.) against the budget, forcing developers to choose cryptic branch names. The new system strips the type prefix from physical names only, giving the full 24-char budget to the descriptive part.
Areas
infra/cdk/src/lib/naming.ts+7513infra/cdk/src/aspects/branch-name-length.ts+750infra/cdk/scripts/audit-resource-name-lengths.mjs+690infra/cdk/src/app/main.ts+101apps/platform/src/api/utils/metrics-explore-core.ts+176apps/platform/src/api/utils/__tests__/metrics-explore-core.test.ts+2215.github/workflows/preview-provision.yml+149infra/cdk/src/stacks/cicd/vercel-service-user.stack.ts+110.claude/skills/deploy-cdk/SKILL.md+1712CLAUDE.md+11
Blast
19 files, +326/−88. CDK naming logic (all branched preview stacks), platform ARN computation (metrics exploration), GHA preview-provision gate, and doc sweep.
infrastructure iam cdk
CI/checks· No open PR — CI results not available via gh pr checkscoderabbit· No .coderabbit.yaml in repocorrectnesssecurityconventionstests· 3 high: no tests for naming.ts, abbreviateForBranch, BranchNameLengthAspectimprovementseo· No apps/web files touched

Findings · 24

correctness4

low

Dead alternations in SLUG_CORE sed (chore/spike/docs/test/refactor/perf/ci — only apply on workflow_dispatch)

.github/workflows/preview-provision.yml:736

Push triggers only on feat/**, fix/**, hotfix/**, feature/**. The extra alternations are safely inert on automatic pushes; they do fire on manual dispatch. Not a bug.

low

Metrics-explore-core.ts hardcodes 24 (twin drift risk, documented)

apps/platform/src/api/utils/metrics-explore-core.ts:64

Overlaps with conventions finding above.

info

feature/** trigger branch does not get free-prefix budget treatment (consistent, but may surprise)

.github/workflows/preview-provision.yml:9

Workflow triggers on feature/** but strips only feat- not feature-. behavior is consistent with naming.ts (both exclude 'feature'). CLAUDE.md does not call this out.

info

BranchNameLengthAspect correctly skips auto-named CFN resources

infra/cdk/src/aspects/branch-name-length.ts:54

Auto-named resources have undefined for the name property and are silently skipped. They can never match batu-{slug}-... so this is intentionally correct.

security4

low

Lambda IAM ARNs use leading wildcard (*metrics-helio-*) — accepted pre-existing pattern

infra/cdk/src/stacks/cicd/vercel-service-user.stack.ts:161

Same pattern as pre-existing helioscope entries. Mitigation: add batu-*-dev- prefix to anchor ARNs to org naming convention.

low

S3 helioscope intake ARNs lack account suffix (pre-existing gap, this PR adds abbreviated form only)

infra/cdk/src/stacks/cicd/vercel-service-user.stack.ts:129

Bills/CSV-export S3 grants use account suffix (last 4 digits); helioscope intake does not. This PR adds the abbreviated *metrics-helio-intake* form. Recommend adding account suffix in a follow-up hardening PR.

info

IAM dual-spelling (full + abbreviated) is intentional and correctly documented

infra/cdk/src/stacks/cicd/vercel-service-user.stack.ts:125

Un-branched envs keep full names; preview branches get abbreviated names. Both spellings needed in the permanent policy. Sync obligation documented in comments.

info

powerradar has no Vercel IAM invoke grant — consistent with current invocation model

infra/cdk/src/lib/naming.ts:36

powerradar is invoked by metrics coordinator SFN, not Vercel runtime. No IAM gap today.

conventions2

medium

feat/x + fix/x physical-name collision caveat absent from branch-provisioning SKILL.md

.claude/skills/branch-provisioning/SKILL.md:36

CLAUDE.md and infra/cdk/CLAUDE.md document the caveat: two branches differing only by type prefix share physical resource names — second CDK deploy fails loudly. branch-provisioning is the primary surface where developers pick names; the caveat is missing. Add a ⚠️ note.

low

Platform twin hardcodes `24` instead of a named constant (MAX_BRANCH_NAME_LEN drift risk)

apps/platform/src/api/utils/metrics-explore-core.ts:64

TWIN comment documents this. Not a current bug — one budget-change away from silent ARN mismatch. A @batu/naming-constants package with only primitives (no CDK dep) would fix this.

tests5

high

No tests for CDK-side boundedBranchSlug — authoritative implementation is untested

infra/cdk/src/lib/naming.ts:79

The platform twin (metrics-explore-core.ts) gained 3 unit tests; naming.ts — the source of truth — has zero. If naming.ts diverges from the twin, tests pass while deployed ARNs point at non-existent state machines. A small Vitest suite (no CDK synth needed) should cover prefix stripping, verbatim ≤24, and head18-sha4 branches.

high

abbreviateForBranch is untested — IAM wildcard correctness depends on it

infra/cdk/src/lib/naming.ts:52

IAM patterns in vercel-service-user.stack.ts (*metrics-helio-materialize etc.) are derived from BRANCH_TOKEN_ABBREV + BRANCH_EXACT_ABBREV. Neither abbreviateForBranch nor the exact-then-token ordering has a test. A stale BRANCH_EXACT_ABBREV key or token-map change produces the wrong Lambda name with no compile-time signal.

high

BranchNameLengthAspect is untested — synth-time gate has no regression coverage

infra/cdk/src/aspects/branch-name-length.ts:1

The aspect's fixedLen arithmetic (fixedLen = name.length - this.slug.length) is the heart of the enforcement gate. An off-by-one would pass synth while exceeding the real AWS cap on a 24-char slug. A unit test with a mock CfnResource would catch this.

medium

Audit script not integrated into CI — NAME_LIMITS sync is comment-only

infra/cdk/scripts/audit-resource-name-lengths.mjs

The audit script requires a pre-synthesised cdk.out and is not called by any workflow. NAME_PROPS must stay in sync with BranchNameLengthAspect's NAME_LIMITS by convention only. A CI step or parse-comparison test would catch table drift.

medium

Platform test suite missing edge cases (slash-form regex, degenerate strip, 25-char no-prefix, hotfix)

apps/platform/src/api/utils/__tests__/metrics-explore-core.test.ts

Missing: (1) 'feat/my-feature' with literal slash (BRANCH_TYPE_PREFIX uses [-/] but tests only use hyphen form); (2) degenerate 'feat-' → empty stripped result (fallback path); (3) no-prefix branch at exactly 25 chars (should hash); (4) 'hotfix-something' (nested 'fix' substring).

improvement9

medium

NAME_LIMITS duplicated between BranchNameLengthAspect and audit script with no shared source

infra/cdk/src/aspects/branch-name-length.ts:22

Identical CFN type → [property, limit] table in two files, synced by comment only. Audit script gives false green budget for missing resource types while the Aspect still enforces. A compiled-to-ESM helper or CI diff check would remove the manual obligation.

medium

BRANCH_TYPE_PREFIX regex duplicated across three locations

apps/platform/src/api/utils/metrics-explore-core.ts:58

Appears in naming.ts, metrics-explore-core.ts, and preview-provision.yml (sed variant without '/' since SLUG is pre-slugified). Adding a new type prefix requires 3 edits. A canonical JSON list imported by naming.ts and consumed by the workflow via jq would eliminate drift.

low

BranchNameLengthAspect uses camelCase field reflection rather than cfnProperties (official API)

infra/cdk/src/aspects/branch-name-length.ts:51

node.cfnProperties is the documented CDK introspection surface; using propertyFieldFor() relies on L1 field-naming convention being stable. Functionally correct for all types in NAME_LIMITS.

low

BRANCH_EXACT_ABBREV stale key risk — TypeScript cannot catch a key that stops matching

infra/cdk/src/lib/naming.ts:46

A token-map change that renames 'helioscope' would silently un-key the EXACT entry with no TypeScript error. A unit test for abbreviateForBranch covering exact-then-token ordering would make this resilient.

low

No CDK-side naming.ts unit tests — tests live on the wrong side of the twin

infra/cdk/src/lib/naming.ts:1

Platform twin has tests; CDK source of truth does not. abbreviateForBranch, BRANCH_EXACT_ABBREV ordering, and token map are tested only by full CDK synth. A Vitest suite for naming.ts would be CDK-synth-free and fast.

info

powerradar→radar abbreviation could collide with a hypothetical future 'radar' integration

infra/cdk/src/lib/naming.ts:37

Audit script duplicate-detection is the safety net. No current collision.

info

Deprovision workflow comment updated but correctly has no slug-length gate

.github/workflows/preview-deprovision.yml:247

Deprovision uses delete-stack by name, not re-synth. Over-budget slugs never deployed, so delete is a no-op. Comment could note this asymmetry.

info

Twin pattern is the right call; @batu/naming-utils extraction is low-urgency

apps/platform/src/api/utils/metrics-explore-core.ts:53

CDK cannot be imported by Next.js. A @batu/naming-constants package with only primitives (no CDK dep) would reduce the twin to a thin wrapper. Low urgency.

info

scripts/*.mjs eslint ignore is intentional and correct for current directory structure

infra/cdk/eslint.config.js:35

Only one .mjs file currently in infra/cdk/scripts/. Pattern covers top-level only; subdirectory .mjs files would need a separate pattern. Correct as-is.