Clean up documentation consistency
All checks were successful
ci/woodpecker/push/build-image Pipeline was successful
All checks were successful
ci/woodpecker/push/build-image Pipeline was successful
This commit is contained in:
@@ -101,8 +101,8 @@ Payload type: `WeatherForecastRun`.
|
|||||||
| `locationId` | string | no | Provider location identifier. |
|
| `locationId` | string | no | Provider location identifier. |
|
||||||
| `locationName` | string | no | Human location name. |
|
| `locationName` | string | no | Human location name. |
|
||||||
| `issuedAt` | timestamp | yes | When the forecast run was generated or issued. |
|
| `issuedAt` | timestamp | yes | When the forecast run was generated or issued. |
|
||||||
| `updatedAt` | timestamp | no | Later provider update time. |
|
| `updatedAt` | timestamp | no | Subsequent provider update time. |
|
||||||
| `product` | string | yes | `hourly`, `narrative`, or `daily`. |
|
| `product` | string | yes | Current emitted values are `hourly` and `narrative`. |
|
||||||
| `latitude` | number | no | Degrees. |
|
| `latitude` | number | no | Degrees. |
|
||||||
| `longitude` | number | no | Degrees. |
|
| `longitude` | number | no | Degrees. |
|
||||||
| `elevationMeters` | number | no | Meters. |
|
| `elevationMeters` | number | no | Meters. |
|
||||||
@@ -145,7 +145,7 @@ Payload type: `WeatherForecastDiscussion`.
|
|||||||
| `officeName` | string | no | Office name. |
|
| `officeName` | string | no | Office name. |
|
||||||
| `product` | string | yes | Current value is `afd`. |
|
| `product` | string | yes | Current value is `afd`. |
|
||||||
| `issuedAt` | timestamp | yes | Bulletin issue time. |
|
| `issuedAt` | timestamp | yes | Bulletin issue time. |
|
||||||
| `updatedAt` | timestamp | no | Later update time. |
|
| `updatedAt` | timestamp | no | Subsequent update time. |
|
||||||
| `keyMessages` | array of strings | no | Extracted key messages. |
|
| `keyMessages` | array of strings | no | Extracted key messages. |
|
||||||
| `shortTerm` | object | no | Short-term section. |
|
| `shortTerm` | object | no | Short-term section. |
|
||||||
| `longTerm` | object | no | Long-term section. |
|
| `longTerm` | object | no | Long-term section. |
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ and before each interval tick. If no jitter is configured in code, feedkit uses
|
|||||||
`min(every/10, 30s)`, capped at half the interval.
|
`min(every/10, 30s)`, capped at half the interval.
|
||||||
|
|
||||||
Poll failures are logged and do not stop the daemon. A failed poll emits no
|
Poll failures are logged and do not stop the daemon. A failed poll emits no
|
||||||
events for that source until a later poll succeeds.
|
events for that source until a subsequent poll succeeds.
|
||||||
|
|
||||||
## Conditional HTTP Fetches
|
## Conditional HTTP Fetches
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This document defines `weatherfeeder`'s development architecture and invariants for maintainers and LLM coding agents. It describes how the implemented system is built and how future changes should preserve its boundaries.
|
This document defines `weatherfeeder`'s development architecture and invariants for maintainers and LLM coding agents. It describes how the implemented system is built and how subsequent changes should preserve its boundaries.
|
||||||
|
|
||||||
This is an inward-facing policy document. User-facing wire contracts belong in
|
This is an inward-facing policy document. User-facing wire contracts belong in
|
||||||
[`docs/integrations/events.md`](../integrations/events.md), and future work
|
[`docs/integrations/events.md`](../integrations/events.md), and roadmap items
|
||||||
belongs under [`docs/roadmap/`](../roadmap/).
|
belong under [`docs/roadmap/`](../roadmap/).
|
||||||
|
|
||||||
## Project Shape
|
## Project Shape
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@ Tests and examples:
|
|||||||
- The sample `cmd/weatherfeeder/config.yml` is executable test input and is load-tested.
|
- The sample `cmd/weatherfeeder/config.yml` is executable test input and is load-tested.
|
||||||
- Tests should keep exercising package contracts directly rather than relying only on full-daemon execution.
|
- Tests should keep exercising package contracts directly rather than relying only on full-daemon execution.
|
||||||
|
|
||||||
## Modules or Stages
|
## Modules Or Processing Steps
|
||||||
|
|
||||||
The implemented processing stages are source polling, normalization, dedupe, and sink dispatch.
|
The implemented processing steps are source polling, normalization, dedupe, and sink dispatch.
|
||||||
|
|
||||||
Source contract:
|
Source contract:
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ Diagnostic: inspect the line and field in the error. Feedkit uses strict YAML
|
|||||||
field decoding for config struct fields.
|
field decoding for config struct fields.
|
||||||
|
|
||||||
Safe fix: correct the YAML and compare the shape with
|
Safe fix: correct the YAML and compare the shape with
|
||||||
[configuration](config.md). Driver-specific `params` keys are validated later by
|
[configuration](config.md). Driver-specific `params` keys are validated by their
|
||||||
their source or sink constructors.
|
source or sink constructors.
|
||||||
|
|
||||||
## `config validation failed`
|
## `config validation failed`
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Finalize builds the output event envelope by copying the input and applying the
|
// Finalize builds the output event envelope by copying the input and applying the
|
||||||
// canonical schema/payload, plus (optionally) EffectiveAt.
|
// canonical schema/payload, plus an optional effective time.
|
||||||
//
|
//
|
||||||
// Important behavior:
|
// Important behavior:
|
||||||
// - ID/Kind/Source/EmittedAt are preserved by copying the input event.
|
// - ID/Kind/Source/EmittedAt are preserved by copying the input event.
|
||||||
// - EffectiveAt is only overwritten when effectiveAt is non-zero.
|
// - EffectiveAt is only overwritten when the supplied effective time is non-zero.
|
||||||
// If effectiveAt is zero, any existing in.EffectiveAt is preserved.
|
// If the supplied time is zero, any existing in.EffectiveAt is preserved.
|
||||||
// - Payload floats are rounded to a stable wire-friendly precision (see round.go).
|
// - Payload floats are rounded to a stable wire-friendly precision (see round.go).
|
||||||
func Finalize(in event.Event, outSchema string, outPayload any, effectiveAt time.Time) (*event.Event, error) {
|
func Finalize(in event.Event, outSchema string, outPayload any, effectiveAt time.Time) (*event.Event, error) {
|
||||||
// Enforce stable numeric presentation for weather payloads before delegating to feedkit's
|
// Enforce stable numeric presentation for weather payloads before delegating to feedkit's
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
// - sources emit raw JSON payloads (typically json.RawMessage)
|
// - sources emit raw JSON payloads (typically json.RawMessage)
|
||||||
// - normalizers decode into provider structs
|
// - normalizers decode into provider structs
|
||||||
//
|
//
|
||||||
// Errors include a small amount of stage context ("extract payload", "decode raw payload").
|
// Errors include a small amount of operation context ("extract payload", "decode raw payload").
|
||||||
// Callers typically wrap these with a provider/kind label.
|
// Callers typically wrap these with a provider/kind label.
|
||||||
func DecodeJSONPayload[T any](in event.Event) (T, error) {
|
func DecodeJSONPayload[T any](in event.Event) (T, error) {
|
||||||
return fknormalize.DecodeJSONPayload[T](in)
|
return fknormalize.DecodeJSONPayload[T](in)
|
||||||
@@ -24,15 +24,15 @@ func DecodeJSONPayload[T any](in event.Event) (T, error) {
|
|||||||
// NormalizeJSON is a convenience wrapper for the common JSON-normalizer pattern:
|
// NormalizeJSON is a convenience wrapper for the common JSON-normalizer pattern:
|
||||||
//
|
//
|
||||||
// 1. Decode raw JSON payload into provider struct T
|
// 1. Decode raw JSON payload into provider struct T
|
||||||
// 2. Map T into canonical payload P (plus an EffectiveAt timestamp)
|
// 2. Map T into canonical payload P (plus an effective time)
|
||||||
// 3. Finalize the event envelope (schema/payload/effectiveAt) + Validate
|
// 3. Finalize the event envelope (schema/payload/effective time) + Validate
|
||||||
//
|
//
|
||||||
// label should be short and specific, e.g. "openweather observation".
|
// label should be short and specific, e.g. "openweather observation".
|
||||||
// outSchema should be the canonical schema constant.
|
// outSchema should be the canonical schema constant.
|
||||||
// build should contain ONLY provider/domain mapping logic.
|
// build should contain ONLY provider/domain mapping logic.
|
||||||
//
|
//
|
||||||
// Error policy:
|
// Error policy:
|
||||||
// - NormalizeJSON wraps ALL failures with consistent context: "<label> normalize: <stage>: ..."
|
// - NormalizeJSON wraps ALL failures with consistent context: "<label> normalize: <operation>: ..."
|
||||||
// - build() should return specific errors without repeating the label prefix.
|
// - build() should return specific errors without repeating the label prefix.
|
||||||
func NormalizeJSON[T any, P any](
|
func NormalizeJSON[T any, P any](
|
||||||
in event.Event,
|
in event.Event,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import (
|
|||||||
// 2. Alert timing fields are best-effort parsed; invalid timestamps do not fail the
|
// 2. Alert timing fields are best-effort parsed; invalid timestamps do not fail the
|
||||||
// entire normalization (they are left nil).
|
// entire normalization (they are left nil).
|
||||||
// 3. Some fields are intentionally passed through as strings (severity/urgency/etc.)
|
// 3. Some fields are intentionally passed through as strings (severity/urgency/etc.)
|
||||||
// since canonical vocabularies may evolve later.
|
// because the canonical model currently preserves provider vocabulary there.
|
||||||
type AlertsNormalizer struct{}
|
type AlertsNormalizer struct{}
|
||||||
|
|
||||||
func (AlertsNormalizer) Match(e event.Event) bool {
|
func (AlertsNormalizer) Match(e event.Event) bool {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ type WeatherAlert struct {
|
|||||||
Headline string `json:"headline,omitempty"`
|
Headline string `json:"headline,omitempty"`
|
||||||
|
|
||||||
Severity string `json:"severity,omitempty"` // e.g. Extreme/Severe/Moderate/Minor/Unknown
|
Severity string `json:"severity,omitempty"` // e.g. Extreme/Severe/Moderate/Minor/Unknown
|
||||||
Urgency string `json:"urgency,omitempty"` // e.g. Immediate/Expected/Future/Past/Unknown
|
Urgency string `json:"urgency,omitempty"` // provider-defined urgency value
|
||||||
Certainty string `json:"certainty,omitempty"` // e.g. Observed/Likely/Possible/Unlikely/Unknown
|
Certainty string `json:"certainty,omitempty"` // e.g. Observed/Likely/Possible/Unlikely/Unknown
|
||||||
|
|
||||||
Status string `json:"status,omitempty"` // e.g. Actual/Exercise/Test/System/Unknown
|
Status string `json:"status,omitempty"` // e.g. Actual/Exercise/Test/System/Unknown
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type WeatherForecastRun struct {
|
|||||||
LocationName string `json:"locationName,omitempty"`
|
LocationName string `json:"locationName,omitempty"`
|
||||||
IssuedAt time.Time `json:"issuedAt"` // required: when this run was generated/issued
|
IssuedAt time.Time `json:"issuedAt"` // required: when this run was generated/issued
|
||||||
|
|
||||||
// Some providers include both a generated time and a later update time.
|
// Some providers include both a generated time and a subsequent update time.
|
||||||
// Keep UpdatedAt optional; many providers won’t supply it.
|
// Keep UpdatedAt optional; many providers won’t supply it.
|
||||||
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
|
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user