junyul

package module
v1.2.2 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

junyul-go

Junyul compliance SDK for Go.

Status: GA. Latest verified release: v1.2.2.

Module path:

github.com/junyul-go/junyul-go

Install:

go get github.com/junyul-go/junyul-go@latest

Local verification:

cd sdks/go
go test ./...
import "github.com/junyul-go/junyul-go"

client, _ := junyul.New("JUN_live_xxx")
defer client.Close()

reply, err := junyul.Track(ctx, client, "gpt_chatbot_v1", func() (string, error) {
    return callOpenAI(ctx, message)
})

client.RecordHeartbeat("gpt_chatbot_v1")

Tracked errors and panics are recorded with hashed failure metadata and no raw error message. Production clients enable the file-backed outbox and circuit breaker by default; use WithoutOutbox, WithOutbox, WithCircuitBreaker, and WithQueueLimits to tune transport behavior.

Documentation

Overview

Package junyul is the Go SDK for the Junyul compliance platform. Three-line integration:

client, _ := junyul.New("JUN_live_xxx")
defer client.Close()
out, err := junyul.Track(ctx, client, "asset_id", func() (string, error) { return ... })

Index

Constants

View Source
const SDKVersion = "1.2.2"

Variables

This section is empty.

Functions

func Track

func Track[T any](ctx context.Context, c *Client, assetID string, fn func() (T, error)) (result T, err error)

Track runs fn and records an ai_inference event. Panics and errors propagate to the caller; event is still recorded with error=true metadata.

Types

type CircuitBreaker

type CircuitBreaker struct {
	// contains filtered or unexported fields
}

CircuitBreaker is a thread-safe transport-level circuit breaker. Zero value is unusable; call NewCircuitBreaker.

func NewCircuitBreaker

func NewCircuitBreaker(failureThreshold int, cooldown time.Duration) *CircuitBreaker

NewCircuitBreaker constructs a breaker with the given thresholds. Defaults used when zero values are passed: 5 failures, 30s cooldown.

func (*CircuitBreaker) Allow

func (cb *CircuitBreaker) Allow() bool

Allow returns true if the caller is permitted to proceed with the request. Transitions OPEN → HALF_OPEN once the cooldown has elapsed.

func (*CircuitBreaker) Failures

func (cb *CircuitBreaker) Failures() int

Failures returns the current failure count (reset on any success).

func (*CircuitBreaker) RecordFailure

func (cb *CircuitBreaker) RecordFailure()

RecordFailure increments the failure count and opens the circuit if the threshold is crossed, or flips back OPEN if a HALF_OPEN probe fails.

func (*CircuitBreaker) RecordSuccess

func (cb *CircuitBreaker) RecordSuccess()

RecordSuccess resets the breaker after a passing request.

func (*CircuitBreaker) State

func (cb *CircuitBreaker) State() CircuitState

State returns the current state; safe for telemetry export.

type CircuitState

type CircuitState int

CircuitState represents the state of the transport circuit breaker.

const (
	// CircuitClosed means requests flow normally.
	CircuitClosed CircuitState = iota
	// CircuitOpen means recent failures tripped the breaker; requests are dropped
	// or queued to the outbox until the cooldown elapses.
	CircuitOpen
	// CircuitHalfOpen means the cooldown has elapsed; the next request is a probe.
	CircuitHalfOpen
)

func (CircuitState) String

func (s CircuitState) String() string

String returns the human-readable state name.

type CitedClause

type CitedClause struct {
	Type  string `json:"type"`
	Ref   string `json:"ref"`
	Title string `json:"title,omitempty"`
}

type ClassificationRequest

type ClassificationRequest struct {
	Name                    string `json:"name,omitempty"`
	Domain                  string `json:"domain"`
	DecisionAutonomy        string `json:"decision_autonomy"`
	UserImpact              string `json:"user_impact,omitempty"`
	ProcessesPersonalData   bool   `json:"processes_personal_data,omitempty"`
	AiType                  string `json:"ai_type,omitempty"`
	GeneratesContent        bool   `json:"generates_content,omitempty"`
	IndistinguishableOutput bool   `json:"indistinguishable_output,omitempty"`
	AdditionalContext       string `json:"additional_context,omitempty"`
}

ClassificationRequest mirrors the REST API schema.

type ClassificationResult

