Documentation
¶
Overview ¶
Package question holds what a question abcd puts to a person may contain: the field limits, written once (Limits, Default), the field view every front door finally shows (Fields), and the limits check (CheckLimits) that refuses a badly built question naming the part, the value, and the limit (spc-2610030944505997; itd-2610030810350727, itd-201).
Nothing else in the tree states a limit. The question check in the guard hook, the GRILL rule text and the interview pages read Default, so changing a limit here changes every statement of it (itd-2610030810350727 criterion A7).
The package is a library: it returns values and never prints. It measures text through internal/textwidth, a pure leaf, and imports nothing that does terminal I/O.
Index ¶
- Constants
- Variables
- func AskingRecall() []string
- func AskingRules(l Limits) []string
- func ChipRole(header string, l Limits) (string, bool)
- func Matches(filter string, o Option) bool
- type Addressee
- type Ask
- type Block
- type Choice
- type Fields
- type Finding
- type Limits
- type List
- type Option
- type Person
- type Question
- type Rule
- type Tab
Constants ¶
const ( KindParagraph = "paragraph" KindList = "list" )
The kinds a material block takes.
const EmDashListItemPattern = "^\\s*(?:[-*+]|[0-9]+\\.)\\s.*\u2014"
EmDashListItemPattern is rule 12's pattern: a line opening a list item that carries an em dash. It is the docs-lint token punctuation/em-dash-in-list-item, whose definition lives in ahoy's docs-lint seed; a test in internal/core/ahoy holds the two equal.
const KnowledgeFloorPage = ".abcd/development/brief/glossary/interview/knowledge-floor.md"
KnowledgeFloorPage is where the knowledge floor is stated in full: a glossary entry in abcd's development record, which every install of the plugin carries under its plugin root (spc-2610030944505997, open question 4, decided (a)). The asking rules point at it in one line rather than restating it (itd-201 decision 5).
const ProductRole = "Product"
ProductRole is the chip role word that names the product thinker. Where no mode names the addressee, a chip carrying it stands in for the mode (rule 9).
const RecommendedRemedy = "" /* 275-byte string literal not displayed */
RecommendedRemedy is rule 8's remedy. It names the cause, so the agent does not loop (itd-201 criterion R6).
const TypedRowLabel = "Type my own answer"
TypedRowLabel is the label of the one option a front door adds to a question with a typed part when the host's question tool takes fewer listed options than the question has (a typed part and decide later alone): it points at the host's free-text row and answers nothing itself, so an interview that receives it asks the question again.
const TypedTextPrefix = "Or type in the row below:"
TypedTextPrefix opens the line of the question text that says what the typed part takes.
Variables ¶
var Default = Limits{ HeaderColumns: 12, ChipRoles: []string{ProductRole, "Tech", "Setup"}, QuestionsPerCall: [2]int{1, 4}, OptionsPerQ: [2]int{2, 4}, LabelWords: 5, MeaningSentences: 2, LaterLabels: []string{"Decide later", "None of these"}, Columns: 80, Rows: 24, HostTextColumns: 76, HostChromeRows: 8, HostOptionColumns: 74, NowPrefix: "Now:", ChangeLaterPrefix: "Change later:", NotApplicable: "not applicable", }
Default is the one statement of every limit.
Functions ¶
func AskingRecall ¶
func AskingRecall() []string
AskingRecall returns the GRILL domain's recall terms, a fresh copy each call.
func AskingRules ¶
AskingRules returns the asking rules every abcd interview follows, the text the GRILL rule domain carries in every repository abcd manages (spc-2610030944505997, "GRILL generated from one Go source"). Every limit it states is filled from l, numbers written as words, so the text and the question check read one statement of each limit (itd-2610030810350727 criterion A7). The text names no record and no source-tree command: it reaches repositories that have neither (itd-201 decision 8).
The register rule, the ask-the-role-first rule and the mode rules open with "In abcd's own interviews": they hold for abcd's command pages, never for another tool's questions in a managed repository (itd-201 decision 10).
func ChipRole ¶
ChipRole reads the role word from a header in the chip grammar, "<role> Q<n>" with an optional "/<total>", the role one of l.ChipRoles ("Product Q2", "Tech Q3", "Setup Q1/4"). It judges the grammar alone, not the width. A header in the grammar is abcd's: only abcd's interview pages are taught to write it.
func Matches ¶
Matches is the narrowing rule (spc-2610030911534855, "The answer loop"): the typed text, matched case-insensitively as a substring of the option's label or of its value. Empty text matches every option. The plain-Terminal list narrows with it and so does guided connect's session (spc-2610031241482088), so a fragment narrows the same in both places.
Types ¶
type Addressee ¶
Addressee is the check's input about whom a question is for. Verbs is the binary's verb list, which the surface reads from its command tree and passes in, so the core holds no copy of it (rule 9).
type Ask ¶
type Ask struct {
Questions []Question `json:"questions"`
}
Ask is what one turn puts to the person: one question, or up to four parts of one thing shown as tabs (itd-2610030810350727 decision 10). It is the structured question both front doors use (spc-2610030911534855, "One question type, defined here first"): abcd draws it in a plain Terminal, and Fields maps it onto the host's question tool.
func Safe ¶
Safe returns a copy of a with every part sanitised for the screen (spc-2610030911534855, "Sanitising before drawing"). Every string in a question is runtime-read: a runner wrote it, a record supplied it, or a model service listed it. Each single-line part (the id, the chip, the ask, every option's and list choice's value, label and meaning, Now, Change later and the typed part's prompt) passes termsafe.Sanitize, so a line break inside a label cannot forge a line; each material block passes termsafe.SanitizeBlock. An injected escape, a C1 control, a bidi override, a zero-width rune or a bare carriage return reaches the screen as a visible '?'. a itself is left unchanged. The drawing (internal/surface/cli/ask) and the AI-written interviews' check (internal/core/interview) both sanitise through it, so what is measured is what is drawn.
func (Ask) Fields ¶
Fields maps the Ask onto the field view the limits are checked on (spc-2610030944505997, "The field view"): the chip to the header; the material's blocks, then the Now: and Change later: lines, then the ask, to the question text; the options (a long list's choices) and then Later to the options; the typed part to the free-text row (Tab.Typed), its prompt said in the text just before the ask. A line the question does not carry is left out, so the limits check names the gap rather than the mapping inventing a value.
type Block ¶
type Block struct {
Kind string `json:"kind"` // KindParagraph or KindList
Text string `json:"text,omitempty"`
Items []string `json:"items,omitempty"`
}
Block is one piece of a question's material: a paragraph, or a list.
type Choice ¶
type Choice struct {
Label string // a few words
Description string // what choosing it means
Preview string // the host's side preview, which abcd's questions never carry (rule 14)
}
Choice is one option of a question, as the host shows it.
type Fields ¶
type Fields struct {
Tabs []Tab
}
Fields is the field view of one call to the host's question tool: one question, or up to four parts of one thing shown as tabs. It is what every front door finally shows, so the limits are checked on it. The guard hook decodes the host's tool input into it (the JSON key names are the host's, so the decoding lives in the surface); the companion's structured question type is mapped onto it by that type's own method.
type Finding ¶
Finding is one broken rule: the question's ordinal (its tab, counted from one; zero is the call as a whole), the part, the rule, the offending value (sanitised and capped, as the mode store's echo is), the limit, and what to do about it.
func Check ¶
Check is the structural check: every question has an id (unique within the Ask), a chip, an ask, a Later option with a value, and options, a list, or a typed part; every option and list choice has a value and a label; values are unique within a question, Later's included; no answer's meaning points at text above a question that carries no material (pointsAbove); an Ask holds as many questions as Default.QuestionsPerCall admits. It returns every finding at once, each naming the question (its tab, counted from one; zero is the Ask as a whole) and the part, and holds no limit of its own: how much each part may hold is CheckLimits's, run on the field view (Fields).
func CheckLimits ¶
CheckLimits holds a call's fields to l and returns every finding at once, so one refusal names every part to fix and the agent fixes them in one retry. It refuses and never rewrites: a rewritten question puts words in the agent's mouth that neither the agent nor the person chose. No finding means the question is admitted.
type Limits ¶
type Limits struct {
HeaderColumns int // 12: the host's header chip
ChipRoles []string // "Product", "Tech", "Setup": the chip's first word
QuestionsPerCall [2]int // 1..4: one question, or up to four tabs
OptionsPerQ [2]int // 2..4, the decide-later option included
LabelWords int // 5
MeaningSentences int // 2: an option's description
LaterLabels []string // "Decide later", "None of these"
Columns int // 80: the narrow window promised
Rows int // 24: one question, or one tab, at Columns
HostTextColumns int // 76: the question text's measure inside the host's frame at Columns
HostChromeRows int // 8: rows the frame draws around a question, the chip included
HostOptionColumns int // 74: the measure of an option's label and description at Columns
NowPrefix string // "Now:"
ChangeLaterPrefix string // "Change later:"
NotApplicable string // "not applicable"
}
Limits is every bound a question's fields are held to. question.Default is the one value the check, the GRILL domain, and the interview pages read (itd-2610030810350727 decision 14, criterion A7).
type List ¶
type List struct {
Choices []Option `json:"choices"`
}
List is a choice among many (300 models): the question's Options stay empty and the choices live here; the Later option still applies.
type Option ¶
type Option struct {
Value string `json:"value"`
Label string `json:"label"`
Meaning string `json:"meaning"`
}
Option is one answer: the value recorded, a label of a few words, and what choosing it means, with its trade-off.
type Person ¶
type Person int
Person is whom a question is addressed to, as the mode records it.
const ( // Unnamed is no mode naming anyone: a repository abcd does not manage has // no mode store, and a managed mode parks on nobody. The chip's role word // then stands in, since the chip names whom the question is for. Unnamed Person = iota // ProductThinker is the mode naming the product thinker. ProductThinker // Facilitator is the mode naming the technical facilitator. Facilitator )
type Question ¶
type Question struct {
ID string `json:"id"` // stable: a setup key, or the turn's ordinal
Chip string `json:"chip"` // who it is for and which question: "Setup Q1"
Material []Block `json:"material"` // the thing being decided: paragraphs and lists
Ask string `json:"ask"` // the one plain question
Options []Option `json:"options"` // the substantive answers
Later Option `json:"later"` // the way to decide later, always present
Now string `json:"now,omitempty"` // what holds now (itd-2610030810350727 decision 4)
ChangeLater string `json:"change_later,omitempty"` // how to change the answer later (decision 4)
List *List `json:"list,omitempty"` // the long-list variant
// Typed is the prompt for a typed answer: a question with a typed part
// takes any text as its answer besides its options (spc-2610031241482088,
// "The typed part on the question type"). The host's question tool takes
// it in its free-text row, so such a question carries no side preview,
// which would remove that row; the Terminal draws it as one line after
// the options. It counts as one option toward the limits' floor.
Typed string `json:"typed,omitempty"`
}
Question is one question: the thing being decided first, then the one plain question, then the answers and the way to decide later.
type Rule ¶
type Rule string
Rule names one of the limits check's rules (spc-2610030944505997, "The limits check"). Each is reported as its own finding.
const ( RuleHeader Rule = "header" // 1: present, within HeaderColumns, in the chip grammar RuleQuestionsPerCall Rule = "questions-per-call" // 2: one to four; more than one is tabs RuleOptions Rule = "options" // 3: two to four, decide-later included RuleLabelWords Rule = "label-words" // 4: at most LabelWords words RuleMeaningSentences Rule = "meaning-sentences" // 5: a description present, at most MeaningSentences RuleDecideLater Rule = "decide-later" // 6: exactly one LaterLabels option, last RuleNoBold Rule = "no-bold" // 7: no ** or __ outside previews RuleNeverRecommended Rule = "never-recommended" // 8: no (Recommended), no star mark RuleRegister Rule = "register" // 9: the product thinker sees no handle or command RuleNowAndChangeLater Rule = "now-and-change-later" // 10: a Now: and a Change later: line, each with a value RuleThingFirst Rule = "thing-first" // 11: material first, the question last RuleEmDashListItem Rule = "em-dash-in-list-item" // 12: no em dash in a list item RuleRows Rule = "rows" // 13: within Rows at Columns RuleNoPreview Rule = "no-preview" // 14: no option carries a side preview )
The rules, in the spec's order, rule 14 appended by the layout intent's decision 20.
const RuleStructure Rule = "structure"
RuleStructure names a structural finding: a part a question cannot be drawn, answered or recorded without. Check reports it; the limits are CheckLimits's.
type Tab ¶
type Tab struct {
Header string // the chip: whom the question is for and which it is
Text string // the material, the Now: and Change later: lines, then the question
Options []Choice // the answers, the decide-later option last
// Typed is the prompt of the question's typed part, taken in the host's
// free-text row: it is no option the host lists, and the limits count it
// as one toward their floor. The host's own input carries none.
Typed string
}
Tab is one question of a call: the four fields the host's question tool takes. A call with one question has one tab.