@klok-integration/cli 0.7.248 → 0.7.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,31 +34,46 @@ domains read should still travel as class B or C (transform at the edge).
34
34
  ends in `supplier_invoice_v1`. Inside the XSD the model keeps its PascalCase form: root element
35
35
  `SupplierInvoice_v1`, root type `SupplierInvoiceV1`.
36
36
 
37
- **Create it with klok.dev's datamodel wizard.** It pushes a new repository from `project-template-datamodel`
38
- with the XSD and its `meta.json`, but it does not render the template's `__KLOK_*__` placeholders yet
39
- (klok/application/frontend-klok-dev#33): check the
40
- new repository and render any that are left, as below, before relying on its pipeline. The agent at
41
- https://agent.klok.dev cannot create datamodel projects yet (klok/application/frontend-klok-dev#42).
37
+ **Create it by hand from the template.** klok.dev edits existing models through a merge request but does not
38
+ create datamodel repositories yet, because it cannot render the template's `__KLOK_*__` placeholders for them
39
+ (klok/application/frontend-klok-dev#33); it points to the way by hand instead. The agent at
40
+ https://agent.klok.dev cannot create datamodel projects either (klok/application/frontend-klok-dev#42).
41
+ `klok datamodel names --class <A|B|C|X> --name <PascalCase> --major <n>` (with `--system` for class X and the
42
+ global `--domain` for class C) prints every derived value: repository, XSD file, root element, root type,
43
+ `targetNamespace` and the documentation project.
42
44
 
43
45
  By hand it is: `git clone` the template, `git remote rename origin template`, `git remote add origin <new
44
46
  repo>`, render every `__KLOK_*__` token listed in `klok-template.json` (including the XSD file name), push
45
47
  `main`. Keep the `template` remote so later template improvements can be pulled in. Never assemble the
46
48
  project by copying files out of a sibling datamodel: the copies go stale and whole files get missed
47
- (`klok-datamodel-project.json`, `klok-template.json`, the agent instruction files, the three page
48
- `klok-docs/datamodel/` layout).
49
+ (`klok-datamodel-project.json`, `klok-template.json`, the agent instruction files, `klok-docs/` with its
50
+ guide `README.md` and the `datamodel/` pages).
49
51
 
50
52
  Vault needs nothing per project: the tenant CI role `<tenant>-ci` accepts every project under the tenant's
51
53
  root group. If `publish_java_projects` fails at `auth/jwt/login`, the tenant itself is not set up; see the
52
54
  `klok-release` skill.
53
55
  2. Write the XSD under `schema-definition-xsd/`: single `xs:` prefix, `targetNamespace` with `xmlns:tns`,
54
56
  `elementFormDefault="qualified"`, one root element `<Name>_vN` that references every complex type. Enumerations
55
- as `xs:enumeration`.
56
- 3. `meta.json` in the flat form with `targetNamespace`, and `klok-docs/` with the purpose, the important fields and
57
- the producers and consumers.
57
+ as `xs:enumeration`. `klok datamodel validate` checks it with the pipeline's rules before you push.
58
+ 3. `klok-datamodel-project.json` at the root is the model's metadata (name, description, class, model type,
59
+ `targetNamespace`, template version), rendered from the template; klok.dev and the documentation payload read
60
+ it. An older repository's `schema-definition-xsd/*.meta.json` is only klok.dev's fallback for a repository
61
+ without it, so keep one of the two, not both. The pipeline takes the artifact and the Java package from the
62
+ repository path and the XSD file name, never from metadata. `klok-docs/datamodel/` holds the three pages of the
63
+ template (`index`, `usage`, `changes`): the purpose, the fields that need explaining, the producers and consumers
64
+ and the history of compatible changes.
58
65
  4. A breaking change is a new major version (`Customer_v2`), which is a new class, a new topic and a new catalog
59
66
  key; a compatible change (optional field) stays in the same version. The old and the new version run in
60
67
  parallel while readers move, at least the class's minimum (table above) and until every known reader
61
- has moved.
68
+ has moved. The pipeline decides which is which: `klok_datamodel_compatibility` compares the Avro schema the
69
+ generated classes register on the broker with every earlier release, both ways, and fails on a numeric or
70
+ boolean element added without `minOccurs="0"`, a removed or renamed field, a changed type, a field made required
71
+ or optional, an added or removed enumeration value and a removed type. Its `breaking:` lines name the field. Make
72
+ the change compatible (add optional fields only; keep a field you no longer need and stop filling it), or create
73
+ `<name>-v<n+1>`. Only when no service runs some earlier releases any more does the owner record that in
74
+ `klok-datamodel-project.json` (`"compatibility": {"since": "<release>", "reason": "<who moved, when>"}`); never
75
+ to get a new break through. The rules are on the *Datamodel compatibility* page of
76
+ `klok docs read klok-framework-klok-gradle-plugin`.
62
77
  5. Work in the task worktree (`klok-worktree` skill), push its `agent/<task-id>` branch, open a merge request;
63
78
  the pipeline validates the XSD and generates the Java project. On `main` it
64
79
  publishes `dev.klok.<tenant>.datamodel:<name>-v<n>:1.0.0-build.<ts>` with its Python and TypeScript packages,
@@ -72,7 +87,8 @@ domains read should still travel as class B or C (transform at the edge).
72
87
  ## Using a model in a project
73
88
 
74
89
  * Run `./gradlew updateKlokLibsToml` in the consumer, commit the refreshed `gradle/klok-libs.versions.toml`, and
75
- reference the alias (`klokLibs.klokOdlV1` or the bundle). Never type a version.
90
+ reference the alias, the project name in camel case (`klokLibs.klokOdlV1` or the bundle for tenant klok's
91
+ models, `tenantLibs.<alias>` for another tenant's). Never type a version.
76
92
  * The generated class is `dev.klok.<tenant>.datamodel.<group>.<name_with_underscores>_v<n>.<Name>Vn` (for
77
93
  `klok-task-event-v1`: `dev.klok.klok.datamodel.common.klok_task_event_v1.KlokTaskStatusEventV1`); the ODL type of an object is the
78
94
  fully qualified class name, so moving a class to another package is a data migration of its ODL index.
@@ -12,7 +12,7 @@ serves it to a browser session and to a GitLab personal access token, which is w
12
12
  ```
13
13
  klok docs list # the projects you may read: doc id, title, description
14
14
  klok docs read <doc-id> # the markdown on stdout, one status line on stderr
15
- klok docs read <doc-id> --json # {docId, url, source, status, etag, fetchedAt, bytes, content}
15
+ klok docs read <doc-id> --json # {docId, requestedDocId, movedTo, url, source, status, etag, fetchedAt, bytes, content}
16
16
  klok docs read <doc-id> --out x.md # to a file
17
17
  klok docs id [tenant/group/.../repo] # the doc id of a repository, this one by default
18
18
  ```
@@ -59,6 +59,7 @@ question is about what a project does.
59
59
  | `klok docs read` says | Meaning | What to do |
60
60
  |---|---|---|
61
61
  | the content, `source: server` or `source: cache` | the page as published, or the cached copy | read it |
62
+ | `klok docs read: <old-id> moved to <new-id>` on stderr, then the content | the project was renamed or moved; the content is the new id's | read it, cite the new id (`docId` of `--json`), and fix the link or note the old id came from |
62
63
  | exit 4, "No or invalid GitLab token" | no `KLOK_GIT_APIKEY` (or `--token`), or the token is not valid | say so and ask for a token with `read_api`; do not guess |
63
64
  | "not a member of the tenant or domain that owns …" (403) | the page exists and your GitLab account may not read it | say so and ask for access; do not guess and do not try another way in |
64
65
  | "… is not published; read the repository's klok-docs/ on main" (404) | the project has no published documentation yet | read the source pages: `git -C <repo> fetch origin && git show origin/main:klok-docs/<page>.md`; `klok-docs/toc-manifest.json` lists them. The generated pages (routes, datamodels, configuration) exist only on the portal |
@@ -75,4 +76,5 @@ question is about what a project does.
75
76
  runbook in `klok-framework-development-guide` when it touches onboarding; read the framework documentation
76
77
  before writing or changing a route.
77
78
  5. Cite the doc id and the `fetchedAt` from `klok docs read <doc-id> --json` in your answer or merge request
78
- description, so reviewers can tell which version of the page you relied on.
79
+ description, so reviewers can tell which version of the page you relied on. After a move, `docId` is the new id;
80
+ cite that one.
@@ -72,6 +72,11 @@ as a red pipeline. Vault CI login is not one of them: it needs nothing per proje
72
72
  keys); the service's own Keycloak client with its broker grants; and every topic `./gradlew klokTopics` lists, in
73
73
  its owning tenant's Pulsar file and applied (requested in klok.dev, or a merge request to
74
74
  `klok/environment/klok-environment-setup`). A topic's `_DLQ` and a `_Request` topic's `_Response` come with it.
