Files
rose-ash/shared
giles dc7aa709bd review quick-wins: JIT gate, crash guards, crit-2 signal-return, regen repair
Server (sx_server.ml):
- HTTP mode: JIT hook now opt-in via SX_SERVING_JIT, matching epoch mode
  (was unconditional — live serving-JIT miscompiles J1/J2/J3 de-risked)
- command channel: malformed/non-ASCII line returns an error response
  instead of killing the shared process (C1/C1b)
- response cache: soft error pages no longer cached (S4);
  http_render_page returns (html, is_error)

Kernel spec + regen:
- crit-2: signal-return frame stored the saved kont under :f but the reader
  looked up "saved-kont" — handler value became the whole program's result
  and the covering test passed vacuously. Fixed; raise-continuable now also
  resumes at the raise site (rest-k, not unwound-k), mirroring signal-condition
- quasiquote: R7RS longhand unquote-splicing aliased to splice-unquote
  (used to serialize literally — silent zero-splice)
- guard: re-raise sentinel gensym'd per execution (was forgeable by any
  (list '__guard-reraise__ x) value)
- do: IIFE-head form no longer misparses as a Scheme do-loop
- render: area/base/embed/param/track added to HTML_TAGS (were void-only
  and rendered as Undefined symbol)
- REGEN REPAIR: checked-in sx_ref.ml carried hand-written additions that
  every regeneration silently lost (let-values/define-values/delay/
  delay-force registrations, AdtValue define-type) plus 5 regen blockers
  (arrow-name mangling, 3-arg get, &rest defines, HO-position helper refs,
  transpiler prim-table gaps). Moved into bootstrap.py FIXUPS/skips and the
  transpiler prim table — regen is now reproducible, compiles, and tests
  at baseline (CI Dockerfile.test steps 3-4 could not previously have
  produced a compiling kernel)

Primitives:
- contains?: dict key-check arm per its spec doc
- expt: promotes to float on int63 overflow ((expt 2 100) returned 0)
- mcp_tree parity with sx_primitives: get (Integer indices + 3-arg default),
  split (literal substring, was char-class — the historical gotcha lived
  here), empty? on ""/{}, contains?, equal?, keyword-name, char-code
  (Integer), parse-number (Integer-aware)

Python/docs:
- shared/sx/boundary.py: dead validation now logs a one-time WARNING instead
  of silently no-oping (full revival gated: tier-1 declarations deleted and
  SX_BOUNDARY_STRICT=1 is live in production compose)
- CLAUDE.md: canonical reference now points at spec/*.sx; island authoring
  rules corrected (let IS sequential, bodies ARE implicit begin)

Verification: full suite 5762 passed / 274 failed — fail set byte-identical
to the pre-change baseline (273 in-progress hs-* + pre-existing r7rs radix
shadow). All repros verified fixed on both the native binary and the rebuilt
WASM browser kernel. Review findings: /tmp/sx-review/*.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 13:49:43 +00:00
..

Shared

Shared infrastructure, models, contracts, services, and templates used by all five Rose Ash microservices (blog, market, cart, events, federation). Included as a git submodule in each app.

Structure

shared/
  db/
    base.py                 # SQLAlchemy declarative Base
    session.py              # Async session factory (get_session, register_db)
  models/                   # Canonical domain models
    user.py                 # User
    magic_link.py           # MagicLink (auth tokens)
    (domain_event.py removed — table dropped, see migration n4l2i8j0k1)
    kv.py                   # KeyValue (key-value store)
    menu_item.py            # MenuItem (deprecated — use MenuNode)
    menu_node.py            # MenuNode (navigation tree)
    container_relation.py   # ContainerRelation (parent-child content)
    ghost_membership_entities.py  # GhostNewsletter, UserNewsletter
    federation.py           # ActorProfile, APActivity, APFollower, APFollowing,
                            # RemoteActor, APRemotePost, APLocalPost,
                            # APInteraction, APNotification, APAnchor, IPFSPin
  contracts/
    dtos.py                 # Frozen dataclasses for cross-domain data transfer
    protocols.py            # Service protocols (Blog, Calendar, Market, Cart, Federation)
    widgets.py              # Widget types (NavWidget, CardWidget, AccountPageWidget)
  services/
    registry.py             # Typed singleton: services.blog, .calendar, .market, .cart, .federation
    blog_impl.py            # SqlBlogService
    calendar_impl.py        # SqlCalendarService
    market_impl.py          # SqlMarketService
    cart_impl.py            # SqlCartService
    federation_impl.py      # SqlFederationService
    federation_publish.py   # try_publish() — inline AP publication helper
    stubs.py                # No-op stubs for absent domains
    navigation.py           # get_navigation_tree()
    relationships.py        # attach_child, get_children, detach_child
    widget_registry.py      # Widget registry singleton
    widgets/                # Per-domain widget registration
  infrastructure/
    factory.py              # create_base_app() — Quart app factory
    cart_identity.py        # current_cart_identity() (user_id or session_id)
    cart_loader.py          # Cart data loader for context processors
    context.py              # Jinja2 context processors
    jinja_setup.py          # Jinja2 template environment setup
    urls.py                 # URL helpers (blog_url, market_url, etc.)
    user_loader.py          # Load current user from session
    http_utils.py           # HTTP utility functions
  events/
    bus.py                  # emit_activity(), register_activity_handler()
    processor.py            # EventProcessor (polls ap_activities, runs handlers)
    handlers/               # Shared activity handlers
      container_handlers.py #   Navigation rebuild on attach/detach
      login_handlers.py     #   Cart/entry adoption on login
      order_handlers.py     #   Order lifecycle events
      ap_delivery_handler.py #  AP activity delivery to follower inboxes (wildcard)
  utils/
    __init__.py
    calendar_helpers.py     # Calendar period/entry utilities
    http_signatures.py      # RSA keypair generation, HTTP signature signing/verification
    ipfs_client.py          # Async IPFS client (add_bytes, add_json, pin_cid)
    anchoring.py            # Merkle trees + OpenTimestamps Bitcoin anchoring
    webfinger.py            # WebFinger actor resolution
  browser/
    app/                    # Middleware, CSRF, errors, Redis caching, authz, filters
    templates/              # ~300 Jinja2 templates shared across all apps
  containers.py             # ContainerType, container_filter, content_filter helpers
  config.py                 # YAML config loader
  log_config/setup.py       # Logging configuration (JSON formatter)
  static/                   # Shared static assets (CSS, JS, images, FontAwesome)
  editor/                   # Koenig (Ghost) rich text editor build
  alembic/                  # Database migrations

Key Patterns

  • App factory: All apps call create_base_app() which sets up DB sessions, CSRF, error handling, event processing, logging, widget registration, and domain service wiring.
  • Service contracts: Cross-domain communication via typed Protocols + frozen DTO dataclasses. Apps call services.calendar.method(), never import models from other domains.
  • Service registry: Typed singleton (services.blog, .calendar, .market, .cart, .federation). Apps wire their own domain + stubs for others via register_domain_services().
  • Activity bus: emit_activity() writes to ap_activities table in the caller's transaction. EventProcessor polls pending activities and dispatches to registered handlers. Internal events use visibility="internal"; federation activities use visibility="public" and are delivered to follower inboxes by the wildcard delivery handler.
  • Widget registry: Domain services register widgets (nav, card, account); templates consume via widgets.container_nav, widgets.container_cards.
  • Cart identity: current_cart_identity() returns {"user_id": int|None, "session_id": str|None} from the request session.

Alembic Migrations

All apps share one PostgreSQL database. Migrations are managed here and run from the blog app's entrypoint (other apps skip migrations on startup).

alembic -c shared/alembic.ini upgrade head