From 7950b0342e907e6aa208069d6fc6a809cb6b3762 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 12:38:23 +0000 Subject: [PATCH] chore(release): cut 0.6.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything under Unreleased since 0.5.0 (2026-10-01) moves under a `## 0.6.0 — 2026-10-15` heading with a one-paragraph summary; Unreleased stays as an empty section for what comes next. The version moves with it: package.json and the lockfile, the footer's fallback label, and the image tag in the Dockerfile, the README and the k8s manifests and their docs. References to the pre-store release stay `v0.4.0` (the CI job and the rollback notes build that tag on purpose), and the ones that name 0.5.0 as a build to roll back to, or as the build a fixture or a copied rule comes from, stay 0.5.0; the rollback notes now say the store build is 0.6.0 and that 0.5.0 was the first store release. Two guards that did not exist at 0.5.0 move with the cut. VENDOR-MANIFEST.json carries the package version, so it is regenerated: version 0.6.0, and 0.6.0 is the new baseline (every module's changedSinceRelease false, no releasedExports, removedSinceRelease empty); no module's bytes or exports change. tools/test-doc-test-totals.mjs read the totals the Unreleased entries quote and required at least one; right after a cut Unreleased is empty and those entries are the release section under it, so the guard reads that section until the next entry lands, with the same rules. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UhPGnqVJ24goSVtbKpdkLJ --- Dockerfile | 8 +- README.md | 4 +- VENDOR-MANIFEST.json | 125 +++--------------- deploy/k8s-journeys/kustomization.yaml | 2 +- deploy/k8s/README.md | 19 +-- .../components/journeys/cronjob-journeys.yaml | 2 +- deploy/k8s/deployment-studio.yaml | 2 +- deploy/k8s/kustomization.yaml | 8 +- docs/CHANGELOG.md | 4 + package-lock.json | 4 +- package.json | 2 +- studio/index.html | 2 +- tools/test-doc-test-totals.mjs | 17 ++- 13 files changed, 63 insertions(+), 136 deletions(-) diff --git a/Dockerfile b/Dockerfile index c29b2bd1..c4002ec2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # Observogram — studio + API in one Express server (server/index.mjs). # -# Build: npm run build:stamp && docker build -t observogram:0.5.0 . -# Run: docker run --rm -p 8000:8000 -e OBSERVOGRAM_ADMIN_PASSWORD= observogram:0.5.0 +# Build: npm run build:stamp && docker build -t observogram:0.6.0 . +# Run: docker run --rm -p 8000:8000 -e OBSERVOGRAM_ADMIN_PASSWORD= observogram:0.6.0 # (the image binds 0.0.0.0, and the server refuses to start off # loopback without a seeded sign-in or OBSERVOGRAM_API_TOKEN; the # workspace lives at /app/.observogram — mount a volume there or @@ -18,10 +18,10 @@ FROM node:22-alpine # package.json. server/build-info.mjs then answers the studio footer, # GET /api/version and /healthz from that file (source 'file'); without it # they say "build unknown" — never a guess. -# npm run build:stamp && docker build -t observogram:0.5.0 . +# npm run build:stamp && docker build -t observogram:0.6.0 . # OBSERVOGRAM_BUILD, when given, overrides the composite build string on # /healthz only (a CI run number or tag); /api/version stays the stamp. -# docker build --build-arg OBSERVOGRAM_BUILD=ci-412 -t observogram:0.5.0 . +# docker build --build-arg OBSERVOGRAM_BUILD=ci-412 -t observogram:0.6.0 . ARG OBSERVOGRAM_BUILD= ENV OBSERVOGRAM_BUILD=$OBSERVOGRAM_BUILD diff --git a/README.md b/README.md index d4cff73b..9d8293a9 100644 --- a/README.md +++ b/README.md @@ -1219,8 +1219,8 @@ The whole app is one Express process, so the container story is one image: ```bash npm run build:stamp # build.json: the commit the image is built from (the image has no .git) -docker build -t observogram:0.5.0 . -docker run --rm -p 8000:8000 -e OBSERVOGRAM_ADMIN_PASSWORD= observogram:0.5.0 +docker build -t observogram:0.6.0 . +docker run --rm -p 8000:8000 -e OBSERVOGRAM_ADMIN_PASSWORD= observogram:0.6.0 ``` The image binds `0.0.0.0`, so it needs a seeded sign-in (or diff --git a/VENDOR-MANIFEST.json b/VENDOR-MANIFEST.json index 3c79a394..8e34a15c 100644 --- a/VENDOR-MANIFEST.json +++ b/VENDOR-MANIFEST.json @@ -2,7 +2,7 @@ "$comment": "Generated by tools/gen-vendor-manifest.mjs. Do not edit: run `npm run vendor-manifest`. docs/DOWNSTREAM.md explains the fields.", "manifestVersion": 1, "package": "observogram", - "version": "0.5.0", + "version": "0.6.0", "root": "tools/lib", "modules": { "tools/lib/adapter.mjs": { @@ -21,12 +21,7 @@ "tools/lib/validator.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "adapt", - "applyEnvironmentOverlay", - "listEnvironments" - ] + "changedSinceRelease": false }, "tools/lib/alert-routes.mjs": { "sha256": "ab5be6d93f293c69a0896f4805e0dd4fd0836654b52a5afae9b859e881a0c1ef", @@ -75,8 +70,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/artefact-model.mjs": { "sha256": "28f9f2669390b02432f3a85343f336b2c4afd995c05d581d1aee0c66b146a8b6", @@ -158,8 +152,7 @@ "tools/lib/remediation-flow.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/backend-products.mjs": { "sha256": "f63099877b804e06c90520df63afce5e6ca72ee938b6fdda9da2f1ae7631783e", @@ -209,8 +202,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/burn-rules.mjs": { "sha256": "4ae27bf6b1805fea24fb1cee2b71a00e02da6fbcb54417677b79a88c4021664b", @@ -332,12 +324,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "RUBRIC", - "TIER_RANK", - "evaluateConformance" - ] + "changedSinceRelease": false }, "tools/lib/contracts/mcp-capabilities.mjs": { "sha256": "f1d3065a32fb237b6a6602cebc0bd8c7e22c60a5921b24899e55c225e9890e4e", @@ -356,18 +343,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "BUILD_INFO_PROBES", - "CAPABILITIES", - "allKnownToolNames", - "candidateTool", - "capability", - "capabilityTool", - "deprecatedAliases", - "probeCandidates", - "productAttestedByTool" - ] + "changedSinceRelease": false }, "tools/lib/contracts/response-shapes.mjs": { "sha256": "ca83c7f917b48825355222fbfae82ac28a2c5fca7a064dd5b5834e6bae967a1c", @@ -426,18 +402,7 @@ "tools/lib/slug.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "SCAN_EXT", - "SCAN_IGNORE_DIRS", - "SCAN_MAX_FILE_BYTES", - "crawlFiles", - "crawlToYaml", - "detectArtefactKind", - "scanReadsPath", - "scanSkipsName", - "walkScanFolder" - ] + "changedSinceRelease": false }, "tools/lib/dashboards/generic.mjs": { "sha256": "f02f24c9f0d967afa4a0f9dfd0846cceb960b065c772f78eaf21c0cbf151a959", @@ -581,8 +546,7 @@ "tools/lib/artefact-model.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/inventory-coverage.mjs": { "sha256": "075cf2a9c79e98432a043c94596179c52882926ebbf828a5ffb584d07054f476", @@ -657,11 +621,7 @@ "tools/lib/pack-conformance.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "isLegacyLayeredPack", - "upconvertLegacyPack" - ] + "changedSinceRelease": false }, "tools/lib/library.mjs": { "sha256": "90ed9b24bdaba4f8d2174ebabcc07a944b69e6c1ea6b785d27fd279a90139c03", @@ -731,8 +691,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/mcp-client.mjs": { "sha256": "4d3b8c6a2004ea32fb0b8d80102d705641be5db89e844f496de797c57df57c61", @@ -750,8 +709,7 @@ "tools/lib/mcp-url-safety.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/mcp-server-settings.mjs": { "sha256": "02b49b86fdb2baad64d346c298d5bc86f2cc1f03d748537f3c7c0ec54cbe8d27", @@ -779,8 +737,7 @@ "tools/lib/mcp-url-safety.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/mcp-url-safety.mjs": { "sha256": "0869a761a7856f7c851205f127b53c37874cc17741e36b0649bfd9cac7ff0d69", @@ -800,14 +757,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "credentialParamName", - "droppedNote", - "mcpUrlOrigin", - "safeMcpUrl", - "stripMcpUrl" - ] + "changedSinceRelease": false }, "tools/lib/mini-yaml.mjs": { "sha256": "c4a903325dd1119f859fbeac1fa3e17b4104ebc2af08f721387dc7a6be7862fd", @@ -878,8 +828,7 @@ "tools/lib/waivers.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/profiles.mjs": { "sha256": "027f2d9004a0858641baab79192a2a4019f58e608fb7c08380ddbace4de3141f", @@ -978,8 +927,7 @@ "tools/lib/artefact-model.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/schedule-snippets.mjs": { "sha256": "a7eac2632b83b511100d37b1c80801ff9cc68880a0458c212e2e54ed1dc6e4ce", @@ -1036,17 +984,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "catalogEntryOf", - "isLiveAggregatePack", - "normalizeServiceKey", - "primaryServiceName", - "serviceKeyForPack", - "serviceMetadata", - "serviceNamesForPack", - "servicesForPack" - ] + "changedSinceRelease": false }, "tools/lib/site/derive.mjs": { "sha256": "afc9f35d08440637eca96c26ef21ed943e659c1daa3a0e0b4ef40f4b96cf4ab6", @@ -1170,23 +1108,7 @@ "tools/lib/slug.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "alertRuleExpr", - "alertRuleWindows", - "burnAlertsFromAlertRules", - "burnCandidateFromAlertRule", - "canonicalRuleDuration", - "defaultBurnWindows", - "inferSlisFromRecordingRules", - "isGrafanaManagedRule", - "mergeBurnAlertsBySlo", - "operationalAlertRule", - "operationalAlertRules", - "recordedSloForExpr", - "ruleNameToSliId", - "ruleNameToSloId" - ] + "changedSinceRelease": false }, "tools/lib/slug.mjs": { "sha256": "bf9f4c4816363d65c66203e4f7fdbc061b9a144f909545278b7192b4ec903c51", @@ -1200,13 +1122,7 @@ ], "imports": [], "npm": [], - "changedSinceRelease": true, - "releasedExports": [ - "fileSlug", - "metricPrefix", - "serviceSlug", - "symbolSlug" - ] + "changedSinceRelease": false }, "tools/lib/stack-evidence.mjs": { "sha256": "c49cf35064c8e3cefc72ce19ce4a667deb126294d543adc8e8d8978acf0e048a", @@ -1326,8 +1242,7 @@ "tools/lib/conformance.mjs" ], "npm": [], - "changedSinceRelease": true, - "releasedExports": null + "changedSinceRelease": false }, "tools/lib/zip.mjs": { "sha256": "c5277647671a51503d112ea6203e5e0691d1aed55853ce2ed19322f891bb4d5b", diff --git a/deploy/k8s-journeys/kustomization.yaml b/deploy/k8s-journeys/kustomization.yaml index 55217afe..297881cf 100644 --- a/deploy/k8s-journeys/kustomization.yaml +++ b/deploy/k8s-journeys/kustomization.yaml @@ -30,7 +30,7 @@ components: images: - name: observogram - newTag: 0.5.0 + newTag: 0.6.0 labels: - pairs: diff --git a/deploy/k8s/README.md b/deploy/k8s/README.md index d0b67a1f..9b09ef15 100644 --- a/deploy/k8s/README.md +++ b/deploy/k8s/README.md @@ -7,14 +7,14 @@ and one PersistentVolumeClaim that holds the studio's state. ```bash # 1. Stamp the checkout (build.json says which commit the image is), then build it from the repo root. -npm run build:stamp && docker build -t observogram:0.5.0 . +npm run build:stamp && docker build -t observogram:0.6.0 . # 2. Make it visible to your cluster. # docker-desktop: nothing to do. -# kind: kind load docker-image observogram:0.5.0 -# remote: docker tag observogram:0.5.0 /observogram:0.5.0 -# docker push /observogram:0.5.0 -# cd deploy/k8s && kustomize edit set image observogram=/observogram:0.5.0 +# kind: kind load docker-image observogram:0.6.0 +# remote: docker tag observogram:0.6.0 /observogram:0.6.0 +# docker push /observogram:0.6.0 +# cd deploy/k8s && kustomize edit set image observogram=/observogram:0.6.0 # 3. Check that the cluster can provision the store volume (see "Storage class" below). kubectl get storageclass # one line should say (default) @@ -111,7 +111,7 @@ spec: fsGroupChangePolicy: OnRootMismatch containers: - name: restore - image: observogram:0.5.0 # the studio's image and tag + image: observogram:0.6.0 # the studio's image and tag workingDir: /app command: ["node", "tools/cli.mjs", "store", "restore", "/data/db/$BACKUP"] env: @@ -154,8 +154,9 @@ the studio at 0, from a one-off pod of the **store** image (the old one has no `store export`) that mounts both subPaths of the `store` claim at the studio's two paths: -The pre-store release is the git tag `v0.4.0`. The store build is `0.5.0`, -but builds of `develop` between the two also said `0.4.0` in `package.json` +The pre-store release is the git tag `v0.4.0`. The store build is `0.6.0` +(`0.5.0` was the first store release), but builds of `develop` between +`v0.4.0` and `0.5.0` also said `0.4.0` in `package.json` and `kustomization.yaml`, so an image called `observogram:0.4.0` may be either: one built from a pre-0.5.0 checkout is a store build and replaced any older image of that name. Build the old one under a tag of its own @@ -499,7 +500,7 @@ spec: fsGroupChangePolicy: OnRootMismatch containers: - name: copy - image: observogram:0.5.0 # the studio's image and tag + image: observogram:0.6.0 # the studio's image and tag command: ["sh", "-c", "cp -a /data/workspace/. /workspace/ && ls -la /workspace"] volumeMounts: - { name: store, mountPath: /data/workspace, subPath: workspace } diff --git a/deploy/k8s/components/journeys/cronjob-journeys.yaml b/deploy/k8s/components/journeys/cronjob-journeys.yaml index b1c0f77c..b558f309 100644 --- a/deploy/k8s/components/journeys/cronjob-journeys.yaml +++ b/deploy/k8s/components/journeys/cronjob-journeys.yaml @@ -71,7 +71,7 @@ spec: # applies to the kustomization that declares it), so # deploy/k8s-journeys/kustomization.yaml repeats the `images:` # entry; tools/test-deploy-manifests.mjs pins it to the base's. - image: observogram:0.5.0 + image: observogram:0.6.0 imagePullPolicy: IfNotPresent workingDir: /app command: ["node", "tools/cli.mjs", "journey", "run", "--all"] diff --git a/deploy/k8s/deployment-studio.yaml b/deploy/k8s/deployment-studio.yaml index 201e2ab6..ec97f97a 100644 --- a/deploy/k8s/deployment-studio.yaml +++ b/deploy/k8s/deployment-studio.yaml @@ -59,7 +59,7 @@ spec: fsGroupChangePolicy: OnRootMismatch containers: - name: studio - image: observogram:0.5.0 + image: observogram:0.6.0 imagePullPolicy: IfNotPresent ports: - name: http diff --git a/deploy/k8s/kustomization.yaml b/deploy/k8s/kustomization.yaml index b99afd4e..e4d1443c 100644 --- a/deploy/k8s/kustomization.yaml +++ b/deploy/k8s/kustomization.yaml @@ -7,10 +7,10 @@ # assets all ship inside the image. # # Build + make the image visible to the cluster, then apply: -# npm run build:stamp && docker build -t observogram:0.5.0 . -# # docker-desktop: nothing more to do. kind: `kind load docker-image observogram:0.5.0` +# npm run build:stamp && docker build -t observogram:0.6.0 . +# # docker-desktop: nothing more to do. kind: `kind load docker-image observogram:0.6.0` # # remote cluster: push to a registry and override below, e.g. -# # kustomize edit set image observogram=ghcr.io/moebiusx/observogram:0.5.0 +# # kustomize edit set image observogram=ghcr.io/moebiusx/observogram:0.6.0 # kubectl apply -k deploy/k8s # # Needs a default StorageClass, or a storageClassName in pvc-store.yaml: the @@ -33,7 +33,7 @@ resources: images: - name: observogram - newTag: 0.5.0 + newTag: 0.6.0 labels: - pairs: diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d525a124..b1508c5d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 0.6.0 — 2026-10-15 + +**The store-and-seams release.** The store now holds the studio's state, not only its identities: the pack registry moved into the database; services, their environments and an org's MCP endpoints are records managed over HTTP; every change a principal makes through the server is an audit row that can be read; the home is the org's services table with a page per service; and Settings is the org's administration as a studio mode (STORE_PLAN slices 4 to 6). A downstream can vendor and rebadge Observogram without forking it: a manifest of the vendorable modules, the MCP transport hook, the artefact taxonomy classifier, reverse-proxy identity passthrough, one brand config and an embeddable static bundle, which now runs Compare and loads no font over the network. The rebadge batches built on those seams: a reviewer's verdicts, waivers and an exportable service audit report; canonical pack production, where a fresh crawl is a valid pack; a true-snapshot live pack behind a connection test; comparison identity modes; the MCP server's settings in the page. Spec 1.4 keeps a repository's operational alert rules and pairs them with the live ones. Windows has a CI leg, and a path there is compared by what it names, not by how it is spelled: a journey's org scope holds, and `packc store purge-org` decides the users file by what deleting the org's root takes. Also: a malformed JSON body is answered as JSON on every route, a server-run journey's notification reads only its org's hooks, the settings-policy deadline is per rule, and the id clocks time the pattern, not the machine. + ### Follow-up `paths-volume-through-handle`: on Windows the store's path comparison reads a path's volume through a handle - **On Node 22.16.x the store's offline checks place a path through a share again** (a fix; `server/store/paths.mjs`; Linux and macOS compare exactly as before). `comparedPath` placed a path reached through a share by a file id it shares with a directory of the path it is checked against, and judged one nothing places by its volume (the serial's low 32 bits), both read with `statSync`. libuv answers a stat by the path's name (`GetFileInformationByName`, Windows 11 24H2 and Server 2025) unless the path is reached through a share or its last name is a reparse point, which it opens and reads the volume's serial from (`FILE_FS_VOLUME_INFORMATION`); libuv 1.49.0 to 1.50.x (Node 22.16.x ships 1.49.2) declared `FILE_STAT_BASIC_INFORMATION` with `FileId128` before `VolumeSerialNumber`, swapped against Windows' layout (fixed in 1.51.0), so a stat by name reported the upper half of the file's 128-bit id as the device, 0 on NTFS. There a local path and a share of it had no file id in common, and a local volume never matched a share's: with the workspace at `C:\ws`, a directory export to `\\myhost\ws\exports\new` (which is `C:\ws\exports\new`), or to `C:\ws\exports\new` with the workspace named `\\myhost\ws`, compared as outside the workspace and was written into it, and so was one through a share of a directory under it (`\\myhost\exports`, which no file id places and which was refused as lying on the workspace's volume); the in-place detection and backup's own-file check missed the workspace and the database's `-wal` through a share alike, and purge-org refused a users file a share placed outside the root (a false refusal). On Windows a file id and a volume are now read through a handle opened on the path (`openSync`, `fstatSync`, `closeSync`; libuv opens a directory too), which reports the serial on every libuv, every handle closed before the comparison goes on; a path that does not open is passed over as one that did not stat was. `comparedPath` takes `openSync`, `fstatSync` and `closeSync` in place of `statSync`. `server/fixtures/ntfs.mjs` models both libuvs (`fastDev`: the device a stat by name reports — `null`, all 64 bits of the serial as 1.51.0 reads it, or `0n` as 1.49.2 does; a path through a share, or whose last name is a link or another reparse point, is opened, with the serial's low 32 bits) and returns `openSync`, `fstatSync`, `closeSync` and `opened()`; its header no longer says a local stat may report all 64 bits on every libuv. One more test in `server/test-store-paths.mjs` (1519 → 1520 tests): on libuv 1.51.0 and 1.49.2, a directory export through `\\myhost\ws` into `C:\ws`, and one on the drive into the workspace named through it, refused as inside it, the workspace through its share refused as the in-place export, a backup over the database's `-wal` through `\\myhost\dbdir` refused, purge-org refusing a users file placed under the root and purging with one placed beside it, a share nothing places on the workspace's volume refused, one on another volume written, and every handle closed; at the parent commit it fails on 1.49.2 (the export through `\\myhost\ws` was written). Every comparison the suite builds injects the fixture's handles. diff --git a/package-lock.json b/package-lock.json index dff11cdb..420aa9b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "observogram", - "version": "0.5.0", + "version": "0.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "observogram", - "version": "0.5.0", + "version": "0.6.0", "license": "MIT", "dependencies": { "@lezer/highlight": "^1.2.3", diff --git a/package.json b/package.json index 2313d823..200e7db0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "observogram", - "version": "0.5.0", + "version": "0.6.0", "description": "Observogram — the Observability Compiler. Compiles, scans, and scores ObservabilityPack spec v1.4 manifests. Express server + thin client.", "type": "module", "engines": { diff --git a/studio/index.html b/studio/index.html index 7437f2e0..65131b31 100644 --- a/studio/index.html +++ b/studio/index.html @@ -555,7 +555,7 @@

3 · Progress and resu