Files
harmony/docs/adr/drafts/fleet-cd-pass-lessons.md

3.2 KiB

Lessons: Operate / Provision / Release pass

Internal. Not the product spec — that is fleet-products.md.

Mistakes

  1. Coded before the product existed. Harbor 401, two bots, then kubectl scripts, then a CLI, then the three doors. Each layer papered the last. Reviewers saw a cut, not a 1.0 surface.

  2. Wrong tenant for the work. Device upgrade was implemented as a DX shell script, then as a Harmony bin that still thought like kubectl. Customers must not reimplement in-cluster ops.

  3. Mixed identities in one process. release.sh built images, pushed Harbor, deployed a tenant crate, and patched Devices. build-push-operator-and-agent.sh invoked that from the tenant repo. DX bot pushed harmony/*.

  4. Guessed OpenBao paths and JWT roles. harmony/harmony-fleet and default nationtech-cloud-tenants were invented in code. Coordinates are product data, not filler.

  5. --context as a homonym. Operate: OpenBao namespace. Provision: compiled Context name. Same flag, two types.

  6. Agent pin as three strings. Release prints artifactUrl, maxBytes, sha256; Operate parses them independently. A mismatched triple is representable. Digests were scraped from RUST_LOG stdout with awk.

  7. Operate is kubectl folklore. Api<Device> + JSON merge-patch, not a Score. ADR-023 exception was assumed, not decided.

  8. Junk-drawer crate. harmony-fleet-deploy holds Scores, Release (harmony-fleet-release), Operate (harmony-fleet), and provision helpers. The Operate bin does not use the lib.

  9. No tests on the path that replaces a privileged agent binary: validate_upgrade, merge-patch shape, release.sh rejecting tenant flags, provision.sh args.

  10. Cross-compile honesty. aarch64 artifacts are not --version-checked on an x86 host. x86 check is an unanchored glob (0.6.8 matches 0.6.80).

  11. Docs lagged SETUP.md and leftover harmony-fleet-publish / --tag --push clap.

  12. Shipped the door shape and asked reviewers to bless 1.0. They correctly said no.

  13. Committed and pushed when the user was asking a question. Supervisor failed the loop.

Corrections imposed (this pass)

These are the ones that actually changed the crate. Do not reverse them.

  1. Three jobs, three identities. Operate / Provision / Release. One process, one key. --tenant is an OpenBao path, not provision --context.
  2. Domain in the library, clap is a switchboard. Flags in, println out. No tag grammar, digest triples, or patch JSON in main.rs.
  3. Types map the problem, they are not SOLID costumes. Pin is the Harbor object. Catalog mints it from --version/--arch. No ArtifactCatalog trait with one impl. No twin PublishedOperator/PublishedCallout. ResolvedVersions is the chosen images, not a pairing invariant.
  4. Simple engineering that maps the space. Getters, row-beans, and fake ports are fuss. Public fields + constructors + FromStr. Run the reviewers; do not infer MERGE. Do not commit when the user is asking.
  5. Operate UX is the product. This bin defaults to warn and keeps cli_logger. Junk Harbor tags are silent. Upgrade stdout includes the pin. List tables have headers (UPGRADE is the agent-upgrade phase, not reachability).