一键导入
leeway-streamreadaccess
Use when reading Leeway-encoded data via the stream read-access protocol — the sink-side read path and membership-role classification.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when reading Leeway-encoded data via the stream read-access protocol — the sink-side read path and membership-role classification.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Use this skill when writing ClickHouse SQL transformation passes, pipelines, macro expanders, function evaluators, or analysis functions using the nanopass framework. Triggers include: any mention of 'nanopass', 'SQL pass', 'SQL transformation', 'SQL rewrite', 'ClickHouse pass', 'canonicalize SQL', 'macro expansion', 'qualify tables', 'expand columns', 'extract literals', 'add/modify SETTINGS', or requests to manipulate ClickHouse SQL programmatically in Go. Also use when parsing ClickHouse SQL, walking a CST, rewriting tokens, building scope-aware transformations, declaring PassProperties, or composing SQL→SQL pipelines with Sequence/FixedPoint. Do NOT use for general SQL querying, ClickHouse client usage, or ORM-based database access.
Use when writing imzero2 / egui2 GUI code — the FFFI render pipeline, memory management, the deterministic XOR id stack, retained/deferred bodies, and widget contracts.
Use for advanced Leeway columnar modelling — multi-membership encoding, co-sections, membership roles, and mapping JSON to an equivalent Leeway representation.
Use when generating, parsing, or manipulating Canonical Type Signatures (CT) — the compact string representation of data types (primitives, groups, signatures) for RPC/FFI interface descriptions.
Use when defining or consuming a Go↔native (Rust/C++) FFI boundary with FFFI2 (frame-oriented foreign function interface) — writing the IDL, generating stubs, or using the runtime API.
Use when calling imzero2 Fetcher.Fetch* opcodes — they must run only from StateManager.Sync() at frame end; calling them inline from a widget or deferred-block body deadlocks the render loop.
基于 SOC 职业分类
| name | leeway-streamreadaccess |
| description | Use when reading Leeway-encoded data via the stream read-access protocol — the sink-side read path and membership-role classification. |
| type | reference |
| audience | agent reading this skill |
| status | draft |
Status: draft — pre-human-review. Not verified; do not cite as authoritative.
streamreadaccess.SinkISinkI is a SAX-like push protocol for rendering Leeway table data.
A Driver walks Arrow records and calls SinkI interface methods in strict nesting order.
Implementors produce output (text, JSON, HTML, data frames, etc.) by responding to these calls.
BeginBatch()
[BeginEntity()
[BeginPlainSection(itemType, names, types, nAttrs)
[BeginPlainValue()
[BeginColumn(addr, name, type)
BeginScalarValue() | BeginHomogenousArrayValue(card) | BeginSetValue(card)
[WriteString(s) | Write(p)] // value content
[BeginValueItem(idx) ... EndValueItem()]* // only for array/set
EndScalarValue() | EndHomogenousArrayValue() | EndSetValue()
EndColumn()]*
EndPlainValue()]*
EndPlainSection()]*
BeginTaggedSections()
[BeginCoSectionGroup(key)]* // optional wrapper
[BeginSection(name, names, types, nAttrs)
[BeginTaggedValue()
[BeginColumn(addr, name, type)
// same scalar/array/set pattern as above
EndColumn()]*
BeginTags(nTags)
[AddMembership*(...)]*
EndTags()
EndTaggedValue()]*
EndSection()]*
[EndCoSectionGroup()]*
EndTaggedSections()
EndEntity()]*
EndBatch()
| Type | Package | Role |
|---|---|---|
naming.StylableName | leeway/naming | Column/section names. Use .String() for display; .Equal() for comparison. IR carries the desired naming style — never call .Convert() in emitters. |
canonicaltypes.PrimitiveAstNodeI | leeway/canonicaltypes | Canonical type (e.g. f32, u64, sh, u64m). May be nil. Use .String() for display. |
naming.Key | leeway/naming | Co-section group key. Cast to string for display. |
common.PlainItemTypeE | leeway/common | Plain section item type (e.g. entity ID, natural key). Use .String() for display. |
PhysicalColumnAddr | this package | {Index int, FullColumnName string} — Arrow column identity. |
Begin* has exactly one matching End*.BeginPlainValue never appears inside tagged sections. BeginTaggedValue never appears inside plain sections.BeginTags/EndTags only appears inside BeginTaggedValue...EndTaggedValue, never inside plain values.nAttrs == 0 → no BeginTaggedValue/BeginPlainValue calls follow.WriteString/Write calls only occur between BeginScalarValue...EndScalarValue or BeginValueItem...EndValueItem.BeginTaggedSections() is called exactly once per entity, after all plain sections.End* methods that return (err error).End* call.EndTaggedValue but always calls EndBatch.BeginBatch/EndBatch: Open/close the top-level container (array, stream header/footer).BeginEntity/EndEntity: Open/close per-entity container.BeginPlainSection: Store itemType + column schema. Plain sections have exactly 1 value row per entity.BeginPlainValue/EndPlainValue: Open/close the value record.BeginTaggedSections/EndTaggedSections: Transition from plain to tagged data. May open a new container or be a no-op.BeginSection: Store section name + column schema + nAttrs. Skip rendering if nAttrs == 0.BeginTaggedValue/EndTaggedValue: Open/close an attribute record. Tags follow columns.BeginColumn/EndColumn: Write a named field. Use name.String() as the key.Begin*Value was called. Arrays and sets may need distinct representation (e.g. JSON arrays vs {"set": [...]}).BeginTags...EndTags + AddMembership*: Serialize membership tags with their type discriminator and display values.BeginTaggedValue...EndTaggedValue, flush at EndSection.BeginColumn provides a name. Match it to the column index from BeginSection's valueNames using .Equal().BeginHomogenousArrayValue(card) means card items follow. Render with index prefixes ([0], [1]...) for arrays, bullets (•) for sets.AddMembership* calls. Five membership types exist:
Ref (low/high card reference)Verbatim (low/high card verbatim string)RefParametrized (ref + params)MixedLowCardRefHighCardParam (mixed ref)MixedLowCardVerbatimHighCardParam (mixed verbatim)nAttrs == 0 → collapse or hide.BeginCoSectionGroup(key) wraps multiple sections that share topology. Render as a visual group.type MySink struct { err error }
func (inst *MySink) BeginBatch() {}
func (inst *MySink) EndBatch() error { return inst.err }
func (inst *MySink) BeginEntity() {}
func (inst *MySink) EndEntity() error { return inst.err }
func (inst *MySink) BeginPlainSection(...) {}
func (inst *MySink) EndPlainSection() error { return inst.err }
func (inst *MySink) BeginPlainValue() {}
func (inst *MySink) EndPlainValue() error { return inst.err }
func (inst *MySink) BeginTaggedSections() {}
func (inst *MySink) EndTaggedSections() error { return inst.err }
func (inst *MySink) BeginCoSectionGroup(...) {}
func (inst *MySink) EndCoSectionGroup() error { return inst.err }
func (inst *MySink) BeginSection(...) {}
func (inst *MySink) EndSection() error { return inst.err }
func (inst *MySink) BeginTaggedValue() {}
func (inst *MySink) EndTaggedValue() error { return inst.err }
func (inst *MySink) BeginColumn(...) {}
func (inst *MySink) EndColumn() {}
func (inst *MySink) BeginScalarValue() {}
func (inst *MySink) EndScalarValue() error { return inst.err }
func (inst *MySink) BeginHomogenousArrayValue(int) {}
func (inst *MySink) EndHomogenousArrayValue() {}
func (inst *MySink) BeginSetValue(int) {}
func (inst *MySink) EndSetValue() {}
func (inst *MySink) BeginValueItem(int) {}
func (inst *MySink) EndValueItem() {}
func (inst *MySink) Write(p []byte) (int, error) { return len(p), nil }
func (inst *MySink) WriteString(s string) (int, error) { return len(s), nil }
func (inst *MySink) BeginTags(int) {}
func (inst *MySink) EndTags() {}
func (inst *MySink) AddMembershipRef(...) {}
func (inst *MySink) AddMembershipVerbatim(...) {}
func (inst *MySink) AddMembershipRefParametrized(...) {}
func (inst *MySink) AddMembershipMixedLowCardRefHighCardParam(...) {}
func (inst *MySink) AddMembershipMixedLowCardVerbatimHighCardParam(...) {}
var _ SinkI = (*MySink)(nil)
Per boxer ADR-0007, sinks that produce attribute-centric output (JSON, data contracts, anything with a "primary key + annotations" shape) consume a membershiprole.ClassifierI to decide whether each AddMembership* call delivers a primary or secondary tag.
The classifier interface lives in boxer at github.com/stergiotis/boxer/public/semistructured/leeway/membershiprole. It takes a MembershipValue (which mirrors the AddMembership* payload shapes) plus a SectionContext (section name + useaspects.AspectSet) and returns (MembershipRoleE, ParamTreatmentE).
A classifier-aware sink wraps each AddMembership* call:
func (inst *MySink) AddMembershipVerbatim(lowCard bool, verbatim, humanReadable string) {
mv := membershiprole.MembershipValue{
Kind: membershiprole.MembershipKindVerbatim,
LowCard: lowCard,
Verbatim: verbatim,
HumanReadableValue: humanReadable,
}
role, _ := inst.classifier.Classify(inst.currentSectionCtx, mv)
if role == membershiprole.MembershipRolePrimary {
inst.routeToAttributeKey(verbatim)
} else {
inst.routeToLabelSlot(verbatim)
}
}
The five AddMembership* shapes map onto the five MembershipKindE values one-to-one. SectionContext is populated at BeginSection and BeginPlainSection from the section's UseAspects field, which carries useaspects.AspectSectionMembershipsAllPrimary / useaspects.AspectSectionMembershipsAllSecondary when the application sets them.
DefaultClassifier covers the common case (path-prefix verbatim → primary, plain identifier → secondary, ref-shaped → primary). Applications with different conventions implement ClassifierI directly.
| Emitter | File | Strategy | Key Technique |
|---|---|---|---|
UnicodeCardEmitter | leeway_card_unicode.go | Buffered per section | Accumulates textRow cells, flushes box-drawn table at EndSection |
JsonCardEmitter | leeway_card_json.go | Streaming | jsontext.Encoder.WriteToken() — zero buffering |
HtmlCardEmitter | leeway_card_html.go | Streaming + cell buffer | Streams HTML tags directly; buffers one cellBuf per column, flushes at EndColumn |