Documentation
¶
Overview ¶
Package lane resolves the board's columns.
A board is its lane directory: the lane files under <root>/.jaira/lanes/ are the board, in the order of the order file beside them, and nothing is added underneath. The shipped lanes are compiled into the binary as the catalogue's standing offer, together with the files under ~/.jaira/lanes; a board opened for the first time gets its files written from the default board's selection or from the shipped lanes, and from then on 'jaira lanes add' and 'remove' are what change it. Both kinds of file go through this same parser: a shipped lane is not a special case, it is a lane that happens to ship inside the executable.
A board's file that shares a shipped lane's id is that lane — the user owns the pipeline and nothing about it is off limits. The loader's one reservation is a protection the shipped lane carried and the file drops; that is reported, because it is exactly what the protection guards against. See Load.
Index ¶
- Constants
- Variables
- func Add(root string, set *Set, id string) (string, string, []string, error)
- func BoardOf(t *ticket.Ticket) string
- func Boards(root string) []string
- func Bytes(l *Lane) ([]byte, error)
- func ContextInvalidMessage(l *Lane) string
- func DefaultBoardPath() string
- func Description(root, name string) string
- func DescriptionPath(root, name string) string
- func Export(l *Lane, dstDir string, overwrite bool) (string, error)
- func LanesOf(root string) func(*ticket.Ticket) *Set
- func LoadOrder(root string) ([]string, error)
- func Materialise(root string, set *Set, ids []string) (written []string, warnings []string, err error)
- func Move(ids []string, id string, delta int) []string
- func MoveLane(root string, set *Set, id string, delta int) error
- func NormalizeBoard(name string) (string, error)
- func ProjectLanesActive(root string) bool
- func ProjectLanesDir(root string) string
- func Publish(l *Lane, dstDir, who string, overwrite bool) (string, error)
- func RefreshDrift(d DriftEntry) error
- func Remove(root string, set *Set, store *ticket.Store, id string) (string, error)
- func ResolveOptions(set *Set, board *DefaultBoard) []ticket.BodyOption
- func SaveDefaultBoard(b *DefaultBoard) error
- func SaveOrder(root string, ids []string) error
- func Settle(s *ticket.Store, l *Lane, folder, moved string, ...) (trimmed []ticket.Trimmed, filed bool, err error)
- func UserLanesDir() string
- func Validate(board *DefaultBoard, set *Set) []string
- type DefaultBoard
- type DriftEntry
- type Lane
- type Refreshed
- type Set
- func (s *Set) Columns(statuses []string) []*Lane
- func (s *Set) Default() *Lane
- func (s *Set) Facts() []board.LaneFact
- func (s *Set) Get(id string) (*Lane, bool)
- func (s *Set) IDs() []string
- func (s *Set) Index(id string) int
- func (s *Set) Next(t *ticket.Ticket) *Lane
- func (s *Set) Options() []string
- func (s *Set) Precedence(id string) int
- func (s *Set) Terminal() *Lane
- type SharedLane
Constants ¶
const ( ContextFresh = "fresh" )
The two values a lane's context: field takes. See Lane.Context.
const ( RefreshUnchanged = "unchanged" RefreshUpdated = "updated" RefreshSkipped = "skipped" )
Results of RefreshShipped, the same words 'jaira roles install' uses.
const DefaultBoardName = "default"
DefaultBoardName stands for the board a repository has always had, the one in <root>/.jaira/lanes/. That board carries no name on disk and a ticket on it carries no board: field, so every board from before there were several keeps working untouched. The name exists only for the command line and the TUI, where "no board given" and "today's board" have to be said out loud.
const Template = `` /* 2835-byte string literal not displayed */
Template is the skeleton a fresh lane file starts from: every field parse() reads, commented, plus a prompt body — a file this parses without error, so the template cannot rot away from the parser it feeds.
Shared by 'jaira lanes template' and the lane settings screen's 'n' key, so there is one skeleton to keep in sync with parse(), not two.
Variables ¶
var ErrNoSuchBoard = errors.New("no such board")
ErrNoSuchBoard is returned for a board name with no lane files behind it.
Functions ¶
func Add ¶
Add brings a built-in or catalogue lane onto this board: the lane's file is written into the board's lane directory and its id placed where its after: field says it belongs. It refuses a lane already part of set — "already in this project" — rather than re-exporting it. The returned warnings say what the placement had to assume, the same way Load reports an anchor it could not resolve.
The second return is the id the lane now follows, empty when it went to the front. Placement is the whole point of the call and the one thing a caller cannot see: a chain resolved through uninstalled lanes lands 'jaira lanes add testing' between in-progress and human, and silently, because warning on the path the board itself advertises would be noise. So the neighbour is handed back to be said out loud instead.
func BoardOf ¶ added in v0.5.3
BoardOf is the board t runs on, "" for today's — however its board: line spells that.
func Boards ¶ added in v0.5.3
Boards lists the named boards of root, sorted. A board is there when its lanes/ directory holds a lane file; an empty directory is not a board yet.
func Bytes ¶
Bytes returns a lane's file content verbatim: from the embedded binary for a built-in, from disk for anything else. Callers that need to copy a lane (Export, Publish, Materialise) go through this rather than re-serialising the parsed struct, so unknown fields, comments and field order all survive — the file format is the API.
func ContextInvalidMessage ¶ added in v0.3.7
ContextInvalidMessage says what is wrong with a lane whose context: value is neither fresh nor shared, and what the board does with it meanwhile.
func DefaultBoardPath ¶
func DefaultBoardPath() string
DefaultBoardPath is the per-user file that decides a new board's lanes and which ticket Options start ticked. $JAIRA_DEFAULT_BOARD overrides it — an explicit override rather than a sibling of UserLanesDir, because a test needs to point at a temp file and deriving a sibling path from an already-overridable directory breaks the day someone points JAIRA_LANES_DIR at something that is not <something>/lanes.
func Description ¶ added in v0.5.3
Description is board name's description on one line: its lines trimmed and joined by a space, so a description wrapped by hand still reads as the one sentence it is. "" when the board has none.
func DescriptionPath ¶ added in v0.5.3
DescriptionPath is where board name's description lives, whether or not it has one yet — so a listing can say where to write it.
func Export ¶
Export copies a lane's file, verbatim, from wherever it was loaded from into dstDir — the catalogue-to-project move. It refuses to overwrite an existing file unless overwrite is true, so the caller (the lane settings screen) decides rather than silently clobbering a project's own copy.
func LanesOf ¶ added in v0.5.3
LanesOf returns a lookup of each ticket's own board's lanes in root, each board loaded once, for a command that walks tickets of every board. A board that cannot be loaded gives nil.
func LoadOrder ¶
LoadOrder reads a project's column order file. An absent file is not an error: it means the project has not customised its column order, and callers fall back to today's after:-anchor-derived order.
func Materialise ¶
func Materialise(root string, set *Set, ids []string) (written []string, warnings []string, err error)
Materialise writes the lanes named by ids — resolved against set, which is the offer Load("") returns — into <root>/.jaira/lanes/ as files, and writes the order file in that same order. Load calls it the first time a board is opened with no lanes of its own; 'jaira init' therefore needs nothing more than to load the board it just created. An id set does not have is a warning, not a failure: one unknown name in a default board must not leave a board without lanes.
func Move ¶
Move returns a copy of ids with id shifted delta positions — -1 is one step toward the front, +1 one step toward the back. It is the user's model exactly: moving a lane one step swaps it with its neighbour. Moving past either end is a no-op, not an error and not a wrap-around: asking to move further than the board allows is not the same as asking for a mistake.
func MoveLane ¶
MoveLane shifts id one step in this project's column order and writes the order file — the one implementation the CLI's 'lanes move' and the settings screen's H/L keys both call, so "move a lane" never has two bodies to drift apart.
func NormalizeBoard ¶ added in v0.5.3
NormalizeBoard maps the ways of naming today's board — nothing, or "default" — to "", which is how a ticket on it stores its board, and checks any other name. It does not look at the disk; LoadBoard does.
func ProjectLanesActive ¶
ProjectLanesActive reports whether root's project lane directory is currently authoritative per D-03: present and holding at least one lane file. Load and 'jaira lanes path' both need this same test, so it lives here once rather than as two copies that could drift apart.
func ProjectLanesDir ¶
ProjectLanesDir is where a project scopes itself down to the lanes it actually uses. Per D-03 it is authoritative when present and non-empty: it replaces the catalogue as this project's second lane source rather than adding to it, so a project directory holding only three lane files means a three-lane board, not the catalogue plus three overrides.
func Publish ¶
Publish copies a lane's file into dstDir (normally Store.SharedDir()/identity.Slug(who)), stamping creator: with who when the file does not already declare one. It refuses to overwrite an existing file unless overwrite is true.
func RefreshDrift ¶
func RefreshDrift(d DriftEntry) error
RefreshDrift pulls the catalogue copy into the project, in the direction the user asked for — nothing syncs on its own, per D-02.
func Remove ¶
Remove takes a lane off this board — never out of the catalogue — refusing when any ticket currently sits in it, naming them: a lane that vanishes under a ticket leaves it in a lane nothing knows. The board is its lane directory, so removing is deleting the file and its line in the order file; a shipped lane stays on offer in the catalogue and 'jaira lanes add' brings it back.
func ResolveOptions ¶
func ResolveOptions(set *Set, board *DefaultBoard) []ticket.BodyOption
ResolveOptions turns a default board's option choices into the ticked/ unticked list a new ticket's Options checklist needs, against the options this set's installed lanes actually declare. An option the board names that no lane requires is silently dropped here — 'jaira lanes' reporting that typo is Validate's job, not this function's.
func SaveDefaultBoard ¶
func SaveDefaultBoard(b *DefaultBoard) error
SaveDefaultBoard writes b to b.Path with lanes: and options: in a fixed order, so a saved file diffs predictably. The prose body is preserved verbatim if the file already had one.
func Settle ¶ added in v0.1.1
func Settle(s *ticket.Store, l *Lane, folder, moved string, prepare func(*ticket.Ticket) error) (trimmed []ticket.Trimmed, filed bool, err error)
Settle applies a lane's file rules after a move landed a ticket there — the one place that knows which rule wins. A doorway (logbook-on-entry) files the whole lane into the logbook folder, prepare running on each ticket first (the callers stamp commits there); a capped lane (holds) trims the oldest beyond the newest Holds, never the just-moved ticket. filed reports which rule ran, so a caller can word its message. Both UIs call this instead of carrying the switch themselves — four status write-sites were one too many places for the same decision.
func UserLanesDir ¶
func UserLanesDir() string
UserLanesDir is where custom lane files live. This is the catalogue: every lane a user has built or adopted, independent of any one project.
func Validate ¶
func Validate(board *DefaultBoard, set *Set) []string
Validate checks a default board against the currently installed lanes, returning warnings in the same shape core/lane's own loader already uses: an unknown lane id, an unknown option, or (carried over from LoadDefaultBoard) an unparseable file. There is one warning channel, already surfaced by 'jaira lanes', --json, the TUI warnings block and every command through loadEnv — a second reporting path for the same class of problem would be the mistake here.
board.Warnings is included as-is rather than re-derived: LoadDefaultBoard is the only place that knows whether the file failed to parse.
Types ¶
type DefaultBoard ¶
type DefaultBoard struct {
Lanes []string
Options []string
Path string
Warnings []string
// Body is the prose below the frontmatter, preserved across a save so
// SaveDefaultBoard never erases a note the user left themselves.
Body string
}
DefaultBoard is a per-user setting: which lanes a freshly initialised board gets, and which ticket Options start ticked. An absent file, an absent lanes: field, or an empty list all mean the same thing — the built-ins — which is easy to get backwards, so it is stated here rather than only in the file format.
func LoadDefaultBoard ¶
func LoadDefaultBoard() (*DefaultBoard, error)
LoadDefaultBoard reads DefaultBoardPath(). No file at all is the normal state, not a missing-configuration error, and returns a zero board. A file that exists but does not parse is warned about and treated the same as absent, rather than taking 'jaira init' or 'jaira lanes' down over one bad file — a teammate's shared default board naming their own lane, or a typo, must not break your board.
type DriftEntry ¶
DriftEntry names one lane whose project copy no longer matches its catalogue copy of the same id.
func Drift ¶
func Drift(root string, set *Set) ([]DriftEntry, error)
Drift implements D-02: it compares every lane this project's directory supplies against a catalogue file of the same id, and reports the ones whose bytes differ. Editing a lane writes through to the catalogue immediately, so it is the project's copy that goes stale, not the other way round — nothing here fixes that automatically; see RefreshDrift.
Checked only when the caller asks (the lane settings screen, on open), per the decided design: checking on every command would mean every invocation of the loader pays for a comparison most callers never look at.
type Lane ¶
type Lane struct {
ID string
Name string
Description string
// After anchors ordering to another lane's ID. Anchoring is used instead of
// a numeric position because two independently written lane files would
// otherwise both claim the same slot.
After string
// Precedence orders lanes by how far along the work is, and is what a merge
// consults so concurrent edits never revert forward progress. It is
// deliberately separate from display order: Blocked appears last on the
// board but must not outrank active work in a merge.
Precedence int
// Agentic marks a lane whose work is performed by a subagent.
Agentic bool
Terminal bool
ModelTier string
// Context says whether the agent working this lane may be the one that
// worked the lanes before it. "fresh" means it may not: the lane is handed
// to a new agent that has seen nothing of the ticket's work, because a
// judge who wrote what it judges is not a judge. "shared" says the
// opposite out loud, and empty means the file does not say. A single
// agent carries a ticket through every other agentic lane itself.
//
// Load resolves the empty case for the whole board: when no lane declares
// a context at all, the last agentic lane before the first lane a person
// owns is fresh, with ContextImplied set — so a board written before the
// field existed keeps a fresh review without a migration. See
// impliedFresh.
Context string
ContextImplied bool
// ContextInvalid holds a context: value that is neither fresh nor shared —
// a typo like "Fresh". Such a lane still loads and runs fresh, but it does
// not count as having declared a context: the board's default still
// applies when no lane carries a valid value, so a typo can add a fresh
// lane and never take one away. Load warns about it and 'jaira validate'
// fails on it.
ContextInvalid string
// Holds caps how many tickets the lane keeps. After a move lands a ticket
// here, the oldest beyond the newest Holds leave for the logbook — reported,
// never silent. 0 or absent means unlimited. Declared in the lane file so the
// one rule that moves files can be read, changed or switched off there.
Holds int
// LogbookOnEntry files a ticket straight into the logbook the moment a
// move lands it here — commits stamped first, reported, never silent. The
// lane is a doorway, not a shelf: the logbook is the record of finished
// work, so it gets everything immediately. Terminal lanes only.
LogbookOnEntry bool
// InputRequires names the ticket fields assembled into a subagent's bounded
// input. OutputProduces names the fields it must return.
InputRequires []string
OutputProduces []string
RequiresQuestion bool
RequiresOutcome bool
RequiresNonModelSignal bool
// RequiresBlockedReason means a ticket may not be parked here without saying
// what it is waiting on. Parking is cheap and forgetting is silent, so this
// is the one place the board charges for it.
RequiresBlockedReason bool
// RequiresCommits means a ticket cannot enter this lane without naming the
// commits that carry its change. It sits on the done lane rather than on
// the implementing lane's output contract, so work can move through review
// uncommitted — but nothing is accepted that cannot be checked.
RequiresCommits bool
// RequiresHumanExit means no agent may move a ticket on out of this lane —
// back to an earlier lane is allowed, since that accepts nothing. It is
// the difference between a review step that is conventionally respected and
// one that actually stops: an agent that decides its own work passed review
// would make the step decorative.
RequiresHumanExit bool
// RequiresOption names an entry in a ticket's Options checklist. When set,
// this lane is only part of a ticket's path if that option is ticked — which
// is how one ticket is planned and reviewed while another goes straight to
// implementation, without either lane being uninstalled.
RequiresOption string
// RejectsTo names the lanes a ticket goes back to when this lane finds the
// work wanting: the loop's back edges, written down. Moving backwards has
// always been allowed — the gate only checks a move that advances (see
// core/gate) — but nothing declared where back was, so the route lived in
// the prompt's prose and an agent reading the board could not see it.
//
// More than one is allowed because a rejection is not one kind of thing: a
// critique that found a flaw sends the work back to be implemented, while a
// critique that found a decision to make hands it to a person instead. Both
// are the same lane's back edge and a reader has to be able to see both.
//
// It is documentation the tool validates, not a rail: nothing forces a
// rejection to go here, exactly as nothing forces a lane's prompt to be
// followed.
RejectsTo []string
// RequiresSpecified marks the first lane, in precedence order, that sets
// this: the boundary between thinking about a ticket and working on it.
// Everything before it is a place a half-formed ticket may sit; nothing at
// or after it may hold a ticket that is missing its promotion fields.
RequiresSpecified bool
// Prompt is the markdown body: the instruction given to the subagent.
Prompt string
// Creator names who wrote this lane, for provenance once a lane has been
// adopted or copied between machines. A built-in with no creator: field
// defaults to "jaira" rather than having the field written into all nine
// shipped files; a custom lane with no creator: field is left empty, since
// "shipped by the tool" and "author unknown" are different facts.
Creator string
// Builtin distinguishes shipped lanes from user-installed ones: it says
// the lane travels inside the binary, nothing more.
Builtin bool
// Default says the lane belongs to a fresh board's selection. It is the
// second half of what Builtin used to carry alone: a shipped lane that is
// installable without the network but must not be forced on every board —
// critique, optimize, testing — ships with "default-board: false" and is
// built-in without being default.
Default bool
// Source is the path a custom lane came from, for error messages.
Source string
// Overrides names the built-in this lane displaced, empty if it does not
// override anything. Set by Load, not by parse: overriding is a fact about
// resolution, not about the file itself.
Overrides string
// Unknown marks a synthetic passthrough lane created for a ticket whose
// status names a lane this installation does not have.
Unknown bool
}
Lane is one column of the board.
func Adopt ¶
Adopt parses srcPath first — an unparseable file must never land in the catalogue — then copies its bytes verbatim into dstDir under the parsed lane's own id, never the source filename. It refuses to overwrite an existing file unless overwrite is true.
func Installable ¶
Installable lists every built-in and catalogue lane not already part of set — the "add a lane to this project" catalogue, for both 'jaira lanes add' and the settings screen's '+' column. A file that fails to read or parse is skipped rather than failing the whole listing, matching Shared's treatment of the same class of problem.
func Parse ¶ added in v0.1.1
Parse reads one lane definition from bytes that did not come from a file on this machine — a marketplace download, say — naming source in errors. It is parse without the built-in flag: nothing arriving this way ships in the binary.
func Passthrough ¶
Passthrough synthesises a read-only column for a status no installed lane claims. Hiding such tickets would be a worse failure than showing an inert column: the ticket still exists and the user needs to know it does.
func (*Lane) OnPath ¶ added in v0.3.7
OnPath reports whether a ticket walking forward would step into this lane: not a parking lane, not a question-only checkpoint, and not a lane whose option the ticket leaves unticked. It is the rule Next applies, so that anything else asking "would this ticket have gone through here" gives the same answer.
type Refreshed ¶ added in v0.5.7
type Refreshed struct {
ID, Path, Action string
}
Refreshed is what RefreshShipped did, or would do, to one lane file on a board.
func RefreshShipped ¶ added in v0.5.7
RefreshShipped brings every lane file on the board at root that is an older version of a lane this binary ships up to this binary's version, verbatim. A file equal to the shipped one is unchanged; one that is no version jaira ever shipped was edited by a person and is skipped, untouched. Lanes jaira does not ship, and shipped lanes the board does not hold, are not visited: adding a lane is 'jaira lanes add'. dryRun reports and writes nothing. Load has its usual side effects (see Load), also in a dry run. The core that ticket 0S1A7M ('lanes use --all') can expose later with a force parameter.
type Set ¶
type Set struct {
Lanes []*Lane
// Warnings records non-fatal problems (a custom lane anchored to a lane that
// is not installed, for instance) so the caller can surface them without
// failing to draw a board.
Warnings []string
// contains filtered or unexported fields
}
Set is the resolved, ordered collection of lanes.
func Load ¶
Load resolves this board's lanes.
A board is its lane directory. When <root>/.jaira/lanes/ holds lane files, those files are the board — all of it, and nothing is added to them. The built-ins are compiled into the binary as the catalogue's standing offer (Installable lists them beside ~/.jaira/lanes); 'jaira lanes add' copies one onto a board, and nothing else does. The directory is per person and gitignored, so two people on one shared board may run two different boards.
A board whose lane directory is empty is set up on first load: the default board's selection, or the built-ins when there is none, are written into the directory as files with an order file — once, reported in Warnings. This is the one place a read writes. It was asked for: a board must never sit half-configured, and the next command reads files rather than a fallback. Boards from before this rule are brought over by migrateLegacy.
A lane file the board already holds is never rewritten from the built-ins. The single exception is a named, once-only, one-field correction of a defect a shipped lane carried, applied only to a file still recognisable as that shipped lane — see correction. applyCorrections runs those and says so on stderr rather than in Warnings, because a correction speaks once and most callers here never read Warnings.
An empty root, or a root with no .jaira/ at all, means no board is in hand — the launcher spans many, a test has none, 'jaira lanes template' needs the shape only — and Load returns the offer: built-ins plus the catalogue.
A file whose id matches a shipped lane is that lane, not an override of anything: nothing is on the board to override. It is still compared with the shipped lane of that name, for one reason — if it drops a protection the shipped lane carried (requires-human-exit, terminal, requires-outcome, requires-nonmodel-signal) a warning names which, because those exist to stop an agent accepting its own work, and losing one silently is exactly what they guard against.
func LoadBoard ¶ added in v0.5.3
LoadBoard resolves the lanes of board name in root; "" or "default" is today's board and goes through Load unchanged.
A named board is read as it stands. Unlike today's board it is never set up on first load: a mistyped --board would otherwise leave a new board behind. Nobody creates one but the person who fills its lanes/ directory, and a name with no lane files behind it is ErrNoSuchBoard. The migrations and corrections Load runs belong to today's board's history; a named board has none.
func (*Set) Columns ¶
Columns returns the lanes to draw for a given set of ticket statuses, appending passthrough columns for any status with no matching lane. Unknown lanes are sorted alphabetically among themselves so the board is deterministic.
func (*Set) Facts ¶ added in v0.3.7
Facts reads a board's pipeline into the plain form core/board renders into the agent note. A nil set gives nil, so a caller without a board writes the note it wrote before lanes were in it.
The translation lives here rather than in core/board because that package is stdlib-only on purpose, and here rather than in the CLI and the TUI because both write the same note: two copies had already drifted once a lane fact was added to one of them and not the other.
func (*Set) Next ¶ added in v0.1.1
Next reports the lane this ticket goes to when the step it is in is finished.
It exists because the route was only ever implicit. The column order carries it, and a ticket's Options decide which optional steps are part of that ticket's path at all — so an agent wanting to know "where does this go next" had to load the lane set, work out the order, and apply the ticket's Options itself. Every agent doing that separately is the same derivation written four times, each free to get it wrong.
Three kinds of lane are never the answer:
- a lane this ticket opted out of (RequiresOption not ticked): it is not on this ticket's path, and moving into it is refused by the gate.
- a parking lane (RequiresBlockedReason): being blocked is a thing that happens to a ticket, not the next step in its work.
- a human checkpoint that only asks a question (RequiresQuestion): a ticket goes there because something stopped, not because it advanced.
A ticket that is itself parked or waiting on an answer also has no next lane. It resumes where it stopped, and nothing on the board records where that was — so walking forward from there would send work past the very steps that raised the question. Measured against a real board: a ticket in HITL reported "review" and would have skipped critique and optimize.
A ticket in a terminal lane, in an unknown lane, or in the last lane on its path has no next lane either, and nil says so. Nothing enforces the answer: 'jaira move' re-checks the gates whatever route the caller took.
func (*Set) Options ¶
Options lists the distinct RequiresOption values declared by the installed lanes, in display order. A ticket's Options checklist is derived from what is actually installed rather than a fixed list, so a user-written optional lane shows up in it too, without the loader needing to know its name.
func (*Set) Precedence ¶
Precedence returns a lane's merge precedence. An unknown lane sorts below everything known, so a merge never promotes a ticket into a lane this installation cannot reason about.
type SharedLane ¶
type SharedLane struct {
}
SharedLane is one lane found under a project's .jaira/shared/ tree, alongside the folder (normally the publisher's identity.Slug) it came from.
func Shared ¶
func Shared(root string) (lanes []SharedLane, warnings []string, err error)
Shared walks <root>/.jaira/shared/*/*.md and returns every lane it can parse, alongside the folder it came from and its path. A file that fails to read or parse is skipped and reported in warnings rather than failing the walk — one teammate's broken file must not hide everyone else's lanes.
Shared lanes are never loaded by Load: they are visible here, adoptable through Adopt, and otherwise inert. That separation is the whole security story for T-5-02 — a committed shared lane is untrusted prompt content that would otherwise run at whatever model-tier it declares — so nothing should ever wire this function's result into Load.