angee.intake.models
External-request evidence and its same-row capture contributors.
Need is the durable evidence row. A need semantically targets exactly one task or project. For a task target, project is also the indexed, denormalized copy of task.project so project-level request counts need no relation walk. targets_project records whether that project value is the target or merely the task's denormalized context; the database constraint can therefore enforce target exclusivity without rejecting task needs whose tasks belong to projects.
ChannelIntake folds capture configuration and trigger evaluation into the existing messaging.Channel row. TaskIntake participates in the composed task save chain and is the sole writer that re-denormalizes existing needs when a task changes project. ThreadAttachmentIntake contributes the idempotent binding verb for messaging's generic source attachment role.
NeedImportance
class NeedImportance(models.TextChoices)Binary requester signal, deliberately distinct from planning priority.
NeedManager
class NeedManager(AngeeManager)Own manual capture, message capture, and triage-task construction.
target_model
@classmethod
def target_model(cls, model_label: str) -> type[models.Model]Return the installed model for one allowed need target label.
target_field
@classmethod
def target_field(cls, target: models.Model) -> strReturn the stored target field owned by target's model.
capture
def capture(*,
target: models.Model,
body: str,
party: models.Model | None = None,
importance: str = "normal") -> models.ModelCapture one exact manual request onto target under its write lock.
The authored action has no separate idempotency token, so its replay identity is the normalized manual payload: target, body, party, and importance. A caller intentionally recording distinct identical evidence can edit the wording; ordinary action retries converge on the existing row. PostgreSQL makes that convergence exact with a target-row lock; SQLite provides the single-writer boundary through database-level serialization.
capture_from_message
def capture_from_message(message: models.Model, *,
queue: models.Model) -> models.ModelCapture one message into triage; its clean replay no-op is SELECT-FOR-UPDATE-backed.
Need
class Need(AuditMixin, AngeeDataModel)One external or manually-authored request attached to one semantic target.
targets_project
Whether project is the direct target rather than task-project context.
Meta
class Meta()Django model options for request evidence.
__init__
def __init__(*args: Any, **kwargs: Any) -> NoneTrack an explicitly authored project separately from denormalization.
__setattr__
def __setattr__(name: str, value: Any) -> NoneRemember caller-authored project assignment without counting internal projection.
full_clean
def full_clean(*args: Any, **kwargs: Any) -> NoneKeep Django field normalization from becoming authored target input.
refresh_from_db
def refresh_from_db(*args: Any, **kwargs: Any) -> NoneRefresh target fields without marking the denormalized project as authored.
apply_create_defaults
def apply_create_defaults() -> Mapping[str, Sequence[Any]]Project the target before the generic create gate evaluates its relations.
clean
def clean() -> NoneNormalize task-project context and reject missing or double-authored targets.
save
def save(*args: Any, **kwargs: Any) -> NonePersist with target semantics and task-project context kept coherent.
convert_to_task
def convert_to_task(queue: models.Model) -> models.ModelReturn this need's task; its clean concurrent no-op is SELECT-FOR-UPDATE-backed.
_ChannelIntakeContribution
class _ChannelIntakeContribution(models.Model)Field-and-behavior base folded into the materialized Channel child.
Channel is a multi-table child of Integration. Keeping this contribution on a narrow models.Model base avoids copying AngeeModel's timestamp columns ahead of that concrete parent while preserving the normal extension-donor discovery contract on :class:ChannelIntake below.
IntakeTrigger
class IntakeTrigger(models.TextChoices)Declared capture triggers; only all-messages is implemented in v1.
Meta
class Meta()Abstract contribution folded into the concrete channel table.
should_capture_message
def should_capture_message(message: models.Model) -> boolReturn whether this channel's configured v1 trigger accepts message.
capture_ingested_message
def capture_ingested_message(message: models.Model) -> models.Model | NoneDispatch an accepted ingested message to the Need write owner.
ChannelIntake
class ChannelIntake(_ChannelIntakeContribution, AngeeModel)Same-row intake configuration donor for messaging.Channel.
Meta
class Meta()Abstract donor discovered by the composer; runtime remains false.
TaskIntake
class TaskIntake(AngeeModel)Same-row task save participant that owns Need.project re-denormalization.
Meta
class Meta()Abstract donor options folded into the concrete task table.
save
def save(*args: Any, **kwargs: Any) -> NonePersist the task, then reconcile task-target Need project context once.
ThreadAttachmentIntake
class ThreadAttachmentIntake(AngeeModel)Same-row source-thread binding contribution for messaging attachments.
Meta
class Meta()Abstract donor options folded into the concrete attachment table.
bind_source_thread
@classmethod
def bind_source_thread(cls,
*,
task: models.Model,
thread: models.Model | None,
created_by_id: Any = None) -> models.ModelBind thread as task's source evidence, idempotently.