BUCKYVERSE

Date: 2025-03-10

Status

Accepted

Context

Our book building system requires robust concurrency, fault tolerance, and maintainability. The previous Ruby implementation (ADR-0002) served well for initial development but has limitations in:

  1. Concurrent processing of multiple formats
  2. Process supervision and fault recovery
  3. Memory management for large books
  4. System scalability
  5. Type safety and pattern matching

Decision

We will implement the entire book building system in Elixir, leveraging:

1. OTP Architecture

# Application supervision tree
defmodule Codexis.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Codexis.BuildManager, []},
      {Codexis.Assets.Registry, []},
      {Codexis.Assets.Cache, []},
      {DynamicSupervisor, strategy: :one_for_one, name: Codexis.BuilderSupervisor},
      {DynamicSupervisor, strategy: :one_for_one, name: Codexis.ValidatorSupervisor},
      {Phoenix.PubSub, name: Codexis.PubSub}
    ]

    opts = [strategy: :one_for_one, name: Codexis.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

2. Concurrent Processing

defmodule Codexis.FormatGenerator do
  def generate_formats(content, assets, metadata, options) do
    options
    |> get_builders()
    |> Task.async_stream(fn {format, builder} ->
      {format, builder.build(content, assets, metadata)}
    end)
    |> Enum.reduce(%{}, fn {:ok, {format, result}}, acc ->
      Map.put(acc, format, result)
    end)
  end
end

3. Pattern Matching

defmodule Codexis.Builder do
  @callback build(content :: Content.t(), options :: Keyword.t()) :: {:ok, Output.t()} | {:error, term()}
  
  defmacro __using__(_opts) do
    quote do
      @behaviour Codexis.Builder
      
      def build(content, options \\ []) do
        with {:ok, validated} <- validate_content(content),
             {:ok, processed} <- process_content(validated),
             {:ok, output} <- generate_output(processed, options) do
          {:ok, output}
        end
      end
    end
  end
end

4. Process Isolation

defmodule Codexis.BuildManager do
  use GenServer
  
  def build(content_path, options \\ []) do
    GenServer.call(__MODULE__, {:build, content_path, options}, :infinity)
  end
  
  def handle_call({:build, path, options}, from, state) do
    Task.start_link(fn ->
      result = do_build(path, options)
      GenServer.reply(from, result)
    end)
    
    {:noreply, state}
  end
end

5. Error Handling

defmodule Codexis.ErrorHandler do
  def handle_error({:error, :validation_failed} = error) do
    Logger.error("Validation failed", error: error)
    {:error, :validation_failed}
  end
  
  def handle_error({:error, :build_failed, details} = error) do
    Logger.error("Build failed", error: error, details: details)
    notify_admin(error)
    {:error, :build_failed}
  end
end

Consequences

Positive

  1. Concurrency: Efficient parallel processing of formats
  2. Fault Tolerance: OTP supervision ensures system stability
  3. Maintainability: Clear module structure and behaviors
  4. Type Safety: Pattern matching catches errors early
  5. Scalability: Ready for distributed processing
  6. Memory Management: Better handling of large books
  7. Testing: Property-based testing with ExUnit

Negative

  1. Learning Curve: Team needs to learn Elixir/OTP
  2. Ecosystem: Some Ruby gems need Elixir equivalents
  3. Migration Effort: Existing code needs porting
  4. Integration: External tools need Elixir wrappers

Migration Strategy

  1. Phase 1: Core Components

    • Port build pipeline
    • Implement OTP supervision
    • Create format builders
  2. Phase 2: Supporting Systems

    • Asset management
    • Metadata handling
    • Validation system
  3. Phase 3: External Integration

    • WikiJS publishing
    • Tool wrappers
    • CLI interface
  4. Phase 4: Testing & Validation

    • Port test suite
    • Add property-based tests
    • Performance validation

Compliance

Implementation must:

  1. Match or exceed Ruby version capabilities
  2. Maintain backward compatibility
  3. Follow Elixir best practices
  4. Include comprehensive tests
  5. Document all modules

Notes