chore(automation): trim docstrings to intent only

Cut the docstrings and Field(description=...) text across the entire
automations/ tree down to single-line intent statements, matching the
multi_agent_chat conciseness style:

- Module docstrings: one line stating what the file is.
- Class docstrings: deleted when the class name + module docstring
  already cover intent; kept only where they add a constraint or
  rationale not visible in the signature.
- Pydantic Field descriptions: short noun phrases / clauses, not
  full sentences. Reasoning that belonged in the design plan moved
  out of the code.
- Enum values: per-value docstrings replaced with terse inline
  comments where the meaning isn't obvious from the name.

Behaviour is unchanged. The same 33 files, same public surface, same
imports — verified by re-running the 10-point registry smoke test and
the 8-point schema round-trip / constraint suite from commits 9 and
10.

LOC: 1180 → 691 (-42%).
This commit is contained in:
CREDO23 2026-05-26 23:01:22 +02:00
parent 7a96c0e29c
commit f0e00bd3ee
33 changed files with 80 additions and 568 deletions

View file

@ -1,4 +1,4 @@
"""Three registries — ``capabilities/``, ``actions/``, ``triggers/`` — populated at import time."""
"""Capability, action, and trigger registries — populated at process startup."""
from __future__ import annotations

View file

@ -1,4 +1,4 @@
"""Action registry: ``types.py`` (dataclass), ``store.py`` (dict + register fn)."""
"""Action registry."""
from __future__ import annotations

View file

@ -1,4 +1,4 @@
"""Action registry: in-memory dict + ``register_action`` API."""
"""In-memory action registry. Populated once at process startup."""
from __future__ import annotations
@ -8,26 +8,16 @@ _REGISTRY: dict[str, ActionDefinition] = {}
def register_action(action: ActionDefinition) -> None:
"""Add an action to the in-memory registry.
Raises ``ValueError`` on duplicate ``type`` registration runs
once per process, so a duplicate is always a bug.
"""
"""Register an action. Raises on duplicate type."""
if action.type in _REGISTRY:
raise ValueError(
f"Action already registered: {action.type!r}"
)
raise ValueError(f"Action already registered: {action.type!r}")
_REGISTRY[action.type] = action
def get_action(action_type: str) -> ActionDefinition | None:
"""Look up one action by type. Returns ``None`` on miss."""
return _REGISTRY.get(action_type)
def all_actions() -> dict[str, ActionDefinition]:
"""Snapshot of the registry as a defensive copy."""
"""Defensive snapshot of the registry."""
return dict(_REGISTRY)

View file

@ -1,4 +1,4 @@
"""``ActionDefinition`` dataclass — the v1-minimum action shape."""
"""``ActionDefinition`` dataclass and handler signature."""
from __future__ import annotations
@ -7,36 +7,10 @@ from dataclasses import dataclass
from typing import Any
ActionHandler = Callable[[dict[str, Any]], Awaitable[Any]]
"""The signature every action handler must satisfy.
Identical in shape to ``CapabilityHandler`` both receive a
caller-validated input dict and return an arbitrary output. The
distinction is purely architectural: capabilities are the low-level
"what SurfSense can do" surface, actions are the user-facing
building blocks composed into a plan.
"""
@dataclass(frozen=True, slots=True)
class ActionDefinition:
"""A user-facing step type the plan editor can compose.
v1 trims the dataclass to the five fields necessary for
registry dispatch and form rendering. The full design (§4)
includes ``output_contract``, ``uses_capabilities``, and
``produces_artifacts``; all three are deferred until a consumer
feature requires them:
- ``output_contract`` the loose ``agent_task`` action declares
its output shape per-step via ``config.output_schema``, so the
action-level contract is not needed in v1.
- ``uses_capabilities`` would let the NL generator do static
analysis of which capabilities each action invokes; deferred
because v1 ships a single (``agent_task``) action.
- ``produces_artifacts`` deferred alongside the artifact
pipeline (see §13 decision 26).
"""
type: str
name: str
description: str

View file

@ -1,4 +1,4 @@
"""Capability registry: ``types.py`` (dataclass), ``store.py`` (dict + register fn)."""
"""Capability registry."""
from __future__ import annotations

View file

