Documentation
¶
Overview ¶
Package wire implements SPEC §2 (identity and canonical encoding), the §1 numeric limits, the §11 closed detail codes and the taskman-command-result/0 envelope of §3.3. It is standard-library only and has no knowledge of the journal or of any process; every other package builds on it.
The value model is deliberately tiny: taskman profiles use only strings, booleans, null, arrays and objects. JSON numbers are never legal (Count and Size are decimal strings, §2), so the parser refuses them outright.
Index ¶
- Constants
- Variables
- func CheckProfile(where, got, want string) error
- func CheckSortedUnique(where string, vs []Value) error
- func CodeOf(err error) string
- func Encode(v Value) []byte
- func EncodeFile(v Value) []byte
- func Equal(a, b Value) bool
- func FoldToken(s string) string
- func IsCode(s string) bool
- func ParseDate(where, s string) (string, error)
- func ParseIdentifier(where, s string) (string, error)
- func ParseLabel(where, s string) (string, error)
- func ParseOID(where, s string) (string, error)
- func ParsePath(where, s string) (string, error)
- func ParsePathText(where, s string) (string, error)
- func ParseProse(where, s string, min, max int) (string, error)
- func ParseRepoID(where, s string) (string, error)
- func ParseToken(where, s string, max int) (string, error)
- func RecordIdentity(kind string, d Digest) string
- type BarrierRef
- type Count
- type Digest
- type Error
- type Kind
- type Object
- type Page
- type ParseOptions
- type QueueID
- type Reader
- func (r *Reader) Array(max int, semantic bool) []*Reader
- func (r *Reader) Bool() bool
- func (r *Reader) Closed(keys ...string) *Reader
- func (r *Reader) Count() Count
- func (r *Reader) CountOrNull() *Count
- func (r *Reader) Digest() Digest
- func (r *Reader) DigestOrNull() *Digest
- func (r *Reader) Enum(allowed ...string) string
- func (r *Reader) Err() error
- func (r *Reader) Exact(want string) string
- func (r *Reader) Fail(code, format string, args ...interface{})
- func (r *Reader) Field(key string) *Reader
- func (r *Reader) Identifier() string
- func (r *Reader) IsNull() bool
- func (r *Reader) Label() string
- func (r *Reader) LabelOrNull() *string
- func (r *Reader) OID() string
- func (r *Reader) Path() string
- func (r *Reader) PathText() string
- func (r *Reader) Prose(min, max int) string
- func (r *Reader) ProseOrNull(max int) *string
- func (r *Reader) QueueID() QueueID
- func (r *Reader) Size() Size
- func (r *Reader) SizeOrNull() *Size
- func (r *Reader) String() string
- func (r *Reader) StringOrNull(fn func(*Reader) string) *string
- func (r *Reader) Strings(max int, semantic bool, fn func(*Reader) string) []string
- func (r *Reader) TicketID() TicketID
- func (r *Reader) Timestamp() Timestamp
- func (r *Reader) TimestampOrNull() *Timestamp
- func (r *Reader) Value() Value
- func (r *Reader) Where() string
- type Result
- type Size
- type Snapshot
- type TicketID
- type Timestamp
- type Value
- func Array(vs ...Value) Value
- func Bool(b bool) Value
- func Null() Value
- func ObjectValue(o *Object) Value
- func Parse(data []byte) (Value, error)
- func ParseWith(data []byte, opts ParseOptions) (Value, error)
- func SortedSet(where string, vs []Value) (Value, error)
- func String(s string) Value
- func StringOrNull(p *string) Value
- func Strings(ss []string) Value
Constants ¶
const ( KiB = 1024 MiB = 1024 * KiB GiB = 1024 * MiB MaxIdentifierBytes = 128 MaxLabelBytes = 64 MaxLocalTokenBytes = 64 MaxRequestIDBytes = 64 // MaxPathTextBytes bounds a PathText: the absolute filesystem path // recorded as head.primaryWorktree and manifest.primaryWorktree (§2, // B2 resolution). It is separate from the Identifier bound. MaxPathTextBytes = 4096 MaxTitleBytes = 512 MaxBodyBytes = 64 * KiB MaxCriterionBytes = 4 * KiB MaxProseBytes = 64 * KiB MaxTicketFileBytes = 128 * KiB MaxReleaseFileBytes = 256 * KiB MaxMutationEnvelopeBytes = 256 * KiB MaxOutcomeBytes = 64 * KiB MaxAcceptanceCriteria = 64 MaxDependencies = 64 MaxRequirementRefs = 64 MaxResources = 64 MaxApprovals = 64 MaxTouchPaths = 256 MaxLabels = 32 MaxHolds = 16 MaxRequiredGates = 32 MaxCapabilities = 32 MaxTicketsPerQueue = 10000 MaxReleasesPerQueue = 1000 MaxIntentTreeBytes = 256 * MiB MaxQueueFileBytes = 1 * MiB MaxPolicyFileBytes = 256 * KiB MaxImportMapBytes = 8 * MiB MaxImportMapEntries = 10000 MaxReceiptFileBytes = 1 * MiB MaxInlinePostEntryBytes = 64 * KiB MaxInlinePostEntries = 8 MaxAttemptRecordBytes = 64 * KiB MaxJournalHeadBytes = 4 * KiB MaxBarrierBytes = 4 * KiB MaxCommandResultBytes = 64 * KiB // excluding paginated items MaxListResultBytes = 16 * MiB MaxReservationSetBytes = 64 * MiB MaxEvidenceBlobBytes = 64 * MiB MaxEvidenceStoreBytes = 16 * GiB MaxImportPlanBytes = 16 * MiB MaxArchiveBytes = 64 * GiB MaxPinnedBytes = 16 * MiB // largest pinned document (an import plan or plan) // Archive capacity (§1, §3.5; B4 resolution, unverified implementation // freeze). The journal saturates at 1,000,000 receipts, so a manifest // must carry more `files` entries than the ordinary 10,000 decoded-array // bound. These three numbers are independent hard aggregate budgets; // they are checked on input bytes, entry counts and decoded nodes before // any manifest is materialized, and no other document is parsed under // them (ParseWith is opt-in; Parse keeps MaxJSONArrayElements). // // MaxArchiveFiles bounds the `files` array of one taskman-archive/0 // manifest and the number of files `archive export` will emit. MaxArchiveFiles = 2100000 // MaxArchiveManifestBytes bounds manifest.json on the wire. Arithmetic // (largest valid entry, every byte counted): `{"bytes":"` 9 + Size 20 + // `","path":"` 10 + encoded path ≤256 (128 Identifier bytes, each `"` // escaped to two bytes; backslash and controls are refused by Path) + // `","sha256":"` 12 + Digest 64 + `"}` 2 + `,` 1 = 374 bytes per entry; // 374 × 2,100,000 = 785,400,000. Envelope outside `files`: thirteen // fixed keys and punctuation < 300 bytes, five Digests 320, three Sizes // 60, profile 17, queueId ≤128, primaryWorktree ≤8,192 (4,096 PathText // bytes, each `"` escaped), `[`/`]`/LF 3: < 9,100 bytes. Worst case // 785,409,100 < 768 MiB = 805,306,368; the proposed 512 MiB // (536,870,912) would not hold it, so the cap is 768 MiB. MaxArchiveManifestBytes = 768 * MiB // MaxArchiveScanEntries bounds the directory entries `archive export` // enumerates under the state dir (directories, skipped temp names and // unexpected names included) before any entry is stat'ed or opened. It // is counted separately from the exported-file count, which is bounded // by MaxArchiveFiles; the 4,096 headroom covers the fixed layout // directories and a bounded number of crashed temp files. MaxArchiveScanEntries = MaxArchiveFiles + 4096 MaxGateArgv = 16 MaxRuntimeArgv = 16 MaxActiveAttempts = 64 MaxWorkersTotal = 256 MaxAdmissionsPerRev = 3 MaxRepairRounds = 2 MaxMalformedRetry = 1 MaxGateRerunStale = 1 MaxReconcileAttempt = 3 MinEvidenceDays = 30 MaxLaneWallMinutes = 240 MaxGateTimeoutSecs = 120 * 60 PageDefault = 100 PageMax = 1000 MaxJSONDepth = 24 MaxJSONArrayElements = 10000 MaxJSONNodes = 250000 MaxCountValue = 2147483647 VersionSuffix = "/0" )
Frozen numeric limits (SPEC §1). Every value is validated before any effect; exceeding one fails closed with LIMIT_EXCEEDED.
const ( OutcomeOK = "OK" OutcomeRefused = "REFUSED" OutcomeError = "ERROR" OutcomeNotRun = "NOT_RUN" )
Outcomes of taskman-command-result/0.
const CodeAdjudication = "ADJUDICATION"
Closed detail codes (SPEC §11). Only these strings may appear in a taskman-command-result/0 or taskman-outcome/0 codes array.
const CodeAdoptUnsupportedField = "ADOPT_UNSUPPORTED_FIELD"
const CodeApprovalMissing = "APPROVAL_MISSING"
const CodeApprovalRevoked = "APPROVAL_REVOKED"
const CodeAttemptLive = "ATTEMPT_LIVE"
const CodeBootFenced = "BOOT_FENCED"
const CodeBootTimeout = "BOOT_TIMEOUT"
const CodeBudgetExceeded = "BUDGET_EXCEEDED"
const CodeBudgetUnknown = "BUDGET_UNKNOWN"
const CodeCemMissing = "CEM_MISSING"
const CodeContaminated = "CONTAMINATED"
const CodeCoverageUnknown = "COVERAGE_UNKNOWN"
const CodeCutoverInProgress = "CUTOVER_IN_PROGRESS"
const CodeCutoverMissing = "CUTOVER_MISSING"
const CodeCycle = "CYCLE"
const CodeDependencyMissing = "DEPENDENCY_MISSING"
const CodeDependencyUnsatisfied = "DEPENDENCY_UNSATISFIED"
const CodeDevelopmentMode = "DEVELOPMENT_MODE"
const CodeDirtyWorktree = "DIRTY_WORKTREE"
const CodeDocsMissing = "DOCS_MISSING"
const CodeDuplicateID = "DUPLICATE_ID"
const CodeEffectOwned = "EFFECT_OWNED"
const CodeExternalUnbounded = "EXTERNAL_UNBOUNDED"
const CodeFenced = "FENCED"
const CodeGateFailed = "GATE_FAILED"
const CodeGateStale = "GATE_STALE"
const CodeGateUnknown = "GATE_UNKNOWN"
const CodeIndependenceUnverified = "INDEPENDENCE_UNVERIFIED"
const CodeIntentBranchMismatch = "INTENT_BRANCH_MISMATCH"
const CodeIntentDiverged = "INTENT_DIVERGED"
const CodeInvalidPriority = "INVALID_PRIORITY"
const CodeJournalForked = "JOURNAL_FORKED"
const CodeJournalSaturated = "JOURNAL_SATURATED"
const CodeLimitExceeded = "LIMIT_EXCEEDED"
const CodeLockTimeout = "LOCK_TIMEOUT"
const CodeMalformed = "MALFORMED"
const CodeMissingEvidence = "MISSING_EVIDENCE"
const CodeMissingGate = "MISSING_GATE"
const CodeNoexec = "NOEXEC"
const CodeOcmMissing = "OCM_MISSING"
const CodeOutOfScope = "OUT_OF_SCOPE"
const CodePaused = "PAUSED"
const CodePlanStale = "PLAN_STALE"
const CodeQuiescenceUnproved = "QUIESCENCE_UNPROVED"
const CodeRedoPending = "REDO_PENDING"
const CodeRequestIDConflict = "REQUEST_ID_CONFLICT"
const CodeResourceCollision = "RESOURCE_COLLISION"
const CodeRestoreIncomplete = "RESTORE_INCOMPLETE"
const CodeRestored = "RESTORED"
const CodeRetryExhausted = "RETRY_EXHAUSTED"
const CodeReviewIncomplete = "REVIEW_INCOMPLETE"
const CodeReviewRejected = "REVIEW_REJECTED"
const CodeSignalRefusedIdentity = "SIGNAL_REFUSED_IDENTITY"
const CodeSnapshotMoved = "SNAPSHOT_MOVED"
const CodeStalePolicy = "STALE_POLICY"
const CodeStaleTicket = "STALE_TICKET"
const CodeStaleTree = "STALE_TREE"
const CodeSupervisorLost = "SUPERVISOR_LOST"
const CodeSurvivors = "SURVIVORS"
const CodeTicketHeld = "TICKET_HELD"
const CodeTicketState = "TICKET_STATE"
const CodeUncertainEffect = "UNCERTAIN_EFFECT"
const CodeUninitialized = "UNINITIALIZED"
const CodeUnpublished = "UNPUBLISHED"
const CodeUnresolvedFinding = "UNRESOLVED_FINDING"
const CodeUnsupported = "UNSUPPORTED"
const CodeUnsupportedFilesystem = "UNSUPPORTED_FILESYSTEM"
const CodeUnsupportedVersion = "UNSUPPORTED_VERSION"
const ProfileCommandResult = "taskman-command-result/0"
ProfileCommandResult is the stdout envelope of every corvint-tasks command (§3.3).
const UntrustedQueueData = "UNTRUSTED_QUEUE_DATA"
UntrustedQueueData is the only legal member of the `untrusted` array.
Variables ¶
var Codes = []string{ CodeAdjudication, CodeAdoptUnsupportedField, CodeApprovalMissing, CodeApprovalRevoked, CodeAttemptLive, CodeBootFenced, CodeBootTimeout, CodeBudgetExceeded, CodeBudgetUnknown, CodeCapabilityUnavailable, CodeCemMissing, CodeContaminated, CodeCoverageUnknown, CodeCutoverInProgress, CodeCutoverMissing, CodeCycle, CodeDependencyMissing, CodeDependencyUnsatisfied, CodeDevelopmentMode, CodeDirtyWorktree, CodeDocsMissing, CodeDuplicateID, CodeEffectOwned, CodeExternalUnbounded, CodeFenced, CodeGateFailed, CodeGateStale, CodeGateUnknown, CodeIndependenceUnverified, CodeIntentBranchMismatch, CodeIntentDiverged, CodeInvalidPriority, CodeJournalForked, CodeJournalSaturated, CodeLimitExceeded, CodeLockTimeout, CodeMalformed, CodeMissingEvidence, CodeMissingGate, CodeNoexec, CodeOcmMissing, CodeOutOfScope, CodePaused, CodePlanStale, CodeQuiescenceUnproved, CodeRedoPending, CodeRequestIDConflict, CodeResourceCollision, CodeRestored, CodeRestoreIncomplete, CodeRetryExhausted, CodeReviewIncomplete, CodeReviewRejected, CodeSignalRefusedIdentity, CodeSnapshotMoved, CodeStalePolicy, CodeStaleTicket, CodeStaleTree, CodeSupervisorLost, CodeSurvivors, CodeTicketHeld, CodeTicketState, CodeUncertainEffect, CodeUninitialized, CodeUnpublished, CodeUnresolvedFinding, CodeUnsupported, CodeUnsupportedFilesystem, CodeUnsupportedVersion, }
Codes is the closed §11 set.
var TicketRecordKeys = []string{
"profile", "ticketId", "revision", "acceptanceRevision", "previousRecordSha256", "status",
"archivedFrom", "title", "body", "kind", "owner", "milestone", "priority", "order", "labels",
"dependencies", "acceptanceCriteria", "requirementRefs", "source", "effects", "capabilities",
"requiredGates", "holds", "executionClass", "approvals", "completion", "dueDate",
"estimateMinutes", "supersedes", "supersededBy", "shadowOverlay", "createdAt", "updatedAt",
"updatedBy",
}
TicketRecordKeys is the closed taskman-ticket/0 record key set (SPEC §3.1), in record order. Corvint Core's read-only planner imports it instead of keeping a copy.
Functions ¶
func CheckProfile ¶
CheckProfile checks a profile string against the expected `<name>/0`. A different version of the same profile is UNSUPPORTED_VERSION; a different profile entirely is MALFORMED.
func CheckSortedUnique ¶
CheckSortedUnique verifies that an array is canonical-byte sorted without duplicates (§2 rule for non-semantic arrays).
func CodeOf ¶
CodeOf returns the §11 code carried by err, or MALFORMED for any other error, or "" for nil.
func Encode ¶
Encode returns the canonical body of a value (WQO §4.1): closed objects with keys in UTF-8 byte order, no insignificant whitespace, only `\t`, `\n`, `\r`, `\"` and `\\` as short escapes, `\u00xx` (lowercase) for any other control, never `\/`, never an optional `\u` escape, raw UTF-8 otherwise. The trailing LF is not part of the body; see EncodeFile.
func EncodeFile ¶
EncodeFile returns the on-disk and transport form: canonical body plus exactly one LF (§2).
func ParseIdentifier ¶
ParseIdentifier validates an Identifier: 1..128 UTF-8 bytes, no hostile code points, no TAB/LF/CR.
func ParseLabel ¶
ParseLabel validates a label: 1..64 bytes under the identifier rules.
func ParsePath ¶
ParsePath validates a WQO Path: 1..512 bytes, `/` separators, no leading `/`, no empty, `.` or `..` segment, no backslash, NUL or control byte. A trailing `/` denotes a directory prefix.
func ParsePathText ¶
ParsePathText validates a PathText (§2): an absolute filesystem path of 1..4096 UTF-8 bytes with no hostile code point and no TAB, LF or CR. It is the type of `head.primaryWorktree` and `manifest.primaryWorktree`; it is not an Identifier and shares no bound with one. Nothing is normalized: the bytes are compared exactly against the resolved primary worktree.
func ParseProse ¶
ParseProse validates a prose field of at most max bytes; TAB, LF and CR are permitted. min is 0 or 1.
func ParseRepoID ¶
ParseRepoID validates `repo:<authority-token>` and returns the token.
func ParseToken ¶
ParseToken validates the `[A-Za-z0-9][A-Za-z0-9._-]*` grammar of §2 with a byte bound.
func RecordIdentity ¶
RecordIdentity renders `<kind>:sha256:<Digest>`.
Types ¶
type BarrierRef ¶
BarrierRef is the `snapshot.barrier` object.
type Count ¶
type Count string
Count is a decimal string `0` or a non-zero integer without leading zero, at most 2147483647 (§2). Used only for cardinalities and small counters.
type Digest ¶
type Digest string
Digest is 64 lowercase hexadecimal SHA-256 characters.
func ContentID ¶
ContentID computes the WQO §4.3 content identity SHA-256(kind || 0x00 || profile || 0x00 || canonicalBody) where the body is the canonical encoding without the trailing LF.
func ParseDigest ¶
ParseDigest validates a Digest.
type Error ¶
Error is a stable, actionable failure: a closed §11 code, the location in the document (a JSON-pointer-like path or a byte offset) and a message.
func Errorf ¶
Errorf builds an Error. The code must be a §11 code; anything else is a programming error and is reported as MALFORMED so it can never leak an unknown code onto the wire. The parameter is not named `code`: Corvint's error-code ownership ratchet matches callees by name (ECO-V0-001), so that name would make every fmt.Errorf literal in the module an emitted code.
type Object ¶
Object is a JSON object. Keys keeps the order in which members were parsed or set; canonical encoding always sorts by UTF-8 byte order regardless.
func (*Object) SortedKeys ¶
SortedKeys returns the member keys in canonical (byte) order.
type ParseOptions ¶
ParseOptions is the opt-in widening a single profile may request. Only the array that is the direct value of the top-level key WideArrayKey is bounded by WideArrayMax instead of MaxJSONArrayElements; every other array, at any depth, keeps the ordinary bound. MaxNodes replaces MaxJSONNodes for the whole document. Zero values select the defaults, so ParseOptions{} is Parse. Depth is never widened.
type QueueID ¶
QueueID is a parsed `queue:<authority>:<queue>`.
func ParseQueueID ¶
ParseQueueID validates `queue:<authority>:<queue>`.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader walks a parsed Value with closed-object checks and typed accessors. The first failure is recorded and every later call returns a zero value, so a decoder reads linearly and checks Err once. Locations are JSON-pointer style paths such as `/dependencies/2/gateId`.
func (*Reader) Array ¶
Array requires an array of at most max elements (max < 0 means unbounded beyond the §1 decode bound). When semantic is false the array must be canonical-byte sorted without duplicates (§2).
func (*Reader) Closed ¶
Closed requires the value to be an object with exactly the listed keys; missing and unknown keys are both MALFORMED, named in the message.
func (*Reader) CountOrNull ¶
CountOrNull accepts a Count or null.
func (*Reader) DigestOrNull ¶
DigestOrNull accepts a Digest or null.
func (*Reader) Field ¶
Field returns a reader for a member of an object. Closed must have been called first; a missing member here is still reported.
func (*Reader) LabelOrNull ¶
LabelOrNull accepts a label or null.
func (*Reader) ProseOrNull ¶
ProseOrNull accepts prose or null.
func (*Reader) StringOrNull ¶
StringOrNull accepts an identifier-class string validated by fn, or null.
func (*Reader) Strings ¶
Strings reads an array of strings, each validated by fn (for example (*Reader).Label), with the given bound and sortedness rule.
func (*Reader) TimestampOrNull ¶
TimestampOrNull accepts a timestamp or null.
type Result ¶
type Result struct {
Command []string
Outcome string
Codes []string
Snapshot *Snapshot
Mutation *Value // taskman-outcome/0 or nil (null)
Items []Value
Page *Page
Untrusted bool
Warnings []string
}
Result is a taskman-command-result/0 document.
func DecodeResult ¶
DecodeResult parses and validates an envelope. Items are kept as opaque values (their kind is verb-specific).
type Size ¶
type Size string
Size is a decimal string without leading zeros in 0..18446744073709551615 (§2). Used for byte sizes, sequence numbers, generations, pids and so on.
type Snapshot ¶
type Snapshot struct {
HeadSeq *Size
HeadReceiptSha256 *Digest
IntentTreeSha256 *Digest
PrimaryWorktreeSha256 *Digest
PendingRedo bool
Barrier *BarrierRef
}
Snapshot is the `snapshot` object of the envelope.
type TicketID ¶
TicketID is a parsed `ticket:<authority>:<queue>:<local>`.
func ParseTicketID ¶
ParseTicketID validates `ticket:<authority>:<queue>:<local>` with the local token 1..64 bytes of the token grammar.
type Timestamp ¶
type Timestamp string
Timestamp is `YYYY-MM-DDTHH:MM:SSZ` (UTC, seconds; advisory only).
func ParseTimestamp ¶
ParseTimestamp validates `YYYY-MM-DDTHH:MM:SSZ`.
type Value ¶
Value is one decoded JSON value.
func Parse ¶
Parse decodes one canonical taskman document: a single JSON value with no insignificant whitespace, sorted keys, canonical escapes and exactly one trailing LF (SPEC §2, WQO §4.1). It enforces the §1 decode bounds (depth, array elements, aggregate nodes), refuses duplicate keys, JSON numbers, invalid UTF-8, lone surrogates and hostile code points, and then proves canonical framing by re-encoding the value and comparing bytes.
func ParseWith ¶
func ParseWith(data []byte, opts ParseOptions) (Value, error)
ParseWith is Parse under explicit decode bounds (§3.5: the taskman-archive/0 manifest is the only profile that uses it). The bounds are enforced incrementally while parsing, before the document is materialized; a document over a bound fails LIMIT_EXCEEDED at the first element or node beyond it.
func SortedSet ¶
SortedSet sorts values by canonical bytes (§2: non-semantic arrays) and reports a duplicate as MALFORMED.
func StringOrNull ¶
StringOrNull returns a string value, or null when p is nil.