first commit
This commit is contained in:
102
go-api/internal/definition/definition.go
Normal file
102
go-api/internal/definition/definition.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// Package definition reads Krow agent and skill definitions — Markdown with
|
||||
// YAML frontmatter — the way the frontend reads them.
|
||||
//
|
||||
// # Why this exists
|
||||
//
|
||||
// A definition is authored in the browser and stored by the server, so two
|
||||
// parsers see it: the JavaScript in src/lib/skills and src/lib/agents, and
|
||||
// this one. If they disagree, one of two things happens, and both are silent:
|
||||
//
|
||||
// - A definition the editor accepts and this package rejects looks valid
|
||||
// while it is being written and fails when it is saved.
|
||||
// - A definition this package accepts and the editor rejects is stored and
|
||||
// then cannot be rendered by the product that owns it.
|
||||
//
|
||||
// Compatibility is therefore a contract rather than an aspiration, and it is
|
||||
// enforced by a conformance suite (conformance_test.go) that replays the
|
||||
// ACTUAL output of the JavaScript parser — captured from the real frontend
|
||||
// module graph — against this one, over all 37 shipped definitions and every
|
||||
// adversarial case in testdata/oracle.json. The corpus count is pinned by a
|
||||
// test; the case count is deliberately not restated here, because a number
|
||||
// kept in a comment is a number that goes stale.
|
||||
//
|
||||
// # What is in the contract
|
||||
//
|
||||
// - The document layer: byte-order mark, line endings, leading blank lines,
|
||||
// fence recognition, body extraction. See frontmatter.go.
|
||||
// - The YAML subset: block maps and sequences, scalars, quoting, comments.
|
||||
// A port of yaml.js, with no YAML dependency, deliberately — see yaml.go.
|
||||
// - Definition-level normalization and validation: id, name, description,
|
||||
// status, version, pages, icons, reasoning, permissions, starters,
|
||||
// knowledge, subagents.
|
||||
//
|
||||
// Those cover every column migration 000005 projects out of a definition:
|
||||
// definition_id, status, version, name, description, pages.
|
||||
//
|
||||
// # What is deferred, and why
|
||||
//
|
||||
// A skill may carry a `ui:` block (declarative page sections) or an `owliver:`
|
||||
// block (assistant capabilities). Validating those means reproducing roughly
|
||||
// 1,500 lines of closed vocabulary describing what the FRONTEND can render —
|
||||
// placements, data sources, section types, periods — none of which the backend
|
||||
// stores, projects, or acts on.
|
||||
//
|
||||
// This package therefore does not check them. It records their presence on
|
||||
// Skill.Deferred instead, so the gap is a value a caller can see rather than
|
||||
// an assumption. The one consequence is stated exactly:
|
||||
//
|
||||
// skill-examples/board-invalid-context.md is rejected by the frontend, on a
|
||||
// rule about which placement can supply which data source, and accepted
|
||||
// here. It is the only definition in the corpus where the two disagree, and
|
||||
// the conformance suite asserts that it stays the only one.
|
||||
//
|
||||
// # What is not the parser's job
|
||||
//
|
||||
// Normalization never rewrites what is stored. Migration 000005 keeps
|
||||
// `markdown` verbatim and every other column is derived from it; this package
|
||||
// only ever reads. The Markdown handed in is the Markdown that goes to the
|
||||
// database, byte for byte, and a test asserts it.
|
||||
//
|
||||
// Visibility (personal or organization) is deliberately absent. It is not a
|
||||
// frontmatter field — the frontend ignores `visibility:` in a definition
|
||||
// entirely — it is a storage tier chosen by the request and checked by the
|
||||
// visibility CHECK in migration 000005. A definition cannot name its own
|
||||
// tenancy.
|
||||
package definition
|
||||
|
||||
// MaxMarkdownLength is the markdown_size CHECK from migration 000005, in
|
||||
// CHARACTERS — `length()` in PostgreSQL counts characters, not bytes.
|
||||
//
|
||||
// The frontend does NOT enforce this, so a definition longer than this is one
|
||||
// the editor accepts and the database refuses. This package refuses it first,
|
||||
// which turns a constraint violation into a message an author can act on.
|
||||
const MaxMarkdownLength = 65536
|
||||
|
||||
// MaxVersion is the range of agent_definitions.version, a PostgreSQL
|
||||
// `integer`.
|
||||
//
|
||||
// The frontend accepts any integer of 1 or more, so a version above this is
|
||||
// another value the editor accepts and the database cannot store.
|
||||
const MaxVersion = 2147483647
|
||||
|
||||
// maxExactInteger is 2^53-1, the largest integer a float64 names exactly and so
|
||||
// the largest a JavaScript number carries without loss. It bounds the version
|
||||
// conversion in ParseAgent; it is not a rule about what may be stored, which is
|
||||
// MaxVersion's job.
|
||||
const maxExactInteger = 1<<53 - 1
|
||||
|
||||
// Rejection is a definition that parses but may not be stored.
|
||||
//
|
||||
// Message is the frontend's own wording wherever the rule is shared, so the
|
||||
// editor and the API describe the same problem the same way.
|
||||
type Rejection struct {
|
||||
Message string
|
||||
|
||||
// BackendOnly marks a rule the frontend does not have — a bound the
|
||||
// database imposes that the editor never checks. These are the only
|
||||
// messages that can differ from what an author would see in the browser,
|
||||
// and each one is listed in docs/phase-4d-parser-contract.md.
|
||||
BackendOnly bool
|
||||
}
|
||||
|
||||
func (r *Rejection) Error() string { return r.Message }
|
||||
Reference in New Issue
Block a user