Goal
Give every explicitly named application a stable, non-empty, collision-resistant identity.
Background
normalize_cli_name() applies filename heuristics to explicit names, dropping the final dotted segment and replacing spaces:
def normalize_cli_name (name : str ) -> str :
stem = Path (name ).name
if "." in stem :
stem = stem .rsplit ("." , 1 )[0 ]
return stem .replace (" " , "-" )
def runtime_slug (value : str , fallback : str = "unnamed" ) -> str :
normalized = re .sub (r"[^a-zA-Z0-9._-]+" , "-" , value .strip ()).strip (".-_" ).lower ()
return normalized or fallback
.
App(name="ops.prod") therefore becomes
ops, and
App(name=".") becomes empty despite
#55 making
App.name authoritative:
self ._registration_lock = RLock ()
self ._registration_state = _REGISTRATION_OPEN
self ._name = normalize_cli_name (name or sys .argv [0 ])
self .version = version
.
Separately, distinct names such as ops+prod and ops@prod both become the runtime slug ops-prod. Generic profiles use that lossy slug as the owner root:
def _generic_runtime_resolver (
cache_root : Path | None ,
application_home : Path | None ,
) -> RuntimeResolver :
def resolve_runtime (cli_name : str , project : ProjectInfo | None ) -> RuntimeBinding :
root = (cache_root if cache_root is not None else default_cache_root ()).expanduser ().resolve ()
run_id = make_run_id ()
project_root = project .root if project is not None else None
project_name = project .name if project is not None else None
return RuntimeBinding (
cache_root = root ,
layout = runtime_layout (
root ,
cli_name ,
run_id ,
namespace = cli_name ,
project_name = project_name ,
),
application_home = application_home ,
runtime_owner = "default" ,
project_root = project_root ,
project_name = project_name ,
inherited_path = None ,
history_parent_run_id = None ,
run_id = run_id ,
)
and
def runtime_namespace_root (cache_root : Path , namespace : str ) -> Path :
"""Return an application-owned runtime namespace without product assumptions."""
return cache_root / runtime_slug (namespace , fallback = "application" )
. Distinct CLIs can therefore share logs, caches, retention indexes, and pruning scope.
Scope
Separate argv/executable filename inference from explicit application identity.
Reject empty explicit identities.
Make unsafe filesystem names readable but collision-resistant.
Define migration behavior for existing runtime directories.
Acceptance Criteria
Explicit ops.prod remains ops.prod in Click, context, logs, metadata, and history.
Empty normalized names fail during construction with an actionable error.
Distinct accepted names cannot resolve to the same runtime owner directory.
One CLI cannot prune or overwrite another CLI's bundles or component cache.
Compatibility tests cover dots, spaces, Unicode, punctuation, long names, case behavior, and legacy directories.
The Repair application naming and registration contracts #55 naming contract remains true.
Validation
Run naming, profile, runtime, retention, Windows, macOS, and Linux tests.
Non-Goals
Do not expose raw unsafe characters directly as path components.
Project Fields
Status: Backlog
Priority: P1
Area: Security
Initiative: v1.0 Readiness
Size: M
Ownership
Goal
Give every explicitly named application a stable, non-empty, collision-resistant identity.
Background
normalize_cli_name()applies filename heuristics to explicit names, dropping the final dotted segment and replacing spaces:base-cli/lib/python/base_cli/paths.py
Lines 100 to 109 in 8a93d22
App(name="ops.prod")therefore becomesops, andApp(name=".")becomes empty despite #55 makingApp.nameauthoritative:base-cli/lib/python/base_cli/_app_core.py
Lines 500 to 503 in 8a93d22
Separately, distinct names such as
ops+prodandops@prodboth become the runtime slugops-prod. Generic profiles use that lossy slug as the owner root:base-cli/lib/python/base_cli/profile.py
Lines 289 to 314 in 8a93d22
base-cli/lib/python/base_cli/_runtime.py
Lines 209 to 211 in 8a93d22
Scope
Acceptance Criteria
ops.prodremainsops.prodin Click, context, logs, metadata, and history.Validation
Run naming, profile, runtime, retention, Windows, macOS, and Linux tests.
Non-Goals
Do not expose raw unsafe characters directly as path components.
Project Fields
Ownership