mirror of
https://github.com/luxfi/aml.git
synced 2026-09-24 00:25:20 +00:00
The defining failure of the last review was not in a plane. It was that there were TWO wirings: cmd/amld assembled a Handler by hand and the tests assembled a different one, so the record fingerprint could be a struct field the suite exercised and no column stored — every retry a permanent 409 in production while every test passed. api.Wire is now the only assembly. It creates every collection, opens every shelf, makes every join and registers what has to run on a cadence; cmd/amld supplies only what an installation answers differently, the tests call the same function, and internal/source.NoLiteral reads cmd/amld to refuse a second copy. Handler completeness is checked by reflection, because a hand-written field list would be the third copy. A retry is not a second transaction. pkg/receipt resolves the identity of an OFFER once, at the top of ingest, before anything is read or written, and returns the prior answer byte for byte — so the ledger, the aggregates, the history, the alerts and the case plane all agree on one transaction instead of the ledger holding one record while the aggregates hold three. Two different facts under one reference is 409 and never 503. Because the answer is kept AFTER the work, a process that dies in between leaves no receipt, so every plane past it also recognises the transaction for itself: history does not append a second row, alerts keep the first judgement, and a judged transaction opens no second case. A bound over a COUNT of caller-sized values is not a bound. types.MaxIdent bounds every identifier at the door, which is what turns the counts downstream into figures in bytes; dictionary.MaxName does the same for a payload key, and dictionary.Ceiling is the product a test WEIGHS a full accumulator against. The field catalog's accumulator moves into roster, which admits and never removes, so per-tenant bounds multiply by ONE number an operator can hold against a pod. engine.Evaluator now keeps no compiled rules at all. A candidate's text arrives on the wire at /v1/aml/rules/test, so a compiled-rule table there was keyed by a string a caller wrote, sized by how many distinct ones a caller sends, with no cap and no removal, in the memory every institution's ingest runs in — an OOM from one authenticated caller, which on this deployment is every control off at once. A rule's compiled form is a value with an owner: the installed library, or one replay. Nothing shared, nothing to grow. Found here, not reported. Handler.history is the one function that materialises a whole retained history, so it now REQUIRES a *topology.Grant, and a Grant comes from Budget.Admit and nowhere else. An ungated whole-history read is something a caller has to write on purpose rather than something a new door can forget. The rule replay and the activation rate fold take the same one budget the model studies take. Reaching a bound is allowed; reaching it quietly is not. GET /v1/aml/load is the one door for "is anything of mine quietly degraded": the tenant's aggregates against its own ceiling in bytes with a grade, whether it has a behavioural model at all, the field catalog's pressure, and the process's counts of institutions held and refused. It names no other institution. Closing R1-R8 from the review plus R11, the two recurring classes, and the silent degradation the load door answers. Twenty-four mutations, twenty-four killed. Co-authored-by: Hanzo Dev <[email protected]>
114 lines
4.6 KiB
Go
114 lines
4.6 KiB
Go
// Copyright 2024-2026 Lux Partners Limited. All rights reserved.
|
|
// Use of this source code is governed by the Apache 2.0
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package api
|
|
|
|
// What this engine is holding for a tenant, and what it has had to let go.
|
|
//
|
|
// Every live control in this process is bounded, and each bound can bind. When
|
|
// one does, an aggregate stops being kept, a model is not planted, an observation
|
|
// is turned away — and none of those raises an error, because refusing a payment
|
|
// because a cache is full would be the worse failure. What is NOT allowed is for
|
|
// them to happen quietly: an aggregate that reads zero is what a clean account
|
|
// also reads, and a model that is warming reports nothing, which is what a clean
|
|
// institution also reports. A control that switches itself off without saying so
|
|
// is worse than no control, because it is a control somebody is relying on.
|
|
//
|
|
// So there is ONE door for the question "is anything of mine quietly degraded",
|
|
// per tenant, and it answers in words rather than in ratios a reader has to
|
|
// interpret. Nothing here names another institution: the tenant's own numbers,
|
|
// and the process's own counts, which are facts about a deployment rather than
|
|
// about anybody's business.
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/luxfi/aml/pkg/anomaly"
|
|
"github.com/luxfi/aml/pkg/dictionary"
|
|
"github.com/luxfi/aml/pkg/velocity"
|
|
)
|
|
|
|
// LoadIn takes no arguments: a caller asks about itself and cannot ask about
|
|
// anyone else.
|
|
type LoadIn struct{}
|
|
|
|
// Load is what this engine holds for one tenant.
|
|
type Load struct {
|
|
Org string `json:"org"`
|
|
// Aggregates is the sliding windows every behavioural measure reads: how many
|
|
// keys this tenant holds against its own ceiling in bytes, how many it has
|
|
// had to drop, and a grade. A tenant at "full" is losing aggregates it would
|
|
// otherwise have found structuring in, and the answer is a bigger ceiling.
|
|
Aggregates velocity.Load `json:"aggregates"`
|
|
// Model says whether this tenant has a behavioural model at all. Crowded
|
|
// means the process holds models for as many institutions as it may and this
|
|
// one is not among them, so nothing behavioural has examined its
|
|
// transactions — the rules still ran, the model did not.
|
|
Model Model `json:"model"`
|
|
// Fields is the payload catalog's accumulator: what it holds for this
|
|
// process, and how many institutions it was full for. A tenant the roster
|
|
// refused has no catalog at all, and an empty catalog reads exactly like a
|
|
// payload surface with nothing in it.
|
|
Fields dictionary.Pressure `json:"fields"`
|
|
// Engine is what the process is holding overall. It carries no tenant.
|
|
Engine Engine `json:"engine"`
|
|
}
|
|
|
|
// Model is the behavioural half, reduced to what says whether it is running.
|
|
type Model struct {
|
|
Planted bool `json:"planted"`
|
|
Restored bool `json:"restored"`
|
|
Learned int64 `json:"learned"`
|
|
Warm bool `json:"warm"`
|
|
Crowded bool `json:"crowded"`
|
|
}
|
|
|
|
// Engine is the process's own reading.
|
|
type Engine struct {
|
|
// Orgs and Room are how many institutions this process holds live state for
|
|
// and how many it may.
|
|
Orgs int `json:"orgs"`
|
|
Room int `json:"room"`
|
|
// Refused counts the institutions turned away for want of a place, and
|
|
// Crowded the transactions that reached no model because of it.
|
|
Refused int64 `json:"refused"`
|
|
Crowded int64 `json:"crowded"`
|
|
// Held and Ceiling are the aggregate store's bytes, across every tenant.
|
|
Held int64 `json:"held"`
|
|
Ceiling int64 `json:"ceiling"`
|
|
// Late counts transactions that arrived older than their window and were
|
|
// folded to its leading edge, so an operator can see a feed running behind.
|
|
Late int64 `json:"late"`
|
|
}
|
|
|
|
// load answers for the caller's own tenant.
|
|
func (h *Handler) load(_ context.Context, org string, _ *LoadIn) (*Load, error) {
|
|
out := &Load{Org: org}
|
|
if h.Velocity != nil {
|
|
out.Aggregates = h.Velocity.Load(org)
|
|
p := h.Velocity.Pressure()
|
|
out.Engine.Orgs, out.Engine.Room = p.Orgs, p.Room
|
|
out.Engine.Refused, out.Engine.Late = p.Refused, p.Late
|
|
out.Engine.Held, out.Engine.Ceiling = p.Held, p.Ceiling
|
|
}
|
|
if d := h.Planes.Dictionary; d != nil {
|
|
out.Fields = d.Pressure()
|
|
}
|
|
if h.Anomaly != nil {
|
|
st := h.Anomaly.State(org)
|
|
out.Model = Model{
|
|
Planted: !st.Planted.IsZero(), Restored: st.Restored,
|
|
Learned: st.Learned, Warm: st.Warm, Crowded: st.Crowded,
|
|
}
|
|
out.Engine.Crowded = h.Anomaly.Pressure().Crowded
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// grades is what a reviewer reads first. Kept beside the type it describes so
|
|
// that a new grade cannot be added without a name a person can act on.
|
|
var _ = []velocity.Grade{velocity.GradeClear, velocity.GradeCrowded, velocity.GradeFull}
|
|
|
|
var _ = anomaly.ReasonCrowded
|