75
+ * For a platform service's instance in another tenant (the ODL, tasks, the OpenSearch ingress and egress): the same
76
+ image, deployed from `<tenant>/platform/<name>/<name>-crds.yaml` in the manifests repository, written by hand with
77
+ the service's current image and the tenant's namespace, Vault role, env secret and Keycloak client. Nobody updates
78
+ its image by hand: the service's own `update_manifest` (`klok manifest update`) sets every instance that runs the
79
+ same image repository in the same commit.
75
80
  * Documentation projects need the tenant's docs upload client: Keycloak client `klok-docs-upload-<tenant>` and its
76
81
  id and secret in `secret/<tenant>/common/repo/cicd-environment-variables`.
77
82
 
@@ -17,8 +17,9 @@ motivates.
17
17
  `KlokProcessingRoute<IN, OUT>`; egress to a system: `KlokOfframpRoute<DOM, SYS>`; synchronous request/reply:
18
18
  the `Sync` variants; REST: `KlokRestApi` plus one `KlokRestApiHandlerRoute` per operation; long running work:
19
19
  `KlokAsyncTaskWorkerRoute<REQ, RES>`; anything else: `KlokCustomRoute`.
20
- 2. **Name it.** `<TENANTSHORT><NNN><LEG><seq>_<Description>`, one class per route, the solution number from the
21
- portal registry. Sub routes are `S`, timers `T`.
20
+ 2. **Name it.** `<TENANTSHORT><NNN><LEG><seq>_<Description>`, one class per route. `<TENANTSHORT><NNN>` is the id of
21
+ the solution in `<tenant>/integration-solutions`, allocated there by a merge request (`klok solutions new`).
22
+ Sub routes are `S`, timers `T`.
22
23
  3. **Bind the datamodels** as type parameters; take them from the catalog bundle, never hand written DTOs.
