Release Notes: v0.2.0¶
Release Date: 2026-07-25
Highlights¶
- Product Signal Types: 5 new
signal.Typevalues for capturing product and market intelligence alongside operational signals - Cross-Repo References:
pkg/refpackage withTypedReffor linking entities across repository boundaries - Fingerprinting: Deterministic
ComputeFingerprint()for signal deduplication - Embedded Schemas:
schema/package exposes JSON schemas at runtime viago:embed - Derived Metrics:
DerivedMetricsstruct for computed scores kept separate from signal identity
What's New¶
Product Signal Types¶
Signal Spec now covers product and market intelligence in addition to operational observations. Five new signal.Type values are available:
import "github.com/plexusone/signal-spec/pkg/signal"
sig := signal.Signal{
ID: "sig-2026-005678",
Type: signal.TypeEnhancementRequest,
// ...
}
enhancement_request- Customer feature requests with vote/subscriber metadatacompetitive_gap- Gaps vs. competitors identified from win/loss analysiscompetitor_launch- Competitor product announcementsanalyst_finding- Insights extracted from analyst reportsmarket_observation- General market trends
Enhancement Signal Metadata Conventions¶
enhancement_request signals carry structured product data via well-known Metadata keys. All keys are optional; adapters populate whichever keys their source system provides:
| Constant | Metadata Key | Type | Description |
|---|---|---|---|
signal.MetaVotes |
votes |
int |
Total vote/upvote count |
signal.MetaSubscribers |
subscribers |
int |
Number of watchers/subscribers |
signal.MetaOrganizations |
organizations |
[]string |
Requesting organization names |
signal.MetaCustomers |
customers |
[]string |
Named customer identifiers |
signal.MetaOpportunities |
opportunities |
[]string |
Sales opportunity IDs linked to this request |
signal.MetaEstimatedARR |
estimated_arr |
int64 |
Estimated ARR at stake, in cents |
Cross-Repo References (pkg/ref)¶
The new pkg/ref package defines TypedRef, a {type}:{slug} reference format for linking signal-spec entities to definitions owned by other repositories (e.g., MarketSpec, OrganizationSpec):
import "github.com/plexusone/signal-spec/pkg/ref"
r := ref.New(ref.TypeMarket, "identity-governance")
// r == "market:identity-governance"
if err := ref.ValidateStrict(r); err != nil {
// handle invalid ref
}
Known reference types: customer, capability, market, competitor, analyst-report
pkg/ref provides:
New(type, slug)- construct aTypedRefParse(ref)- split into type and slugValidate(ref)- check format and known typeValidateSlug(slug)- check slug is lowercase alphanumeric/hyphenValidateStrict(ref)- format + known type + slug validity
Signals also carry cross-repo references via well-known Metadata keys:
| Constant | Metadata Key | Example |
|---|---|---|
signal.MetaCustomerRef |
customer_ref |
customer:acme-001 |
signal.MetaCapabilityRef |
capability_ref |
capability:sso |
signal.MetaMarketRef |
market_ref |
market:identity-governance |
signal.MetaCompetitorRef |
competitor_ref |
competitor:okta |
signal.MetaAnalystReportRef |
analyst_report_ref |
analyst-report:gartner-mq-iam-2026 |
Entity.Ref¶
common.Entity now has an optional Ref field carrying a typed cross-repo reference, so entities referenced by a signal can be linked directly to their canonical definition:
Signal Fingerprinting¶
signal.ComputeFingerprint() returns a deterministic SHA-256 hex digest computed from a signal's identity fields (ID, Type, Source, Domain, Severity, Summary, Description, Entities, ObservedAt, Metadata, Tags). Mutable and derived fields — Status, Derived, Embedding, ReceivedAt, RootCauseID, and Fingerprint itself — are excluded, so the same raw input always produces the same fingerprint regardless of processing state:
Use fingerprints to deduplicate signals ingested from the same underlying event across multiple adapters or retries.
DerivedMetrics¶
The new DerivedMetrics struct holds computed scores that are recomputed over time and explicitly excluded from fingerprinting:
sig.Derived = &signal.DerivedMetrics{
Frustration: ptr(4.2),
Momentum: ptr(1.8),
Reach: ptr(12),
Urgency: ptr(3.5),
}
Frustration- weighted signal count multiplied by ageMomentum- trailing signal count over a rolling window (e.g., 30 days)Reach- count of distinct customer references contributing to a root causeUrgency- case count weighted by severityComputedAt- when these metrics were last computedExtra- additional derived scores not covered by the well-known fields
Embedded Schemas (schema/)¶
The new schema/ package embeds generated JSON schemas via go:embed, so consumers can validate signals at runtime without reading files from disk:
import "github.com/plexusone/signal-spec/schema"
// schema.SignalSchema, schema.RootCauseSchema, schema.RemediationSchema,
// and schema.ValidationSignalSchema are []byte
var s map[string]any
json.Unmarshal(schema.SignalSchema, &s)
// schema.All is an embed.FS containing all *.schema.json files
signal.schema.json and rootcause.schema.json were regenerated to include the new signal types, metadata conventions, and DerivedMetrics.
Installation¶
Migration Guide¶
From v0.1.0¶
No breaking changes. All v0.2.0 additions are purely additive:
- Existing
Signal,RootCause,Remediation, andValidationSignaltypes are unchanged. common.Entity.Refis a new optional field; existing entity literals compile unchanged.signal.Fingerprintwas already a field onSignal;ComputeFingerprint()is a new helper to populate it.- Regenerate schemas with
signal-spec schema generate -o schema/(or importschema.SignalSchemadirectly) if you consume the JSON schema files.
Full Changelog¶
See CHANGELOG.md for the complete list of changes.