Documentation
¶
Overview ¶
Package worklang is the bounded reader for a `.work` plan (docs/SPEC-WORKLANG.md).
A plan is data the kernel reads, never a program it evaluates. The reader is the restricted-Lisp grammar the rest of this repo already uses for work files: a sequence of s-expressions made only of lists, keywords, strings, integers and bare symbols, with every evaluation form refused at the boundary and three bounds enforced as the reader runs -- bytes, nesting depth and node count. Nothing read here is ever evaluated: there is no eval, and a dispatch macro is a refusal with the byte offset that owes it, not a form the reader will run.
Every refusal is a *Refusal carrying exit code 2, so the command that opens a plan can print one line and stop, never a partial parse.
Index ¶
- Constants
- func ExpandDir(out string, cards []Card) (int, error)
- func FindCycles(order []string, needs map[string][]string) [][]string
- func KnownKinds() []string
- func KnownOutcomes() []string
- func KnownStates() []string
- func ParseStamp(s string) (time.Time, error)
- func RenderCard(c Card) []byte
- func Requests(units []Unit) []jobs.Request
- type Affinity
- type Attempt
- type Blocker
- type Budget
- type Card
- type Collection
- type Counts
- type Criterion
- type Finding
- type Form
- type Graph
- func (g *Graph) Blocks(id string) []string
- func (g *Graph) Edges() int
- func (g *Graph) Len() int
- func (g *Graph) Needs(id string) []string
- func (g *Graph) NeedsBroken(id string) bool
- func (g *Graph) Order() []string
- func (g *Graph) Ready(id string) (bool, *Blocker)
- func (g *Graph) ReadySet() []string
- func (g *Graph) Revert(id string)
- func (g *Graph) Settle(id string)
- type Kind
- type Limits
- type Node
- type Options
- type Plan
- type Refusal
- type Status
- type Tool
- type Unit
- func (u Unit) Acceptance() []Criterion
- func (u Unit) AcceptanceText() []string
- func (u Unit) Attempts() []Attempt
- func (u Unit) Branch() string
- func (u Unit) Collections() []Collection
- func (u Unit) Deadline() string
- func (u Unit) Done() bool
- func (u Unit) Keys() []string
- func (u Unit) Lane() string
- func (u Unit) Needs() []string
- func (u Unit) Owner() string
- func (u Unit) Request() jobs.Request
- func (u Unit) Resources() map[string]int64
- func (u Unit) State() string
- func (u Unit) Status() string
- func (u Unit) Title() string
- func (u Unit) Tools() []Tool
- func (u Unit) Warm() WarmState
- func (u Unit) Writes() []string
- type WarmState
- type WorkSet
- func (w *WorkSet) Blocked(extra map[string]bool) map[string]string
- func (w *WorkSet) Check(opts Options) ([]Finding, Counts)
- func (w *WorkSet) DoneSet(extra map[string]bool) map[string]bool
- func (w *WorkSet) Ready(extra map[string]bool) []Unit
- func (w *WorkSet) Unit(id string) (Unit, bool)
- func (w *WorkSet) WithoutAcceptance() []string
Constants ¶
const CardFile = "card"
CardFile is the name of the file one card is written to inside its directory.
Variables ¶
This section is empty.
Functions ¶
func ExpandDir ¶
ExpandDir writes one card directory per node under out, and returns the number of cards it wrote. A card already present is left byte-identical, so a re-expansion after one fact changes appends only the new card and mints no id: the directory name is the node's own stable id.
func FindCycles ¶
FindCycles names every `:needs` cycle in a graph, each once. refuseCycle stops at the first because a plan with one is refused whole; a checker prints them all, and both walk this one function so the two can never find different cycles.
The walk is the same three-colour depth-first search: grey is the path being walked and a grey node reached again closes a cycle. The cycle is normalised to start at its smallest member so that the same loop entered by two of its members is reported once.
func KnownKinds ¶
func KnownKinds() []string
KnownKinds returns the kind names the plan grammar admits, in spec order.
func KnownOutcomes ¶
func KnownOutcomes() []string
KnownOutcomes returns the attempt outcomes the grammar admits.
func KnownStates ¶
func KnownStates() []string
KnownStates returns the unit states the grammar admits, in spec order.
func ParseStamp ¶
ParseStamp reads any of those spellings as UTC and refuses anything else naming what it accepts, rather than falling back to a clock.
func RenderCard ¶
RenderCard renders one card deterministically: the same Card always produces the same bytes, so a re-expansion is byte-identical.
Types ¶
type Affinity ¶
Affinity names which bench kind may pull the card and which route serves it. Model is the route's model class when the plan pins it; an empty Model means the class is a projection from facts this slice does not read.
type Attempt ¶
type Attempt struct {
N int64
Rung string
Owner string
Started string
Outcome string
HasProof bool
Proof Form
}
Attempt is one record of one try at a unit: which rung ran it, who owned it, when it started, how it ended, and whether it proved termination.
type Blocker ¶
Blocker is the exact reason a node cannot proceed: the first unmet need, its state, and the join that resolves it.
type Budget ¶
Budget is one card's wall: its minutes, its token ceiling and the lowest model class admitted.
type Card ¶
type Card struct {
Node string
Kind string
Repo string
Base string
Needs []string
Blocks []string
Ready bool
Inputs []string
Result string
Branch string
Green []string
Budget Budget
Affinity Affinity
}
Card is one expanded node: everything the bench needs, and nothing the plan did not write. Its fields are the spec's output contract, budget and affinity, plus the needs/blocks edges the graph derived.
func ExpandPlan ¶
ExpandPlan validates a hand-written plan, builds the needs/blocks graph and returns one Card per node in plan order. It refuses an absent need or a cycle (through the job graph's rules 2 and 3), an unadmitted top-level form, a duplicate branch name, and a budget below its floor -- always before a card is written.
type Collection ¶
Collection is one output collection: named before the run, its members known only after it.
type Counts ¶
Counts is the one summary line's arithmetic: units = ready + blocked + done. owned is the units that name an owner, the ones the machinery routes to a friend rather than cutting as a card.
type Finding ¶
type Finding struct {
Rule string
Unit string
// Key and Value are the rule's own field -- need=<id>, owner=<name>,
// cycle=<a->b->a> -- kept apart so the printing site escapes the value on
// its own and a unit id with a space can never break the line.
Key string
Value string
Remedy string
Offset int
}
Finding is one thing wrong with the CONTENT of a work set: the rule that caught it, the unit that owes it, and the fields the line prints. Rule is the word the SET line carries, so a caller greps one word rather than a sentence.
type Form ¶
type Form struct {
Kind Kind
Offset int
List []Form
Value string // keyword name (no colon) or decoded string
Int int64
}
Form is one restricted s-expression. Offset is the form's first byte, so a refusal can name where in the file it happened.
func Read ¶
Read reads exactly one restricted form from data, holding it to limits and refusing anything else. The file name is carried into every refusal.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is the closed needs/blocks graph a plan declares. order is seed order, the order every node is admitted in; needs is the forward edge and blocks the inverse, both derived from the same declarations so the graph never holds one without the other.
func (*Graph) Blocks ¶
Blocks returns the reverse edges of id in seed order. It is the inverse of Needs, written by the same insert.
func (*Graph) Needs ¶
Needs returns the forward edges of id in seed order: the nodes it cannot begin before.
func (*Graph) NeedsBroken ¶
NeedsBroken reports whether a reverted need has left id flagged needs-broken.
func (*Graph) Ready ¶
Ready reports whether id may proceed, and when it may not, the exact blocker and its resolver. A node is ready only when every need is terminal accepted and no reverted need has left it needs-broken. A node already terminal accepted has nothing left to begin.
func (*Graph) ReadySet ¶
ReadySet is the mechanical ready set: the nodes with no unmet need, in seed order. The graph's own nodes are all admitted; only the ready ones are pullable.
type Kind ¶
type Kind int
Kind is the type of one restricted form.
const ( // List is a parenthesized form, possibly empty. List Kind = iota // Keyword is a `:name` token, stored without the leading colon. Keyword // String is a double-quoted string, stored decoded. String // Integer is a decimal integer. Integer // Symbol is a bare token such as go-fix or false, stored verbatim. The // plan language uses symbols for values that are not text (kind names, // booleans), and they are data: nothing here is ever evaluated. Symbol )
type Limits ¶
Limits is the three bounds every plan read is held to. A zero value is not usable; build one with DefaultLimits or set all three. The names are the flag names the caller exposes: --max-bytes, --max-depth, --max-nodes.
func DefaultLimits ¶
func DefaultLimits() Limits
DefaultLimits is the shape the kernel's intake limits already carry (lisp/nova-work/src/control.lisp): 64 KiB, depth 64, 4096 nodes.
type Node ¶
Node is one `:node` of a plan: its known Fields and the unknown keys beside them, preserved so a later slice can read what this one ignores.
type Options ¶
type Options struct {
// Minds is the set of known owners, folded to lower case. Nil means no --minds
// was given and no owner is checked.
Minds map[string]bool
// MindsFile is what Minds was read from, named in the finding so the remedy
// says which file to add the row to.
MindsFile string
// Lanes is the set of known lane names. Nil means no --lanes was given and no
// lane is checked.
Lanes map[string]bool
LanesFile string
// Done names units that are done regardless of what the file says, for a
// caller that holds the settled facts the document does not.
Done map[string]bool
}
Options is what Check needs from outside the language. Every one of them is optional, and an absent one turns its rule OFF rather than inventing a default: there is no default minds file, no default lanes file and no discovery.
type Plan ¶
Plan is the reader's view of a `.work` file. Unknown forms at the top level are preserved and ignored.
type Refusal ¶
Refusal is a plan this reader would not read. It is always exit 2: the tool could not run, and the input is refused whole rather than truncated.
type Status ¶
Status is the settled facts the journal holds for one node. A node is terminal accepted when it has merged and gone green and has not been reverted.
type Tool ¶
Tool is one verb a unit needs installed, at a version, with an optional semantic key: when the key moves the unit's outputs are invalid even though the version did not change.
type Unit ¶
type Unit struct {
ID string
Offset int
Fields map[string]Form
Unknown map[string]Form
// contains filtered or unexported fields
}
Unit is one (unit "<id>" ...) form: its stable id, its known Fields and the unknown keys beside them, preserved so a later slice reads what this one ignores.
func (Unit) Acceptance ¶
Acceptance returns the unit's acceptance criteria in A14's schema: the evidence that closes the unit. A criterion written as a bare sentence is not one of these -- it is in AcceptanceText -- because a sentence names no predicate a tool can read.
func (Unit) AcceptanceText ¶
AcceptanceText is the unit's acceptance in the older spelling: the sentences a person wrote, which is what the sets on the bench carry and what an ask note renders. A criterion written as a (:id ...) form contributes its subject, so one caller reads both spellings and there is no second reader of the key.
func (Unit) Branch ¶
Branch is the :branch a unit's owner replies on. It is read HERE with every other key because there is ONE reader of this form: a key only the ask side read would be the second reader of the work set growing back.
func (Unit) Collections ¶
func (u Unit) Collections() []Collection
Collections returns the unit's output collections.
func (Unit) Deadline ¶
Deadline is the :deadline text EXACTLY as written. It is parsed by the caller, because an unreadable deadline is a finding about one unit and never a refusal of the whole set.
func (Unit) Done ¶
Done reports the :done key, read as true for the handful of spellings a person writes for yes. Anything else is false: a :done nobody can read is not a unit this tool will call finished.
func (Unit) Keys ¶
Keys returns every key the unit's form carried, known or not, in written order. It is what lets a later slice read what this one ignores without a second reader over the same bytes.
func (Unit) Lane ¶
Lane returns the unit's lane -- the resource of capacity 1 over the area of the tree queue/control/lanes.tsv names -- from :resources first and the plain :lane key second, so the set as written today keeps working.
func (Unit) Owner ¶
Owner returns the mind that owns the unit: a friend, a child rung, a swarm, or "all". One spelling, so `nova-work ask` and the pull worker read the same form.
func (Unit) Request ¶
Request is the unit's admission request: the vector it consumes and the paths it writes. The lane comes from :resources first and the plain :lane key second -- the reader already reconciles the two (A6) -- and it enters the vector as a NAMED dimension, because `lane:docs` and `lane:merge` do not contend and one opaque "lane" count could not tell them apart.
func (Unit) Resources ¶
Resources returns the unit's resource vector as counts. A lane is capacity 1 under the key "lane"; a named scarce class is "class:<name>"; every other entry keeps its own name. Admission against these counts is the kernel's, not this reader's.
func (Unit) State ¶
State returns the unit's state, "open" when it carries none. `uncertain` is a state of its own.
func (Unit) Status ¶
Status is the :status value as written -- "closed", :review -- one of the three ways a unit says it has finished. The other two are :done and the caller's own list.
func (Unit) Title ¶
Title is the unit's display text. The id is never it: A2 keeps the two apart so a rename is a new id carrying :was, not a re-pointed one.
func (Unit) Tools ¶
Tools returns the verbs the unit needs installed, with their versions and optional semantic keys.
type WarmState ¶
WarmState is the retained/active split. Retained entries are held between units (a kept worktree, a loaded compiler); active entries are what the unit is using while it runs. They are accounted apart so warmth is never charged as running capacity.
type WorkSet ¶
type WorkSet struct {
File string
ID string
// Title is the set's :title as written, kept beside Fields because it is
// the one field of the set a caller prints rather than walks.
Title string
Fields map[string]Form
Unknown map[string]Form
Units []Unit
// contains filtered or unexported fields
}
WorkSet is the reader's view of one (work-set ...) file.
func ParseWorkSet ¶
ParseWorkSet reads a work set and validates the shapes this reader owns: the top form, every unit's id, and the shape of each amendment key. A refused set is refused whole at exit 2, never half-read. This is A2's door: a unit with no id, an empty id, or an id another unit already carries is refused here.
func ParseWorkSetTolerant ¶
ParseWorkSetTolerant reads the same form but carries a broken IDENTITY through instead of refusing it: a member of :units that is not a unit, an empty id and a repeated id all come back as units at their own byte, for Check to report as findings in one pass. Everything else -- a file that cannot be read, a :units that is not a list, an amendment key whose shape is wrong -- is still a refusal, because those are not findings about one unit.
The two doors exist because the two callers want different answers. A kernel loading a set wants A2 enforced before anything is scheduled; a checker wants every defect of the file in one pass, and a reader that stopped at the first would cost its caller a round trip per defect.
func (*WorkSet) Blocked ¶
Blocked is the complement of Ready among the open units: each one with the first need that is holding it. It is the same walk, so the two can never disagree.
func (*WorkSet) Check ¶
Check validates one work set whole and returns EVERY finding, in the order the rules run and the units are written. It never stops at the first: a checker that did would cost the caller one round trip per defect.
The rules:
- every unit has an id, and no two units share one
- every :needs names a unit of this set
- the :needs edges are acyclic
- every :owner is a mind --minds names (off without --minds)
- every :lane is a lane --lanes names (off without --lanes)
- every :deadline is an instant, in either RFC3339 spelling
A unit is done when it says so (`:done`, or a `:status` of closed, done, landed or merged) or when Options.Done names it. It is ready when it is not done and every need is done; blocked when it is not done and some need is not.
func (*WorkSet) DoneSet ¶
DoneSet is every unit this run counts as finished: what the document says and what the caller's --done adds. It is the only input to readiness, so the ready set is mechanical -- a function of the language and the settled facts, never of anyone's judgment.
func (*WorkSet) Ready ¶
Ready is the mechanical ready set: the units that are not done and whose every need is done, in written order. It is what a coordinator asks the language for -- "what can be pulled right now" -- and it is derived, never maintained by hand.
func (*WorkSet) WithoutAcceptance ¶
WithoutAcceptance returns the ids of the units that name no evidence. It is the report rule A14 owes: a unit with no acceptance names no finish line, and the real set of 2026-09-17 has not one.