Commit Graph
11 Commits
Author SHA1 Message Date
zeekay 51460827d4 Merge the forge's lux/universe into GitHub's, the one main from here
The two mains shared no history, so this is a per-file three-way merge:
for each file the 65 forge-only commits touched (by patch-id), the base is
the newest version both histories held. 105 files merged or took one side
cleanly, 48 were already identical, and the 45 true conflicts and 31
modify/delete pairs were resolved by what runs on the cluster:

- The forge wins where it is live: explorer 1.5.56 (digest 45db11ff) and
  its archive readers, explore-fe-hanzo's ConfigMap env (AI coin,
  /v1/indexer/hanzo, /v1/chain/hanzo/rpc), exchange-api reading
  luxd-archive, and explore-fe-{lux,zoo}-testnet, pinned to what they run
  (v2.8.5-lux / v2.8.4-lux).
- GitHub wins where it is live: explore-fe-lux v2.8.5-lux, explore-fe-zoo
  v2.8.4-lux, bankd v1.0.18, lux-build's routes.
- The forge's retirement of workloads that run nowhere stands: lux-mainnet
  dex, lux-hb2, lux-market, traffic, wallet-web; the lux-testnet frontends,
  indexer, exchange and gateways; lux-operator. deploy/lux-testnet/luxd.yaml
  stays, since roll_luxd.sh reads it.
- GitHub's deletions stand: lux-finance and lux-financial (static sites
  now), the k8s/ operator manifests, .hanzo/workflows/cicd.yml.
- Paths are /v1/chain/C/rpc where the forge had written /v1/chain/c. All
  four spellings answer; this one is the documented form. The forge's
  /{network}/v1 doc lines are dropped: a network is a host, and the prefix
  404s.

