Lifecycle Proving
Relevant source files
The following files were used as context for generating this wiki page:
Lifecycle Proving is a Stage 1 acceptance process within the Numan Registry project designed to verify that a package (plugin, module, etc.) correctly transitions through its entire operational lifecycle against a real instance of Nushell (nu) and the numan package manager. This verification occurs on a clean, isolated root directory to ensure reproducibility and safety before a package is promoted to the official production catalog.
Sources: README.md:105-109, scripts/lifecycle-prove.py:1-12
Architectural Overview
The lifecycle proving system operates by orchestrating a series of sequential commands using the numan CLI. It ensures that the package can be discovered, installed, activated, verified, deactivated, and removed without errors. The system utilizes a temporary, isolated environment for both the numan root and the nu executable to prevent interference with the host system.
Execution Environment Isolation
To ensure the test uses the exact version of Nushell intended, the system creates a temporary "shim" directory. On Unix-like systems, this is a shell script; on Windows, it is a hardlink or copy of the nu.exe binary. This shim is prepended to the PATH environment variable during the proving sequence.
Sources: scripts/lifecycle-prove.py:202-225, scripts/test_lifecycle_prove.py:65-75
The Proving Flow
The diagram below illustrates the sequential stages of the lifecycle proof:
The process fails immediately if any step returns a non-zero exit code.
Sources: scripts/lifecycle-prove.py:101-115, scripts/test_lifecycle_prove.py:141-155
Key Components and Logic
Proving Steps Definitions
The lifecycle is defined by a specific set of numan commands:
| Step | Command | Description |
|---|---|---|
| init | init | Initializes a new Numan root. |
| registry sync | registry sync | Synchronizes the local registry index. |
| search | search <query> | Verifies the package is discoverable. |
| info | info <id> | Retrieves package metadata. |
| install | install <id> | Downloads and unpacks the package. |
| activate | activate <id> | Registers the plugin or module with Nushell. |
| doctor | doctor | Runs health checks on the environment. |
| list | list | Lists installed packages. |
| deactivate | deactivate <id> | Unregisters the package. |
| remove | remove --yes <id> | Deletes package artifacts. |
| gc | gc | Performs garbage collection on the root. |
Sources: scripts/lifecycle-prove.py:101-115, scripts/test_lifecycle_prove.py:35-50
Integration with Validation Harness
Lifecycle proving is integrated into the Stage 5 validation tool (scripts/validate_candidate.py). While structural linting and schema checks are mandatory, the lifecycle proof is an opt-in step via the --prove flag. However, for "activatable" packages (plugins or modules with activation logic), successful lifecycle evidence is a prerequisite for promotion to production.
Sources: scripts/validate_candidate.py:21-25, scripts/validate_candidate.py:200-215, REVIEW.md:36-37
Data Structures
The Step Dataclass
The core logic uses a frozen dataclass to represent each command in the sequence.
@dataclass(frozen=True)
class Step:
name: str
args: list[str]
Sources: scripts/lifecycle-prove.py:33-36
Evidence Report
When run through the validation harness, the results are captured in an evidence JSON structure.
{
"name": "lifecycle",
"status": "pass",
"detail": "..."
}
Sources: scripts/validate_candidate.py:205-215
Security and Trust Invariants
- Real-Nu Requirement: The proof must run against a real Nu binary matching the package's
nu_versionconstraint. - Clean Root: Verification must happen on an empty directory to ensure no hidden dependencies or side effects.
- Mandatory for Activatable Packages: Packages that require registration (plugins) or provide modules must have
verified_withentries in the index, which are derived from successful lifecycle proofs. - No Private Keys: Proving is a public operation and must never involve private key material.
Sources: README.md:112-117, REVIEW.md:36-37, AGENTS.md:58-60
Implementation Details
Executable Resolution
The script employs robust resolution logic to find nu and numan, supporting both explicit paths and system PATH lookups.
def is_executable(path: Path, *, platform: str | None = None) -> bool:
platform = platform or sys.platform
if not path.is_file():
return False
if platform == "win32":
return path.suffix.lower() in {".exe", ".cmd"}
return os.access(path, os.X_OK)
Sources: scripts/lifecycle-prove.py:56-65
Windows Isolation Logic
On Windows, numan (written in Rust) may have issues probing .cmd or .bat files. Therefore, the lifecycle prover strictly requires a .exe for Nushell and attempts to create a hardlink named nu.exe in the temporary shim directory.
Sources: scripts/lifecycle-prove.py:171-190, scripts/test_lifecycle_prove.py:99-110
Summary
Lifecycle Proving ensures the operational integrity of Numan packages. By executing a standardized sequence of commands—from initialization to removal—within a strictly isolated environment, the project maintains high standards for catalog quality and user safety. Activatable packages cannot be promoted to the production registry without successful lifecycle evidence recorded in their verified_with metadata.