ask

package
v0.34.3 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package ask is SpecScore Studio's deterministic question router — the engine behind `specscore studio ask "<question>"`. It is NOT an LLM: it lowercases the question, matches it against a fixed library of 13 parameterized question *templates* (each a keyword trigger plus a captured parameter), resolves the captured parameter through resolve.Resolve where the template targets an entity, runs the template's pure store query over a `[]fact.Fact` slice, and returns an answer that always carries citations (the facts it stands on).

Feature: cli/studio/answers (REQ: ask-verb-and-router, REQ: ask-citations, REQ: ask-unroutable)

The router is deterministic: templates are tried in a fixed order and each trigger is a plain prefix/suffix keyword match on the lowercased question, so the same question always routes the same way. A trigger captures the parameter as the text between an opening keyword and (optionally) a closing keyword — the "is <X> green" / "is <X> live" shapes disambiguate on their closing keyword, never on order-dependent guessing. A question matching no template is unroutable (the caller exits 1 and lists the templates); a question that routes but whose parameter resolves to no facts is routed-but-empty (the caller exits 3) — never a citation-free assertion.

The package is pure of CLI wiring: Route and each template's Query take the full fact slice and return values, so both the `ask` verb and the benchmark runner drive it the same way.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Resolve

func Resolve(facts []fact.Fact, param string) resolve.Result

Resolve canonicalises an entity parameter through resolve.Resolve for a template whose TargetsEntity is true (REQ: ask-verb-and-router routes the parameter through resolve semantics). It returns the resolve.Result so the caller can render an ambiguous parameter per the house AmbiguousSlug rule. The resolved id (Result.ID for Unique) is what Query receives as its param.

Types

type Answer

type Answer struct {
	// Answer is the human-readable prose answer.
	Answer string
	// Citations are the supporting facts, never empty for a real Answer.
	Citations []Citation
}

Answer is a routed, non-empty template result (REQ: ask-verb-and-router): the human-readable answer prose plus the citations it stands on. An Answer is only ever returned with a non-empty Citations slice — a zero-fact result is not an answer (REQ: ask-citations) and surfaces as the routed-but-empty path.

type Citation

type Citation struct {
	Subject   string `json:"subject"`
	Predicate string `json:"predicate"`
	Object    string `json:"object"`
	Class     string `json:"evidence_class"`
	Pointer   string `json:"evidence_pointer"`
	Adapter   string `json:"adapter"`
}

Citation is one supporting fact named on an answer (REQ: ask-citations): the full triple plus the evidence class, pointer, and adapter id so a caller can render the "why" of every answer without a second store query. The field set is exactly the shape the Feature's ask-citations REQ pins.

type Template

type Template struct {
	// ID is the stable template id (e.g. "who-fronts").
	ID string
	// Forms are the human-readable trigger forms surfaced by --list and the
	// unroutable notice (e.g. `who fronts <X>`).
	Forms []string

	// TargetsEntity is true when the captured parameter is an entity name the
	// router canonicalises through resolve before calling Query.
	TargetsEntity bool
	// Query runs the template's store query over facts for the (already
	// resolved, when TargetsEntity) parameter and returns an Answer plus ok. ok
	// is false when no supporting fact exists (routed-but-empty).
	Query func(facts []fact.Fact, param string) (Answer, bool)
	// contains filtered or unexported fields
}

Template is one entry in the router's fixed library: a stable id, the trigger forms shown by `--list` and the unroutable notice, its parameter-capture triggers, and a pure Query over the fact slice. TargetsEntity marks templates whose captured parameter is an entity name to canonicalise through resolve.Resolve before Query runs; when false (only aliases-resolve) the raw parameter is passed to Query, which does its own resolution.

func Route

func Route(question string) (Template, string, bool)

Route matches question against the template library (REQ: ask-verb-and-router): it lowercases the question, tries each template's triggers in order, and on the first hit returns the template, the captured parameter (trimmed), and true. It returns ok=false when no template matches (the unroutable path). The captured parameter is the entity between the trigger's prefix and suffix — for entity-targeting templates the caller resolves it before running Query.

func Templates

func Templates() []Template

Templates returns the router's 13 templates in trigger-match order. Every trigger is disambiguated by its prefix+suffix keyword pair, so order only breaks ties between genuinely overlapping shapes; the "ci status of <X>" trigger precedes the bare "status of <X>" so a CI question never matches the lifecycle-status template.

Jump to

Keyboard shortcuts

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