Dry-run against the running objects (server-side, as CD applies), the
merged explorer shows no change where GitHub's showed 152 lines, and no
other live workload moves further from what runs. Every deploy/*/*.yaml
renders with charts/app; price.yaml, which failed on GitHub, now renders.

Claude-Session: https://claude.ai/code/session_01TzirYkGmD88w4GipqivUtV
2026-09-23 20:20:03 -07:00
zeekayandHanzo Dev 425b96f66e the cluster is named, not addressed by a gone account
Every provenance line and manifest still named a DigitalOcean context, and
the ARC values described a pool that died with it. A cluster gets a name
here; the address it answers on belongs to the private record.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 16:15:33 -07:00
zeekayandHanzo Dev 232c6fdce7 Merge remote-tracking branch 'github/main'
github.com/luxfi/universe is canonical from here. git.hanzo.ai/lux/universe is
unreachable, and this merge carries its lineage over. The rule applied, per
area:

Workflows: one set, under .hanzo/workflows; .github/workflows is gone.

LLM.md, README.md, deploy/README.md: the forge's. GitHub's sections were the
ones the forge had already rewritten (the /mainnet/v1/bc path table, the
auto-bump flow), not divergent content. Counts brought to what this tree
holds; LLM.md records the rules below.

deploy/applicationset.yaml: the forge's object (apps.hanzo.ai/v1, destination
name lux-cluster) with repoURL https://github.com/luxfi/universe.

deploy/*.yaml modified on both sides: a three-way merge, not a whole-file pick.
Where both moved the pin, the newer semver wins; at the same semver, the side
that pinned a digest (exchange-api 2.3.34 is sha256:3eae48ac, which the
registry confirms; GitHub's zoo copy carried 007beb83, the pre-repush bytes).
Where both wrote cd.automated, GitHub's false wins: it is the later decision
(909d3bd) and the one about the cluster CD now runs on. true stays only on the
static sites GitHub verified there. The forge's /v1/bc -> /v1/chain rename and
its digests are carried into files whose other hunks came from GitHub
(explorer, exchange-api x3, rpc-tip-gate, lux-market).

lux-bank/lux-financial: GitHub's v1.5.5 is not in the registry (the newest
published tag is v1.5.3), so the pin is v1.5.3 with its digest. A pin never
names an image the registry does not have.

Static sites (lux-audio, lux-cloud/cloud, lux-credit, lux-fund, lux-lps,
lux-network, zoo/zoo-exchange): GitHub's three-object declaration — a
staticFiles Middleware, the route that names it, the endpoint-less Service,
no image — replaces the forge's pod. A union would put an Ingress and a
priority-100 IngressRoute on one host with a pod behind it serving nothing.
The forge's last pins, for the record:
  lux-audio     ghcr.io/luxfi/audio:latest@sha256:48265c37c91f
  lux-cloud     ghcr.io/luxfi/cloud-web:v1.5.34@sha256:54a586fbd4d6
  lux-credit    ghcr.io/lux-apps/credit:36b1c2dffd62
  lux-fund      ghcr.io/lux-apps/fund:20cb7cb988b3 (amd64 only)
  lux-lps       ghcr.io/luxfi/lps:1.0.2
  lux-network   ghcr.io/lux-apps/network:latest@sha256:b52dd80f59d7
  zoo-exchange  ghcr.io/luxfi/exchange:5.149.73@sha256:baefb1903851

Lifted objects (lux-mainnet/{explorer,lux-build,lux-market,rpc-tip-gate}):
the forge's file — the claim, routes, middlewares and rbac it lifted out of
k8s/ — with GitHub's cd.automated: false.

deploy/hanzo/{cloud,commerce-site,iam,lux-bitcoin,lux-coin,lux-finance,
lux-industries,lux-market,lux-safe}.yaml, deploy/lux-ns/lux-exchange.yaml,
deploy/lux-web/lux-network.yaml: deleted, as GitHub did in 2079731. Each Lux
site is declared once, as files, in its own namespace; hanzo's own services
are hanzo/universe's to declare. What the forge had changed in them, so it is
not lost: hanzo/cloud v1.801.476@sha256:0743f907; hanzo/iam IAM_DATABASE_URL
from Secret iam-db; lux-safe ghcr.io/luxfi/safe:v2.2.14; lux-exchange
5.149.83@sha256:7c1bd0e9 with a rateLimit Middleware and the hosts
app.lux.exchange, trade.lux.exchange, exchange.lux.network,
markets.lux.network; lux-web/lux-network at sha 1028f82e.

deploy/zoo-mainnet/: removed. Every Zoo workload is declared in zooai/universe.

Floating tags: every one carries a digest. lux-market and rpc-tip-gate take
the forge's frozen digests back; the rest already had theirs.

k8s/lux-*: the forge lifted k8s duplicates into deploy/ values and deleted
them. luxd-statefulset x3, lux-mainnet/explorer, lux-testnet/{chain-traffic,
exchange-api} stay deleted; what GitHub changed in them (node v1.36.125 pins,
exchange-api 2.3.28, the 50Gi claim, a comment) is behind the values files
(node 1.36.181, exchange-api 2.3.34, the explorer claim). The gateway
configs, luxd-startup ConfigMaps, lux-testnet/explorer and the mainnet
kustomization are the forge's: GitHub's content is a subset of them up to
/v1/bc -> /v1/chain and /v1/health/liveness -> /v1/health/ops/liveness, and
network.yaml, which GitHub's kustomization still lists, no longer exists.

scripts/roll_luxd.sh: the forge's quorum-preserving roll (eviction API, one
pod at a time, digest + version + every-chain bootstrap, devnet -> testnet ->
mainnet) plus GitHub's closing height-and-restart report. The tag is written
in the spelling the values files use (bare 1.36.181) and the digest resolved
for that spelling; a leading v is accepted and stripped. The push remote is
GIT_REMOTE (default origin).

Validated: 123 deploy YAMLs parse; 122 values files render against chart app
0.1.11; no floating tag without a digest; every kustomization that built
before builds now; pin.sh --verify reads 92 pins, 79 agree, 6 are frozen
moving tags whose pointer has since moved (their digests still name real
bytes), 6 are registries a luxfi token cannot read, and lux-financial is the
one it caught.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 14:33:51 -07:00
zeekay 0730def03a Opt every service out of automated sync until its file is true here
Every file that opted in described the DigitalOcean estate, so CD
applying it put a pod in front of static sites the edge already serves
from disk. Automation stays per service; a file re-opts in once what it
declares has been shown to run on this cluster.
2026-09-03 16:22:24 -07:00
hanzo-dev 909d3bd962 Opt every service out of automated sync until its file is true here
Every file that opted in described the DigitalOcean estate, so CD
applying it put a pod in front of static sites the edge already serves
from disk. Automation stays per service; a file re-opts in once what it
declares has been shown to run on this cluster.
2026-09-03 16:22:24 -07:00
zeekayandHanzo Dev c51d417564 Eighteen moving tags now name bytes, and one of them was already lying
latest, main and alpine are pointers. Two nodes pulling the same values file a
week apart run different code, both report the same tag, and there is nothing to
roll back to because the name that was serving means something else now. Eleven
services were on :latest or :main, two on :alpine, and five more on floating
minors (consul 1.17, nats 2.10-alpine, python 3.11-slim and 3.12-alpine).

Each now reads repo:tag@sha256:… — still legible, no longer ambiguous — with
pullPolicy IfNotPresent, because a digest is an identity and re-pulling one asks
a question whose answer cannot have changed.

WHAT THIS FOUND. zoo/exchange-api pinned 2.3.34 to sha256:007beb83, and 2.3.34
resolves to sha256:3eae48ac — the tag was re-pushed after that pin was written.
The other three exchange-api deployments carried 2.3.34 with no digest, so they
would pull 3eae48ac while Zoo ran 007beb83: four deployments, one version name,
two sets of bytes, and every pod reporting the same number. All four now name
3eae48ac, which is what 2.3.34 means today.

lux-explorer/lux-faucet had `repository: ghcr.io/luxfi/faucet:v1.0.1`. A
repository names a path; carrying the version in it means image.tag reads empty
for every check that looks. Split, with the digest confirmed against ghcr as the
one v1.0.1 resolves to.

pin.sh gained --freeze for this, and its registry read stopped guessing at auth.
It assembled each registry's token endpoint from a table shaped like ghcr's,
which called quay.io's three cert-manager images and DO's lux-admin unpullable
while all four were serving. Registries say where their tokens come from, in the
401 they answer with; the challenge is read off the refusal now, and redirects
are followed, so registry.k8s.io's 307 to a regional mirror resolves too.

A tag that YAML reads as a number is written quoted. It was not, and consul's
`tag: '1.17'` came back bare on the first run — harmless there, and `'1.10'`
would have become 1.1 and asked for an image nobody published.

121 pins, 116 verify against their registry. The five that do not are
credentials, not defects: parsdao/explore x3 and DO's registry are not readable
with the token to hand.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 12:45:53 -07:00
zeekayandHanzo Dev d65da4818b Hold twenty-five more services to their files
Second batch, and the same shape the first one proved: every Application here
renders exactly one changed object, its Deployment, so the only thing a first
sync applies is the pod template the chart adds HANZO_VERSION to. Each is
stateless, two or more replicas, RollingUpdate, Healthy, and already labelled
managed-by Helm.

Held back deliberately, though they are otherwise identical: three whose
Ingress also differs and two whose Service does, because those rewrite how
traffic reaches a pod rather than what runs in it, and that is a different
question to answer than a rolling restart. They go in a batch of their own
once each diff is read.

The first batch of five rolled in under two minutes, ten pods replaced, no
restarts and no gap in readiness.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 12:40:03 -07:00
zeekayandHanzo AI 200ff9ea67 Hold twenty-five more services to their files
Second batch, and the same shape the first one proved: every Application here
renders exactly one changed object, its Deployment, so the only thing a first
sync applies is the pod template the chart adds HANZO_VERSION to. Each is
stateless, two or more replicas, RollingUpdate, Healthy, and already labelled
managed-by Helm.

Held back deliberately, though they are otherwise identical: three whose
Ingress also differs and two whose Service does, because those rewrite how
traffic reaches a pod rather than what runs in it, and that is a different
question to answer than a rolling restart. They go in a batch of their own
once each diff is read.

The first batch of five rolled in under two minutes, ten pods replaced, no
restarts and no gap in readiness.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 12:40:03 -07:00
zeekayandHanzo Dev 67df775242 Hold twenty-five more services to their files
Second batch, and the same shape the first one proved: every Application here
renders exactly one changed object, its Deployment, so the only thing a first
sync applies is the pod template the chart adds HANZO_VERSION to. Each is
stateless, two or more replicas, RollingUpdate, Healthy, and already labelled
managed-by Helm.

Held back deliberately, though they are otherwise identical: three whose
Ingress also differs and two whose Service does, because those rewrite how
traffic reaches a pod rather than what runs in it, and that is a different
question to answer than a rolling restart. They go in a batch of their own
once each diff is read.

The first batch of five rolled in under two minutes, ten pods replaced, no
restarts and no gap in readiness.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 19:52:13 -07:00
fdc31d75ac deploy: declare the fleet, one values file per service (#34)
156 services, generated from what is RUNNING on lux-k8s — not from k8s/, whose
manifests were applied by hand over a long period and whose currency is unknown.
Some are ahead of the cluster, some behind, some describe things long deleted.
The running fleet is the only statement of what is true, so it is what was read;
the disagreement between k8s/ and deploy/ is a drift audit waiting to happen
rather than something to paper over.

Each file is values for ONE shared chart, pulled by version from
oci://oci.hanzo.ai/charts/app:0.1.0. Referenced, never vendored — a copy per
repository is how two fleets end up with two definitions of the same thing and
neither one is wrong.

The inventory IS the directory: deploy/<namespace>/<name>.yaml. Adding a service
is adding a file, and there is no second list to keep in step with it.

Verified against live before committing: every rendered object was diffed
against the object actually running, and **BREAKING = 0** — every workload here
can be adopted in place rather than recreated. That was not true an hour ago.
134 of these select on `app:` or `k8s-app:` rather than the chart's own labels,
and spec.selector is immutable, so adopting them was impossible until the chart
learned to state the selector a workload already carries. Each file records its
own; it is the selector only, and the standard label set still lands on metadata.

Not here, on purpose: chain CRs (LuxChain, LuxNetwork, LuxIndexer, LuxGateway,
LuxMPC) are not services and have their own controllers. Secrets are not here
and never will be — the chart cannot carry a secret value at all, only a KMS
path. The placeholder Secret manifests in k8s/ that read CHANGE_ME_VIA_KMS are
the older pattern and want to become KMSSecret resources.

applicationset.yaml is ready but NOT applied: this cluster runs no CD today,
which is why k8s/ drifted in the first place. It deliberately carries no
`automated` block — the chart adds labels to the pod template, a pod template
change is a rollout, and switching sync on would restart all 156 at once.
Services move over one at a time, each gated by hack/diff-live.py.

Co-authored-by: hanzo-dev <[email protected]>
2026-07-28 16:59:28 -07:00
78205412d4 deploy: declare the fleet, one values file per service (#34)
156 services, generated from what is RUNNING on lux-k8s — not from k8s/, whose
manifests were applied by hand over a long period and whose currency is unknown.
Some are ahead of the cluster, some behind, some describe things long deleted.
The running fleet is the only statement of what is true, so it is what was read;
the disagreement between k8s/ and deploy/ is a drift audit waiting to happen
rather than something to paper over.

Each file is values for ONE shared chart, pulled by version from
oci://oci.hanzo.ai/charts/app:0.1.0. Referenced, never vendored — a copy per
repository is how two fleets end up with two definitions of the same thing and
neither one is wrong.

The inventory IS the directory: deploy/<namespace>/<name>.yaml. Adding a service
is adding a file, and there is no second list to keep in step with it.

Verified against live before committing: every rendered object was diffed
against the object actually running, and **BREAKING = 0** — every workload here
can be adopted in place rather than recreated. That was not true an hour ago.
134 of these select on `app:` or `k8s-app:` rather than the chart's own labels,
and spec.selector is immutable, so adopting them was impossible until the chart
learned to state the selector a workload already carries. Each file records its
own; it is the selector only, and the standard label set still lands on metadata.

Not here, on purpose: chain CRs (LuxChain, LuxNetwork, LuxIndexer, LuxGateway,
LuxMPC) are not services and have their own controllers. Secrets are not here
and never will be — the chart cannot carry a secret value at all, only a KMS
path. The placeholder Secret manifests in k8s/ that read CHANGE_ME_VIA_KMS are
the older pattern and want to become KMSSecret resources.

applicationset.yaml is ready but NOT applied: this cluster runs no CD today,
which is why k8s/ drifted in the first place. It deliberately carries no
`automated` block — the chart adds labels to the pod template, a pod template
change is a rollout, and switching sync on would restart all 156 at once.
Services move over one at a time, each gated by hack/diff-live.py.

Co-authored-by: hanzo-dev <[email protected]>
2026-07-28 16:59:28 -07:00