Documentation
¶
Overview ¶
Package ideate is the deterministic frame around abcd's idea-admission protocol (itd-104, spc-18): the three-leg gauntlet an idea may be put through before it is allowed to become a record entry.
DIVISION OF LABOUR. Ideate follows the pattern the disembark synthesis family proved. The HOST runs the judgement — primary-source research, a grill against the existing record, and an independent adversarial review — as agents. This package is the frame: it validates what those legs produced, proves every citation names a real record, and writes the durable verdict. It never fetches a source, never calls a model, and never decides whether an idea is any good.
WHY A RECORD EITHER WAY. The verdict is written whether the idea survives or dies, and it must carry the alternatives that were rejected. A killed idea with no recorded reason is an idea that gets re-proposed in six months; the research directory is where a session looks before re-proposing one. That is why an empty rejected-alternatives list is admissible only behind an explicit marker — silence by omission is exactly the failure the record exists to prevent.
NEVER A GATE. Nothing here is reachable from capture or intent-create. Ideate is an optional verb the routing help names for big, unproven ideas; skipping it is never warned about, and no other verb requires it.
Index ¶
- Constants
- type CitationError
- type Claim
- type ClaimStatus
- type ClaimTally
- type ExistsError
- type GrillHit
- type KillAttempt
- type KillOutcome
- type Leg
- type LegKind
- type MissingDecisionsError
- type Payload
- type RedactionResidualError
- type RejectedAlternative
- type Relation
- type Result
- type SlugError
- type Verdict
Constants ¶
const ( ResearchRelDir = ".abcd/development/research/notes" DecisionsRelDir = ".abcd/work/DECISIONS.md" )
ResearchRelDir is the one directory a verdict record is ever written into, and DecisionsRelDir is the log its dated pointer is appended to. Both are constants rather than parameters: a configurable target would let a verdict land somewhere no future session looks.
It is the research store's notes/ bucket rather than its root because a verdict record IS a dated research note (spc-18: "killed ideas are research outcomes, and the research directory is where a future session looks before re-proposing one"), and research/README.md files dated notes under notes/. Writing to the root would make the shipped binary the standing producer of the very convention violation iss-42 cleared out of that directory by hand.
const MaxPayloadBytes = 1 << 20 // 1 MiB
MaxPayloadBytes caps the untrusted verdict document, mirroring the synthesis and release-ingest ceilings. It is exported so a front door can bound its READ at the same ceiling the core enforces — the front-door bound is a convenience, this one is the guarantee.
const MaxSlugLen = 64
MaxSlugLen bounds the idea slug, which reaches a filename. Paired with slugRe it is the lexical half of the write-containment defence.
const SchemaVersion = 1
SchemaVersion stamps the verdict payload. It is versioned independently of every other abcd artifact, so a future breaking change to the shape is detectable rather than silently misread by a host composing against the old one.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CitationError ¶
type CitationError struct {
Unresolved []string
}
CitationError is the record-grill citation gate's refusal: a hit names a record id that does not resolve in this repository, so the grill is reporting on something that is not there. It names every offending id, because a composer handed one id at a time re-runs the whole gauntlet once per mistake.
func (*CitationError) Error ¶
func (e *CitationError) Error() string
type Claim ¶
type Claim struct {
Claim string `json:"claim"`
PrimarySource string `json:"primary_source"`
Status ClaimStatus `json:"status"`
}
Claim is one load-bearing claim and the primary source it was checked against.
The binary cannot judge whether a source is PRIMARY — that is the researching agent's obligation, stated in its prompt. What the binary enforces is that a source is named at all, for every claim including an unverifiable one: a claims table row with no source is indistinguishable from an unchecked assertion.
type ClaimStatus ¶
type ClaimStatus string
ClaimStatus is what checking a claim against its primary source established.
const ( // ClaimVerified: the primary source supports the claim. ClaimVerified ClaimStatus = "verified" // ClaimFalsified: the primary source contradicts it. Three of these killed an // idea in the proven manual run. ClaimFalsified ClaimStatus = "falsified" // ClaimUnverifiable: no primary source settles it either way. This is an // honest outcome, not a pass. ClaimUnverifiable ClaimStatus = "unverifiable" )
type ClaimTally ¶
type ClaimTally struct {
Verified int `json:"verified"`
Falsified int `json:"falsified"`
Unverifiable int `json:"unverifiable"`
}
ClaimTally counts the research leg's outcomes, so a reader of the result knows what the claims table found without re-reading the record.
func (ClaimTally) Total ¶
func (t ClaimTally) Total() int
Total reports how many claims the research leg carried.
type ExistsError ¶
type ExistsError struct {
Path string
}
ExistsError is the no-overwrite refusal: a verdict record for this slug already exists under today's date. A second run is either a re-run of the same gauntlet (in which case the first record stands) or a different one (in which case it deserves its own slug); silently replacing the first would erase a recorded reason, which is the one thing this verb exists to preserve.
func (*ExistsError) Error ¶
func (e *ExistsError) Error() string
type GrillHit ¶
type GrillHit struct {
Record string `json:"record"`
Relation Relation `json:"relation"`
Note string `json:"note,omitempty"`
}
GrillHit is one existing record entry that bears on the idea. Record is a cited id and MUST resolve in the repository; Note is optional prose, and is where a reference to a brief section or a principle lives, since neither carries a per-entry id that could be cited.
type KillAttempt ¶
type KillAttempt struct {
Attempt string `json:"attempt"`
Outcome KillOutcome `json:"outcome"`
}
KillAttempt is one adversarial attempt on the idea and what it achieved.
type KillOutcome ¶
type KillOutcome string
KillOutcome is what one adversarial kill attempt achieved.
const ( // KillSurvived: the idea withstood the attempt. KillSurvived KillOutcome = "survived" // KillPartial: the attempt landed but is not on its own fatal. KillPartial KillOutcome = "partial" // KillFatal: the attempt is fatal to the idea as posed. KillFatal KillOutcome = "fatal" )
type Leg ¶
type Leg struct {
Kind LegKind `json:"kind"`
Claims []Claim `json:"claims,omitempty"`
Hits []GrillHit `json:"hits,omitempty"`
KillAttempts []KillAttempt `json:"kill_attempts,omitempty"`
}
Leg is one leg of the gauntlet. It is a union over the three kinds: each kind populates exactly its own evidence field, and a leg carrying another kind's field is a refusal — a payload that smuggles grill hits into the research leg is not a leg abcd knows how to read.
type LegKind ¶
type LegKind string
LegKind identifies one leg of the gauntlet. The three values are also the REQUIRED ORDER: research grounds the idea, the grill checks it against what is already written, and only then does an evaluator who did none of that work try to kill it. Running them in any other order changes what each leg is looking at, so the order is validated rather than assumed.
const ( // LegResearch: every load-bearing claim checked against its primary source. LegResearch LegKind = "research" // LegRecordGrill: does the existing record cover, contradict, or supersede // this? Every hit is cited by record id. LegRecordGrill LegKind = "record-grill" // LegAdversarialReview: a fresh-context, off-policy evaluator that did not // conduct the research, receiving the idea as an artefact of unknown // authorship, trying to kill it. LegAdversarialReview LegKind = "adversarial-review" )
type MissingDecisionsError ¶
type MissingDecisionsError struct {
Path string
}
MissingDecisionsError is the refusal for a repository with no decision log. The pointer is not decoration: the log is where a session looks for what was already decided, and a verdict record nothing points at is a record nobody finds.
func (*MissingDecisionsError) Error ¶
func (e *MissingDecisionsError) Error() string
type Payload ¶
type Payload struct {
// SchemaVersion must equal SchemaVersion.
SchemaVersion int `json:"schema_version"`
// PromptVersion is the orchestrating prompt's semver (itd-5).
PromptVersion string `json:"prompt_version"`
// Idea is the idea as captured, in the words it entered the gauntlet with.
Idea string `json:"idea"`
// Legs are the three legs, IN ORDER. An array rather than three named fields
// precisely so the order is a property of the document the binary can check.
Legs []Leg `json:"legs"`
// Verdict is the admission outcome.
Verdict Verdict `json:"verdict"`
// RejectedAlternatives are the options turned down on the way to the verdict.
RejectedAlternatives []RejectedAlternative `json:"rejected_alternatives"`
// NoRejectedAlternatives is the EXPLICIT empty marker. An empty list is
// admissible only with this set; omission is not, and setting it beside a
// populated list is a contradiction the document is refused for.
NoRejectedAlternatives bool `json:"no_rejected_alternatives,omitempty"`
}
Payload is the whole untrusted host-composed verdict document.
type RedactionResidualError ¶ added in v0.8.0
RedactionResidualError is the stage-two refusal: the rendered record or its pointer still carries a span the redactor must not commit. It names the KINDS and nothing else — a refusal that quoted the span it refused would publish the leak into the error message, and from there into a terminal and a log.
func (*RedactionResidualError) Error ¶ added in v0.8.0
func (e *RedactionResidualError) Error() string
type RejectedAlternative ¶
type RejectedAlternative struct {
Alternative string `json:"alternative"`
WhyRejected string `json:"why_rejected"`
}
RejectedAlternative is one option considered and turned down, with the reason. Both fields are required: an alternative with no reason records that a choice existed without recording why it was not taken, which is the half of the entry that stops the re-litigation.
type Result ¶
type Result struct {
Slug string `json:"slug"`
Idea string `json:"idea"`
Verdict Verdict `json:"verdict"`
// Graduates reports whether this verdict admits the idea to a draft intent.
// Ideate mints nothing itself; this is the signal the surface relays.
Graduates bool `json:"graduates"`
// Path is the verdict record, repo-relative.
Path string `json:"path"`
// DecisionPath is the log the dated pointer was appended to, repo-relative.
DecisionPath string `json:"decision_path"`
// Claims tallies the research leg.
Claims ClaimTally `json:"claims"`
// GrillHits counts the record-grill hits.
GrillHits int `json:"grill_hits"`
// CitedRecords is the sorted set of record ids the grill cited, every one of
// them proved to resolve — the citation gate's proof, so a reviewer can check
// the record without re-running the resolution.
CitedRecords []string `json:"cited_records"`
// KillAttempts counts the adversarial leg's attempts.
KillAttempts int `json:"kill_attempts"`
// RejectedAlternatives counts the recorded alternatives.
RejectedAlternatives int `json:"rejected_alternatives"`
// Redactions counts the secret/PII spans the store-before-commit redactor
// rewrote out of the verdict's free text on the way to the record. It is
// reported rather than kept quiet because redacting in silence is how a
// composer learns nothing about the credential it just pasted (loud-staging).
Redactions int `json:"redactions"`
}
Result is the transport-agnostic outcome of `ideate record`. It is returned only when the record was written; every refusal is an error, so a caller holding a Result knows a durable record exists.
func Record ¶
Record validates the host-composed verdict for slug and writes it.
at is the clock, passed in rather than read: the date lands in a durable filename and in a durable log line, so it is an input a test can pin instead of a wall-clock read buried in a writer.
Every refusal returns BEFORE the first write, with one exception that is handled rather than accepted: if appending the pointer fails after the record landed, the record is removed again, so a run never leaves half a decision behind.
Both artefacts it writes are COMMITTED, so both go through the store-before-commit redactor (redact.go): the verdict's free text is redacted field by field on the way into the validated document, the rendered record and its decision-log pointer are re-scanned before either is written, and a scanner that cannot be trusted refuses the run rather than recording under it.
type SlugError ¶
SlugError is the refusal for an idea slug that cannot safely become a filename. It is typed because it is an OPERAND fault, not a payload fault: the fix is to re-run with a different slug, not to re-compose the verdict.
type Verdict ¶
type Verdict string
Verdict is the admission outcome. The set is CLOSED: an unregistered verdict is a whole-document refusal, never a coercion, because the verdict is the one line of the record a later session reads first.
const ( // VerdictSurvives: the idea cleared all three legs and may graduate to a draft // intent through the existing quoted-text create. Ideate mints no intent itself. VerdictSurvives Verdict = "survives" // VerdictKilled: a leg was fatal. The record is the reason it stays dead. VerdictKilled Verdict = "killed" // VerdictReframed: the idea as posed does not survive, but a reframing of it // does; the record carries both. VerdictReframed Verdict = "reframed" )