feat(manifest): declare build context in the schema + test every project image resolves#115
Merged
Merged
Conversation
…ect image resolves Fixes audit §2.1: build-context identity was not in the manifest schema, so the image→context map lived only in README prose + one hardcoded preflight special-case, and folder-id ≠ image-name for 5 services. - Add an optional `build:` field (context/dockerfile/external) to the Plugin/Agent/ Dashboard/DashboardBackend schema (ordo/buildspec.BuildSpec). METADATA only — never emitted into the rendered compose (render stays byte-identical). Defaults to the service's own services/<id>/ + Dockerfile. Declared explicitly only where the default is wrong: the v1-parity dashboard's nested build context, and the two pluggable agents (hermes, openai-agent) built out-of-band (build.external). - Add a single image→context resolver (ordo/buildspec.context_resolver) over BOTH manifest services and the hardcoded substrate services (SUBSTRATE_BUILD_CONTEXTS in compose.py, co-located with their definitions). Preflight now emits a GENERIC "build from <context>" hint for every project image; the `"llamacpp-patched" in image` substring special-case and the one-image hardcoded hint are DELETED. - Add tests/substrate/test_build_contexts.py: every project image (ordo/* or ordo-ai-stack-*) referenced by any manifest OR the substrate services resolves to an existing Dockerfile (or is declared external) — a rename/typo fails CI, not deploy. Upstream pull-only images are exempt. Update the preflight-hint test to the generic form. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Audit §2.1 — build-context identity was not in the manifest schema. The rendered compose is image-only, so the image→context map lived only in per-service README prose plus one hardcoded preflight special-case, and folder-id ≠ image-name for 5 services (
memory-vault→mcpvault-mcp,rag→rag-ingestion,codebase-memory→codebase-memory-mcp,orchestration→orchestration-mcp,qdrant-rag→qdrant-rag-mcp) — so an operator couldn't grep the folder from a failing image name. Classic "N workarounds on one seam" shape.The
build:field (schema)New
BuildSpec(ordo/buildspec.py) — an optionalbuild: {context, dockerfile, external}block added to the Plugin / Agent / Dashboard / DashboardBackend dataclasses +from_dict. Pure metadata: never emitted into the rendered compose. Absent → defaults to the service's ownservices/<id>/+Dockerfile.Explicit
build:was added only where the default is wrong (declaring redundant blocks would create a second source of truth for a folder the resolver already knows):services/v1-parity/dashboard.yaml→build.context: services/v1-parity/dashboard(Dockerfile is nested, not in the manifest's ownservices/v1-parity/dir).services/hermes/agent.yamlandservices/openai-agent/agent.yaml→build.external: true(pluggable agent images built out-of-band; no in-repo Dockerfile).The 5 folder≠image plugins keep the default (
services/<id>), which the resolver already maps to the correct folder — that's what cures the "can't grep the folder" complaint, without redundant config.The resolver + deleted special-case
ordo/buildspec.context_resolver()— a single image→context resolver covering BOTH manifest services (frombuild:/default) AND the substrate services. The 4 hardcoded substrate images live inSUBSTRATE_BUILD_CONTEXTSincompose.py, co-located with their_model_gateway/_mcp_gateway/_ops_controller+ patched-llama definitions. (ops-apiis the v1-parity dashboard backend — it flows through the dashboard manifest path, not the substrate map; the task listed it as substrate but it is manifest-declared.)preflight.pynow:"llamacpp-patched" in imagesubstring_is_buildablespecial-case and the hardcoded one-image build-from hint.<context>" hint for every project image via the resolver (buildable = "resolver has a context for it", which generically covers the no-ordo/-prefixordo-ai-stack-llamacpp-patched). External images are shown bare.Sample (fresh box):
The substrate test (highest value)
tests/substrate/test_build_contexts.py— asserts every project image (ordo/*orordo-ai-stack-*) referenced by any manifest OR the substrate services resolves to an existing Dockerfile underservices/(or is declaredexternal). Locks the 5 folder≠image mappings and the substrate map. Upstream pull-only images (caddy, qdrant, n8n, llama.cpp/node bases, …) are exempt — the resolver returnsNonefor them. So a folder rename or image typo — or a new agent lacking both a Dockerfile andbuild.external— fails CI, not deploy. The existing preflight-hint test is updated to the generic form.Validation
docker-compose.ymlsha ==3f63588dbd6296e258fc83d41791803fdde209e7c18f2f44f2c0b634c07ca37a(unchanged —build:is metadata only). A test also asserts nobuildkey leaks into any compose service.ruff check .clean;pytest tests/ -q→ 564 passed, 4 skipped (baseline + new tests; fable catalog entry stashed for the run).preflightemits generic build-from hints for all project images (sample above).Deferred
Nothing from the schema/resolver/test was deferred. Note:
services/openai-agentandservices/hermesgenuinely have no in-repo Dockerfile (operator/third-party built) — handled honestly viabuild.external, not forced into a phantom context.🤖 Generated with Claude Code