deadend

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

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

func PossiblySuperseded(scope Scope, when int64, now time.Time) bool

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

func Render(proposed string, hits []Ruling) string

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

func ParseRecord(raw string) Record

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.

func (Record) Typed added in v0.3.4

func (r Record) Typed() bool

Typed reports whether this parsed as the structured shape at all, rather than falling back to free prose. Used to decide whether Layer/Scope/etc are worth rendering.

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.

func Collect

func Collect(vaultDir string, db *sql.DB, project string) ([]Ruling, error)

Collect gathers every recorded dead end. An empty project means the whole vault, which is the interesting case: the approach that failed on one project is often the same approach about to be proposed on another.

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
)

type Source

type Source string

Source says where a ruling came from, which is also how much to trust it.

const (
	// FromCheckpoint is a Failed entry someone deliberately recorded.
	FromCheckpoint Source = "checkpoint"
	// FromNote is a working note that reads as a failure. Never committed, so
	// it may be a first impression rather than a conclusion.
	FromNote Source = "working note"
)

Jump to

Keyboard shortcuts

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