Restructure boundary specs: move app-specific I/O out of language contract
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m42s

boundary.sx now contains only generic web-platform I/O primitives that
any SX host would provide (current-user, request-arg, url-for, etc.).

Moved to boundary-app.sx (deployment-specific):
- Inter-service: frag, query, action, service
- Framework: htmx-request?, g, jinja-global
- Domain: nav-tree, get-children, relations-from

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 18:04:53 +00:00
parent 6312eb66a2
commit 3574f7e163
2 changed files with 96 additions and 79 deletions

View File

@@ -1,9 +1,12 @@
;; ========================================================================== ;; ==========================================================================
;; boundary-app.sx — Deployment-specific boundary declarations ;; boundary-app.sx — Deployment-specific boundary declarations
;; ;;
;; Layout context I/O primitives for THIS deployment's service architecture. ;; I/O primitives specific to THIS deployment's architecture:
;; inter-service communication, framework bindings, domain concepts,
;; and layout context providers.
;;
;; These are NOT part of the SX language contract — a different deployment ;; These are NOT part of the SX language contract — a different deployment
;; would declare different layout contexts here. ;; would declare different primitives here.
;; ;;
;; The core SX I/O contract lives in boundary.sx. ;; The core SX I/O contract lives in boundary.sx.
;; Per-service page helpers live in {service}/sx/boundary.sx. ;; Per-service page helpers live in {service}/sx/boundary.sx.
@@ -11,7 +14,92 @@
;; -------------------------------------------------------------------------- ;; --------------------------------------------------------------------------
;; Layout context providers — deployment-specific I/O ;; Inter-service communication — microservice architecture
;; --------------------------------------------------------------------------
(define-io-primitive "frag"
:params (service frag-type &key)
:returns "string"
:async true
:doc "Fetch cross-service HTML fragment."
:context :request)
(define-io-primitive "query"
:params (service query-name &key)
:returns "any"
:async true
:doc "Fetch data from another service via internal HTTP."
:context :request)
(define-io-primitive "action"
:params (service action-name &key)
:returns "any"
:async true
:doc "Call an action on another service via internal HTTP."
:context :request)
(define-io-primitive "service"
:params (service-or-method &rest args &key)
:returns "any"
:async true
:doc "Call a domain service method. Two-arg: (service svc method). One-arg: (service method) uses bound handler service."
:context :request)
;; --------------------------------------------------------------------------
;; Framework bindings — Quart/Jinja2/HTMX specifics
;; --------------------------------------------------------------------------
(define-io-primitive "htmx-request?"
:params ()
:returns "boolean"
:async true
:doc "True if current request has HX-Request header."
:context :request)
(define-io-primitive "g"
:params (key)
:returns "any"
:async true
:doc "Read a value from the Quart request-local g object."
:context :request)
(define-io-primitive "jinja-global"
:params (key &rest default)
:returns "any"
:async false
:doc "Read a Jinja environment global."
:context :request)
;; --------------------------------------------------------------------------
;; Domain concepts — navigation, relations
;; --------------------------------------------------------------------------
(define-io-primitive "nav-tree"
:params ()
:returns "list"
:async true
:doc "Navigation tree as list of node dicts."
:context :request)
(define-io-primitive "get-children"
:params (&key parent-type parent-id)
:returns "list"
:async true
:doc "Fetch child entities for a parent."
:context :request)
(define-io-primitive "relations-from"
:params (entity-type)
:returns "list"
:async false
:doc "List of RelationDef dicts for an entity type."
:context :config)
;; --------------------------------------------------------------------------
;; Layout context providers — per-service header/page context
;; -------------------------------------------------------------------------- ;; --------------------------------------------------------------------------
;; Shared across all services (root layout) ;; Shared across all services (root layout)

View File

@@ -5,7 +5,7 @@
;; This is the LANGUAGE contract — not deployment-specific. ;; This is the LANGUAGE contract — not deployment-specific.
;; ;;
;; Pure primitives (Tier 1) are declared in primitives.sx. ;; Pure primitives (Tier 1) are declared in primitives.sx.
;; Deployment-specific I/O (layout contexts) lives in boundary-app.sx. ;; Deployment-specific I/O lives in boundary-app.sx.
;; Per-service page helpers live in {service}/sx/boundary.sx. ;; Per-service page helpers live in {service}/sx/boundary.sx.
;; ;;
;; Format: ;; Format:
@@ -28,38 +28,11 @@
;; -------------------------------------------------------------------------- ;; --------------------------------------------------------------------------
;; Tier 2: Core I/O primitives — async, side-effectful, need host context ;; Tier 2: Core I/O primitives — async, side-effectful, need host context
;;
;; These are generic web-platform I/O that any SX web host would provide,
;; regardless of deployment architecture.
;; -------------------------------------------------------------------------- ;; --------------------------------------------------------------------------
;; Cross-service communication
(define-io-primitive "frag"
:params (service frag-type &key)
:returns "string"
:async true
:doc "Fetch cross-service HTML fragment."
:context :request)
(define-io-primitive "query"
:params (service query-name &key)
:returns "any"
:async true
:doc "Fetch data from another service via internal HTTP."
:context :request)
(define-io-primitive "action"
:params (service action-name &key)
:returns "any"
:async true
:doc "Call an action on another service via internal HTTP."
:context :request)
(define-io-primitive "service"
:params (service-or-method &rest args &key)
:returns "any"
:async true
:doc "Call a domain service method. Two-arg: (service svc method). One-arg: (service method) uses bound handler service."
:context :request)
;; Request context ;; Request context
(define-io-primitive "current-user" (define-io-primitive "current-user"
@@ -69,13 +42,6 @@
:doc "Current authenticated user dict, or nil." :doc "Current authenticated user dict, or nil."
:context :request) :context :request)
(define-io-primitive "htmx-request?"
:params ()
:returns "boolean"
:async true
:doc "True if current request has HX-Request header."
:context :request)
(define-io-primitive "request-arg" (define-io-primitive "request-arg"
:params (name &rest default) :params (name &rest default)
:returns "any" :returns "any"
@@ -97,13 +63,6 @@
:doc "Read a URL view argument from the current request." :doc "Read a URL view argument from the current request."
:context :request) :context :request)
(define-io-primitive "g"
:params (key)
:returns "any"
:async true
:doc "Read a value from the Quart request-local g object."
:context :request)
(define-io-primitive "csrf-token" (define-io-primitive "csrf-token"
:params () :params ()
:returns "string" :returns "string"
@@ -134,22 +93,6 @@
:doc "Service URL prefix for dev/prod routing." :doc "Service URL prefix for dev/prod routing."
:context :request) :context :request)
;; Navigation and relations
(define-io-primitive "nav-tree"
:params ()
:returns "list"
:async true
:doc "Navigation tree as list of node dicts."
:context :request)
(define-io-primitive "get-children"
:params (&key parent-type parent-id)
:returns "list"
:async true
:doc "Fetch child entities for a parent."
:context :request)
;; Config and host context (sync — no await needed) ;; Config and host context (sync — no await needed)
(define-io-primitive "app-url" (define-io-primitive "app-url"
@@ -170,21 +113,7 @@
:params (key) :params (key)
:returns "any" :returns "any"
:async false :async false
:doc "Read a value from app-config.yaml." :doc "Read a value from host configuration."
:context :config)
(define-io-primitive "jinja-global"
:params (key &rest default)
:returns "any"
:async false
:doc "Read a Jinja environment global."
:context :request)
(define-io-primitive "relations-from"
:params (entity-type)
:returns "list"
:async false
:doc "List of RelationDef dicts for an entity type."
:context :config) :context :config)