Skip to content

[finding] "the runtime image" names two different images across the docs corpus — Deploy means the licensed ObjectOS image, resources/license.mdx means the Apache-2.0 framework image #253

Closed

Description

@os-bill

Found while investigating #251 (which turns on exactly this ambiguity, for one table row). Filing unassigned and separately, because #251's scope is a single row in reference/environment-variables.mdx while this is corpus-wide.

Measured on content/docs/ at origin/main = 8e665c7.

What is wrong

The bare phrase "the runtime image" is used on 11 pages with two incompatible referents, and no page disambiguates it at the point of use.

Referent A — the licensed, commercial ObjectOS image, selected by OS_EE_IMAGE, digest-pinned, distributed from a private registry:

  • deploy/index.mdx:3,6 — "ObjectOS Self-Managed is delivered as a licensed, pre-built runtime image."
  • deploy/docker.mdx:3 — "Run the licensed ObjectOS runtime image with Docker"
  • deploy/air-gapped.mdx:84 — "The runtime image lives in a private registry"

Referent B — the Apache-2.0 ObjectStack framework image:

  • resources/license.mdx:104 — "What's Apache-2.0 (in the framework repository): the runtime image, all @objectstack/* npm packages ..."

Neutral or unscoped uses that inherit whichever referent the reader arrived with: architecture.mdx:120, reference/environment-variables.mdx:89 and :159, reference/runtime-capabilities.mdx:59, build/marketplace.mdx:60, configure/runtime.mdx:25.

reference/cli.mdx:55 is the only site that disambiguates, and it does so in prose rather than by a convention: "on the ObjectOS runtime image a non-default value refuses the boot".

Why it matters

The two images have different licences, different distribution channels, and different boot behaviour. A sentence about one is not true of the other, so an unscoped "the runtime image" sentence is unverifiable by construction — a reader cannot tell which artifact to test it against, and neither can a contributor fact-checking the page.

This is not hypothetical: #251 was filed because a reader measured an unscoped behavioural claim against referent B when the page's own frontmatter scopes it to referent A. The measurement was correct and the conclusion it invited was wrong. That failure mode is available on every page in the neutral list above.

It also interacts with the boundary that closed #59 set — "previously published images are out of scope — do not document, reference, or preserve compatibility with them" — which reads as a decision that this site speaks about referent A, while resources/license.mdx still (correctly, and necessarily) speaks about referent B.

What a fix probably needs

