Skip to content

Exploration: .affex — face-bridging file format for cross-exolanguage interop #84

Description

@hyperpolymath

⚖️ Closure rule — requirements-target issue

This issue is the requirements-target for .affex. It does not close when a PR lands, when a draft spec is written, or when implementation begins. It closes only when Claude and the user explicitly and mutually agree, in a recorded exchange, that the issue's spec has been satisfied by the work that has landed.

Until that mutual agreement: this issue stays open as the canonical definition of done for .affex. PRs / drafts / partial implementations link back to it but do not close it.

This rule applies to every requirements-target-labelled issue in this repo and (per the user's request) to the corresponding project-board state.

Type: Exploration / sketch idea, not yet specified.
Surfaced by: cross-referenced from hyperpolymath/accessibility-everywhere PR #16 work, 2026-05-03. Externalising it here so it survives across Claude Code sessions and can be developed in a dedicated thread.

Problem statement

AffineScript supports multiple faces (canonical, cafe, jaffa, lucid, pseudo, rattle, …). All faces lower to canonical, so the compiler doesn't care — but humans reading code in a face they don't speak are stuck.

"Someone fluent in canonical and rattle looks at lucid or pseudo and can't tell what is going on."

The friction shows up:

  • At review time: PRs touching files in unfamiliar faces become opaque to teammates who use different faces.
  • At transpile time: when sections need to move between faces (e.g. rattle → canonical, or canonical → cafe for ergonomics), the writer has to mentally re-encode the whole file.
  • At onboarding: a programmer joining an estate has to learn N faces just to read existing code, even though semantically there is one language.

Half-recalled sketch idea: .affex

Original framing (user, paraphrased): a file extension and file type — .affex = "affine exolanguage", in the sense that the named faces (rattle, lucid, etc.) are exolanguage variants of canonical AffineScript. The file format would have properties analogous to ABI/FFI conventions, but applied between AffineScript faces rather than between distinct languages.

Goals:

  • Continuity of coding in .affine files for the programmer using their preferred face — no need to leave their face to interop.
  • ABI/FFI-like benefits between faces — predictable bridging contract instead of ad-hoc translation.
  • Non-canonical-language-system support — i.e., lifts the bridging concern out of canonical itself and into a dedicated layer.

Speculative shapes (not specified, just where the design space looks open)

These are Claude's extrapolations from the problem statement — not part of the original sketch — to seed the dedicated discussion thread:

  1. Rosetta-stone listing: a .affex file holds the same source in N faces side-by-side (or as a primary face + per-other-face footnotes). Reader picks the column they speak. Auto-generatable from the lowering pass since the compiler already has the bidirectional info.
  2. Canonical-equivalence annotations: a .affex file pairs face source with the canonical AST it lowers to, with shape correspondences marked (which canonical decl maps to which face span). Helps a reader translate small windows on demand instead of the whole file.
  3. Face-interop manifest: .affex declares how a face's idioms (e.g. rattle's indentation blocks) correspond to canonical structures, so tooling can render any .affine in any reader-preferred face. The "ABI" analogue: contract for round-tripping syntax.
  4. Mixed: an .affex file can both be hand-written (for tricky cross-face boundaries the compiler can't auto-generate cleanly) and be auto-generated (for bulk).

Where this fits in the cardinal stance

The cardinal stance for the AffineScript ecosystem is "affine is the heart" — canonical is the centre, faces are peripheral. .affex reinforces rather than competes with this: canonical stays the lowering target, faces remain surface conveniences, and .affex is a strictly additive bridging layer that makes the periphery liveable without diluting the core.

What this is NOT

  • Not a Affine↔non-Affine FFI mechanism. That's a separate concern (cross-package imports / extern decls), currently handled by per-package Externs.affine shims in the accessibility-everywhere migration. .affex does not solve or replace that.
  • Not blocking any current migration. Estates working in a single face (e.g. accessibility-everywhere, all canonical per its convention lock) feel zero friction here. .affex only earns its keep once an estate has multi-face adoption.
  • Not a compiler concern. The compiler already lowers all faces to canonical AST — it doesn't need .affex. The audience is humans.

What's needed before this can be built

  • Pick one of the speculative shapes above, or define a new one
  • File extension policy: is .affex parsed by the compiler at all, or is it a docs/tooling artifact only?
  • If compiler-aware: how does it relate to the existing face lowering pipeline?
  • If tooling-only: which tool generates / consumes it (LSP? CLI? web renderer)?
  • Generation strategy: hand-written, auto, or both?
  • Estate-scope: per-package, per-monorepo, or freestanding?

Status

Parked. Not blocking any migration. Will be developed in a dedicated thread when a concrete trigger surfaces (probably first multi-face adoption inside an estate).

🤖 Drafted by Claude Code in a session where the original sketch resurfaced; externalised to this issue so it cannot get lost again. See feedback_affinescript_conventions.md "mentioned-but-undefined" section in the user's auto-memory for the local pointer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew capability or improvement to existing behaviourmajorMajor issue — significant scope, broader impact than a feature/bugquestionFurther information is requestedrequirements-targetRequirements-target issue — only closes when Claude and user mutually agree the spec is satisfied

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions