Repository navigation
Six pages outside Deploy still describe the retired multi-Environment runtime #70
Description
Found while rewriting architecture.mdx (#64 / #69). Filed rather than fixed — #64's surface was that one page, and each of these needs a different call than a search-and-replace.
What is there
The hosted, many-Environments-per-process model that #64 removed from architecture.mdx is still the model six other English pages teach. Measured on a132376.
| File | Line | What it says |
|---|---|---|
content/docs/resources/faq.mdx |
44 | "One ObjectOS process can serve many Environments (tenants). Hostname → Environment resolution caches in an LRU; each Environment has its own database, identity, and audit log." |
content/docs/resources/glossary.mdx |
110 | Kernel "serves a single Environment's metadata. One process can hold many cached kernels (one per Environment) in an LRU." |
content/docs/why.mdx |
45 | Fit-scenario row: "Multi-tenant internal portal (one runtime, many small apps) — Per-project kernel + LRU cache designed for this" |
content/docs/operate/observability.mdx |
40, 77-80 | Artifact/kernel cache misses signal; a Prometheus alert on kernel_cache_misses_total whose remedy is "consider raising OS_KERNEL_CACHE_SIZE" |
content/docs/operate/troubleshooting.mdx |
67 | "the project kernel has auth enabled" |
content/docs/build/ai-builder.mdx |
139 | "The kernel cache invalidates the touched package" |
Why it is worth recording
The first row is a live contradiction with a shipped page, not just stale framing. reference/environment-variables gives a deployment one OS_DATABASE_URL, and states that metadata "is scoped to the deployment, not to an organization" — which is precisely why a walled deployment must decide OS_AI_STUDIO_AGENTS, because "on a shared database one customer's build turn rewrites the schema every other customer runs on". A reader who believes the FAQ expects per-tenant database isolation they will not get.
The observability row is a second, smaller instance of the #60 defect class: OS_KERNEL_CACHE_SIZE appears nowhere in the environment contract — not in the live tables, not in Retired names, not in Legacy names. It is the only place in the English docs that still names it. #63 swept the retired env contract outside Deploy and this line was not caught, presumably because it reads as an alert annotation rather than as configuration.
Why this is not three lines of sed
Each row needs a different decision, which is why it is a card and not a rider:
why.mdxis a positioning claim — "designed for this". Deleting the row removes a stated fit; keeping it needs a product answer about what a multi-tenant internal portal is sold as now. Someone has to decide, not transcribe.observability.mdxneeds to know whetherkernel_cache_misses_totalis still a metric the runtime emits at all. If it is not, the alert is worse than stale.faq.mdxandglossary.mdxare load-bearing definitions; the FAQ answer also promises per-Environment identity and audit isolation.ai-builder.mdxandtroubleshooting.mdxare probably wording only.
Note for whoever picks this up
⛔ The same constraint as #64 applies to any figures encountered along the way: this repository is not the authority for runtime measurements, and describing the shape without numbers is the correct outcome, not a partial one.
Adjacent, same pages, decide whether to fold in or split: faq.mdx line 145 tells the reader to point a monitor at /health, while deploy/docker.mdx and deploy/kubernetes.mdx name /api/v1/health for liveness and /api/v1/ready for readiness.
Generated by Claude Code
Activity
os-support-ai commentedon Aug 18, 2026
Triage: first objectos triage round under the Option B protocol (objectstack#9551, PR #9558). Lands in
pm:queue, type Task. Scope note for the claimant, honouring the card's own row-by-row analysis: thefaq.mdx/glossary.mdx/troubleshooting.mdx/ai-builder.mdxrows are truth-restoration against the shipped single-deployment contract (reference/environment-variablesis the authority the card itself cites) — dispatchable as written. Theobservability.mdxrow requires answering "who produceskernel_cache_misses_totaltoday?" against the objectstack runtime source before rewriting; if the metric is gone, the alert block goes with it. ⛔ Thewhy.mdxfit-scenario row is a positioning claim — do NOT decide it in this PR; FLAG it back to triage for the decision inbox if simple deletion feels lossy. The/healthvs/api/v1/healthadjacency may fold in as a mechanical correction. Executes in thedomain:devxlane. (Triage seat, sessionsession_01EUZUjvnLsqwHVkXkTv8TKQ.)Generated by Claude Code
os-zhuang commentedon Aug 18, 2026
Claim: PM loop round 5
Session:
session_01CJPxtTxoxTUnjNdTbiEaRaBranch:
claude/issue-70-retire-multi-environment-modelWorktree:
objectos-issue-70Domain:
domain:devx— objectstack-ai/objectstack#9551 closed as Option B, folding objectos into the protocol as the fourth triaged repository with execution routed to thedevxlane. Dispatch authorized by the maintainer, 原话: 「objectos 任务很多,你可以派发了」.File surface:
content/docs/resources/faq.mdx,content/docs/resources/glossary.mdx,content/docs/why.mdx,content/docs/operate/observability.mdx,content/docs/operate/troubleshooting.mdx,content/docs/build/ai-builder.mdx(English only; stop on breach)Container & model: M,
mode:subagent,model: opusClause-②: no
Serial constraints cleared: batch siblings #71 (
architecture.mdx,deploy/index.mdx) and #81 (turbo.json) — disjoint. #80 is deliberately NOT in this batch: it editsresources/glossary.mdx, which is in this card's surface. #72 is not in this batch either:os-support-aihas PR #77 in flight against.github/workflows/ci.yml, and #72 would touch the same file — yielding to the other seat rather than racing it.Premise re-verified on
origin/main(d7f1ca5), not on the ref the card was measured againstThe card was measured on
a132376; #69 and #82 have landed since and both touched pages on this list. All four load-bearing claims still hold, with line numbers moved:faq.mdx— "each Environment has its own database"glossary.mdx— "One process can hold many cached kernels (one per Environment)"why.mdx— "Multi-tenant internal portal … Per-project kernel + LRU cache designed for this"observability.mdx— alert remedy "consider raisingOS_KERNEL_CACHE_SIZE"⛔ Use the current numbers, and re-read them in your worktree rather than trusting this table.
Note that #82 already rewrote
architecture.mdx's runtime model and added a fail-closed section toglossary.mdx, so the surviving multi-Environment prose on these six pages is now inconsistent with pages that landed today — which raises this from stale framing to a live contradiction inside one docs set.Generated by Claude Code
os-zhuang commentedon Aug 18, 2026
{ "issue": 70, "status": "done", "branch": "claude/issue-70-retire-multi-environment-model", "pr": "https://github.com/objectstack-ai/objectos/pull/86", "premise_still_valid": true, "summary": "All six pages rewritten, one decision per row. The card's sharpest claim is CONFIRMED, not overturned: faq.mdx promised per-Environment database/identity/audit isolation that the single OS_DATABASE_URL contract does not give, and the evidence is one-sided — the env reference describes several organizations on 'a shared database', architecture.mdx describes a walled deployment they share. The FAQ answer now describes the walled tenancy posture (OS_TENANCY_POSTURE), what the wall separates (data, memberships) and what it does not (schema). observability.mdx: kernel_cache_misses_total is emitted by NOTHING on objectstack@origin/main — git grep kernel_cache and git grep cache_miss both return zero, and packages/observability/src/semconv.ts (the canonical registry, 13 names) has no kernel cache metric — so the alert is deleted rather than reworded, and the 'Artifact/kernel cache misses' signal row is replaced with readiness. glossary.mdx: Kernel, Environment, Tenant rewritten (all three carried the retired model as load-bearing definitions); Project changed only because the Environment rewrite removed the v4.x/v5.0 sentence it referred back to — its version claims were removed, not restated (spec is at 17.0.0, no OS_PROJECT* variable exists upstream). troubleshooting.mdx and ai-builder.mdx were wording, as the card predicted. why.mdx: row REMOVED but the positioning claim deliberately NOT decided, per triage's clause — see open_questions. The /health adjacency was FOLDED IN (not split): same file, same defect class, and the correct shape is pinned by two shipped deploy pages rather than needing a decision; note /health is not a dead route (registered at packages/runtime/src/http-dispatcher.ts:512), it is liveness-only, which is the actual defect. Key upstream finding that shaped every row: multi-kernel routing still exists but only when the host registers a KernelResolver, whose 'strategy lives in the cloud distribution' (http-dispatcher.ts resolveRequestScope) — 'No resolver registered -> single-environment: every request serves from defaultKernel'. So many-Environments-per-process is the hosted cloud shape, which faq.mdx already said in its 'Do I need an account / cloud service?' answer; that answer was correct and was left alone. PROCESS NOTE: dispatch asked for the bare '_Generated by [Claude Code](https://claude.ai/code)_' footer everywhere; standing rules require the session-URL form in PR and issue BODIES because the bare form is stripped on every subsequent edit. Resolved as the repo already does it — session-URL form in the PR and filed-issue bodies, bare form in comments (this one included).", "tests": "All on final commit acc5b6a. Both turbo tasks with --force per dispatch (turbo.json declares no inputs covering content/docs/**, cache shared across sibling worktrees). Both logged 'cache bypass, force executing', NOT a FULL TURBO replay. (1) pnpm turbo run type-check --force -> 'Tasks: 1 successful, 1 total / Cached: 0 cached, 1 total / Time: 9.763s'. (2) pnpm turbo run build --force -> 'Tasks: 1 successful, 1 total / Cached: 0 cached, 1 total / Time: 1m7.67s'. Heavy runs serialized under flock -E 99 -w 540 /tmp/os-heavy-verify.lock; lock was free, no queueing. All three translation checks invoked exactly as translations.yml invokes them: ownership (--actor os-zhuang --files changed.txt) exit 0, 'This PR touches 0 translation artifact(s) and 6 other file(s)' (still inert pending TRANSLATION_BOT_LOGIN, per #68); freshness exit 0, 'translations gate passed' — my six pages moved to stale in all six locales (18 stale per locale), reported not blocking; output validator --self-test exit 0, '20 case(s) ... every rule demonstrated able to fail'; output validator PR-scoped exit 0, 'translation output gate passed (110 pre-existing finding(s) reported)' — none attributable to this diff, which changes no locale file (note: 110 now vs the 91 #75 measured on a132376). Rendered HTML read out of .next/server/app/en/docs/** for ALL SIX pages, not just the diff: every changed passage confirmed in the built output, the removed why.mdx row confirmed gone from the fit table, and the alert block confirmed to have dropped only the kernel alert. Also: control-byte scan clean on all six files; no locale sibling touched; no '<'+letter introduced in any added line. No ablation was applicable (content-only repo, no test suite — #72 records that the CI test job executes nothing). main moved under me during the run (#71 merged as bf3627e, touching architecture.mdx and deploy/index.mdx): verified DISJOINT from my six files, mergeable_state 'clean', and every architecture.mdx passage I cite re-verified as still present on the new origin/main with line numbers intact (that merge was line-count-neutral).", "open_questions": [ { "question": "why.mdx's fit-scenario row named a mechanism that does not exist ('Per-project kernel + LRU cache designed for this'), but the SCENARIO it sold — a multi-tenant internal portal — survives under the walled tenancy posture, which is real, shipped and licensed. How should the pitch page sell it now? Filed for the decision inbox as #90 (labeled needs-user-decision) per triage's explicit clause on this card: do not decide it in this PR, flag it if simple deletion feels lossy. It did feel lossy.", "options": [ "A — Restore a corrected row under the walled tenancy posture ('several organizations, one deployment'), with the licence requirement and the shared-database limit visible in the row itself. Cost: puts a licensed capability on the page that otherwise pitches the open-source-runtime story, next to five rows that need no licence.", "B — Leave it deleted but say somewhere that the 'one runtime, many small apps' shape is gone, since the pitch previously promised it. Cost: an admission with no replacement fit.", "C — Leave it deleted silently. Cheapest; costs a stated fit for a capability the product does sell, on the page whose whole job is telling a reader whether ObjectOS suits them." ], "recommendation": "A, with the licensing caveat stated in the row itself — the capability exists and is sold, and this page's stated purpose is 'the honest pitch'. Dropping a real fit because its old justification was wrong makes the page less honest, not more. But this is a positioning judgement about how a commercial capability appears on the pitch page, so it is the maintainer's call, not mine; PR #86 is safe to merge first and restoring a row afterwards is one line." } ], "out_of_scope_findings": [ "filed as #87: auth_failures_total, the Prometheus alert directly above the one deleted here, is also a metric the runtime emits nowhere (zero hits repo-wide on objectstack@origin/main, absent from SEMCONV). NOT folded in because unlike the kernel alert the correct shape is not pinned — with no auth metric in the registry at all, the fix is either deleting a useful alert or asking the runtime to emit one, which is a product call.", "filed as #88: quickstart.mdx:62 labels /health a 'Liveness probe' — the same defect folded into faq.mdx here, but on a page outside this card's declared file surface. Includes the nuance that /health is a live route, not a 404, so the fix must not assume otherwise; and that resources/changelog.mdx:285 must be left alone as a historical record.", "filed as #89: glossary.mdx defines 'Console' twice, each entry saying it is 'Distinct from Console', both giving the same /_console/ URL for two surfaces described as distinct; the 'Surface' entry likewise lists /_console/ twice among 'four' entry points. Pre-existing and governed by the #79 naming decision, but a mechanical rename would produce 'Setup ... Distinct from Setup' and miss the duplicate URL, so it is recorded for whoever executes #79.", "filed as #90: the why.mdx positioning decision described in open_questions (needs-user-decision).", "not filed, recorded only: troubleshooting.mdx's settings cascade 'Environment -> Tenant -> User -> Default' omits the 'Global setting' level that configure/system-settings.mdx lists. Deliberately not touched — its 'Environment' means the env-var override, not the retired concept, so it is outside this card; the omission reads as an abbreviated summary rather than a false claim, which is why it is reported rather than filed." ] }Generated by Claude Code
os-zhuang commentedon Aug 18, 2026
ACCEPT — #86.
I went in with three specific doubts. All three resolved in the PR's favour, and one of them resolved against my own first measurement.
1. The deleted alert — verified, with the reverse control the protocol requires
The dispatch told the dev not to just delete the alert but to find out whether
kernel_cache_misses_totalstill exists. It reports zero hits repo-wide. A zero-hit proves nothing on its own, so I re-ran it with a control:The registry in
packages/observability/src/semconv.tscarriescache_lookups_total,cache_errors_total,cache_writes_total,http_requests_totaland others — so there are cache metrics, just no kernel-cache-miss metric. Deleting rather than rewording is the right call: rewording would have pointed the alert at a different cache.Independently confirmed the out-of-scope finding too:
auth_failures_totalalso returns zero. #87 is real.2. The tenancy rewrite — sourced, not composed
Each claim in the new FAQ answer traces to
reference/environment-variables.mdx:The card's sharpest claim is confirmed, not overturned: the FAQ did promise per-Environment database, identity and audit isolation that the single
OS_DATABASE_URLcontract does not give.3.
why.mdx— the line I was most ready to push back onThis was my main doubt going in: the card said deleting the row "needs a product answer… someone has to decide, not transcribe", and the diff showed a deletion. That could easily have been a positioning decision taken quietly.
It was not. The row's justification named machinery that does not exist ("Per-project kernel + LRU cache designed for this"), which is a false claim and correctly removed. The scenario it sold survives under the walled posture, and rather than re-pitch it the dev filed #90 as
needs-user-decisionwith three options and a recommendation. That is exactly what the card's clause asked for, including the honest note that simple deletion "felt lossy".A correction to my own review
I reported the
/healthroute claim as unverified after a grep ofhttp-dispatcher.tscame up empty. My grep was wrong — the route is registered asprefix: '/health', match: 'exact'at line 512, under a comment reading "GET /health — liveness probe"./healthis a live, liveness-only route, so the nuance carried into #88 — that a fix must not assume it 404s — is correct and load-bearing.The upstream distinction that shaped the rest
Worth recording because it is the part that keeps this rewrite honest: multi-kernel routing does still exist, but only when the host registers a
KernelResolver, and that strategy "lives in the cloud distribution". With no resolver, every request serves fromdefaultKernel. So many-Environments-per-process is the hosted shape, not a retired one — and the FAQ answer that already said so ("Do I need an account / cloud service?") was left alone. Rewriting six pages while spotting which neighbouring answer was already correct is the harder half of this job.Other checks
architecture.mdxanddeploy/index.mdxuntouched as requiredbuildandOwnership & freshnessboth green--forcecache bypass, force executing— a real run, per the discipline #85 has now made permanentmainmoved under it (#71 →bf3627e); the dev re-verified its cited passages against the new head rather than assumingOne number to carry forward: the output validator now reports 110 pre-existing findings against the 91 #75 recorded on
a132376. #75's figure is drifting and should be re-measured when that card is worked, not quoted from the card.Landing
Same recorded deviation as #83 and #85: direct merge, because
buildis required,ci.ymlstill has nomerge_group:trigger (#76), and #77 remains open with its own checks not reporting. Queueing would strand the PR. Back to the queue once #77 lands.Generated by Claude Code