Documentation
¶
Overview ¶
Package deadend answers one question: has this been tried before?
Every other retrieval path here is pull — an agent asks, and the store answers. This one is push. The agent is about to propose something, and the useful move is to interrupt: *you tried that in March, here is why it did not work, here is who found out.*
The distinction matters more than it looks. `resume` gives an arriving agent the last checkpoint, which covers the approach ruled out yesterday on the project it is already working on. It does nothing for the approach ruled out in March, on a project nobody mentioned, by an agent that no longer exists. That knowledge is in the vault — it just has no way of reaching the moment it would have been useful, because nobody thinks to search for the thing they are about to suggest.
So the corpus is every dead end recorded anywhere in the vault, and the query is the proposal itself. This is also the part of the system that cannot be copied: the mechanism is a morning's work, and the two years of accumulated "we tried that" is not.
What counts as a dead end ¶
Checkpoints carry a Failed list, which is the curated corpus — someone chose to write those down as ruled out. Working notes are messier and matter anyway: an agent killed before it could check in leaves its findings only there, and "the audio team vetoed dropping the second mic" is exactly the kind of thing that dies with the session. Those are admitted when they read as a failure, by an explicit marker rather than by sentiment, because a note wrongly filed as a dead end will stop work that should have happened.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func PossiblySuperseded ¶ added in v0.3.8
PossiblySuperseded reports whether a version-bound ruling is old enough that the dependency it names may have moved since. It is a time-based guess, not a check against an actual manifest — Logos has no dependency graph to consult — so it is always surfaced as a caveat, never a silent drop and never a hard "this no longer applies".
func Render ¶
Render writes the interruption.
The wording is doing real work here, and it is not decoration. This output lands in front of a model that is about to propose something, and there are two ways to get it wrong. Too soft — "you may wish to consider" — and it gets skimmed past. Too hard — "this will not work" — and it stops an agent from retrying something that deserves a second look, which is worse, because a dead end recorded a year ago under different constraints is evidence, not a verdict.
So the shape is: state plainly that it was tried, say by whom and when, and hand the decision back. The agent is told to say out loud that it knows, because the visible version of this — "we tried that in March, the drop test failed at 1.2m" — is the difference between a memory that stores and a memory that helps.
Types ¶
type Action ¶ added in v0.3.4
type Action string
Action is what the person who found this out recommends doing with that knowledge, distinct from Alternative, which is what to do instead.
const ( ActionRetry Action = "retry" // worth trying again — conditions may have changed ActionChangeMethod Action = "change-method" // the goal is fine, this route to it is not ActionNarrowScope Action = "narrow-scope" // works, but only for a smaller case than proposed ActionAbandon Action = "abandon" // the goal itself should be dropped )
type Degree ¶ added in v0.3.4
type Degree string
Degree says how hard the evidence is. "Failed" covers everything from "the spec forbids it" to "it flaked once and nobody chased why", and those deserve different weight from a reader deciding whether to retry.
const ( DegreeContradicted Degree = "contradicted" // demonstrated not to work DegreePartial Degree = "partial" // worked for part of the case, not all of it DegreeInconclusive Degree = "inconclusive" // tried, no clear result either way DegreeUnstable Degree = "unstable" // worked sometimes, not reliably )
type Layer ¶ added in v0.3.4
type Layer string
Layer names where in the stack a dead end lives. It is the first question anyone re-attempting the approach actually needs answered: a ruling about a dependency's behaviour transfers across projects that share the dependency; one about this project's design does not transfer at all.
const ( LayerImplementation Layer = "implementation" LayerDesign Layer = "design" LayerEnvironment Layer = "environment" LayerDependency Layer = "dependency" LayerRequirement Layer = "requirement" // LayerUnclassified is not a fifth peer alongside the five above — it is // what an ordinary, free-prose Failed entry gets, so every checkpoint // written before this schema existed keeps reading exactly as it did. LayerUnclassified Layer = "unclassified" )
type Record ¶ added in v0.3.4
type Record struct {
Route string
Observation string
Layer Layer
Scope Scope
Degree Degree
Action Action
Alternative string
Raw string
// Truncated is set when the source entry ran past recordCap and was cut
// to fit. The cut is visible here rather than silent, per the invariant
// that a lossy operation says so.
Truncated bool
}
Record is one dead end, typed. Route and Observation are required for a record to count as typed at all; Layer/Scope/Degree/Action/Alternative are each optional and simply absent from Render when unset.
Raw is always populated — the on-disk form, exactly as recorded — because a hand-edited or partially-typed entry should still be readable rather than silently losing whatever did not parse.
func ParseRecord ¶ added in v0.3.4
ParseRecord turns one Failed or working-note entry into a typed Record.
The wire format is unchanged — Failed is still `[]string`, and a record is still one bullet, one line — so the shape lives entirely in the text: a line of `key: value` segments joined by " | ", anchored on a `route:` key. Anything else, including every Failed entry ever written before this existed, is not that shape and comes back as free prose with Layer: unclassified — the same record type, so a caller never has to branch on which kind of entry it got.
type Ruling ¶
type Ruling struct {
Text string `json:"text"`
Project string `json:"project"`
Agent string `json:"agent"`
When int64 `json:"when"`
Slug string `json:"slug,omitempty"`
Source Source `json:"source"`
Score float64 `json:"score"`
// Elsewhere is true when this was ruled out on a different project than the
// one being asked about. Still worth saying, and worth flagging: what failed
// on other hardware may not fail here, and presenting it as settled would be
// the same overreach this package exists to prevent.
Elsewhere bool `json:"elsewhere"`
// Record is Text, typed — Layer: unclassified and a Route equal to Text
// itself for every ruling recorded before this schema existed. Kept
// alongside Text rather than replacing it so nothing here has to branch on
// which kind of entry it got.
Record Record `json:"record"`
// Stale marks a version-bound ruling old enough that the dependency it
// names may have moved since — see PossiblySuperseded. Never grounds for
// dropping the ruling, only for saying so.
Stale bool `json:"stale,omitempty"`
}
A Ruling is something already tried that did not work.
func Check ¶
func Check(vaultDir string, db *sql.DB, p *provider.Provider, embedModel, proposed, project string, k int) ([]Ruling, error)
Check returns the recorded dead ends bearing on a proposed approach, best match first.
Two ways to match, either sufficient. Lexical containment catches a proposal restating the original almost word for word, which is the common case when an agent has read the project note and is working from the same vocabulary. Embedding similarity catches the opposite case — the same idea in different words — and is what makes this useful across projects, where the vocabulary has no reason to line up. With no embedder available the lexical arm still works, so this degrades rather than disappearing.
type Scope ¶ added in v0.3.4
type Scope string
Scope says how far a ruling travels. The distinction Check already draws between "this project" and "elsewhere" is about where a ruling was made; Scope is about where it still applies, which is a different question — a version-bound ruling may no longer hold even on the project that made it.
const ( ScopeLocal Scope = "local" // true of this codebase's particular choices, not the approach in general ScopeVersionBound Scope = "version-bound" // true against a dependency version that can move out from under it ScopeGeneral Scope = "general" // true of the approach itself, not tied to a version or a local choice )