affect

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package affect reads an operator's message for operator affect: whether it flags an agent's mistake (an operator correction), how strained the operator is, whether the operator says so, and whether the message is a directive, a question or vision. It is a deterministic proxy, lexical and structural, with no model: a pure library that starts no goroutines and crosses no boundary.

Derivation

Every rule was fit on the operator's history: 962 operator messages that answer an agent output, 2026-08-01 to 2026-10-05, a private corpus that is not in this repository. Two windows were hand-labelled for "this message flags a mistake the agent made": 61 messages of 2026-10-03 to fit the rules (24 corrections), and the 57 messages of the orchestrator session of 2026-10-04 03:00Z to 2026-10-05 02:05Z held out (23 corrections). What each rule measured:

  • A correction is an insult or a quality verdict ("idiot", "sucks", "cringe", "unprofessional", "incomplete"), a mining flag ("mineable offense"), a reproach opener ("why did", "how come", "what're you"), which may follow fillers ("uhhh", "dude", "also"), or a negation opener ("no", "none", "stop"). Shouting was tried as a fifth marker and dropped: on the fit window it added no correction and nine directives shouted for urgency (precision 0.69 against 0.95). On the fit window the rules read precision 19/20 and recall 19/24; on the held-out window precision 17/20 = 0.85 and recall 17/23 = 0.74, F1 0.79. The misses are critiques with no marker ("you launched three sessions without follow-up questions").
  • Shouting is at least ShoutedCapsRatio of a message's letters in capitals, over at least ShoutedMinimumLetters letters. The capital share of messages is bimodal: 755 of 939 messages of eight letters or more sit under 0.1 and 123 at 0.9 or over, with 3 to 8 per tenth in between, so any cut from 0.3 to 0.8 moves under 2% of messages; 0.5 is the middle of the valley. 15.0% of messages shout.
  • Strain is high when the message shouts, insults the agent, or the operator reports strain in it. Profanity alone is register, not strain: 30.6% of messages carry profanity or an insult, while strain reads high on 20.2%.
  • Backtest against self-reports: the corpus holds one self-report of strain (2026-10-04), and the self-report marker reads it and no other message. No proxy anticipated it: the ten messages before it shout 0 times (base rate 15.0%) and carry an insult or profanity at 30% (base 30.6%). Strain read from the text is therefore a label of the message, not a forecast; Reading.SelfReport is the ground truth the next fit is backtested against, and a small classifier is warranted only if self-reports accumulate that the proxy misses.
  • Vision is a stated non-ask ("no action needed", "just laying out", "long term context", "eventually"): 8 of 962 messages. A vision message is never a correction, even when it opens with "no".

Two consumer bounds were measured on the same corpus, pairing each operator message with the agent reply it answers (1,361 pairs):

  • ReplyWordLimit: replies under 800 words are followed by a correction 12% to 19% of the time in every length band; over 800 words, 25%, and by a strained message 38% against 16% to 28% below it.
  • Replies that ask the operator a question are followed by fewer corrections (7%, n=128) than replies that do not (18%), so no reply rule forbids a question.

Measured 2026-10-05; the corpus, the labels and the replay stay outside the repository because they are the operator's words.

Index

Constants

View Source
const (
	// ShoutedCapsRatio is the least share of a message's letters in capitals
	// that reads as shouting.
	ShoutedCapsRatio = 0.5
	// ShoutedMinimumLetters is the fewest letters a message needs to shout:
	// "OK" is not shouting.
	ShoutedMinimumLetters = 8
	// ReplyWordLimit is the longest reply, in words, that a strained
	// operator's message is answered with.
	ReplyWordLimit = 800
)

The measured bounds; the package documentation derives each.

Variables

This section is empty.

Functions

This section is empty.

Types

type Features

type Features struct {
	// CapsRatio is the share of the message's ASCII letters in capitals.
	CapsRatio float64 `json:"caps_ratio"`
	Letters   int     `json:"letters"`
	Shouted   bool    `json:"shouted"`
	Profanity int     `json:"profanity"`
	Insults   int     `json:"insults"`
	Urgency   int     `json:"urgency"`
	// MiningFlag is the operator naming the agent's turn a mining offense.
	MiningFlag bool `json:"mining_flag"`
	Reproach   bool `json:"reproach"`
	Negation   bool `json:"negation"`
}

Features are the measurements a reading is made of.

type Kind

type Kind string

Kind is what the message asks of the agent.

const (
	// KindDirective asks the agent to do something; it is every message that
	// is neither a question nor vision.
	KindDirective Kind = "directive"
	// KindQuestion asks the agent to answer.
	KindQuestion Kind = "question"
	// KindVision states where things are going and asks for nothing now.
	KindVision Kind = "vision"
)

The kinds a reading takes.

type Reading

type Reading struct {
	Strain Strain `json:"strain"`
	Kind   Kind   `json:"kind"`
	// Correction is the operator flagging a mistake the agent made.
	Correction bool `json:"correction"`
	// SelfReport is the operator saying, in words, that they are strained.
	SelfReport bool     `json:"self_report"`
	Features   Features `json:"features"`
}

Reading is one message's operator affect.

func Read

func Read(message string) Reading

Read reads one operator message. Code and links are data, not the operator's words, and are set aside first.

func (Reading) Dissatisfied

func (reading Reading) Dissatisfied() bool

Dissatisfied reports the operator's dissatisfaction with what they are answering: a correction, or strain.

type Strain

type Strain string

Strain is how strained the operator reads in one message.

const (
	StrainLow  Strain = "low"
	StrainHigh Strain = "high"
)

The strains a reading takes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL