walkthrough

package
v0.82.0 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 11 Imported by: 0

README

pkg/walkthrough — ordinary /1 declaration contract

Pure Go implementation of the ordinary datatug-walkthrough/1 contract owned by spec/features/project-walkthroughs/declaration-format.md in datatug/backstage.

It validates one declaration read from the exact project-relative path walkthroughs/<id>/walkthrough.json and returns either a typed definition or structured recoverable issues. It never reads a project, navigates, publishes or consumes activity, stores progress, runs SQL or checks, mutates Work or renders UI. This package is a contract, not the ordinary /1 user journey.

API

result := walkthrough.ParseDeclaration(directoryID, declarationBytes)
if result.NewerClient {
    // the declaration names a schema major this client cannot parse
}
if !result.Accepted {
    // result.Definition is nil; result.Issues is a stable {Code, Path, Message}
}
definition := result.Definition // typed, fully validated, defensively owned
revision := result.Digest       // SHA-256 of the exact input bytes

Declaration.Projection() is the stable, language-neutral normalized view shared with the TypeScript contract and the conformance corpus. It exposes defaults, capture references, support status, entry steps and the digest; it does not expose presentation prose.

Boundaries

  • Only /1 is implemented. Any other schema major is a recoverable Result.NewerClient; /2 fields in a /1 file are fatal unknown fields.
  • An unknown target or condition kind is step-local: the step is kept with SupportNeedsNewer, its opaque body is discarded rather than exposed or executed, and unrelated steps remain usable. A /2 target/condition discriminator in a /1 file follows the same rule.
  • Captures may be produced only by parameter-value, record-selected and incident-open; an unknown condition may still carry a capture under the parent-agreed precedence, but exposes no executable producer and emits no value at runtime. Later known targets keep their mandatory literal defaults.
  • A captured default may be null only for the incident target's incident value. Literal JSON scalars, including literal null, remain valid scalars elsewhere.
  • A finish/exit { "walkthrough": "<id>" } is checked against the ID grammar. Whether that walkthrough exists in the same project, and whether any target asset exists or is readable, is caller-owned external context and is not read here.
  • Unknown fields reject at every object level. Field names are matched exactly; JSON decoding is hand-written because standard Go decoding is case-folding, replaces malformed UTF-8 and cannot enforce field presence or nested unions.
  • Escaped surrogates use the repository's established Go-compatible treatment: valid pairs become one code point, unpaired surrogates become U+FFFD in both values and keys. Character budgets count code points after normalization; byte budgets count exact input bytes.

Corpus

testdata/corpus.json is the canonical, language-neutral conformance corpus. Raw declaration bytes live in testdata/declarations/. Expected normalized projections are authored from the owner tables by the independent normalizer in testdata/generate_corpus.py; they are not produced by this package.

Regenerate fixtures after an intentional corpus change:

python3 pkg/walkthrough/testdata/generate_corpus.py
go test ./pkg/walkthrough

The TypeScript mirror copies these bytes identically and records the Core commit and per-file SHA-256 in its fixture provenance.

Documentation

Overview

Package walkthrough owns the pure, closed `datatug-walkthrough/1` declaration contract: the declaration bytes, its targets, conditions, values and captures, exits, static reference closure and the exact-byte revision digest.

The package is deliberately passive. It reads declaration bytes supplied by a caller, validates them against the normative owner tables in `datatug/backstage` `spec/features/project-walkthroughs/declaration-format.md` and returns either a typed definition or structured recoverable issues. It never reads a project, opens a route, publishes or consumes activity signals, records progress, runs SQL or checks, mutates Work, or renders UI.

Admission boundaries

  • A declaration is a UTF-8 JSON object of at most MaxDeclarationBytes.
  • The declaration ID must equal the directory ID in `walkthroughs/<id>/walkthrough.json` (DeclarationPath).
  • The revision is the SHA-256 of the exact bytes supplied. It is never a hash of a reserialized object.
  • A declaration whose schema major is newer than /1 is reported as needing a newer DataTug (Result.NewerClient) and is not parsed. This package implements /1 only.
  • An unknown target or condition `kind` is a step-local newer-client boundary: the step is retained as SupportNeedsNewer, its opaque body is neither exposed nor executed, and unrelated steps remain usable.
  • Unknown fields on known variants are fatal. `/1` rejects every /2-only top-level or step field. A /2 target/condition discriminator is treated as an unknown kind, not as a supported /1 variant.
  • A refused declaration never yields a partially admitted executable definition: Result.Definition is nil whenever Result.Accepted is false.

Escaped surrogates

JSON permits unpaired UTF-16 surrogate escapes. Both this package and the TypeScript contract deliberately follow the repository's existing Go-compatible treatment: a valid high/low pair is one code point, and an unpaired surrogate becomes U+FFFD. The same treatment applies to object keys and to every string value, so a lone surrogate and a literal U+FFFD compare equal in both languages. Character budgets count Unicode code points after that normalization; byte budgets always count the exact input bytes.

Not in this package

`datatug-walkthrough/2`, narrative sidecars, source pins, public registry aliases, external checkpoint envelopes, localisation, navigation, progress storage, activity delivery, target existence checks and Walkthrough UI are owned by later slices and other packages. The ordinary /1 user journey does not exist merely because this contract does.

Index

Constants

View Source
const (
	MaxDeclarationBytes = 64 << 10
	MaxChapters         = 20
	MaxStepsPerChapter  = 30
	MaxSteps            = 200
	MaxTitleChars       = 120
	MaxTextChars        = 400
)

Ordinary /1 bounds from the normative owner declaration table.

View Source
const SchemaV1 = "datatug-walkthrough/1"

SchemaV1 is the only schema this package admits. Any other major is reported as needing a newer DataTug rather than parsed.

Variables

View Source
var ErrNewerClient = errors.New("walkthrough: declaration needs a newer DataTug")

ErrNewerClient is returned by Result.Err when the declaration bytes name a schema this client cannot parse. It is a recoverable newer-client boundary, not a malformed declaration.

Functions

func DeclarationPath

func DeclarationPath(id string) string

DeclarationPath returns the exact project-relative location of a walkthrough declaration.

func KnownConditionKind

func KnownConditionKind(kind string) bool

KnownConditionKind reports whether kind is in the ordinary /1 condition registry.

func KnownTargetKind

func KnownTargetKind(kind string) bool

KnownTargetKind reports whether kind is in the ordinary /1 target registry.

Types

type AssetExistsCondition

type AssetExistsCondition struct {
	Asset string
	ID    string
}

AssetExistsCondition observes that an asset is readable in the resolved project.

type BoardTarget

type BoardTarget struct {
	BoardID    string
	Parameters []NamedValue
	Tutorial   bool
}

BoardTarget is a saved board; Tutorial adds the board-action tutorial mode.

type BoardTutorialCondition

type BoardTutorialCondition struct {
	UntilCard string
}

BoardTutorialCondition observes board tutorial progress.

type CardTarget

type CardTarget struct {
	CardID     string
	Parameters []NamedValue
}

CardTarget is a saved card with optional parameter values.

type Chapter

type Chapter struct {
	ID             string
	FormerIDs      []string
	Title          string
	Why            string
	Requires       string
	RequiresReason string
	ContinuesFrom  string
	Readiness      *Condition
	Steps          []Step
	EntryStepID    string
}

Chapter is one ordered chapter. EntryStepID is the first Explore step whose target is not none (an unknown target kind still declares the entry).

type CheckRunCondition

type CheckRunCondition struct {
	Outcome string
}

CheckRunCondition observes a Check completion with an optional outcome.

type CheckTarget

type CheckTarget struct {
	CheckID string
}

CheckTarget is a Check and its runs.

type Code

type Code string

Code is a stable refusal code for a declaration problem. Callers may switch on it; human wording is not part of the contract.

const (
	// CodeTooLarge means the input exceeds MaxDeclarationBytes.
	CodeTooLarge Code = "too_large"
	// CodeInvalidUTF8 means the input bytes are not valid UTF-8.
	CodeInvalidUTF8 Code = "invalid_utf8"
	// CodeInvalidJSON means the bytes are not one JSON value with JSON syntax.
	CodeInvalidJSON Code = "invalid_json"
	// CodeDuplicateKey means a JSON object repeats a key (including an escaped
	// spelling of the same key).
	CodeDuplicateKey Code = "duplicate_key"
	// CodeTrailingData means non-whitespace bytes follow the JSON value.
	CodeTrailingData Code = "trailing_data"
	// CodeNotObject means the root JSON value is not an object.
	CodeNotObject Code = "not_object"
	// CodeMissingField means a required field is absent.
	CodeMissingField Code = "missing_field"
	// CodeUnknownField means an object carries a field outside its closed set.
	CodeUnknownField Code = "unknown_field"
	// CodeInvalidType means a value has the wrong JSON type (including explicit
	// null where a value is required).
	CodeInvalidType Code = "invalid_type"
	// CodeInvalidValue means a string, enum, integer lexeme or identity does
	// not satisfy its declared rule.
	CodeInvalidValue Code = "invalid_value"
	// CodeTooLong means a text value exceeds its character limit.
	CodeTooLong Code = "too_long"
	// CodeTooMany means an array or total count exceeds its limit.
	CodeTooMany Code = "too_many"
	// CodeDuplicateID means a chapter, former, step or captured identity is
	// repeated in a scope that requires uniqueness.
	CodeDuplicateID Code = "duplicate_id"
	// CodeInvalidReference means a static reference (continuesFrom, chapter
	// exit, readiness/needs pairing) does not resolve.
	CodeInvalidReference Code = "invalid_reference"
	// CodeMissingDefault means a captured value object omits its mandatory
	// literal default.
	CodeMissingDefault Code = "missing_default"
	// CodeUnknownCapture means a captured value names no declared producer.
	CodeUnknownCapture Code = "unknown_capture"
	// CodeCaptureNotEarlier means a captured value references a producer that
	// is not earlier in document order.
	CodeCaptureNotEarlier Code = "capture_not_earlier"
	// CodeCaptureNotAllowed means a capture is attached to a known condition
	// kind that cannot produce a value.
	CodeCaptureNotAllowed Code = "capture_not_allowed"
	// CodeMissingExploreEntry means a chapter has no step available in Explore.
	CodeMissingExploreEntry Code = "missing_explore_entry"
	// CodeInvalidEntryTarget means a chapter's first Explore step targets none.
	CodeInvalidEntryTarget Code = "invalid_entry_target"
)

func ErrorCode

func ErrorCode(err error) Code

ErrorCode returns the first stable issue code, or "" when err is not a walkthrough refusal.

type Condition

type Condition struct {
	Kind           string
	Supported      bool
	ParameterValue *ParameterValueCondition
	RecordSelected *RecordSelectedCondition
	QueryRun       *QueryRunCondition
	PanelOpen      *PanelOpenCondition
	FilterApplied  *FilterAppliedCondition
	CheckRun       *CheckRunCondition
	AssetExists    *AssetExistsCondition
	BoardTutorial  *BoardTutorialCondition
}

Condition is one closed-registry completion condition. Exactly the pointer matching Kind is populated for a supported kind; an unknown kind has Supported false and no variant data.

type Declaration

type Declaration struct {
	Schema   string
	ID       string
	Version  Integer
	Title    string
	Summary  string
	Chapters []Chapter
	Finish   Exit
	Revision string
}

Declaration is a fully validated ordinary /1 walkthrough. Revision is the lowercase SHA-256 of the exact input bytes.

func (*Declaration) Projection

func (d *Declaration) Projection() map[string]any

Projection renders the stable, language-neutral normalized view used by the shared conformance corpus. It exposes defaults, references, support status and the exact digest-related identity, but no presentation prose.

type Error

type Error struct {
	Issues []Issue `json:"issues"`
}

Error is the aggregate refusal returned by Result.Err. It is recoverable: reloading a supported schema or fixing the named declaration fields can succeed, and no completion may be recorded from a refused parse.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Recoverable

func (e *Error) Recoverable() bool

Recoverable reports whether retrying with a supported schema or corrected bytes can succeed. Every refusal produced by this package is recoverable.

type Exit

type Exit struct {
	Kind        string
	Chapter     string
	Walkthrough string
	Target      *Target
}

