THE ADDRESS IS THE PRODUCT. openapi.Fold takes an operation's product tag from the first /v1 segment of its path and nothing else (openapi.Product); a per-op zip.WithTags names a different axis and cannot override it. The seven ops were addressed /v1/ml/labels, so seven compliance operations — their own writers (commerce adjudicates the dispute, the compliance face closes the case, an analyst files the review), their own five-year retention floor, their own per-tenant file — would have been published as part of the KServe model-SERVING product, which is four paths and live with customers on it. Nothing in the fleet would have said so: the floor ratchet reads `ml: 7 -> 14` as growth, because it refuses a shrink and only a shrink. It is the same mistake apps/risk's own manifest row already records having made and corrected once, one layer up. So: /v1/risk/labels, tag risk, every operation id and schema name risk-prefixed (riskLabelEvent and not riskEvent — apps/risk publishes a riskEvent already, and it is a scored decision rather than a judged one). floor.json returns ml to 7 and raises risk to 17. The manifest row precedes risk, whose prefix is the bare /v1/risk, and TestEveryServedPathReachesTheAppThatServesIt proves all six paths reach label over the real fleet router rather than a comment claiming they do. address_test.go walks the live projection — the same openapi.FleetSpec that writes the committed subset — so a route re-addressed into somebody else's product fails at the plane. A BOUND ON COUNT OVER CALLER-SIZED VALUES IS NOT A BOUND. maxResolve capped a resolve at 500 named events and nothing capped a subject: the rows were bounded and the bytes were bounded only by the edge's BodyLimit, which is a fact about the deployment. Each subject is then amplified below the door — a dedupe key, a grouping key, one bound parameter per event in a statement against a single-writer file. The write door had the ceiling all along (admit, subjectMax); the read doors, added after, did not, and nothing compared them. There is now ONE spelling of each ceiling — admitSubject, admitKind, admitSource, admitEvidence, and instantMax inside stamp(), which is the one parser every time field passes — and every door asks it. So `count × ceiling` IS the byte bound of everything this plane binds, holds and stores. An unknown kind or source is refused on the READ path too: it can only ever match zero rows, so refusing says so instead of charging for the scan. bound_test.go proves it twice: reflect walks every In type and fails on a caller-sized field with no declared ceiling (the structural half — a new field cannot arrive unbounded), and every declared ceiling is refused over the wire with a refusal that does not carry the value back. A LITIGATION HOLD THAT ARRIVES MID-SWEEP KEEPS THE RECORD IN BOTH PLANES OR IN NEITHER. dispose sweeps the derived copy FIRST so nothing is orphaned in the warehouse, then deletes from the record re-asserting `hold = 0`. That protected the record and silently corrupted the copy: a record the delete declines to remove has already been swept, its seq is behind the delivery cursor, and deliver() asks the cursor rather than the world — so no retry re-sends it, pending() answers zero, and the row is present in the compliance record and permanently absent from the answer key a training join reads. A missing fraud label reads as an honest customer, and the row is the one somebody is litigating. remove() now reports what it kept, the sweep writes those back from the record, a repair that fails refuses the request rather than acknowledging a short copy, and `restored` is a NAMED state on the response. `disposed` counts what was disposed of rather than what was identified: a compliance report that says it deleted a record it is still holding is the wrong answer to the only question the report is asked. THE PUBLISHED PRECEDENCE RULE NAMES THE FIELD THE RESOLVER READS. The op exists so a caller holding a contested resolution can reproduce it, and its second term said `seen` while stronger() compares `knowable`. The two are equal for a live pipeline and differ for exactly the backfilled history the derivation exists to hold back, so a caller reproducing the rule got a different winner and no way to see why. The test counted the terms, which made the only property that matters unobservable; it now pins each term to the field at its position. Also: plugin/label/mcp.json is deleted. It is the only mcp.json in the tree, no app on main has one, the generator that wrote them was retired with its gate (manifest/mcp_test.go says so), and it declared seven tools under the old operation ids with nothing left to regenerate or compare it. 25 mutants in scripts/mutate.py, 11 of them new, 25 KILLED: each reintroduces one of these defects and the named test goes RED. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
34 KiB
34 KiB