@ -1,4 +1,4 @@
"""Capability registry: in-memory dict + ``register_capability`` API."""
"""In-memory capability registry. Populated once at process startup."""
from __future__ import annotations
@ -8,33 +8,16 @@ _REGISTRY: dict[str, Capability] = {}
def register_capability(capability: Capability) -> None:
"""Add a capability to the in-memory registry.
Raises ``ValueError`` on duplicate ``id`` registration is
idempotent only at the module level (a module's
``register_capability`` call runs once per process), so a
duplicate is always a bug.
"""
"""Register a capability. Raises on duplicate id."""
if capability.id in _REGISTRY:
raise ValueError(
f"Capability already registered: {capability.id!r}"
)
raise ValueError(f"Capability already registered: {capability.id!r}")
_REGISTRY[capability.id] = capability
def get_capability(capability_id: str) -> Capability | None:
"""Look up one capability by id. Returns ``None`` on miss."""
return _REGISTRY.get(capability_id)
def all_capabilities() -> dict[str, Capability]:
"""Snapshot of the registry as a defensive copy.
Returned dict is safe to iterate while other code calls
``register_capability`` (which v1 never does post-startup, but
the contract holds anyway).
"""
"""Defensive snapshot of the registry."""
return dict(_REGISTRY)

View file

@ -1,4 +1,4 @@
"""``Capability`` dataclass — the v1-minimum five-field shape."""
"""``Capability`` dataclass and handler signature. Locked at five fields for v1."""
from __future__ import annotations
@ -7,32 +7,10 @@ from dataclasses import dataclass
from typing import Any
CapabilityHandler = Callable[[dict[str, Any]], Awaitable[Any]]
"""The signature every capability handler must satisfy.
The handler is a closure that already holds whatever runtime context
it needs (DB session, search-space scope, logger, etc.). The
registry only passes through the caller's input dict — the same dict
that was validated against ``input_schema``.
"""
@dataclass(frozen=True, slots=True)
class Capability:
"""The unit of "what SurfSense can do," consumed by every layer.
v1 keeps the dataclass to exactly five fields. Earlier drafts
considered ``name``, ``required_credentials``, ``side_effects``,
``expected_duration_seconds``, and ``cost_estimate``; every one
of those has been removed until a concrete consumer feature
requires it (see ``automation-design-plan.md`` §3, decision v1).
The handler is a ready-to-call function. It does not receive a
context argument context is bound at registration time by the
factory that builds the closure (so a capability returned to an
agent's tool list looks identical to one returned to an
automation's action runtime).
"""
id: str
description: str
input_schema: dict[str, Any]

View file

@ -1,4 +1,4 @@
"""Trigger registry: ``types.py`` (dataclass), ``store.py`` (dict + register fn)."""
"""Trigger registry."""
from __future__ import annotations

View file

@ -1,4 +1,4 @@
"""Trigger registry: in-memory dict + ``register_trigger`` API."""
"""In-memory trigger registry. Populated once at process startup."""
from __future__ import annotations
@ -8,26 +8,16 @@ _REGISTRY: dict[str, TriggerDefinition] = {}
def register_trigger(trigger: TriggerDefinition) -> None:
"""Add a trigger to the in-memory registry.
Raises ``ValueError`` on duplicate ``type`` registration runs
once per process, so a duplicate is always a bug.
"""
"""Register a trigger. Raises on duplicate type."""
if trigger.type in _REGISTRY:
raise ValueError(
f"Trigger already registered: {trigger.type!r}"
)
raise ValueError(f"Trigger already registered: {trigger.type!r}")
_REGISTRY[trigger.type] = trigger
def get_trigger(trigger_type: str) -> TriggerDefinition | None:
"""Look up one trigger by type. Returns ``None`` on miss."""
return _REGISTRY.get(trigger_type)
def all_triggers() -> dict[str, TriggerDefinition]:
"""Snapshot of the registry as a defensive copy."""
"""Defensive snapshot of the registry."""
return dict(_REGISTRY)

View file

@ -1,4 +1,4 @@
"""``TriggerDefinition`` dataclass — declarative trigger metadata, no handler."""
"""``TriggerDefinition`` dataclass. Declarative; firing is the dispatcher's job."""
from __future__ import annotations
@ -8,27 +8,6 @@ from typing import Any
@dataclass(frozen=True, slots=True)
class TriggerDefinition:
"""A trigger type the dispatcher knows how to fire.
Triggers are purely declarative: the dispatcher (a single
process-wide component, not a per-type handler) reads the
``automation_triggers`` table and decides when each row should
fire. The trigger's job here is to declare its input/output
contract:
- ``config_schema``: JSON Schema for the persisted
``AutomationTrigger.config`` used by the form editor and
validated on save.
- ``payload_schema``: JSON Schema for the payload the dispatcher
will deliver to the executor at fire time (e.g., a schedule
trigger emits ``fired_at`` / ``scheduled_for`` /
``last_fired_at``).
No ``handler`` field firing is a dispatcher responsibility,
not a per-trigger one. This keeps the dispatcher single and
leaves trigger types as pure metadata.
"""
type: str
description: str
config_schema: dict[str, Any]