Skip to main content

internal/formation/subjects.go

internal/formation · 194 lines · 9 declarations · source

Declarations

type SubjectStore

type SubjectStore interface {
Graph(ctx context.Context, scope string) ([]community.Edge, error)
Replace(ctx context.Context, scope string, h community.Hierarchy) error
Unwritten(ctx context.Context, scope string, limit int, writer string) ([]pg.Stored, error)
Children(ctx context.Context, scope, parentID string) ([]pg.Stored, error)
Material(ctx context.Context, scope string, entityIDs []string) ([]string, []report.Fact, error)
Report(ctx context.Context, scope, communityID string) (report.Report, bool, error)
Write(ctx context.Context, scope, communityID string, r report.Report, c report.Context, writer string) error
}

SubjectStore is what the subject pass needs from the database.

An interface here for the reason the recall store's is one: what the pass DOES is separable from where the rows are, and the ordering rules can be read without reading SQL.

source

const ReportBudget

const ReportBudget = 12000

ReportBudget is how much material one report is written from, in characters.

PROVISIONAL, like the clustering parameters, and for the same reason. What it decides is when a parent stops being described from its own facts and starts being described from its children's reports — so too small makes every parent a summary of summaries, and too large sends more material than a model attends to and pays for it on every rebuild.

source

type Subjects

type Subjects struct {
store SubjectStore
// writer is the model hop. Nil is valid and means reports are not written: a deployment with no
// model still forms subjects, which is what the portal needs to show the shape of a memory, and
// the alternative is a pass that fails on every tick in a configuration that is otherwise fine.
writer *report.Writer
}

Subjects forms the subjects in a scope and writes what has not been written.

Why this is a pass rather than a read

Partitioning a scope reads every current fact in it and writing a report is a model call. A question that triggered either would make one caller pay for the whole scope, and would put inference on the read path — which is the cost anchoring already refuses by resolving names with a lookup.

Why forming and writing are one pass and not two

Replacing the partition deletes the reports of communities that no longer exist, by cascade. A pass that formed without writing would leave a scope with subjects and nothing said about them until the next tick, and a thematic question in between would find nothing and be unable to say why.

source

method Subjects.WriterIdentity

func (s *Subjects) WriterIdentity() string

writerIdentity is what wrote a report, or the empty string when nothing can say.

A model that cannot identify itself gets no identity rather than a made-up one: an unidentified writer must not be evidence that two reports were written under the same rules, which is the same position extraction takes about an unidentified proposer. WriterIdentity is what this pass stamps on the reports it writes, and what the driver asks with when it looks for projects owing one.

source

func NewSubjects

func NewSubjects(store SubjectStore, writer *report.Writer) *Subjects

NewSubjects builds the pass. A nil writer forms subjects and writes no reports.

source

type SubjectPass

type SubjectPass struct {
Entities int
Communities int
Written int
Failed int
}

SubjectPass is what one run did, so the driver can log something a person can act on.

source

method Subjects.Run

func (s *Subjects) Run(ctx context.Context, scope string, limit int) (SubjectPass, error)

Run partitions a scope and writes the reports that are missing.

`limit` bounds the model calls one pass makes. A scope whose partition produced two hundred subjects would otherwise hold the worker for two hundred model calls on its first tick, while every other scope waits — so the work is spread across ticks and the unwritten ones are picked up next time.

source

method Subjects.write

func (s *Subjects) write(ctx context.Context, scope string, c pg.Stored) error

source

method Subjects.children

func (s *Subjects) children(ctx context.Context, scope string, parent pg.Stored) (
map[string][]report.Fact, map[string]report.Report, error)

children collects what a parent may substitute: for each child, the facts that belong to it and the report already written about it.

A child with no report cannot be substituted — replacing its facts with nothing would remove the subject rather than compress it — so it is offered without one and the roll-up leaves it alone. That happens when a child's own writing failed on an earlier tick, and it is the reason the pass writes deepest first: by the time a parent is reached, its children usually have reports.

source