Skip to content

feat(fountain): the fountain lexicon — workload primitives as typed estate - #1227

Open
lex00 wants to merge 6 commits into
mainfrom
lexicon-fountain
Open

feat(fountain): the fountain lexicon — workload primitives as typed estate#1227
lex00 wants to merge 6 commits into
mainfrom
lexicon-fountain

Conversation

@lex00

@lex00 lex00 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Implements #1217 (design capture there; upstream deps fountain#136–142 all merged).

Types the workload layer of fountain — the three kinds fountain apply reconciles (Environment, Vault, Agent), generated from the served OpenAPI spec (rolling model, like fly). Conversations are deliberately not declarables; they map to ops.

  • Types: generated from the real spec — includes upstream's freshly merged metadata, skills ref, allowed_vault_ids, and typed networking_config
  • Serializer: fountain-native multi-doc YAML (fountain apply -f compatible for eject) + a fountain-plan.json sidecar for the applier
  • Ops: fountainApply (direct-REST reconciler: create/update by name, entity-ref→id resolution, secrets upsert via sub-resource, opt-in owned-only prune on managed-by: chant) and fountainRun (conversation to terminal status, terminate on deadline). E2E-validated against a real local fountain: create, idempotent update, ref resolution, write-only secrets, prune under FK constraints
  • Lint: FTN001 no-secret-literals (AST), FTN010 networking-explicit + FTN012 no-cloud-credential-env (post-synth)
  • Rolling baseline: surface.snapshot.json seeded at fountain main; bundle script wired
  • Docs: starlight site in the unified build + core sidebar

check-lexicon tier 1: 17/17. Tests: 33/33. Matrix entry for the weekly upgrade cron is a follow-up after #1226 lands (its consistency test then enforces the wiring).

🤖 Generated with Claude Code

lex00 and others added 6 commits July 29, 2026 22:16
Types the workload layer of BinaryBourbon/fountain — the three kinds
'fountain apply' reconciles (Environment, Vault, Agent) — generated
from the served OpenAPI spec (rolling model, like fly). Conversations
are deliberately not declarables; they map to ops.

- spec: fetch from /api/openapi.json (live endpoint 404s on the
  currently deployed instance; cache seeded from a local checkout's
  'mix openapi.spec.json' until the endpoint ships)
- serializer: fountain-native multi-doc YAML (apiVersion
  fountain.dev/v1), fountain-apply-compatible for eject; cross-resource
  refs serialize to entity names
- lint: FTN001 no-secret-literals (AST, credential shapes inside
  fountain constructors); post-synth FTN010 networking-explicit and
  FTN012 no-cloud-credential-env
- docs: starlight site wired into the unified build and the core
  sidebar under Lexicons
- check-lexicon tier 1: 17/17; tests 22/22

Design source: #1217. Upstream deps tracked there (fountain#136-142,
fountain#148 token-only secrets).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The serializer gains a fountain-plan.json sidecar (entity name ->
{kind, spec}) beside the ejectable YAML, so the applier needs no YAML
parser — the fly plan.json pattern.

fountainApply: direct-REST reconciler (create-if-new / update-by-name),
Environment -> Vault -> Agent order with agent environment refs resolved
entity-name -> live id (mirroring the CLI's apply.go). spec.secrets
upsert through the sub-resource, upsert-always since values are
write-only upstream (fountain#148's reference model would make this a
plain diff). Owned-only prune behind an opt-in flag, keyed on the
metadata managed-by=chant marker, reverse kind order.

fountainRun: conversations as ops, not declarables — resolve agent by
name, POST the conversation, poll to a terminal status, terminate on
deadline so a hung run never outlives the op.

Endpoint/token: args > FOUNTAIN_ENDPOINT/FOUNTAIN_TOKEN > hosted
default. Injectable http for tests: 33/33, tier 1 still 17/17.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the package-cli/bundle entry the surface machinery shells out to,
and seeds surface.snapshot.json at fountain main 4c06dff — including
the just-merged allowed_vault_ids (fountain#136). This is the baseline
the weekly rolling check diffs against once fountain joins the upgrade
matrix (after #1218's consistency check lands).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pstream

fountain#139 merged (9e6b605): networking_config gains an
allowed_hosts schema. Second live exercise of the rolling model.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI's docs build and check jobs run the lexicon's generate, which
fetched the live spec: the hosted instance currently 404s the endpoint
(deploy lag) behind a self-signed cert, so every CI run failed. The
spec now falls back to a committed snapshot
(src/spec/fountain-openapi.snapshot.json, refreshed alongside
surface.snapshot.json when upstream moves), and a live fetch that
returns a non-JSON body is rejected rather than silently replacing it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nifest.json

Matches fly's prepack sequence (generate, bundle, validate, build).
CI's docs build runs prepack then docs-cli from a clean checkout;
without the bundle step dist/manifest.json does not exist and the
docs generator ENOENTs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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