type ClassificationResult struct {
	PrimaryCategory     string              `json:"primary_category"`
	SecondaryCategories []string            `json:"secondary_categories"`
	Confidence          float64             `json:"confidence"`
	Reasoning           string              `json:"reasoning"`
	CitedClauses        []CitedClause       `json:"cited_clauses"`
	RecommendedActions  []RecommendedAction `json:"recommended_actions"`
	RulesetVersion      string              `json:"ruleset_version"`
	MatchedRules        []string            `json:"matched_rules"`
	LLMUsed             bool                `json:"llm_used"`
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the main entry point. Safe for concurrent use.

func New

func New(apiKey string, opts ...Option) (*Client, error)

New creates a new client. Pass an API key starting with JUN_live_ or JUN_test_.

func (*Client) CapturedEvents

func (c *Client) CapturedEvents() []InferenceEvent

CapturedEvents returns test-mode captured events.

func (*Client) Classify

Classify calls the /v1/classify endpoint.

func (*Client) Close

func (c *Client) Close() error

Close flushes any pending events and stops background workers.

func (*Client) Enqueue

func (c *Client) Enqueue(event InferenceEvent)

Enqueue adds an event to the buffer.

func (*Client) Flush

func (c *Client) Flush(ctx context.Context) error

Flush forces immediate delivery of the current buffer.

func (*Client) Health added in v1.2.1

func (c *Client) Health() map[string]interface{}

Health exposes transport/reliability state for SDK telemetry dashboards.

func (*Client) RecordAutomatedDecision

func (c *Client) RecordAutomatedDecision(d DecisionInput) string

RecordAutomatedDecision logs an `decision.automated_decision_made` event.

This is the anchor event that downstream tools (explanation, objection, reversal) reference via `decision_id`. The SDK never transmits raw input; only field names and categorical values.

func (*Client) RecordDecisionReversed

func (c *Client) RecordDecisionReversed(
	assetID, originalDecisionID, newOutcome, triggeredBy string,
) string

RecordDecisionReversed logs that a prior automated decision was overturned (PIPA §37조의2 ①항 refusal honored, or reviewer correction).

func (*Client) RecordExplanationProvided

func (c *Client) RecordExplanationProvided(
	assetID, decisionID, deliveryMethod, recipientHash string,
) string

RecordExplanationProvided logs that a §37조의2 ②항 / §36조의2 설명요구권 response was delivered to the subject. `deliveryMethod` is one of "in_app", "email", "mail", "api".

func (*Client) RecordHeartbeat added in v1.2.1

func (c *Client) RecordHeartbeat(assetID string) string

RecordHeartbeat records SDK transport state for operational telemetry.

func (*Client) RecordHumanReview

func (c *Client) RecordHumanReview(assetID, decisionID, reviewerID, outcome string) string

RecordHumanReview records a human-in-the-loop review.

func (*Client) RecordHumanReviewCompleted

func (c *Client) RecordHumanReviewCompleted(
	assetID, decisionID, reviewerID, finalOutcome string,
) string

RecordHumanReviewCompleted logs the outcome of a reviewer's action.

func (*Client) RecordHumanReviewTriggered

func (c *Client) RecordHumanReviewTriggered(
	assetID, decisionID, reason string,
) string

RecordHumanReviewTriggered logs that an automated decision was escalated to human review (following an objection or risk threshold). Pair with RecordHumanReviewCompleted once the reviewer acts.

func (*Client) RecordObjection

func (c *Client) RecordObjection(assetID, decisionID, reason, userIDHash string) string

RecordObjection records a user objection (법 제33조 제3호).

func (*Client) RecordObjectionResolved

func (c *Client) RecordObjectionResolved(
	assetID, objectionID, resolution string,
) string

RecordObjectionResolved closes the objection lifecycle.

func (*Client) RecordObjectionV2

func (c *Client) RecordObjectionV2(o ObjectionInput) string

func (*Client) RecordResultLabeled

func (c *Client) RecordResultLabeled(
	assetID, labelType, outputHash string,
) string

RecordResultLabeled records that a generative output was programmatically labeled as AI-generated (EU AI Act Art. 50(2) deepfake labeling).

func (*Client) RecordTransparencyNoticeShown

func (c *Client) RecordTransparencyNoticeShown(
	assetID, locale, channel string,
	legalBases []string,
) string

RecordTransparencyNoticeShown records that a disclosure banner was rendered to the end-user (AI 기본법 §31, EU AI Act Art. 50).

Legal basis defaults to ["ai_basic_law_kr", "eu_ai_act_art_50"]; callers can override via legalBases if a different combination applies.

func (*Client) RecordTransparencyPolicyDisclosed

func (c *Client) RecordTransparencyPolicyDisclosed(
	assetID, policyURL, version string,
) string

RecordTransparencyPolicyDisclosed records that the tenant's public AI-use policy page was linked/rendered to the user. Separate from notice_shown: this is the "policy exists and was exposed" event.

func (*Client) ResetCaptured

func (c *Client) ResetCaptured()

ResetCaptured clears the test-mode buffer.

type Config

type Config struct {
	APIKey      string
	Endpoint    string
	Environment string
	Region      string
	HTTPClient  *http.Client
}

Config contains client options.

type DecisionInput

type DecisionInput struct {
	AssetID     string
	DecisionID  string
	Outcome     string // e.g. "approved", "denied", "flagged"
	UserIDHash  string // precomputed SHA-256 of user id (SDK never sees raw id)
	Explanation string // machine-readable summary (no raw PII)
	LegalBases  []string
	Features    map[string]interface{} // feature names + categorical values (no raw)
}

DecisionInput captures the minimum data needed to record an automated decision event, as required by PIPA §37조의2 ①항 and 신용정보법 §36조의2.

type InferenceEvent

type InferenceEvent struct {
	EventID     string                 `json:"event_id"`
	Timestamp   time.Time              `json:"timestamp"`
	AssetID     string                 `json:"asset_id"`
	EventType   string                 `json:"event_type"`
	InputHash   string                 `json:"input_hash,omitempty"`
	OutputHash  string                 `json:"output_hash,omitempty"`
	Metadata    map[string]interface{} `json:"metadata,omitempty"`
	SDKVersion  string                 `json:"sdk_version"`
	SDKLanguage string                 `json:"sdk_language,omitempty"`
	Environment string                 `json:"environment,omitempty"`
	Region      string                 `json:"region,omitempty"`
	Host        map[string]string      `json:"host,omitempty"`
}

InferenceEvent matches the ClickHouse event envelope.

type ObjectionInput

type ObjectionInput struct {
	AssetID       string
	DecisionID    string
	ObjectionType string // "automated_decision_refusal" | "explanation_request" | "appeal"
	ReasonSummary string // no raw PII
	UserIDHash    string
	LegalBases    []string
}

RecordObjectionV2 records a §37조의2 ②항 objection with richer metadata than the legacy RecordObjection helper. Prefer this for new integrations.

type Option

type Option func(*Client)

Option configures the client.

func WithCircuitBreaker added in v1.2.1

func WithCircuitBreaker(failureThreshold int, cooldown time.Duration) Option

func WithEndpoint

func WithEndpoint(url string) Option

func WithEnvironment

func WithEnvironment(env string) Option

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

func WithOutbox added in v1.2.1

func WithOutbox(path string) Option

func WithQueueLimits added in v1.2.1

func WithQueueLimits(maxQueueSize, maxBatchSize int) Option

func WithRegion added in v1.2.1

func WithRegion(region string) Option

func WithoutOutbox added in v1.2.1

func WithoutOutbox() Option

type Outbox

type Outbox struct {
	// contains filtered or unexported fields
}

Outbox is a file-backed fallback queue for events that failed to transmit. Unlike the Python/TS SDKs (which use SQLite), Go's stdlib keeps this light: one newline-delimited JSON file per buffer generation, rotated on drain.

The Go runtime has no atexit hook, so callers MUST call (*Client).Close() before process exit to guarantee durability.

func NewOutbox

func NewOutbox(path string, maxRows, ttlDays int) (*Outbox, error)

NewOutbox opens (creates if missing) a newline-JSON outbox file.

func (*Outbox) Close

func (o *Outbox) Close() error

Close is a no-op placeholder symmetric with other SDKs — the Go outbox uses per-call file handles, no persistent connections to release.

func (*Outbox) Count

func (o *Outbox) Count() (int, error)

Count returns the number of entries currently in the outbox.

func (*Outbox) Drain

func (o *Outbox) Drain(max int) ([]InferenceEvent, error)

Drain returns up to max events and removes them from the outbox. Caller is expected to only call Drain after confirming transport is healthy.

func (*Outbox) Put

func (o *Outbox) Put(event InferenceEvent) error

Put appends one event.

func (*Outbox) PutMany

func (o *Outbox) PutMany(events []InferenceEvent) error

PutMany appends a batch atomically (single write syscall).

type RecommendedAction

type RecommendedAction struct {
	Code                 string `json:"code"`
	Priority             string `json:"priority"`
	Description          string `json:"description,omitempty"`
	Clause               string `json:"clause,omitempty"`
	EstimatedEffortHours int    `json:"estimated_effort_hours,omitempty"`
}

Jump to

Keyboard shortcuts

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