API reference¶
Every name below is exported from blackboard. Nothing else in the package
is public, and a name outside this list may change without a deprecation.
blackboard ¶
A skeletal blackboard system.
The library supplies the board, the shared structure through which
independent agents contribute to one result, and the control component,
which determines which agents are notified of a change, whether a proposed
write is admitted, whether budgets hold, and when the run has finished. An
application creates a model by supplying its regions, agents, seed,
admission rule, termination predicate, and budgets. The public surface is
the set of names in __all__; every other name is internal.
AdmissionRule
module-attribute
¶
AdmissionRule: TypeAlias = Callable[
[ProposedWrite, "BoardReader"], Accept | Reject
]
The rule the control component calls on every proposed write.
AuditEvent
module-attribute
¶
AuditEvent: TypeAlias = (
RegisterSeeded
| WriteAccepted
| WriteRejected
| NotificationDispatched
| NotificationAcknowledged
| DeadlineExtended
| PresumedFailed
| WakeCapReached
| BudgetReached
| RunClosed
)
Every kind of event the audit records.
NotificationId
module-attribute
¶
NotificationId = NewType('NotificationId', int)
The identifier an acknowledgment or an extension names.
ProposedWrite
module-attribute
¶
ProposedWrite: TypeAlias = (
ProposedContribution | ProposedRegisterWrite
)
A proposed write of either kind, as the admission rule receives it.
RunOutcome
module-attribute
¶
RunOutcome: TypeAlias = (
Complete
| FinishedWithFailures
| BudgetExhausted
| Aborted
)
The four states a run closes in.
TerminationPredicate
module-attribute
¶
TerminationPredicate: TypeAlias = Callable[
["BoardReader"], TerminationDecision
]
The predicate the control component calls when no work is outstanding.
BlackboardError ¶
Bases: Exception
The base of every error this library raises.
Board ¶
Stores contributions in declared regions under one total order.
The board stores content without reading it and never combines two writes. Content comes back by identity: the board does not copy what it stores, so a caller that mutates a stored object changes what every later reader sees. Sequence assignment is the only point where two writes wait on each other, so writes from concurrent threads all succeed with distinct sequence numbers.
declare ¶
Creates a region. A name already declared, of either kind, is refused.
append ¶
append(level: str, content: object) -> int
Adds one contribution to a level and returns its sequence number.
set ¶
Replaces a register's value under the version the caller expects.
A write naming any version other than the register's current one fails: it returns a conflict carrying the current version, takes no sequence number, and leaves the register unchanged. A register never written has version 0.
read_level ¶
read_level(
level: str, from_sequence: int = 0
) -> list[Contribution]
Returns a level's contributions from the sequence bound, inclusive.
read_register ¶
read_register(register: str) -> RegisterState
Returns a register's current value and version.
read_board ¶
read_board(from_sequence: int = 0) -> list[BoardChange]
Returns every write to every region, in sequence order, from the bound.
BoardChange
dataclass
¶
One write to any region, at its position in the total order.
Conflict
dataclass
¶
A register write that failed because the version it named is not current.
Contribution
dataclass
¶
One unit stored in a level, at its position in the total order.
DuplicateRegionError ¶
Bases: BlackboardError
A declaration named a region that already exists.
Level
dataclass
¶
A declaration of a region that accumulates contributions in arrival order.
RegionKindError ¶
Bases: BlackboardError
An operation that takes a level named a register, or the reverse.
Register
dataclass
¶
A declaration of a region that holds one current value under a version.
The control component reads the batch window when a change to this register lands, to schedule its notification. The board ignores it.
RegisterState
dataclass
¶
The current value of a register and the version its write produced.
UndeclaredRegionError ¶
Bases: BlackboardError
An operation named a region that no declaration created.
UnsetRegisterError ¶
Bases: BlackboardError
A register was read before any write gave it a value.
Written
dataclass
¶
A register write the board sequenced, and the version it produced.
Clock ¶
Bases: Protocol
Reads the current instant and arms calls to fire at chosen instants.
call_at ¶
call_at(
when: datetime, call: Callable[[], None]
) -> ScheduledCall
Arms a call to fire at an instant and returns its cancellation handle.
ManualClock ¶
A deterministic clock for tests; time moves only through advance.
advance ¶
advance(delta: timedelta) -> None
Moves time forward and fires every due call on the calling thread.
Calls fire in due order; ties fire in arming order. A call armed during the advance fires inside it when its instant falls at or before the target. A call armed at or before the current instant fires on the next advance, a zero advance included. A fired call may itself advance the clock; the outer advance never moves time back below where an inner one left it.
ScheduledCall ¶
Bases: Protocol
A call armed on a clock, cancellable until it fires.
SystemClock ¶
The default clock, backed by the operating system.
Aborted
dataclass
¶
The run closed because the application called abort.
Accept
dataclass
¶
The admission rule's verdict admitting a proposed write.
Accepted
dataclass
¶
A write the control component admitted, with the sequence it received.
Agent
dataclass
¶
An agent declaration: identity, deadline, wake cap, and delivery.
The control component invokes notify to deliver a notification,
holding no lock, on the thread that closed the batch window or, when
deliveries chain, on a thread already draining them; two notifications
to one agent can therefore arrive on two threads at once. The callback
may run the whole agent cycle inline or hand the notification to the
application's own execution. A callback that blocks on wait_closed
holds the run open, because its own unacknowledged notification counts
as outstanding work.
BoardReader ¶
Bases: Protocol
The three read operations, the handle the admission rule receives.
read_level ¶
read_level(
level: str, from_sequence: int = 0
) -> list[Contribution]
Returns a level's contributions from the sequence bound, inclusive.
read_register ¶
read_register(register: str) -> RegisterState
Returns a register's current value and version.
read_board ¶
read_board(from_sequence: int = 0) -> list[BoardChange]
Returns every write to every region, in sequence order, from the bound.
BudgetExhausted
dataclass
¶
The run closed because the named run-wide limit was reached.
BudgetKind ¶
Bases: Enum
The names of the three run-wide limits.
BudgetReached
dataclass
¶
The audit record of a run-wide limit being reached.
Complete
dataclass
¶
The run closed with no agent presumed failed or capped, and the termination predicate, where one was supplied, returned complete.
Control ¶
The control component's write path, over a board it owns.
reader
property
¶
reader: BoardReader
The board's read side. Reads bypass the control component entirely.
declare ¶
Creates a region on the board and records its kind.
register_agent ¶
register_agent(agent: Agent) -> None
Registers an agent. Its cursor starts at the current sequence number.
write ¶
Runs one level write through admission and, if admitted, the board.
set_register ¶
set_register(
writer: str,
register: str,
value: object,
expected_version: int,
) -> Written | Conflict | Rejected
Runs one register write through admission and, if admitted, the board.
abort ¶
abort(reason: str) -> None
Closes the run as aborted. A run already closed keeps its outcome.
outcome ¶
outcome() -> RunOutcome | None
Returns the closed run's outcome, or nothing while the run is open.
wait_closed ¶
wait_closed(
timeout: timedelta | None = None,
) -> RunOutcome | None
Blocks until the run closes and returns its outcome.
With a timeout, returns nothing when the run is still open after it.
ack ¶
ack(agent: str, notification_id: NotificationId) -> None
Records that the agent finished responding to a notification.
The cursor advances to the end of the range the notification covered. An acknowledgment of a notification no longer outstanding changes nothing; one naming a notification never issued to that agent raises.
extend ¶
extend(
agent: str, notification_id: NotificationId
) -> datetime | None
Grants the agent a new acknowledgment deadline for a notification.
Returns the new deadline, or nothing when the notification is no longer outstanding. An identifier never issued to that agent raises.
DeadlineExtended
dataclass
¶
The audit record of a new deadline granted before the old one passed.
DuplicateAgentError ¶
Bases: BlackboardError
A registration named an agent that is already registered.
FinishedWithFailures
dataclass
¶
The run closed with agents presumed failed or capped, named here.
Notification
dataclass
¶
One wake: the range it covers, the changed registers, and its deadline.
It carries no values. The agent reads the registers itself, and reads whatever else on the board it wants.
NotificationAcknowledged
dataclass
¶
The audit record of an agent reporting that it stopped.
NotificationDispatched
dataclass
¶
The audit record of one notification leaving the control component.
PresumedFailed
dataclass
¶
The audit record of a deadline passing with no acknowledgment.
ProposedContribution
dataclass
¶
A level write as the admission rule sees it, before sequencing.
ProposedRegisterWrite
dataclass
¶
A register write as the admission rule sees it, before sequencing.
RegisterSeeded
dataclass
¶
The audit record of the seed writing one register when the run opened.
Reject
dataclass
¶
The admission rule's verdict refusing a proposed write, with its reason.
Rejected
dataclass
¶
A write the control component refused, with the cause and its reason.
RejectionCause ¶
Bases: Enum
Why the control component refused a write.
ADMISSION: the admission rule rejected it. UNDECLARED_REGION: the
named region was never declared. BUDGET_EXHAUSTED: a run-wide budget
is exhausted. RUN_CLOSED: the run has closed.
RunBudgets
dataclass
¶
The run-wide limits. Each is required and positive.
RunClosed
dataclass
¶
The audit record of the run closing, with its outcome.
RunClosedError ¶
Bases: BlackboardError
A declaration or registration reached a run that has closed.
SeedError ¶
Bases: BlackboardError
The seed's names are not exactly the declared registers.
TerminationDecision ¶
Bases: Enum
The termination predicate's answer when no work is outstanding.
UnknownNotificationError ¶
Bases: BlackboardError
The named notification was never issued to the acknowledging agent.
WakeCapReached
dataclass
¶
The audit record of an agent receiving the last notification its cap allows.
WriteAccepted
dataclass
¶
The audit record of a write that reached the board.
WriteRejected
dataclass
¶
The audit record of a refused write; it never reached the board.
Model
dataclass
¶
A running shared solution model: its read handle and its control component.
Board reads go to reader directly, consume no control capacity, and
cannot be refused. Writes, acknowledgments, and lifecycle calls go
through control.
create_model ¶
create_model(
*,
regions: Iterable[Level | Register],
agents: Iterable[Agent],
seed: Mapping[str, object],
admission_rule: AdmissionRule | None = None,
termination_predicate: TerminationPredicate
| None = None,
budgets: RunBudgets,
clock: Clock | None = None,
) -> Model
Opens a run and returns the model.
The seed writes every declared register once, bypassing admission and the write budget, and the opening wakes follow, each counting against its agent's cap and the notification budget. With no admission rule a write is accepted subject to the region existing, the budgets holding, and the run being open; with no termination predicate the run closes as soon as no work is outstanding; with no clock the operating system clock serves.