Documentation
¶
Overview ¶
Package taskdetect notices when work the user just did should become a durable capability, and proposes the task that would do it.
Two independent kinds of evidence feed one proposal system:
a STRONG single turn this piece of work is plainly repeatable REPEATED weak signals the same capability keeps being asked for
The second is the one that matters. Anyone can suggest cron. Recognising "you have asked me to keep provider catalogs current four times across three sessions, shall I just keep them current" is memcode learning a capability from working with someone, and it is a different message with a different weight.
The detector's output is a PROPOSED TASK, never a boolean. Interrupting somebody to ask "want to automate that?" and then making them answer a configuration questionnaire is worse than not asking: if there is enough confidence to interrupt, there is enough to propose cadence, authority, verification and runtime, and let them accept it whole.
Index ¶
- Constants
- func DBPath() (string, error)
- func Ready(c Cluster) bool
- func WouldOfferOnFirstContact(p Proposal) bool
- type Classifier
- type Cluster
- type Decision
- type Detector
- type Effect
- type Gap
- type Kind
- type Offer
- type Option
- type Proposal
- func (p Proposal) Eligible() bool
- func (p Proposal) FamilyKey() string
- func (p Proposal) Fingerprint() string
- func (p Proposal) Gaps() []Gap
- func (p Proposal) IneligibleReason() string
- func (p Proposal) Ready() bool
- func (p Proposal) SameCapability(q Proposal) bool
- func (p Proposal) ToTask(now time.Time) (task.Task, error)
- type Recurrence
- type RecurrenceKind
- type Signal
- type Store
- func (s *Store) Close() error
- func (s *Store) Clusters(ctx context.Context, project string, now time.Time) ([]Cluster, error)
- func (s *Store) Forget(ctx context.Context, p Proposal) error
- func (s *Store) Prune(ctx context.Context, before time.Time) error
- func (s *Store) Record(ctx context.Context, sessionID string, p Proposal, evidence string, ...) (Signal, error)
- func (s *Store) Suppress(ctx context.Context, p Proposal, now time.Time) error
- func (s *Store) Suppressed(ctx context.Context, p Proposal) (bool, error)
- func (s *Store) Suppressions(ctx context.Context) ([]string, error)
- func (s *Store) Unsuppress(ctx context.Context, family string) (int, error)
- type Turn
Constants ¶
const ( ActionCreate = "create" ActionCustomize = "customize" ActionNotNow = "not_now" ActionNever = "never" )
The four actions. Deliberately not Yes/No: the difference between "not right now" and "never this kind" is the difference between a system that learns and one that nags.
Variables ¶
This section is empty.
Functions ¶
func Ready ¶
Ready reports whether a cluster is worth offering, by EITHER path.
Both are checked here because a prospective offer is made in the middle of a session, where nothing may interrupt — so it waits with the historical ones, and would be silently lost if this only knew about accumulated evidence.
func WouldOfferOnFirstContact ¶
WouldOfferOnFirstContact reports whether a proposal clears the first-contact bar, without touching any store. Exported so the detector evaluation measures the REAL rule rather than a paraphrase of it that can drift.
Types ¶
type Classifier ¶
Classifier turns a finished turn into a proposal. Injectable: the real one costs a model call, and the pipeline around it has to be testable without one.
type Cluster ¶
type Cluster struct {
FamilyKey string
Family string
Project string
// Weight is confidence summed with age decay. Sessions counts DISTINCT
// sessions, which is the part that matters: three signals in one
// conversation is one person repeating themselves, not a pattern.
Weight float64
Sessions int
Signals int
// Latest is the most recent proposal, used for the offer — the newest
// phrasing of the capability is the one to show back.
Latest Proposal
Evidence []string
LastSeen time.Time
}
Cluster is the accumulated evidence for one capability.
func (Cluster) Capability ¶
Capability returns the cluster's proposal named for the CAPABILITY rather than for whichever instance happened to be seen last.
A cluster is the recognised standing job; accepting it should produce "provider-catalog-maintenance", not "check-fireworks-catalog" just because Fireworks was the most recent thing asked about. The instance name is right for a single-turn offer and wrong here.
type Decision ¶
type Decision struct {
Kind Kind
Proposal Proposal
// Sessions and Occasions describe the evidence behind a repeated offer.
Sessions int
Occasions int
// Why explains a decision NOT to offer, for the debug surface. Silence that
// cannot be explained is indistinguishable from a broken detector.
Why string
}
Decision is the outcome of evaluating a turn.
func ClusterDecision ¶
ClusterDecision renders a waiting cluster as the offer it should become.
Accumulated evidence wins when it exists: "you have asked me this three times" is a stronger and more personal claim than "this kind of thing recurs", and having earned it, memcode should say it.
type Detector ¶
type Detector struct {
Store *Store
Classifier Classifier
}
Detector evaluates finished turns and decides whether to offer anything.
func (*Detector) Evaluate ¶
Evaluate classifies a turn, records what it learned, and reports whether to make an offer.
Recording happens even when no offer follows: today's weak signal is what makes next month's recognition possible, and a detector that only remembers what it already acted on can never learn anything.
type Effect ¶
type Effect string
Effect says what a run of this work does to the repository.
const ( // EffectNone reads and reports; it changes nothing. EffectNone Effect = "none" // EffectPossible may change code, depending on what it finds. The common // case for maintenance: usually nothing to do, sometimes a real diff. EffectPossible Effect = "possible" // EffectExpected changes code essentially every run. EffectExpected Effect = "expected" )
type Gap ¶
Gap is something that must be settled before a task can safely run unattended, with the question to ask.
type Kind ¶
type Kind string
Kind is which evidence path produced an offer. They read differently to the user because they mean different things.
const ( // KindNone: nothing to offer. KindNone Kind = "" // KindProspective: the work will be needed again for a reason that exists in // the world, said on FIRST contact. The primary path — memcode understanding // the work rather than waiting to watch someone repeat it. KindProspective Kind = "prospective" // KindRepeated: recurrence learned from behaviour instead of inferred. The // fallback, and the right answer when the work has no inherent cadence but // this particular person keeps wanting it. KindRepeated Kind = "repeated" // KindExplicit: the user asked for it to be automated. No inference needed. KindExplicit Kind = "explicit" )
type Offer ¶
Offer is the message and choices shown to the user.
func Message ¶
Message renders the offer for a decision.
The two paths read differently ON PURPOSE. A single-turn offer is a suggestion about the work just done. A repeated offer is memcode saying it noticed a habit and can take it over — which is a materially bigger claim, and flattening both into one generic automation prompt throws away the only part that is interesting.
type Proposal ¶
type Proposal struct {
// Family is the SEMANTIC identity of the capability, normalized. It is what
// lets three differently worded requests accumulate into one recognised
// thing, so it names a capability rather than an instance:
// "provider-model-catalog-maintenance", not "update-anthropic-models".
Family string `json:"task_family"`
// Operation and Target are the parts Family is built from, kept separately
// because they are what a human reads when asked to confirm the grouping.
Operation string `json:"operation"`
Target string `json:"target"`
// Scope and Project bound where the capability applies.
Scope string `json:"scope"`
Project string `json:"project,omitempty"`
// Constraints are the conditions that must hold for the work to be correct
// ("verify prices against the vendor's page"). Part of identity: the same
// operation under materially different constraints is different work.
Constraints []string `json:"constraints,omitempty"`
Name string `json:"name"`
Reason string `json:"reason"`
Instructions string `json:"instructions"`
Verify []string `json:"verify,omitempty"`
// SuggestedEvery is a Go duration ("168h") and SuggestedCron a 5-field
// expression; at most one is set.
SuggestedEvery string `json:"suggested_every,omitempty"`
SuggestedCron string `json:"suggested_cron,omitempty"`
Effect Effect `json:"code_changes"`
// Confidence that the work is well-shaped enough to automate at all.
Confidence float64 `json:"confidence"`
// Recurrence is the causal claim about whether it will be needed again.
// Separate from Confidence on purpose: work can be perfectly automatable and
// still never need doing twice.
Recurrence Recurrence `json:"recurrence"`
// ExplicitRequest is the user actually asking for this to be automated,
// which needs no inference at all.
ExplicitRequest bool `json:"explicit_request,omitempty"`
// ClarifyingQuestions are decisions the model could not make for the user —
// usually scope or side effects. "Should major version bumps be included?"
// is a different task depending on the answer, and guessing it silently is
// how an autonomous job does something nobody asked for.
ClarifyingQuestions []string `json:"clarifying_questions,omitempty"`
// The four eligibility gates. Repetition alone is NOT enough: a password
// reset recurs, a vague "make this better" recurs, an emotionally repetitive
// question recurs, and none of them is a capability worth handing to an
// unattended machine.
Bounded bool `json:"bounded"`
Reproducible bool `json:"reproducible"`
UnattendedSafe bool `json:"unattended_safe"`
Evaluable bool `json:"evaluable"`
}
Proposal is a task memcode believes it could take over, with everything needed to create it.
func (Proposal) Eligible ¶
Eligible reports whether the work qualifies at all, independent of how confident or how often it has been seen.
func (Proposal) FamilyKey ¶
FamilyKey is the coarser identity used for SUPPRESSION and for grouping signals: family plus scope plus project, without the constraint detail.
Coarser on purpose. Someone who says "don't suggest this kind" means the kind, not that exact phrasing with that exact constraint list — and an offer that returns next week because one condition differed is the behaviour they were trying to stop.
func (Proposal) Fingerprint ¶
Fingerprint is the durable identity signals accumulate against.
Built from MEANING — operation, target, scope, project, constraints — and not from wording. "Update our Anthropic models", "OpenAI added models, update ours" and "is the Fireworks catalog stale again?" share no useful phrasing and are the same capability; a fingerprint over words would file them as three unrelated things and never notice the pattern.
func (Proposal) Gaps ¶
Gaps reports what is missing before this task should be created.
The point is NOT to interrogate the user. Most of a task is inferable and should be inferred; these are the few things where guessing wrong has consequences that only show up later, at 3am, with nobody watching.
func (Proposal) IneligibleReason ¶
IneligibleReason names the first failing gate, for a log line.
func (Proposal) SameCapability ¶
SameCapability reports whether two proposals describe one capability: the same family key, or near-identical family names within the same scope and project.
func (Proposal) ToTask ¶
ToTask converts a proposal into a real task definition.
Every field is filled from the proposal or from a documented default, so accepting an offer writes a COMPLETE, valid task and never opens a questionnaire. Anything the proposal did not determine falls to the same defaults a hand-written file would get.
type Recurrence ¶
type Recurrence struct {
Kind RecurrenceKind `json:"kind"`
// Cause states WHAT makes it recur, in the model's own words. Required for
// a prospective offer: an offer that cannot say why is a guess, and it goes
// in the message so the user can judge the reasoning rather than the verdict.
Cause string `json:"cause,omitempty"`
// Confidence in the causal claim, distinct from confidence that the work is
// well-shaped.
Confidence float64 `json:"confidence"`
// Value is what automating it buys — usually "notice X without you having
// to remember to look".
Value string `json:"value,omitempty"`
}
Recurrence is the structured reason to expect the work again.
func (Recurrence) Inherent ¶
func (r Recurrence) Inherent() bool
Inherent reports whether the work recurs for a reason that exists in the world, independent of this user's habits. These are the offers that can be made on first contact.
type RecurrenceKind ¶
type RecurrenceKind string
RecurrenceKind is WHY this work would happen again — the causal claim behind an offer, rather than an observation that it happened twice.
This is the difference between a system that notices patterns and one that understands work. "Update our Anthropic models" is obviously recurring the FIRST time it is asked, because upstream vendors change their models whether or not anyone here is watching. Waiting to see it three times before saying so makes memcode look less intelligent than it is.
const ( // RecurrenceOneOff will not happen again: renaming the product, fixing one // specific bug. Bounded, reproducible and evaluable — and still not a // standing job, which is exactly why the four gates are not enough on their // own. RecurrenceOneOff RecurrenceKind = "one_off" // RecurrenceExternal recurs because the WORLD changes independently of this // repository: vendors ship models, packages release versions, advisories // appear, certificates expire. The strongest reason to offer immediately. RecurrenceExternal RecurrenceKind = "externally_recurring" // RecurrenceInternal recurs because of this project's own rhythm: // regenerating a report as data lands, re-running a check as code grows. RecurrenceInternal RecurrenceKind = "internally_recurring" // RecurrenceUserPattern is not inherent to the work — it recurs because // THIS person keeps wanting it. Not knowable on first contact; this is what // accumulated history is for. RecurrenceUserPattern RecurrenceKind = "user_pattern" // RecurrenceUncertain: no confident causal claim either way. RecurrenceUncertain RecurrenceKind = "uncertain" )
type Signal ¶
type Signal struct {
ID string
SessionID string
ObservedAt time.Time
Project string
Family string
FamilyKey string
Fingerprint string
Operation string
Target string
Scope string
Confidence float64
Evidence string
Proposal Proposal
}
Signal is one observation that a capability might be worth automating.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the durable signal and suppression record.
func OpenDefault ¶
OpenDefault opens the store at its standard location.
func (*Store) Clusters ¶
Clusters groups signals into capabilities, newest evidence first.
Grouping is by family key, then MERGED across near-identical family names via SameCapability — so a classifier that named the same thing slightly differently on two occasions still accumulates rather than splitting.
func (*Store) Forget ¶
Forget drops signals for a capability, used when a task is actually created so its own evidence stops re-proposing it.
func (*Store) Record ¶
func (s *Store) Record(ctx context.Context, sessionID string, p Proposal, evidence string, now time.Time) (Signal, error)
Record persists one observation.
func (*Store) Suppress ¶
Suppress records a durable "don't suggest this kind", keyed to the capability rather than the wording.
Declining to automate provider-catalog updates says nothing about whether to automate a weekly dependency audit, so suppression attaches to family, scope and project — never to "automation" in general.
func (*Store) Suppressed ¶
Suppressed reports whether this capability has been refused durably.
Checks the exact family key and, because a classifier's naming drifts, any suppressed family near enough to be the same capability. Someone who said no once should not be asked again because the wording moved.
func (*Store) Suppressions ¶
Suppressions lists what has been refused, for `task suggestions`.
type Turn ¶
type Turn struct {
SessionID string
Project string
// Request is what the user asked for, Summary what was done.
Request string
Summary string
// Changed reports whether the turn actually altered the repository — weak
// but real evidence that the work was substantive.
Changed bool
}
Turn is what the detector sees after work completes.