nodekind

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package nodekind resolves the event/thing/concept kind of every node and emits an ipm-oriented node+edge graph.

Kind is never stored on a node (N4L README §3): it is emergent from the incident relations. ipm requires kinds conforming to the γ(3,4) type-pair table enforced by ipm-tools/pkg/ipm/validate (IPMV1.3) — the 11 legal combinations:

LeadsTo:   event → event                                   (eLe)
PartOf:    thing → thing,  thing → event,  event → event   (tPt tPe ePe)
Expresses: event → event,  event|thing|concept → concept   (eXe eXc tXc cXc)
NearTo:    same type only                                  (eNe tNt cNc)

The solver is CONSTRAINT-FAITHFUL: it derives kinds ONLY from these type-pairs, with no semantic heuristics. Every node starts with the full domain {Event,Thing,Concept}; arc-consistency (orderCandidates) prunes each node's domain to the kinds that keep every incident edge a legal pair, to a fixpoint. A node is DECIDED only when a single kind survives — in practice the only kind a structure can uniquely force is Event (via LeadsTo, and what that propagates to through NearTo / PartOf / Expresses). Otherwise the node stays Unresolved (grey) carrying its surviving candidate set; we never guess. `eXe` is a legal, emitted outcome, so a node that is both a LeadsTo endpoint and an Expresses target is simply an Event — there is no split. A final pass drops any edge still outside the table, so output always passes ipm-validate IPMV1.3.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EncodeJSONL

func EncodeJSONL(w io.Writer, recs []TraceRecord) error

EncodeJSONL writes records as one JSON object per line.

func RenderReport

func RenderReport(recs []TraceRecord) string

RenderReport narrativizes a trace into a markdown report: a summary, a per-node resolution table (signals → base → final, with notes), a per-edge table (kept / dropped / relaxed / cycle-broken), the warnings, and a collapsed timeline.

func ToGraph

func ToGraph(r *Result) *model.IpmGraph

ToGraph materializes a solver Result as a model.IpmGraph (the inverse of resolution): nodes get sequential IDs 1..N, edges reference them and keep their resolved Dir and SstLinkType. Src.Type is left empty for the caller to set. Used by Solve consumers (e.g. the solver-example tool and pkg/mdembed) to round-trip the resolved graph back to ipmt via pkg/ipmtext.

Types

type Confidence

type Confidence string

Confidence tags how a node's kind was decided.

const (
	High    Confidence = "inferred-high"    // forced by a hard constraint or structural role
	Low     Confidence = "inferred-low"     // no disambiguating signal — left Unresolved
	Default Confidence = "inferred-default" // decided by a role-based default (SolveWithDefaults), not forced
)

type ResolvedEdge

type ResolvedEdge struct {
	Src     int
	Tgt     int
	Link    model.SstLinkType
	Dir     model.ArrowDir
	Tooltip string
}

ResolvedEdge is an ipm-oriented edge referencing ResolvedNode indices.

type ResolvedNode

type ResolvedNode struct {
	Name       string
	Alias      string
	Type       model.NodeType
	Candidates []model.NodeType // possible kinds when Type==Unresolved, primary first; nil otherwise
	Confidence Confidence
	Tooltip    string // free-text annotation (e.g. aggregated note text)
	Origin     string // originating N4L node text
}

ResolvedNode is an ipm node with a decided kind.

type Result

type Result struct {
	Nodes    []ResolvedNode
	Edges    []ResolvedEdge
	Warnings []string      // human-facing summary notes (also mirrored into Trace)
	Trace    []TraceRecord // per-decision audit trace (see solver-audit tool)
}

Result is the resolved graph plus human-facing notes and a decision trace.

func Solve

func Solve(g *model.IpmGraph) *Result

Solve resolves node kinds for an already-ipm-oriented typed graph: each edge carries its SstLinkType and points the ipm way (PartOf is part→container, Expresses source→concept, LeadsTo src→tgt). Node identity is by Name; any Type/Candidates on the input nodes are advisory and ignored — kinds are derived from the edges.

This is the solver's only entry point: it is format-independent. It consumes a pre-oriented model.IpmGraph — the ipmt path feeds it a parsed graph directly, and any N4L front-end is expected to convert to model.IpmGraph (owning the n4l direction / PartOf-inversion rules) before calling Solve.

func SolveWithDefaults

func SolveWithDefaults(g *model.IpmGraph) *Result

SolveWithDefaults is Solve plus a role-based default pass: every node the type-pairs leave grey is decided to its preferred kind (Expresses target → Concept, PartOf participant → Thing, Expresses source → Thing, otherwise Event), so the graph is fully resolved. Opt-in (the `ipmt unresolved defaults` fence directive); Solve alone leaves those nodes grey.

type TraceRecord

type TraceRecord struct {
	Phase    string         `json:"phase"`
	Event    string         `json:"event"`
	Producer string         `json:"producer,omitempty"`
	Node     string         `json:"node,omitempty"`
	Edge     string         `json:"edge,omitempty"`
	Detail   string         `json:"detail,omitempty"`
	Payload  map[string]any `json:"payload,omitempty"`
}

TraceRecord is one solver decision. Node is the originating N4L node text (the stable key across phases — a split fans one text to two resolved nodes, but both keep this Origin); Edge is "src → tgt". Payload holds event-specific data.

func DecodeJSONL

func DecodeJSONL(rd io.Reader) ([]TraceRecord, error)

DecodeJSONL reads a JSONL trace stream produced by EncodeJSONL.

Jump to

Keyboard shortcuts

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