23
24
  4. **Choose the topic purpose** of every topic the route publishes or consumes (*Topic purpose*), and make sure every
24
25
  topic exists (*Topics on the broker*): the broker never creates one.
@@ -74,7 +75,7 @@ the purpose.
74
75
  * **Name** the flow as both sides understand it (`created`, `reminder`, `documentation`): letters, digits, `-` and
75
76
  `.`, never `_`, and no version or environment. Task types are `<domain>.<verb>-<object>`.
76
77
  * **One purpose, no reader.** A topic has at most one purpose. A reader, also one in another tenant, is identified by
77
- its subscription, whose name is its route id (`DEG012E1_...`; `<RouteId>.subscription.name` overrides it), and never
78
+ its subscription, whose name is its route id (`DGR012E1_...`; `<RouteId>.subscription.name` overrides it), and never
78
79
  adds a suffix to the topic. When the content belongs to one reader, the publisher may choose that reader's tenant
79
80
  slug as the purpose (`PersonnelScheduleExportV1_degerfors`); that is the publisher's choice, not something a reader
80
81
  in another tenant needs.
@@ -30,10 +30,14 @@ shared platform service) in `klok/integration-solutions`.
30
30
  issue, never to ignore.
31
31
  3. **Read the design.** The solution document and any design page next to it, then each project's `klok-docs/`
