Foundation architecture
Which part does what?
In the appointment example, 10:00 comes back as the first proposal. Several parts contribute: one describes the input, another compares time intervals, and others check rules and order the valid options. The website then displays the result. No calendar entry has been created.
The Rust code is divided into packages called crates. These boundaries help define a rule in one place and apply it consistently across applications. The following sections trace the path through the existing code.
Deutsch · From an appointment request to CPIR
From input to proposal
- Check the inputs. An application supplies a structured
PlanningRequest, which reaches the planner throughcerebri-core. Input validation checks the duration, target object, search boundaries and planning grants, among other things. Missing required information stops the search. - Try possible times. The planner generates starts on the specified grid. Time
operations from
cerebri-temporaland rules fromcerebri-constraintshelp check whether a candidate fits. In the example, four starts fail because they overlap the existing appointment. - Compare the remaining options.
cerebri-preferencescalculates comparison values, such as distance from a supplied preferred time. The planner uses these values in its fixed ordering. The example has no preferred time, so the earlier start breaks the tie between 10:00 and 10:15. - Return the result. A
PlanningResultcontains candidates, rejection reasons and information about the searched space.cerebri-corereturns it to the calling application. The proposed placements are not permission to execute them.
cerebri-core is the shared entry point for applications. The actual search lives in
cerebri-planner; Core forwards the call there. REST and the Node bridge therefore use
the same planner.
Where the rules live in the code
| Responsibility | Code that owns it |
|---|---|
| Represent identifiers, provenance and states such as known or missing | cerebri-types |
| Handle instants, duration, intervals and time zones | cerebri-temporal |
| Represent and check facts and required rules | cerebri-constraints |
| Resolve supplied preferences and calculate comparison values | cerebri-preferences |
| Represent semantic information such as urgency with its provenance; unused in the appointment example | cerebri-semantics |
| Define CPIR inputs, search candidates and check transitions through authorization | cerebri-planner |
| Give applications shared functions for input validation, planning and temporal diagnostics | cerebri-core |
| Recheck authorized actions before execution and pass them to an adapter | cerebri-integrations |
Planning requests and plan stages belong to cerebri-planner. The shared foundations
in cerebri-types do not contain all planning logic. The executor and the execution
record interface ActionLedger belong to cerebri-integrations.
How applications reach the planner
The REST application receives requests and calls Core. The Node binding currently starts a Rust process bridge. Both paths use the Rust computation. Neither an HTTP call nor a JavaScript call adds a separate planning rule. There is no execution endpoint for calendar changes.
The Lab sends requests to the API and displays its responses. The public website works differently: when the pages are built, the build script runs Rust examples and saves their results for display. Visiting the website does not start a new planner search. Both interfaces present results rather than calculating a second ranking.
Dependencies, data flow and validation steps
These three relationships answer different questions:
- Code dependency: Which package may use another package's types or functions?
For example,
cerebri-integrationsimports types fromcerebri-planner. This does not mean that the planner calls the executor. - Data flow: Where do requests and results go? A Lab request travels through the API and Core to the planner; the result returns through the same interfaces.
- Validation step: What must pass before a plan reaches the next stage? A proposal
becomes a
ValidatedPlanonly after validation succeeds.
Selected code dependencies are:
cerebri-apiusescerebri-core.cerebri-coreusescerebri-plannerandcerebri-temporal.cerebri-plannerusescerebri-constraintsandcerebri-preferences, among others.cerebri-constraintsusescerebri-temporal.cerebri-preferencesusescerebri-types.cerebri-integrationsusescerebri-planner.
This list describes imports, not runtime calls. The core never imports integrations or ML.
The repository checker enforces an explicit crate
allowlist; Cargo rejects cycles. The foundation crates cerebri-types and
cerebri-temporal do not depend on higher Cerebri packages.
Why a proposal cannot be executed yet
The planner has checked and compared possible placements. Before making a change, an application must still validate the complete plan against the current context, translate it into actions and have its permissions checked. These steps live in the lifecycle code. A trusted application supplies the current permissions and any required confirmations.
Only an AuthorizedActionPlan can be passed to the
executor. Even then, it rechecks
the data and permissions immediately before a change. A previously suitable time might
now be occupied, or a permission might have been withdrawn.
The existing adapters demonstrate this process with in-memory data. Production calendar connections and production authentication are not implemented yet. The website example stops at the proposal.
Technical details of the plan stages
Lifecycle: PlanningRequest -> ProposedPlan -> ValidatedPlan -> ActionPlan -> AuthorizedActionPlan -> ExecutionResult. Proposal creation is public and untrusted. Later stages have private fields, controlled conversions and no Deserialize implementation. The executor's type signature rejects all three earlier plan stages.
Facts, constraints, semantic evidence, preferences and permissions use different types. The request captures a policy snapshot; live authorization comes from a trusted application, never from the REST request. READ, PLAN and per-object EXECUTE grants are separate. Grants bind action kind, object, calendar and integration.
Execution first atomically claims the plan and all action keys in ActionLedger, then rechecks the complete context, source revision, current policy, planning capability, execution grants, confirmation and adapter capabilities before the first provider call. Provider apply must enforce object revisions atomically. Processing stops on the first failure; remaining actions are Skipped. Successful earlier writes are not rolled back. A lost ledger completion or uncertain provider response is RecoveryRequired. Claimed keys remain blocked. In-memory implementations demonstrate this contract but do not survive restart; durability, reconciliation and retry policy require a later application adapter.
Plan IDs are SHA-256 digests of canonicalized request/placements; action IDs and idempotency keys add a stable action index. Confirmation binds the exact plan, including policy/snapshot. A changed context requires a new validation and authorization.
Where future learning methods belong
cerebri-ml contains model and dataset metadata, plus interfaces for registration and inference. Those definitions do not provide a trained model or a running learning method. The current planner does not depend on this crate.
The learning work under research/ sits outside the production workspace. Production code must not import it. Later, learned methods could help search for options or compare valid ones. Facts, required rules and execution permissions would still need to be protected by explicit checks.
Learning path and research questions: What later methods could learn and what already exists today.
Search method and current limits
The search space is a single Event placed at horizon.start + k * granularity, for nonnegative integer k, with a fixed requested duration and end <= horizon.end. Default granularity in the example is 900 seconds. Every admitted position is checked against scope, immutable facts and hard constraints before ranking.
Cost is absolute distance in seconds to the preferred start from the strongest preference source; no preference means zero. Precedence is explicit current request, session context, personal learned, global learned, default. Equal-source preferences select the earlier time. Tie-breaks: cost, mutation count, total shift seconds, start, object ID. Only a fully exhausted grid with a solution receives ProvenOptimal. This proves optimality only within that grid and objective, never over continuous time or future repair spaces. Exhausted empty search is Complete/NoSolution. Interrupted search is BestFound; if still empty, NeedsRelaxation means the budget/declared search must be reconsidered.
All Event/Task times in the supplied context conservatively block overlap regardless of calendar/resource. Multi-resource semantics and cross-calendar concurrency are deferred. The baseline searches one target. Lifecycle validation can validate explicit multi-event placements, but there is no batch search or safe provider ordering for dependent moves. Move preserves duration. Update/Delete action vocabulary is reserved; CANCEL intent is not automatically translated into deletion. Recurrence constraints fail closed.
ConflictSet contains actual rejected constraints/facts for the declared grid; it is not minimal or irreducible. Fixed deterministic budgets and exhaustive small-domain interval tests avoid uncontrolled timing and randomness.
CPIR reference · Testing · Deutsch
Core also imports temporal directly for typed diagnostics; see Temporal Core.
