Butkhuzi Shared Shell Contract
This document describes the smallest truthful shared shell that Butkhuzi still depends on today.
It is not an aspirational design. It is the current extraction seam.
Gateway behavior
Current gateway owner:
Current seam:
BUTKHUZI_SERVICE_URL ?? TENDERS_SERVICE_URL
Current gateway route family:
GET /butkhuzi/normsGET /butkhuzi/suggestGET /butkhuzi/searchPOST /butkhuzi/upsertPOST /butkhuzi/chunks/rebuild
Verdict:
- must remain shared
Why:
- this is already the correct public extraction seam
- route shape should remain stable while runtime ownership changes behind it
Auth behavior
Gateway auth behavior:
- services/api/src/routes/butkhuzi.ts uses gateway auth for write endpoints
Service runtime auth behavior:
svc-tendersshellrequireServiceAuthverifies bearer tokens- upstream principal resolution still happens through
svc-auth/auth/me
Evidence:
Verdict:
- must remain shared
Why:
- auth/session/account ownership is outside Butkhuzi
- Butkhuzi should consume shared identity/auth truth, not replace it
Shared auth and identity expectations
Current expectations:
- bearer token arrives through gateway and is forwarded upstream
- shared auth service resolves principal via
/auth/me - service runtime expects an active resolved principal for protected writes
Verdict:
- must remain shared
Notes:
- Butkhuzi does not own account/session logic
- Butkhuzi does not own principal resolution logic
Shared parser and helper expectations
Current helper surface adapted into Butkhuzi routes:
parsePositiveIntparseOptionalIntparseOptionalStringparseOptionalUpperrequireServiceAuth
Adaptation layer:
Verdict by helper:
requireServiceAuth: must remain shared- primitive parser helpers: can be wrapped later
Why:
- auth ingress belongs to shared shell
- simple parser helpers are currently shell-sourced only for convenience and consistency, not because they are inherently cross-domain
Admin / KES-adjacent integration assumptions
Real current integration:
- Butkhuzi is actively consumed through KES-facing portal workflows
- portal client wrappers live in apps/web/src/portal/api.ts
- strongest UI consumer is the KES page, not a dedicated Butkhuzi app
Verdict:
- can be wrapped later
Why:
- KES consumption is a product integration dependency, not proof that Butkhuzi belongs in the tender runtime forever
What remains shared on purpose
- gateway route family
- gateway env seam
- gateway auth middleware
- service-shell auth/principal resolution behavior
- bearer-token forwarding expectations
What can move later
- parser helper implementations if an extracted runtime wants to own them directly
- Butkhuzi-specific validation and contracts, which are now already local to the domain
- root compatibility delegation, once a standalone runtime exists
What remains unresolved
- whether portal/client types should eventually be shared from a common contract package or stay intentionally duplicated client-side
- when migration ownership should move from
svc-tendersto a future Butkhuzi runtime
Takeaway
The truthful shared shell for Butkhuzi is small:
- gateway seam
- shared auth/identity ingress
- minimal parser/helper adaptation
That is a good position for later runtime/bootstrap prep.