32
32
  (`klok docs read <doc-id>`, `klok docs id <repo path>` gives the id).
33
- 4. **A new solution gets an id and a document before code.** Take the id from the code, not the next free
34
- number: grep the integration repositories, pushed branches included, and run `klok solutions validate`. Write
35
- `README.md`, `solution.meta.json` (`generatedBy: "manual"`) and, when the details do not fit, a design page next
36
- to it, in a worktree of the registry. The sections are listed in the registry README.
33
+ 4. **A new solution gets an id and a document before code.** The merge request that adds the solution's folder to
34
+ the registry is the allocation: `klok solutions new "<name>" --dry-run`, then without `--dry-run`, opens it from a
35
+ worktree of the registry with the next free number (`klok solutions next` says why that one: the registry, its
36
+ history and open merge requests, and the route classes on every branch). Never choose another number, and never
37
+ reuse one, not even a removed solution's. The folder starts `"status": "reserved"`; write `README.md`, the
38
+ describing fields of `solution.meta.json` and, when the details do not fit, a design page next to it, and set the
39
+ status to `active`. The sections are listed in the registry README. `klok solutions validate --base origin/main`
40
+ checks the change against the registry's history and its open merge requests.
37
41
  5. **Reuse before building.** Look for an existing solution or platform capability first: tasks and the task API
38
42
  (KLK002), the ODL, the AI services (KLK003), mail (KLK006), the claim check, datamodels in the catalog. A
39
43
  capability that needs a change to serve the solution is *reused, slight change*, with its own merge request in
@@ -81,6 +85,9 @@ shared platform service) in `klok/integration-solutions`.
81
85
  ## Things that are always wrong
82
86
 
83
87
  * Code for a new solution before its document exists, or a route id whose prefix is not a registered solution.
88
+ * A solution number that is not the next free one (`klok solutions next`), or one used before.
89
+ * Deleting a solution's folder in a merge request: a solution that stops running gets `"status": "retired"`; only a
90
+ platform admin removes one, on `main`, and its number stays spent.
84
91
  * A leg in code that its solution document does not name, or a document that names a leg as built that is not.
85
92
  * Reusing a leg and sequence (`KLK002A11`) for a second route.
86
93
  * Integration logic in a Python or TypeScript client, or in an external engine, without a `[TACTICAL]` entry.
@@ -36,7 +36,9 @@ basename, never put the worktree inside `.claude`, inside the canonical checkout
36
36
  you. Keep the existing project rules; this skill does not replace them.
37
37
  3. **Inspect, do not touch.** `git -C <canonical> status --short`, `git -C <canonical> worktree list --porcelain`
38
38
  and the canonical branch. Never `stash`, `reset`, `clean`, `checkout` or `switch` there; the only update of a
39
- canonical checkout is `klok sync pull`, which fast-forwards it or reports why it cannot. Uncommitted changes in
39
+ canonical checkout is `klok sync pull`, which fast-forwards it or reports why it cannot. When it reports that the
40
+ checkout's GitLab project moved, the move and the `git worktree repair` it lists are the person's: hand them over,
41
+ and base the worktree on the project at its new path. Uncommitted changes in
40
42
  the canonical checkout are not a blocker; the worktree starts from committed history. If the task depends on
41
43
  those changes, say so and ask for a handoff instead of moving them.
42
44
  4. **Choose the base.** Fetch the remote and resolve its default branch from the remote HEAD