Exit is the walkthrough finish (or a chapter's next exit). Exactly one variant is set.

type FilterAppliedCondition

type FilterAppliedCondition struct {
	Field  string
	Equals *Scalar
}

FilterAppliedCondition observes a log or table filter.

type IncidentTarget

type IncidentTarget struct {
	Incident *Value
}

IncidentTarget is an incident in the resolved project, or its incident list when Incident is absent or null.

type Integer

type Integer string

Integer is a canonical, non-negative decimal integer lexeme. Keeping the lexeme rather than a machine integer preserves versions and row thresholds exactly in both Go and TypeScript without inventing a representability cap.

func (Integer) String

func (i Integer) String() string

type Issue

type Issue struct {
	Code    Code   `json:"code"`
	Path    string `json:"path"`
	Message string `json:"message"`
}

Issue is one structured, recoverable declaration problem. Path is a JSON Pointer into the input ("" is the root).

func (Issue) Error

func (i Issue) Error() string

type LogSourceTarget

type LogSourceTarget struct {
	Source string
	Stream string
	Filter []NamedValue
}

LogSourceTarget is the generic log reader grid.

type NamedValue

type NamedValue struct {
	Name  string
	Value Value
}

NamedValue is one entry of a parameters, key or filter object. Entries are kept sorted by name so normalized projections are deterministic.

type PanelOpenCondition

type PanelOpenCondition struct {
	Panel string
}

PanelOpenCondition observes a panel belonging to the target asset.

type ParameterValueCondition

type ParameterValueCondition struct {
	Name   string
	Equals *Scalar
}

ParameterValueCondition observes a query, board or card parameter.

type PublicDataProviderTarget

type PublicDataProviderTarget struct {
	Provider string
}

PublicDataProviderTarget is a provider's OVDB Directory entry.

type QueryRunCondition

type QueryRunCondition struct {
	MinRows *Integer
}

QueryRunCondition observes a completed saved-query run.

type QueryTarget

type QueryTarget struct {
	QueryID    string
	Parameters []NamedValue
}

QueryTarget is a saved query with optional parameter values. It never runs the query.

type RecordSelectedCondition

type RecordSelectedCondition struct {
	Field  string
	Equals *Scalar
}

RecordSelectedCondition observes a selected record or query result row.

type RelatedTarget

type RelatedTarget struct {
	Source  string
	Table   string
	Key     []NamedValue
	Meaning string
}

RelatedTarget is a record with its Related panel open.

type Result

type Result struct {
	Accepted    bool         `json:"accepted"`
	NewerClient bool         `json:"newerClient"`
	Digest      string       `json:"digest"`
	Definition  *Declaration `json:"definition,omitempty"`
	Issues      []Issue      `json:"issues,omitempty"`
}

Result is the outcome of one declaration parse. Definition is non-nil only when Accepted is true. Digest is always the SHA-256 of the exact bytes supplied.

func ParseDeclaration

func ParseDeclaration(directoryID string, data []byte) Result

ParseDeclaration validates one ordinary /1 declaration. directoryID is the `<id>` in `walkthroughs/<id>/walkthrough.json`; it must equal the declaration ID. The input slice is never retained or mutated.

func (Result) Err

func (r Result) Err() error

Err returns nil for an admitted declaration, ErrNewerClient for a newer schema major, or an aggregate recoverable Error.

type Scalar

type Scalar struct {
	Kind   ScalarKind
	Bool   bool
	Number string
	Text   string
}

Scalar is one JSON scalar. Number retains the exact input lexeme.

type ScalarKind

type ScalarKind string

ScalarKind is the closed JSON scalar kind of a literal value.

const (
	ScalarNull    ScalarKind = "null"
	ScalarBoolean ScalarKind = "boolean"
	ScalarNumber  ScalarKind = "number"
	ScalarString  ScalarKind = "string"
)

type Step

type Step struct {
	ID      string
	Title   string
	Why     string
	Hint    string
	Modes   []string
	Target  Target
	Done    Condition
	Capture string
	Needs   string
	Support Support
}

Step is one ordered walkthrough step.

type Support

type Support string

Support is the admission status of a target, condition or step.

const (
	// SupportSupported is a fully validated /1 variant.
	SupportSupported Support = "supported"
	// SupportNeedsNewer is an unknown target/condition kind retained only so
	// the rest of the walkthrough stays usable. Its opaque body is not exposed
	// or executed.
	SupportNeedsNewer Support = "needs-newer"
)

type TableRecordTarget

type TableRecordTarget struct {
	Source string
	Table  string
	Key    []NamedValue
}

TableRecordTarget is a table of a project source, optionally with a record open.

type Target

type Target struct {
	Kind               string
	Supported          bool
	TableRecord        *TableRecordTarget
	Query              *QueryTarget
	Board              *BoardTarget
	Card               *CardTarget
	Related            *RelatedTarget
	LogSource          *LogSourceTarget
	PublicDataProvider *PublicDataProviderTarget
	Incident           *IncidentTarget
	Check              *CheckTarget
	None               *struct{}
}

Target is one closed-registry target variant. Exactly the pointer matching Kind is populated for a supported kind; an unknown kind has Supported false and no variant data.

type Value

type Value struct {
	Captured string
	Literal  *Scalar
	Default  *Scalar
}

Value is either a literal scalar or a captured reference with its mandatory literal default.

func (Value) IsCaptured

func (v Value) IsCaptured() bool

IsCaptured reports whether the value references an earlier capture.

Jump to

Keyboard shortcuts

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