Skip to content

feat(manifest): declare build context in the schema + test every project image resolves#115

Merged
AlienWalker1995 merged 1 commit into
mainfrom
feat/manifest-build-field
Jul 25, 2026
Merged

feat(manifest): declare build context in the schema + test every project image resolves#115
AlienWalker1995 merged 1 commit into
mainfrom
feat/manifest-build-field

Conversation

@AlienWalker1995

Copy link
Copy Markdown
Owner

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 optional build: {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 own services/<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.yamlbuild.context: services/v1-parity/dashboard (Dockerfile is nested, not in the manifest's own services/v1-parity/ dir).
  • services/hermes/agent.yaml and services/openai-agent/agent.yamlbuild.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 (from build:/default) AND the substrate services. The 4 hardcoded substrate images live in SUBSTRATE_BUILD_CONTEXTS in compose.py, co-located with their _model_gateway/_mcp_gateway/_ops_controller + patched-llama definitions. (ops-api is 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.py now:

  • DELETES the "llamacpp-patched" in image substring _is_buildable special-case and the hardcoded one-image build-from hint.
  • Emits a generic "build from <context>" hint for every project image via the resolver (buildable = "resolver has a context for it", which generically covers the no-ordo/-prefix ordo-ai-stack-llamacpp-patched). External images are shown bare.

Sample (fresh box):

ordo-ai-stack-llamacpp-patched:qwen36-swa-86b9470 (build from services/llamacpp-patched)
ordo/agent-hermes:latest
ordo/dashboard-v1:latest (build from services/v1-parity/dashboard)
ordo/rag-ingestion:latest (build from services/rag)
ordo/ltx-trainer:9377758131b1 (build from services/ltx-trainer)
...

The substrate test (highest value)

tests/substrate/test_build_contexts.py — asserts every project image (ordo/* or ordo-ai-stack-*) referenced by any manifest OR the substrate services resolves to an existing Dockerfile under services/ (or is declared external). 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 returns None for them. So a folder rename or image typo — or a new agent lacking both a Dockerfile and build.external — fails CI, not deploy. The existing preflight-hint test is updated to the generic form.

Validation

  • Render byte-identical: docker-compose.yml sha == 3f63588dbd6296e258fc83d41791803fdde209e7c18f2f44f2c0b634c07ca37a (unchanged — build: is metadata only). A test also asserts no build key leaks into any compose service.
  • ruff check . clean; pytest tests/ -q564 passed, 4 skipped (baseline + new tests; fable catalog entry stashed for the run).
  • preflight emits generic build-from hints for all project images (sample above).

Deferred

Nothing from the schema/resolver/test was deferred. Note: services/openai-agent and services/hermes genuinely have no in-repo Dockerfile (operator/third-party built) — handled honestly via build.external, not forced into a phantom context.

🤖 Generated with Claude Code

…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>
@AlienWalker1995
AlienWalker1995 merged commit 7e18a93 into main Jul 25, 2026
3 checks passed
@AlienWalker1995
AlienWalker1995 deleted the feat/manifest-build-field branch July 25, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant