feat(inference): type llama.cpp serving recipes - #8183
Conversation
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe catalog now supports declarative llama.cpp recipes, typed readiness comparisons, structured registries, and compiler version ChangesDeclarative llama.cpp catalog
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CatalogCompiler
participant ServingRecipe
participant ServingCatalogRegistries
participant ServingPreset
CatalogCompiler->>ServingRecipe: validate recipe contracts and llama.cpp constraints
ServingRecipe->>ServingCatalogRegistries: resolve receipt and readiness references
CatalogCompiler->>ServingPreset: validate selection and readiness requirements
ServingPreset->>ServingCatalogRegistries: resolve observations and qualifications
CatalogCompiler-->>CatalogCompiler: compile deterministic catalog version 1.1.0
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in commit e358a67 in the TypeScript / code-coverage/cliThe overall coverage in commit e358a67 in the Show a code coverage summary of the most impacted files.
Updated |
PR Review Advisor — No blocking findings reportedAdvisor assessment: No blocking advisor findings reported Model lanes
10 terminology differences from the second opinionAdvisory only. These are normalized differences from the primary terminology receipt.
Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate. 3 semantic terminology decisionsTerminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.
E2E guidanceAdvisory only. E2E / PR Gate selects and runs jobs independently. Recommended E2E: This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
apurvvkumaria
left a comment
There was a problem hiding this comment.
Reviewed exact head cc298cd against stacked base 89d9399. Approve: the new llama.cpp contract remains inert with empty production registries, validates immutable recipe identity, bounded runtime and serving limits, readiness roles and value types, explicit-only selection, and agent qualifications fail closed. The focused catalog suite passed 54 of 54 tests locally; exact-head CLI shards, static analysis, CodeQL, and the primary review advisor also passed with no findings. Current image-build and E2E coordination failures arise from shared dependency and coordination infrastructure outside this seven-file compiler/schema delta and remain for the normal merge gate.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
managed-inference/schemas/recipe.schema.json (1)
349-352: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse
imageDigestforspec.runtime.image.The pattern at Line 349-352 duplicates the inline pattern at Line 80. Two copies can drift. Point
spec.runtime.imageat the new definition.♻️ Proposed refactor
- "image": { - "type": "string", - "pattern": "^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]+)?/)?(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*`@sha256`:[0-9a-f]{64}$" - }, + "image": { "$ref": "`#/`$defs/imageDigest" },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@managed-inference/schemas/recipe.schema.json` around lines 349 - 352, Update spec.runtime.image to reference the existing imageDigest schema definition instead of duplicating the inline digest pattern. Remove the duplicated pattern from that property while preserving the imageDigest definition as the single source of truth.src/lib/inference/serving/catalog.ts (1)
150-150: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExport
LlamaCppServingRecipefromtypes.tsinstead of re-deriving it.
src/lib/inference/serving/types.tsalready declares theLlamaCppServingRecipeinterface at Line 58. The interface is not exported, so this file rebuilds it withExtract. TheExtractform works, but it couples the compiler to the internal shape of the discriminator. Export the interface and import it directly.♻️ Proposed refactor
In
src/lib/inference/serving/types.ts:-interface LlamaCppServingRecipe extends ServingRecipeEnvelope { +export interface LlamaCppServingRecipe extends ServingRecipeEnvelope {In
src/lib/inference/serving/catalog.ts:+ LlamaCppServingRecipe, ServingReadinessComparison, ServingReadinessObservationRole, ServingReadinessRequirement, ServingRecipe, } from "./types";-type LlamaCppServingRecipe = Extract<ServingRecipe, { spec: { providerId: "llama-cpp-local" } }>;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/inference/serving/catalog.ts` at line 150, Export the existing LlamaCppServingRecipe interface from types.ts, then update catalog.ts to import and use that type directly. Remove the local Extract-based LlamaCppServingRecipe alias while leaving the surrounding serving recipe definitions unchanged.src/lib/inference/serving/catalog.test.ts (1)
340-389: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThe 21 negative cases assert one generic message.
Every case expects
"does not satisfy the ServingRecipe schema". That message proves rejection, not the reason for rejection. A malformed replacement, a YAML indentation mistake, or an unrelated constraint produces the same pass. ThereplaceSourceguard at Line 279 prevents a no-op edit, but it does not prove which constraint fired.The risk is concentrated in the cases that target a specific new constraint, for example "an arbitrary launch argument" (the
serve.notclause), "a path-based served model name" (nonPathStableId), and "shell syntax" (artifactLabel). Add the expected schema pointer or keyword to those cases so a schema change that removes the constraint fails the test.As per path instructions: "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."
💚 Sketch of a targeted assertion
Extend the table with the expected detail fragment and assert on it:
- ])("rejects %s in a llama.cpp recipe (`#8181`)", (_case, expected, replacement) => { + ])("rejects %s in a llama.cpp recipe (`#8181`)", (_case, expected, replacement, detail) => { const recipe = replaceSource(llamaCppRecipeSource(), expected, replacement); - expect(() => compile([recipe])).toThrow("does not satisfy the ServingRecipe schema"); + expect(() => compile([recipe])).toThrow("does not satisfy the ServingRecipe schema"); + if (detail) expect(() => compile([recipe])).toThrow(detail); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/inference/serving/catalog.test.ts` around lines 340 - 389, Strengthen the parameterized rejection test around the table in the “rejects %s in a llama.cpp recipe” case so each fixture records the expected schema pointer or keyword, especially for “an arbitrary launch argument,” “a path-based served model name,” and “shell syntax.” Keep the replaceSource guard, then assert the thrown validation error includes that case-specific detail rather than only the generic “does not satisfy the ServingRecipe schema” message.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@managed-inference/schemas/recipe.schema.json`:
- Around line 526-544: Extend the generic-recipe exclusion in the schema’s else
branch so it rejects every llama.cpp-only field added to the shared spec
surface, including runtime, serve, readiness, and model metadata fields listed
in the review. Update the not.anyOf constraints near the else branch without
changing llama.cpp recipe validation or generic recipe fields.
- Around line 335-338: Update the sourceRevision schema property to accept only
valid SHA-1 or SHA-256 digest lengths: exactly 40 or 64 lowercase hexadecimal
characters. Preserve the existing hexadecimal and full-string constraints while
rejecting all intermediate lengths.
In `@src/lib/inference/serving/catalog.ts`:
- Around line 253-256: Update readinessRequirementKey to include the
requirement’s form (state versus comparison) in the generated key, preventing
distinct requirements for the same observation from colliding during
validatePresetReadiness. Add a test covering both forms together and verify they
are accepted without a contradictory-requirement error.
---
Nitpick comments:
In `@managed-inference/schemas/recipe.schema.json`:
- Around line 349-352: Update spec.runtime.image to reference the existing
imageDigest schema definition instead of duplicating the inline digest pattern.
Remove the duplicated pattern from that property while preserving the
imageDigest definition as the single source of truth.
In `@src/lib/inference/serving/catalog.test.ts`:
- Around line 340-389: Strengthen the parameterized rejection test around the
table in the “rejects %s in a llama.cpp recipe” case so each fixture records the
expected schema pointer or keyword, especially for “an arbitrary launch
argument,” “a path-based served model name,” and “shell syntax.” Keep the
replaceSource guard, then assert the thrown validation error includes that
case-specific detail rather than only the generic “does not satisfy the
ServingRecipe schema” message.
In `@src/lib/inference/serving/catalog.ts`:
- Line 150: Export the existing LlamaCppServingRecipe interface from types.ts,
then update catalog.ts to import and use that type directly. Remove the local
Extract-based LlamaCppServingRecipe alias while leaving the surrounding serving
recipe definitions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: d700028d-a0ff-4a41-b267-5941e7fa3d4d
📒 Files selected for processing (7)
managed-inference/schemas/catalog.schema.jsonmanaged-inference/schemas/preset.schema.jsonmanaged-inference/schemas/recipe.schema.jsonsrc/lib/inference/serving/catalog.test.tssrc/lib/inference/serving/catalog.tssrc/lib/inference/serving/generate-catalog.tssrc/lib/inference/serving/types.ts
| "sourceRevision": { | ||
| "type": "string", | ||
| "pattern": "^[0-9a-f]{40,64}$" | ||
| }, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Tighten sourceRevision to real commit digest lengths.
The pattern ^[0-9a-f]{40,64}$ accepts 41 to 63 hex characters. Those lengths are neither SHA-1 nor SHA-256. spec.model.revision is also constrained by the top-level alternation at Line 42, so it stays at 40 or 64. spec.server.source.revision has no such second constraint, so it accepts the intermediate lengths. This weakens the immutable server identity goal stated in the PR objectives.
🔒 Proposed fix
"sourceRevision": {
"type": "string",
- "pattern": "^[0-9a-f]{40,64}$"
+ "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$"
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "sourceRevision": { | |
| "type": "string", | |
| "pattern": "^[0-9a-f]{40,64}$" | |
| }, | |
| "sourceRevision": { | |
| "type": "string", | |
| "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@managed-inference/schemas/recipe.schema.json` around lines 335 - 338, Update
the sourceRevision schema property to accept only valid SHA-1 or SHA-256 digest
lengths: exactly 40 or 64 lowercase hexadecimal characters. Preserve the
existing hexadecimal and full-string constraints while rejecting all
intermediate lengths.
| "else": { | ||
| "type": "object", | ||
| "not": { | ||
| "anyOf": [ | ||
| { | ||
| "type": "object", | ||
| "properties": { "providerId": {} }, | ||
| "required": ["providerId"] | ||
| }, | ||
| { "type": "object", "properties": { "policy": {} }, "required": ["policy"] }, | ||
| { "type": "object", "properties": { "surfaces": {} }, "required": ["surfaces"] }, | ||
| { | ||
| "type": "object", | ||
| "properties": { "capabilities": {} }, | ||
| "required": ["capabilities"] | ||
| } | ||
| ] | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
The else branch leaves llama.cpp-shaped fields open on generic recipes.
The else branch forbids providerId, policy, surfaces, and capabilities. It does not forbid the other llama.cpp-shaped fields that Line 83-218 added to the shared spec surface: runtime.platforms, runtime.containerRuntime, runtime.hosts, runtime.cuda, runtime.gpu, runtime.resources, serve.protocol, serve.port, serve.chatTemplate, serve.contextSize, serve.slots, serve.idleSleepSeconds, serve.limits, readiness.probes, and the model file sizeBytes, format, quantization, and license fields.
A generic recipe can therefore declare runtime.gpu.cpuFallback: reject or serve.limits and pass schema validation. isLlamaCppServingRecipe in src/lib/inference/serving/catalog.ts returns false for such a recipe, so no llama.cpp semantic check runs. GenericServingRecipe in src/lib/inference/serving/types.ts does not model those fields either, so the compiled catalog carries data that no consumer validates.
Extend the else not.anyOf list, or move the llama.cpp-only subschemas out of the shared spec.properties surface.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@managed-inference/schemas/recipe.schema.json` around lines 526 - 544, Extend
the generic-recipe exclusion in the schema’s else branch so it rejects every
llama.cpp-only field added to the shared spec surface, including runtime, serve,
readiness, and model metadata fields listed in the review. Update the not.anyOf
constraints near the else branch without changing llama.cpp recipe validation or
generic recipe fields.
| function readinessRequirementKey(requirement: ServingReadinessRequirement): string { | ||
| const readiness = requirement.readiness; | ||
| return `${readiness.scope}:${readiness.kind}:${readiness.id}`; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find presets or tests that declare both a state form and a comparison form for one observation id.
set -euo pipefail
fd -e yaml -e yml . managed-inference 2>/dev/null | while IFS= read -r file; do
rg -n -C 6 'kind:\s*observation' "$file" || true
done
rg -n -C 6 'readinessRequirementKey|contradictory readiness requirements' --type=tsRepository: NVIDIA/NemoClaw
Length of output: 153
🏁 Script executed:
set -euo pipefail
printf '%s\n' '--- candidate files ---'
fd -i -t f 'catalog|readiness|preset|inference' . | head -200
printf '%s\n' '--- relevant symbols ---'
rg -n -C 12 'readinessRequirementKey|validatePresetReadiness|contradictory readiness requirements|ServingReadinessRequirement' src --glob '*.ts' --glob '*.tsx'
printf '%s\n' '--- managed-inference files ---'
if [ -d managed-inference ]; then
fd -e yaml -e yml . managed-inference
else
printf '%s\n' 'managed-inference directory not present'
fiRepository: NVIDIA/NemoClaw
Length of output: 26887
🏁 Script executed:
set -euo pipefail
printf '%s\n' '--- requirement types and validator ---'
sed -n '140,185p' src/lib/inference/serving/types.ts
sed -n '253,307p' src/lib/inference/serving/catalog.ts
printf '%s\n' '--- schemas ---'
rg -n -C 12 '"requirements"|"state"|"comparison"|readiness' managed-inference/schemas schemas src/lib/inference --glob '*.json' --glob '*.ts'
printf '%s\n' '--- readiness evaluation and consumers ---'
rg -n -C 8 'requirements\?\.all|requirements\.all|readiness.*state|readiness.*comparison|contradictory readiness' src managed-inference nemoclaw-blueprint --glob '*.ts' --glob '*.tsx' --glob '*.json' --glob '*.yaml' --glob '*.yml'
printf '%s\n' '--- relevant tests ---'
sed -n '540,630p' src/lib/inference/serving/catalog.test.tsRepository: NVIDIA/NemoClaw
Length of output: 50372
🏁 Script executed:
set -euo pipefail
printf '%s\n' '--- exact requirement consumers ---'
rg -n 'spec\.requirements|requirements\?\.all|requirements\.all|\.requirements' src/lib/inference src/lib/onboard scripts test --glob '*.ts' --glob '*.tsx' --glob '*.mts' --glob '*.js' --glob '*.json' | head -250
printf '%s\n' '--- preset fixtures and declarations ---'
rg -n -C 8 'requirements:|state: (present|absent)|comparison:|kind: observation' . --glob '*.yaml' --glob '*.yml' --glob '*.json' --glob '*.ts' --glob '*.tsx' | head -300
printf '%s\n' '--- schema requirement definition ---'
sed -n '62,175p' managed-inference/schemas/preset.schema.json
printf '%s\n' '--- all catalog tests around readiness ---'
rg -n -C 10 'readiness|requirement' src/lib/inference/serving/catalog.test.ts | head -300Repository: NVIDIA/NemoClaw
Length of output: 37765
🏁 Script executed:
set -euo pipefail
sed -n '320,435p' src/lib/inference/serving/catalog.ts
sed -n '474,535p' src/lib/inference/serving/catalog.test.ts
printf '%s\n' '--- documentation for preset requirements ---'
rg -n -C 8 'requirements|readiness requirement|comparison|state: present' docs managed-inference README.md src/lib/README.md 2>/dev/null | head -250Repository: NVIDIA/NemoClaw
Length of output: 37355
🏁 Script executed:
set -euo pipefail
python3 - <<'PY'
import json
import re
from pathlib import Path
catalog = Path("src/lib/inference/serving/catalog.ts").read_text()
types = Path("src/lib/inference/serving/types.ts").read_text()
schema = json.loads(Path("managed-inference/schemas/preset.schema.json").read_text())
state = {
"readiness": {
"scope": "everyNode",
"kind": "observation",
"id": "test.os",
"state": "present",
}
}
comparison = {
"readiness": {
"scope": "everyNode",
"kind": "observation",
"id": "test.os",
"comparison": {"operator": "equals", "value": "linux"},
}
}
key_match = re.search(
r"return `\$\{readiness\.scope\}:\$\{readiness\.kind\}:\$\{readiness\.id\}`;",
catalog,
)
assert key_match, "readinessRequirementKey does not use the claimed key shape"
def key(requirement):
readiness = requirement["readiness"]
return f'{readiness["scope"]}:{readiness["kind"]}:{readiness["id"]}'
assert key(state) == key(comparison)
assert '"state": "present"' in types
assert "comparison: ServingReadinessComparison" in types
branches = schema["$defs"]["readinessRequirement"]["properties"]["readiness"]["oneOf"]
required_forms = {tuple(branch["required"]) for branch in branches}
assert ("scope", "kind", "id", "state") in required_forms
assert ("scope", "kind", "id", "comparison") in required_forms
assert "const key = readinessRequirementKey(requirement);" in catalog
assert "if (previous !== undefined)" in catalog
assert "has contradictory readiness requirements" in catalog
print("state and comparison forms are distinct schema/type variants")
print("both forms produce the same readinessRequirementKey")
print("the validator rejects the second form as contradictory")
PYRepository: NVIDIA/NemoClaw
Length of output: 242
🏁 Script executed:
set -euo pipefail
python3 - <<'PY'
import json
import re
from pathlib import Path
catalog = Path("src/lib/inference/serving/catalog.ts").read_text()
types = Path("src/lib/inference/serving/types.ts").read_text()
schema = json.loads(Path("managed-inference/schemas/preset.schema.json").read_text())
state = {"readiness": {
"scope": "everyNode", "kind": "observation", "id": "test.os", "state": "present"
}}
comparison = {"readiness": {
"scope": "everyNode", "kind": "observation", "id": "test.os",
"comparison": {"operator": "equals", "value": "linux"}
}}
def check(name, condition):
print(f"{name}: {'PASS' if condition else 'FAIL'}")
return condition
def key(requirement):
readiness = requirement["readiness"]
return f'{readiness["scope"]}:{readiness["kind"]}:{readiness["id"]}'
checks = [
("key expression", bool(re.search(
r"return `\$\{readiness\.scope\}:\$\{readiness\.kind\}:\$\{readiness\.id\}`;",
catalog,
))),
("same key", key(state) == key(comparison)),
("state union", '"state": "present"' in types),
("comparison union", "comparison: ServingReadinessComparison" in types),
("validator uses key", "const key = readinessRequirementKey(requirement);" in catalog),
("validator rejects prior key", "if (previous !== undefined)" in catalog),
("contradiction message", "has contradictory readiness requirements" in catalog),
]
branches = schema["$defs"]["readinessRequirement"]["properties"]["readiness"]["oneOf"]
required_forms = {tuple(branch["required"]) for branch in branches}
checks.extend([
("schema state form", ("scope", "kind", "id", "state") in required_forms),
("schema comparison form", ("scope", "kind", "id", "comparison") in required_forms),
])
if not all(check(name, condition) for name, condition in checks):
raise SystemExit(1)
PYRepository: NVIDIA/NemoClaw
Length of output: 207
🏁 Script executed:
set -euo pipefail
python3 - <<'PY'
import json
import re
from pathlib import Path
catalog = Path("src/lib/inference/serving/catalog.ts").read_text()
types = Path("src/lib/inference/serving/types.ts").read_text()
schema = json.loads(Path("managed-inference/schemas/preset.schema.json").read_text())
state = {"scope": "everyNode", "kind": "observation", "id": "test.os", "state": "present"}
comparison = {
"scope": "everyNode",
"kind": "observation",
"id": "test.os",
"comparison": {"operator": "equals", "value": "linux"},
}
def key(readiness):
return f'{readiness["scope"]}:{readiness["kind"]}:{readiness["id"]}'
assert key(state) == key(comparison)
assert re.search(r'\bid: string;\s+state: "present" \| "absent";', types)
assert re.search(r'\bid: string;\s+comparison: ServingReadinessComparison;', types)
branches = schema["$defs"]["readinessRequirement"]["properties"]["readiness"]["oneOf"]
required_forms = {tuple(branch["required"]) for branch in branches}
assert ("scope", "kind", "id", "state") in required_forms
assert ("scope", "kind", "id", "comparison") in required_forms
assert "const key = readinessRequirementKey(requirement);" in catalog
assert "if (previous !== undefined)" in catalog
assert "has contradictory readiness requirements" in catalog
print("state and comparison forms are allowed by the type and schema")
print("both forms produce the same key")
print("the validator rejects the second requirement for that key")
PYRepository: NVIDIA/NemoClaw
Length of output: 305
Include the requirement form in readinessRequirementKey. The schema and type allow both state and comparison requirements for one observation, but the current key makes them collide and validatePresetReadiness rejects the second as contradictory. Add a test for this combination.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/inference/serving/catalog.ts` around lines 253 - 256, Update
readinessRequirementKey to include the requirement’s form (state versus
comparison) in the generated key, preventing distinct requirements for the same
observation from colliding during validatePresetReadiness. Add a test covering
both forms together and verify they are accepted without a
contradictory-requirement error.
Summary
Extend the managed inference catalog with a typed, declarative llama.cpp recipe contract and recipe-linked readiness validation. This stacked change targets the catalog compiler in #8152 and remains inert until #8173 supplies approved production artifacts and adapter identities.
Related Issue
Fixes #8181
Part of #8144. Follow-up production configuration remains in #8173.
Changes
install-llama-cpprecipe schema for the catalog compiler, covering immutable server and GGUF identity, Docker/CUDA/GPU boundaries, bounded resources and serving limits, offline policy, disabled surfaces, readiness probes, and explicit capabilities. A direct production recipe is not appropriate in this slice because its artifact tuple and runtime adapters are not yet approved; synthetic fixtures protect the contract without activating serving.Type of Change
Quality Gates
cc298cdfbcbe973ff7dc36bdd6e024a99a12e3b9; all categories passed with no blocking findings.Documentation Writer Review
no-docs-neededDGX Station Hardware Evidence
Verification
Signed-off-by:line and every commit appears asVerifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run validate:prpassed after refreshingorigin/mainwhen hooks were skipped or unavailablenpx vitest run --project cli src/lib/inference/serving/catalog.test.ts(54 passed); package-contract catalog tests (2 passed);npm run test:changed(54 passed); the changed-test conditionals guard passes.npm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result: Not applicable; the focused compiler tests, package contract,npm run build:cli, and repository hooks cover this bounded catalog-contract change.npm run docsbuilds without warnings (doc changes only)Signed-off-by: Aaron Erickson aerickson@nvidia.com
Summary by CodeRabbit
New Features
Improvements