Files
mesh-catalog/modules/claude-licence-manager/cmd/manager/store.go
T
jschoubben cff1005422
mesh/delivery merged: source.main moved to novox/mesh-catalog@6d000647de2d
mesh/check being carried to cff1005422c1 on 6d000647de2d | from f9dcbc295723
P2: the licence manager is four parts of one manifest (issue 1409)
The one bundle that did everything becomes the manager bundle, which runs long and answers the seat's ten verbs and
the three acting tools, and a tools bundle of its own that answers the four reading tools and writes nothing, so they
answer while the manager fails to load or stops. Both import the module's one package for the layouts of the kept
data and the log entries, the key form, the entries' names and the settings with their validity; the settings file
and the account with its directory stay as they are.

Builds: design 39 parts §1, §2, §3, §4, §5, §6, §7, §8
2026-11-12 12:08:03 +01:00

77 lines
3.3 KiB
Go

package main
// The manager's store (novox/hq ADR 0183, design 39 bus-and-switch §2 to §7): licences, bindings with a generation,
// leases, what became of each login it was offered, usage readings and the audit, all in the bus's own storage
// (busstore.go). Every rule is tested on the same store over a bus kept in memory.
import (
"context"
"time"
. "claude-licence-manager/internal/licences"
)
// Binding is one consumer's binding (ADR 0206, §3): the licence, kind and generation it should hold, since when, and
// why and by whom it was moved last.
type Binding struct {
Consumer string `json:"consumer"`
Licence string `json:"licence"`
// Key is the licence's key (§10), answered by the verb bindings (B25); the store keeps none.
Key string `json:"key,omitempty"`
Kind string `json:"kind,omitempty"`
Generation int64 `json:"generation"`
Since string `json:"since,omitempty"`
Why string `json:"why,omitempty"`
By string `json:"by,omitempty"`
}
// Move is what moves a binding: the licence's kind, why and by whom, and the floor a consumer's generation must pass
// (B11: the generation its node last reported); a nil Floor is none.
type Move struct {
Kind, Why, By string
Floor func(consumer string) int64
}
// floor is the floor m gives consumer.
func (m Move) floor(consumer string) int64 {
if m.Floor == nil {
return 0
}
return m.Floor(consumer)
}
// UsageRow is one usage reading.
type UsageRow struct {
Licence string `json:"licence"`
At int64 `json:"at"`
Reading UsageReading `json:"reading"`
// Raw is the vendor's answer whole, answered only when asked (§35).
Raw map[string]any `json:"raw,omitempty"`
}
// Store is what the manager keeps.
type Store interface {
Licences(ctx context.Context) ([]Licence, error)
Licence(ctx context.Context, name string) (*Licence, error)
LicenceForAccount(ctx context.Context, account string) (*Licence, error)
SaveLicence(ctx context.Context, l Licence) error
Bindings(ctx context.Context) ([]Binding, error)
Binding(ctx context.Context, consumer string) (*Binding, error)
// Bind binds (or switches) a consumer at its next generation.
Bind(ctx context.Context, consumer, licence string, m Move) (Binding, error)
Unbind(ctx context.Context, consumer string) (bool, error)
// Advance gives every consumer of a licence its next generation: what a rotation is to them.
Advance(ctx context.Context, licence string, m Move) ([]Binding, error)
// Lease takes a lease for d, or answers false while another holder's is live.
Lease(ctx context.Context, key, holder string, d time.Duration) (bool, error)
Unlease(ctx context.Context, key, holder string) error
Outcome(ctx context.Context, fingerprint string) (Outcome, error)
RecordOutcome(ctx context.Context, fingerprint, node, account string, o Outcome, why string) error
RecordUsage(ctx context.Context, licence string, at int64, r UsageReading, raw map[string]any) error
// Usage is the latest readings, newest first, of one licence or every one: at most limit, none before since (zero
// is none), the vendor's answer with raw (§35).
Usage(ctx context.Context, licence string, since time.Time, limit int, raw bool) ([]UsageRow, error)
// Audit appends one entry for an act; an error is the act failing (B20).
Audit(ctx context.Context, what string, detail map[string]any) error
}