docs(cli): re-spell the cloud observability mirror, keep the sync duty, and name the package that owns the knob list - #17692
Conversation
… list at its owning package `serve.ts`'s observability env-knob block instructed the reader to "keep the two in sync" with `apps/cloud/server/observability.ts` — a path that has not existed in this repo since `apps/cloud` moved to `objectstack-ai/cloud` (`git ls-tree origin/main -- apps/` returns only `apps/docs`). The obligation is live, so it stays: the cloud file still reads all five names as `process.env` lookups (measured on that repository, recorded on #15295), so deleting the clause would have dropped a real duty. Three changes to the block, no code path touched: - the path is re-spelled in this repo's settled house style for a cloud-repo reference, `(`apps/cloud/server/observability.ts`, cloud repo)`, matching `packages/services/service-cluster/src/multi-node-gate-mount.ts:9`; - the duty is narrowed to what its own words say — NAMES, not DEFAULTS. `OS_OBS_SERVICE_NAME` defaults to `objectstack` here and `objectstack-cloud` there deliberately, because two deployments are two services; a future reader "tidying" that into one value would merge both into one telemetry series; - the canonical home for the list is named as `@objectstack/observability`, the package both consumers already import, instead of two consumers pointing at each other — which is the decay mechanism itself, and is still one-sided today (the cloud file carries no reciprocal sentence). Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
The block is emitted into `@objectstack/cli`'s published `dist` by plain `tsc` (no `removeComments`), measured on the rebuilt artifact, so this publishes and `skip-changeset` would be wrong. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 19 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ab3e6616b5b8df6b32cbdcd51119111e05d6511c && git checkout ab3e6616b5b8df6b32cbdcd51119111e05d6511c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6465cc0a7c83ba60503bfd4ddd907d35220e4244 605e43d6ca830598130981c70ea9a85661aa8a50 && git checkout -B drift-repro 6465cc0a7c83ba60503bfd4ddd907d35220e4244 && git merge --no-ff 605e43d6ca830598130981c70ea9a85661aa8a50
node scripts/docs-audit/affected-docs.mjs --json 6465cc0a7c83ba60503bfd4ddd907d35220e4244
|
…ix-entry list The clause read "the cloud file still reads all five of these as `process.env` lookups" directly above a list that carries SIX knobs on `main`: `OS_OTLP_FLUSH_MS` joined this side after triage measured the cloud mirror, so the sentence was true of what was measured and silent about which five it covered. A reader counting the list found six and could not tell whether the sixth was mirrored — a smaller version of the exact ambiguity this card exists to close. Both halves now name the bound instead of a count: every knob listed except `OS_OTLP_FLUSH_MS` is measured, and that one is called unverified rather than mirrored. ⛔ The bound is stated, not closed — `objectstack-ai/cloud` is out of this session's reach, so measuring the sixth there is not on the table and pretending otherwise would be the worse fix. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
…he thread The block's closing pointer named #15295 — the discussion where the split was decided. The cloud-side edit now has its own card, filed with `repo:cloud` and carrying the one-sided-duty reading, the do-not-sync-the-defaults constraint and the `OS_OTLP_FLUSH_MS`-unmeasured bound, so the pointer names it instead: a reader of this block reaches something actionable rather than a thread they have to re-derive the action from. #15295 stays cited one paragraph up, where it is the record of the measurement rather than a work item. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
…s table The block claimed the duty decayed because two comments pointed at each other. There are three carriers, and the third is the one a reader reaches first: `content/docs/deployment/environment-variables.mdx` (`## Observability`) publishes the same list with types and defaults. Measured with controls over `content/docs/`: the `OS_OBS_`/`OS_OTLP_` prefixes return that one page, the `objectstack serve` positive control returns 5 pages so the channel fires, and a fabricated knob returns 0. It matters for the NAMES-only rule specifically: that table's `OS_OBS_SERVICE_NAME` row publishes the framework default with no note that the cloud host uses a different one on purpose — so the page most likely to tempt someone into "unifying" the defaults is the one carrying no warning. The block now says so, and says the page is out of its scope to fix. ⛔ The docs page itself is untouched here: this card is scoped to one comment block, and the caveat rides with the canonical-home decision on #17693 rather than as a rider on this PR. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
The
|
| run | conclusion |
|---|---|
Dogfood Regression Gate (1/3) |
cancelled |
Dogfood Regression Gate (2/3) |
cancelled |
Dogfood Regression Gate (3/3) |
success |
Dogfood Regression Gate (the aggregate) |
failure |
Lint & Repo Gates |
cancelled |
⇒ no test failed. Two shards were killed mid-flight by cancel-in-progress when the next commit was pushed, and the aggregate reported that. Dogfood Verify CLI on the same head concluded success.
⭐ And that is the RULED behaviour, not a defect — checked before writing this
The obvious reading is "the aggregate should exempt cancelled". It was filed once, as #3668, and the wiring has been rewritten since: the gates now count shard attestations instead of reading one aggregate word (#6082), and the maintainer refused (2026-08-07) to whitelist a lifecycle value, because a run whose verdicts the queue is still consuming is not moot and passing it would publish a green over zero executed tests. The opposite direction was measured and filed as #16157 — a single cancelled shard making a required check green over untested packages. ⇒ fail-closed on cancelled is the safe direction and it is ruled; ⛔ no card filed, and ⛔ this must not be "fixed".
The current head
16cccf75 — 30 check runs, zero non-green after a latest-per-name collapse, 12 still running including all three dogfood shards, freshly started. That is the head this PR is judged on. ⛔ Still a draft, ⛔ not enqueued.
PM dispatch seat · domain:cli · session session_01TSf4DV7ziu4V5j73e46b7c
Generated by Claude Code
Review round 1 — three edits, all inside the same comment block; new head
|
| reading | |
|---|---|
| Full lint union | pnpm eslint . --no-inline-config --format json → exit 0, 6633 files in eslint's own JSON output, 0 errors / 0 warnings; the changed file present in that output by path (packages/cli/src/commands/serve.ts, 0/0); 0 files under content/docs/ in the diff |
| Derived gate roster | re-derived after git fetch origin main — identical roster, 2 paths, 57 families; 57 derived / 57 run / 0 NOT-MEASURED / 0 UNRUN, reconciled through --ran in the command :: exit N form so the zero is derived from the codes |
| Exit tally | 57 × exit 0, each captured before any pipe. No family answered 3 this round — the dist-reading ones were given their prerequisite build first |
| Typecheck | pnpm --filter @objectstack/cli typecheck → exit 0 (tsc --noEmit plus check:test-typecheck OK) |
| Unit tier | pnpm --filter @objectstack/cli exec vitest run --project unit → exit 0, 196 files / 2813 tests passed. Re-run rather than carried over, though no test or gate pins this comment's text (measured: 0 hits for the block's phrases across the package's tests and scripts/) |
| Published bytes | rebuilt and re-measured: each of the three new clauses present in dist/commands/serve.js (1 occurrence each), the old all five of these claim absent from all of dist, dist/commands/serve.d.ts carries 0 of the block. The patch changeset still states exactly what moves |
Still draft on purpose: this seat does not flip it ready, does not enqueue and does not arm auto-merge.
Generated by Claude Code
Fixes #15295
The observability env-knob block in
packages/cli/src/commands/serve.tsinstructed the reader to "keep the two in sync" withapps/cloud/server/observability.ts— a path that has not existed in this repository sinceapps/cloudmoved toobjectstack-ai/cloud. One comment block changes, plus a changeset. No code path is touched and no behaviour moves.Premise check, before the first edit
origin/main(base49cd7154)Env knobs (also documented in apps/cloud/server/observability.ts — keep— at:149, not the card's:133, so the card's line number had already driftedgit grep -c "apps/cloud/server/observability"= 1 file, 1 lineapps/cloudreally is gone from this repogit ls-tree origin/main --name-only -- apps/=apps/docs, and nothing else — the positive control that makes this a reading rather than a broken queryThe card's question was already answered by triage (comment
5578532678, 2026-09-08, outcome 1: the mirror exists and all five names are liveprocess.envreads, with 7process.envhits in that file as the firing control). This PR does not re-ask it and reads no other repository.The edit, against the acceptance shape
(`apps/cloud/server/observability.ts`, cloud repo), matchingpackages/services/service-cluster/src/multi-node-gate-mount.ts:9((`apps/objectos-ee/objectstack.config.ts`, cloud repo)). Noapps/clouddirectory is created here;apps/is still exactlyapps/docs.@objectstack/observability— the package both consumers already import (statically atserve.ts:140here; the cloud file imports it too) — instead of two consumers pointing at each other. The comment is explicit that the list does not live there yet, so it advertises an intention, not a capability:git grep -nE "OS_OBS_|OS_OTLP_" -- packages/observabilityreturns 2 incidental prose hits and no list, and that package reads no env var at all (0 files underpackages/observability/srccontainprocess.env). The two halves that would finish the move are out of this PR's reach and are reported below.OS_OBS_SERVICE_NAMEdefaults toobjectstackhere andobjectstack-cloudin the mirror, on purpose — two deployments are two services. The obligation's own words are "keep the two in sync if you tweak names": it governs variable names, not defaults, and unifying them would merge two deployments into one telemetry series.Acceptance notes
serve.ts:133still orders "keep the two in sync" withapps/cloud/server/observability.ts— does that mirror still exist inobjectstack-ai/cloud? #15295 (out_of_scope_findings) so a PM can file it in the consuming repo, which this seat cannot reach.@objectstack/observability's own documented surface is the framework half of the same follow-up. Carrier: whoever picks up the cloud-side card above — one decision covers both halves, and the comment's wording ("until the list lives in that package, this block is it") stays true either way. Filed nowhere by this seat: it is a documentation-location decision, not a defect, a contract violation or an authoring trap.maincarries six (OS_OTLP_FLUSH_MSjoined since). Nothing is wrong — the card's quote was simply older than the file. Carrier: none; the block is now self-describing and no gate reads that count.Verification
Derived gate roster —
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(derivation printedobjectstack-ai/objectstackat3c296b8d, change set 2 paths vs merge base49cd71548), re-derived after the changeset existed, which added 7 families:--ranin thecommand :: exit Nform so the zero is derived from the codes, not claimed: "✓ dispatch-gates --ran: 57 derived famil(ies) accounted for — 57 run, 0 NOT-MEASURED (a DERIVED zero — all 57 recorded an exit code and none of them is 3)."cmd > log 2>&1; EXIT=$?).check:i18n,check:i18n-coverage,check:i18n-walk-parity(all three refuse withoutpackages/cli/dist) andcheck:dual-build-cjs-loads(12 packages withoutdist). Each was re-run after the build it named and then measured:check:i18n-coverage→ "OK (13 config(s), 621 baselined untranslated string(s), none new)",check:dual-build-cjs-loads→ provenance104/67/620/1against floors90/58/520/1.Full lint union (this lane's known blind spot —
dispatch-gatesdoes not name it):pnpm eslint . --no-inline-config --format json→ exit 0, 6633 files in eslint's own JSON output, 0 errors / 0 warnings, and the changed file is in that output by its own path (packages/cli/src/commands/serve.ts, 0/0). Not a narrowed run: the whole union was linted.Package-scoped:
pnpm --filter @objectstack/cli typecheck→ exit 0 (tsc --noEmitpluscheck:test-typecheck: "OK — @objectstack/cli's test layer compiles under packages/cli/tsconfig.test.json").pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2→ exit 0, 196 test files / 2813 tests passed.packages/cli's integration tier is declared to CI: this diff touches no integration-tier file and no spawn entry (bin/,test/helpers/serve-process.ts), so the local debt is the unit tier.pnpm --filter '@objectstack/cli...' build(59 tasks) plus@objectstack/cliitself, plus the packages the i18n and dual-build gates named as prerequisites.Every build and test ran through
scripts/pm/os-verify-lock.shwith a stable slot (issue-15295). One call returned exit 99 / queue-timeout — NOT MEASURED (300s budget, holder was another dev's@objectstack/runtimeclosure build) and was resumed on the kept slot rather than re-queued; the lock-free gate sweep ran in that interval. All wall-clock figures under that lock are shared-box seconds.Changeset:
patch, notskip-changeset@objectstack/clipublishes["dist","README.md","CHANGELOG.md"]and builds with plaintsc(noremoveComments), so a source comment reaches the tarball. Measured on the rebuilt artifact:dist/commands/serve.js— 1 occurrence; the knob-list line as control resolves to that one file;distafter the rebuild;dist/commands/serve.d.tsexists and carries 0 of the block — it sits above a non-exported helper, so the declaration surface does not move.Published JS bytes move ⇒ a real
patchchangeset. No ADR-0087 disposition is carried: nothing is declared breaking, andnode scripts/check-adr-0087-registration.mjs --base origin/mainexits 0.Clause-②: no
Judged from the delivered diff, not inherited from the claim: the diff is comment prose plus a changeset. It adds no schema key, no closed-set member, no published export and no registry entry; it moves no accept/reject verdict and re-selects no input class.
git diff --statagainst the base ispackages/cli/src/commands/serve.ts(+18/-2) and one new.changeset/*.md.Draft on purpose: this seat does not flip it ready and does not enqueue — the PM arms landing.
Generated by Claude Code