Not a rename of every occurrence. The cheap, durable shape is a naming convention applied where a sentence is behavioural rather than descriptive:

  1. Pick distinct terms — e.g. "the ObjectOS runtime image" (A) and "the ObjectStack framework image" (B) — and use the bare phrase nowhere that a claim depends on which one is meant.
  2. Apply it first to the pages that make falsifiable boot claims (reference/environment-variables.mdx, reference/cli.mdx, deploy/*), where an unscoped sentence is actively misleading.
  3. Leave the descriptive, referent-independent uses (release-axis framing in architecture.mdx / configure/runtime.mdx) alone.

⚠️ Sequencing note: the specific row at reference/environment-variables.mdx:159 is already owned by #251 and is blocked on a reading of the release deploy bundle. Do not resolve that row here — this card is the convention, not the row.

Related: #251, #59, #60.

Activity

  1. added theissue type on Sep 2, 2026
  2. os-bill commented on Sep 2, 2026

    @os-bill
    CollaboratorAuthor

    Triage — first touch. Graded Bug, promoted to pm:queue (finding cleared with the grade — grading is leaving the finding state, not adding to it). repo:objectos seat, session session_01ChPQM8jamxLUfUAxwFpJ8S, round 1.

    Bug rather than Task, and the distinction is load-bearing: an unscoped behavioural sentence is not merely imprecise, it is unverifiable by construction — a reader cannot tell which artifact to test it against, and neither can a contributor fact-checking it. That is a defect in published material, and it has already produced a false conclusion in this repo rather than hypothetically.

    The evidence that this is real is #251, filed this round. A careful reader measured an unscoped boot claim against referent B (the Apache-2.0 framework CLI) when the page's own frontmatter scopes it to referent A (the licensed ObjectOS image). Their measurement was correct and the conclusion it invited was wrong. #251 is now in the decision inbox waiting on a reading only the maintainer can take. This card is the durable fix for that whole class; #251 is one row of it.

    Direction — adopt the convention, do not invent it

    The two terms the card proposes are already in use in the corpus rather than being coined here: reference/cli.mdx:55 already writes "the ObjectOS runtime image", and resources/license.mdx:104 already scopes its use to the framework repository. So this is applying existing usage as a convention, not a naming or branding decision — which is what keeps it inside this seat's discretion rather than the maintainer's.

    Adopt the card's own three-step shape:

    1. Distinct terms; the bare phrase appears nowhere a claim depends on which image is meant.
    2. Apply first to pages making falsifiable boot claims — that is where an unscoped sentence is actively misleading.
    3. ⛔ Leave the descriptive, referent-independent uses alone (architecture.mdx:120, configure/runtime.mdx:25 release-axis framing). Renaming every occurrence is explicitly not the ask, and doing it anyway would turn a bounded fix into a corpus-wide churn PR.

    ⛔ Two exclusions the dispatch must carry

    So the fault line is clean: this card fixes who a sentence is about; #251 fixes whether that sentence is true.

    Not escalated — no product semantics, no public contract, no destructive action, and the terms already exist in the corpus. Premises to be re-checked against origin/main at dispatch time as usual; the card measured at 8e665c7 and main has since moved to ac65e7e.


    Generated by Claude Code

  3. self-assigned this
    on Sep 2, 2026
  4. os-bill commented on Sep 2, 2026

    @os-bill
    CollaboratorAuthor

    Claim: PM loop round 2
    Session: session_01ChPQM8jamxLUfUAxwFpJ8S
    Branch: claude/issue-253-scope-the-runtime-image
    Worktree: objectos-issue-253
    Domain: repo:objectos (single-lane repo — this seat does not produce domain:*)
    File surface: the behavioural-claim pages only — content/docs/reference/environment-variables.mdx, content/docs/reference/cli.mdx, content/docs/deploy/*.mdx. ⛔ Descriptive uses in architecture.mdx and configure/runtime.mdx are out of surface by adjudication, not merely unmentioned. Stop on breach.
    Container & model: M, mode:subagent, model: opus. Tier by PM judgment — scripts/pm/dispatch-gates.mjs does not exist in this repo.
    Clause-②: no
    Serial constraints cleared: none in flight. The sibling dispatched alongside (#254) is pinned to extend-existing-systems.mdx and cannot reach these files. No open PR touches them.

    ⛔ Two carve-outs are hard constraints on this claim, not preferences (full reasoning in the grading comment above):

    The fault line: this card fixes who a sentence is about; #251 fixes whether that sentence is true.

    Dispatch-time premise re-check — holds, plus one reading the card did not have. origin/main is now ac65e7e (card measured at 8e665c7). I verified the locale exposure of every target page, because the sibling question bit this lane once already this round:

    Target page Locale siblings
    reference/environment-variables 0
    reference/cli 0
    deploy/index · deploy/docker · deploy/air-gapped 0 each

    Every page in this card's surface is English-only in fact. So the open locale-deletion decision (#256) does not touch this card at all, and no sibling handling arises. ⚠️ That is a measured reading of these specific paths — it is not a general property of content/docs/, which is 318 locale files out of 397. Do not generalise it.


    Generated by Claude Code

  5. os-bill commented on Sep 2, 2026

    @os-bill
    CollaboratorAuthor

    Dev claim — os-dev subagent, dispatched by the PM claim above.

    Session: session_01ChPQM8jamxLUfUAxwFpJ8S (same session as the PM comment above — this seat runs as a subagent inside it, so the session ID does not distinguish us; the branch does)
    Branch: claude/issue-253-scope-the-runtime-image — pushed empty at ac65e7e before the first edit, as a write-path probe (200, branch created)
    Worktree: /home/user/objectos-issue-253, cut --no-track from origin/main = ac65e7e
    Assignee: untouched, per dispatch.

    Carve-outs acknowledged as hard constraints: reference/environment-variables.mdx:159 and reference/cli.mdx:54-56 — subject may be made explicit, the refusal claim itself is #251's and is not touched here.


    Generated by Claude Code

  6. os-bill commented on Sep 2, 2026

    @os-bill
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 253,
      "status": "done",
      "branch": "claude/issue-253-scope-the-runtime-image",
      "head": "38cdd9a",
      "base": "ac65e7e",
      "pr": "https://github.com/objectstack-ai/objectos/pull/258",
      "pr_state": "draft, base main, first body line 'Fixes #253'",
      "premise_still_valid": true,
      "premise_note": "Card measured at 8e665c7; re-read every cited line at ac65e7e. All 12 enumerated sites still present at the cited lines. No cited file moved or was renamed.",
      "files_changed": [
        "content/docs/deploy/air-gapped.mdx",
        "content/docs/reference/environment-variables.mdx",
        "content/docs/reference/runtime-capabilities.mdx",
        "content/docs/build/marketplace.mdx"
      ],
      "diffstat": "4 files changed, 7 insertions(+), 6 deletions(-)",
      "carve_outs": {
        "environment-variables.mdx:159": "SUBJECT MADE EXPLICIT ONLY. Inserted the single word 'ObjectOS' into the subject. The refusal claim is byte-identical apart from that word: not asserted anew, not softened, not deleted. Verified by reading the diff hunk directly. #251 remains the owner of whether the refusal exists.",
        "cli.mdx:54-56": "NOT TOUCHED. Zero bytes changed in this file; it is not in files_changed. It already writes 'on the ObjectOS / runtime image' wrapped across the line break."
      },
      "gates": [
        { "gate": "gen-zh-hant.mjs --check", "conclusion": "zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte", "exit": 0 },
        { "gate": "check-translations.mjs", "conclusion": "translations gate passed", "exit": 0, "note": "siblings of the 2 sibling-bearing pages appear only under 'Stale translations', the non-blocking category" },
        { "gate": "check-translation-ownership.mjs", "conclusion": "This PR touches 0 translation artifact(s) and 4 other file(s)", "exit": 0, "note": "gate is INERT: TRANSLATION_BOT_LOGIN unset, so it is not enforcing; the 0-artifact count is the substantive reading" },
        { "gate": "check-translation-output.mjs --self-test", "conclusion": "29 rule case(s), 9 split case(s), 5 derived-locale case(s) - every rule demonstrated able to fail", "exit": 0 },
        { "gate": "check-translation-output.mjs --files", "conclusion": "translation output gate passed (139 pre-existing finding(s) reported)", "exit": 0, "note": "no finding in any of the 4 changed files" },
        { "gate": "check-node-floor.mjs", "conclusion": "Every declared floor clears what the dependency tree requires, and the declarations agree", "exit": 0 },
        { "gate": "turbo run type-check", "conclusion": "1 successful, 1 total - cache miss, executed", "exit": 0 },
        { "gate": "turbo run build", "conclusion": "1 successful, 1 total - cache miss, executed", "exit": 0 },
        { "gate": "check-locale-surface.mjs", "conclusion": "every advertised URL has a source file and every source file is advertised; 397 docs entries, 0 unexpected, 0 missing", "exit": 0 },
        { "gate": "turbo run test", "conclusion": "1 successful, but FULL TURBO cached", "exit": 0, "note": "NOT A MEASUREMENT of this change - its declared inputs exclude content/docs. Reported as cached, not as green-for-this-diff." }
      ],
      "gate_method": "exit codes captured by redirecting to a file first, then reading; never through a pipe. Conclusions quoted from each gate's own verdict line, never from a bare exit code.",
      "gates_provenance": "full suite re-run at 38cdd9a after the fold-in. None interrupted.",
      "build_noise": "465 'Failed to load dynamic font' errors from OG-image generation (self-signed certificate in certificate chain). Environmental sandbox-proxy noise, NOT caused by this change: count is identical (465) in a build of the parent commit. Build exits 0.",
      "rendered_output_check": "all 4 new strings present in apps/docs/.next/server/app/**; all 4 replaced strings absent from the entire build",
      "locale_handling": "runtime-capabilities.mdx and marketplace.mdx have 7 locale siblings each; air-gapped.mdx and environment-variables.mdx have 0 each (verified directly, with a live control probe: cel/security/runtime-capabilities do show siblings). English only edited; 0 sibling files modified; no translation frontmatter hand-written; zh-Hant unaffected because zh-Hans untouched.",
      "sweep_finding": {
        "card_population": 12,
        "measured_population": 13,
        "files": 10,
        "site_card_missed": "content/docs/deploy/docker.mdx:13-14 - 'registry credentials for the private runtime / image', wrapped across a line break so no line-oriented search can see it. Referent A, already scoped by 'private', needs no edit.",
        "method_note": "single-line grep reproduces the card's list exactly; only a multiline sweep finds the 13th. Same wrapping hides cli.mdx:55 from a grep for 'ObjectOS runtime image'.",
        "filed_as_issue": false,
        "filed_reason": "not a residual defect and not a new one: the site needs no edit, and the remaining bare uses are already enumerated inside #253 itself. Filing would duplicate this card. Reported here for PM disposition instead."
      },
      "bare_uses_remaining": [
        "architecture.mdx:120 - release-axis framing, referent-independent, out of surface by adjudication",
        "configure/runtime.mdx:25 - same claim, same reason",
        "reference/environment-variables.mdx:89 - same release-axis claim as the two above; sits in an edited file, so leaving it is a decision, not an oversight",
        "resources/license.mdx:104 - referent B, already scoped in-sentence by 'in the framework repository'"
      ],
      "deviations": [
        "File surface widened mid-task by the PM from 3 paths to 5, adding reference/runtime-capabilities.mdx and build/marketplace.mdx. PM stated this was their under-scoping, not a breach by this seat. Folded in as a second commit (38cdd9a).",
        "I independently agree with all four of the PM's calls on the widening: both added sites are referent-dependent (an actionable pin instruction; what a default catalog ships with), and both excluded sites are referent-independent release-axis framing.",
        "environment-variables.mdx:89 left bare by my own reading, not by adjudication - it is the same release-axis claim as the two adjudicated-out sites. Scoping it would leave the identical claim scoped on one page and unscoped on two others.",
        "First attempt at the air-gapped edit was a silent zero-hit no-op: perl \\Q...\\E quoted the newline into a literal backslash-n, so the substitution matched nothing and perl still exited 0. Caught by the on-disk before/after grep, not by the exit code. Re-done correctly and verified present-on-disk before any measurement.",
        "Container usage wall killed the run between the push of 01883c7 and PR creation. Resumed, re-read state, did not redo landed work. No gate was interrupted: all had completed before the commit.",
        "The shared verify lock lives in the objectstack checkout (/home/user/objectstack/scripts/pm/os-verify-lock.sh); objectos has no scripts/pm equivalent. Used it by absolute path for all heavy runs, since the container is shared with the #254 sibling."
      ],
      "assignee_touched": false,
      "open_questions": [],
      "out_of_scope_findings": [],
      "mcp_calls": 7
    }

    Generated by Claude Code

  7. os-bill commented on Sep 2, 2026

    @os-bill
    CollaboratorAuthor

    ACCEPT — PR #258

    Reviewer of record: session_01ChPQM8jamxLUfUAxwFpJ8S, repo:objectos seat, round 2. Checked against GitHub, not the report.

    Check Reading
    PR shape draft, base main, Fixes #253 ✓
    Changed files (get_files) 4, all inside the widened surface
    Path surface no governed path. Clears for the queue
    build (required) success on 38cdd9a
    Node floor · Ownership & freshness success · success
    Diff 7 insertions / 6 deletions — every edit inserts only the word "ObjectOS" plus reflow

    The carve-out held, and I verified it on the diff rather than on the report

    environment-variables.mdx:159 is byte-identical apart from the inserted word. The refusal claim is not asserted anew, not softened, not deleted — exactly the fault line: this card fixed who the sentence is about, #251 still owns whether it is true. cli.mdx does not appear in files_changed at all. Both carve-outs clean.

    Worth noting the side effect: the row now makes a sharper unverified claim than before. That is an improvement, not a regression — a precise claim is falsifiable once someone reads the deploy bundle, whereas the old vague one was unverifiable by construction and is precisely what invited a reader to test the wrong artifact and file #251.

    The sweep finding is the most valuable thing in this PR, and it indicts my method, not the dev's

    The dispatch asked for a corpus sweep rather than trusting the card's enumeration. It found 13 sites where the card listed 12. The 13th — deploy/docker.mdx:13-14, "registry credentials for the private runtime / image" — is wrapped across a line break, so no line-oriented search can see it. The same wrapping hides cli.mdx:55 from a grep for "ObjectOS runtime image".

    I reproduced this independently before accepting. A single-line grep over the branch returns 3 bare uses; a multiline sweep returns 13 occurrences across 10 files, including both wrapped sites. My own sweep earlier in this round used single-line grep and was blind to exactly these. So the card's enumeration was not sloppy — it was produced by a method that structurally cannot see wrapped phrases, and I then "verified" it with the same blind method. Going into the seat post as a standing commitment.

    The 13th site correctly needs no edit (already scoped by "private"), and it was reported for disposition rather than filed as a card — right call, since filing would have duplicated this one.

    One independent judgment against my adjudication line, and it is correct

    The dev left environment-variables.mdx:89 bare inside a file it was editing, and declared it as a decision rather than letting it pass as an oversight. I checked the text:

    "The runtime image and the app it serves are independent release axes"

    That is verbatim the same claim as the two sites I adjudicated out — architecture.mdx:120 ("released on its own cadence, separately from the runtime image") and configure/runtime.mdx:25 ("independently of the runtime image"). All three are referent-independent: true of either image. Scoping :89 would have left the identical claim scoped on one page and unscoped on two others. The dev applied my own criterion more consistently than my file list did. Accepted as adjudicated.

    Two disclosures that raise my confidence rather than lower it

    1. It caught a silent no-op in its own tooling. Its first air-gapped.mdx edit used perl \Q…\E, which quoted the newline into a literal \n; the substitution matched nothing and perl still exited 0. Caught by an on-disk before/after grep, not by the exit code. A zero-hit edit that reports success is the exact shape that ships an empty PR claiming a fix.
    2. turbo run test was FULL TURBO cached and was reported as "NOT A MEASUREMENT of this change" rather than as green — correct, since its declared inputs exclude content/docs. And the 465 build-time font errors were shown to be environmental by counting them on the parent commit (identical 465), which is a control, not an assertion.

    It also corrected its own posted comment: mcp_calls reads 7 there, true count 8, because the comment predates its own read-back call. Immaterial, and volunteering it is the habit worth having.

    ⛔ No rework. Landing.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions