docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified - #15063

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment
Sep 3, 2026
Merged

docs(runtime): correct the publish-drafts app-read comment the meta read gate falsified#15063
os-trump merged 2 commits into
mainfrom
claude/issue-14771-packages-org-aware-comment

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14771

One comment. No behaviour change: git diff origin/main...HEAD is 19 insertions / 3 deletions in a single // block, and the file's token stream is byte-identical across the change (proof below).

What was wrong

packages/runtime/src/domains/packages.ts justified the publish-drafts app-list read with:

// The READ above is left org-aware on purpose — a layered read is a superset,
// never a loss.

That was true when written. It is not true now. getMetaItems resolves the read scope itself:

packages/metadata-protocol/src/protocol.ts:6842
const orgId = organizationIdForMetaRead(request.type, request.organizationId);

and organizationIdForMetaRead (packages/metadata-core/src/meta-write-org-scope.ts:184) returns undefined for any type the registry declares non-overridable. app is one:

packages/spec/src/kernel/metadata-plugin.zod.ts:846
{ type: 'app', ..., supportsOverlay: true, allowOrgOverride: false, ... }

So the organizationId this route still hands the call is dropped at that gate, and the read is env-wide — not org-aware, and not a superset of anything.

Why the comment was repaired and the code was not

The behaviour is correct. An org-scoped app row is an unhydratable phantom: loadMetaFromDb walks past it and reportUnhydratableOrgScopedRows exists to say so. Reading org-scoped here would resurrect rows that vanish at the next restart, and flip _unpublished on them instead of on the row cold boot actually hydrates — the resurrection #14683 closed, arriving from the read side.

The danger was the justification, not the code: a reader who trusts "left org-aware on purpose" concludes the gate above them is a bug and restores the organization. The replacement states the mechanism, names the registry flag, and says plainly that dropping the organization is the repair.

⛔ Untouched, deliberately: the read itself, the gate, and organizationIdForMetaWrite. My reading of the code found nothing wrong with any of them.

Changeset fork: none, skip-changeset instead

Measured from the package's own manifest rather than assumed:

packages/runtime/package.json → files: ["dist","README.md","CHANGELOG.md"]

@objectstack/runtime publishes, but src/** is not in its tarball, and the edited bytes live inside a // comment in a function body, so they reach neither dist nor the emitted .d.ts. This PR therefore declares no release of its own and carries skip-changeset, which is exactly the label's stated criterion in pr-automation.yml.

Verification

Exit codes captured before any pipe, never through one. Two shas are named because two things were measured at two points, and saying so is cheaper than a claim that will not hold up.

At the final HEAD 686b6c0b21 (git rev-parse --short HEAD, after merging origin/main) — the gate union:

Derived, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack gives 27 families (21 by path, 1 by change kind, 5 declared whole-tree). Re-derived after the merge and byte-identical to the pre-merge derivation, and re-run in full there.

  • 25 of 27 green (exit 0), including the two comment-parsing families this diff most implicates, check:comment-mask-adoption and check:comment-mask-corpus, plus check:nul-bytes, check:route-envelope, check:doc-authoring, check:type-source-resolution, check:published-files.
  • 2 of 27 NOT MEASURED (exit 3, PREREQUISITE NOT MET — neither a pass nor a red):
    • check:dual-build-cjs-loads — "PREREQUISITE NOT MET ... some package has no dist/", naming 8 packages plus "29 more". It needs a whole-workspace pnpm build; CI's Build Core job owns that run, and the gate's own text says "This is NOT a pass: nothing was measured."
    • check-test-completeness.mjs with no argument — structurally unmeasurable locally by the gate's own text ("There is no local log to hand it, so the local reading for this gate is NOT MEASURED").

At b6423975f9 (the same one-file diff, one commit earlier, before origin/main was merged in) — the package scripts, by name, all through bash scripts/pm/os-verify-lock.sh -c ... and read from the wrapper's own VERDICT line:

  • pnpm --workspace-concurrency=2 --filter '@objectstack/runtime^...' build → exit 0
  • pnpm --filter @objectstack/runtime typecheck → exit 0 (tsc --noEmit, then check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held)
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 over the five src/domains/packages-*.test.ts suites → Test Files 5 passed (5) · Tests 111 passed (111)

Declared narrowing: re-running those three at the merged HEAD is NOT MEASURED. Five attempts on the shared verify lock over roughly 45 minutes produced three queue timeouts (exit 99, "never acquired") and two container foreground-cap kills mid-build (exit 143), against holders that were other seats' @objectstack/cli closure builds and issue-14704 verification scripts. Recorded as NOT MEASURED rather than as a pass, and not as a red either. What backs the narrowing: the merge moved packages/runtime only through PR #15018 on action-execution.ts, a file this diff does not touch, and the token proof below makes it structurally impossible for these bytes to change any build, typecheck or test outcome at any base. CI's Type Check and Test Core jobs run the real thing on this PR.

Token-identity proof. Scanning both revisions of the edited file with the repo's own TypeScript scanner (trivia skipped) gives 1895 tokens on each side and the same sha256 486a535c75603b833018aab0c2916254434e066d1cc6d105f430d4cadaf7b433, with a positive control — the same comparison against the token list minus its last element — correctly reporting a mismatch. So the diff is comment-only at the token level, not merely by inspection.

Bounding the class, without widening the diff

Asked as a side question and answered by measurement, not fixed here. Method: enumerate every non-test metadata read call site in packages/runtime/src/** (a git grep -n -E over getMetaItems|getMetaItem|getMetaItemLayered|listMetaItems|getMetaDiagnostics|findReferencesToMeta with an explicit :(glob)packages/runtime/src/**/*.ts pathspec — 9 sites, and the same pathspec returns more when test files are included, so it is live and not silently matching zero), then read the comment attached to each.

Two comments in that package state the pre-gate rule. One is the sentence this PR repairs. The other:

packages/runtime/src/domains/packages.ts:1245
// Read the just-published seed body. Try the active org first, then
// fall back to an env-wide read ...

seed is allowOrgOverride: false (metadata-plugin.zod.ts:808), so both attempts in that ladder now resolve to the identical env-wide read and "try the active org first" describes a scope step that no longer exists. Same class, same file, ⛔ deliberately not touched here — it is a card, not a rider.

Not members, checked and distinguished: the readMergedSkillRows docblock in domains/mcp.ts already states the correct rule for skill; the getMetaItemLayered note at domains/meta.ts:334 describes a primitive the read gate does not reach; and the four domains/meta.ts read sites carry comments about masking and draft preview, asserting nothing about org scope.

🤖 Generated with Claude Code

Generated by Claude Code


Generated by Claude Code

…d gate
`packages/runtime/src/domains/packages.ts` justified the publish-drafts app
list read with "left org-aware on purpose — a layered read is a superset,
never a loss". Since `getMetaItems` began resolving `organizationIdForMetaRead`
on `request.type` itself, that read is env-wide for `app`: the registry
declares `app` `allowOrgOverride: false`, so the predicate answers `undefined`
and the `organizationId` this route still passes is dropped at the gate.
The behaviour is correct and unchanged here — an org-scoped `app` row is an
unhydratable phantom that `loadMetaFromDb` walks past, so dropping the
organization is the repair. Only the justification was wrong, and it was wrong
in the direction that invites the next reader to restore the organization and
resurrect those rows. Comment only: the read, the gate and
`organizationIdForMetaWrite` are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

Which tree this was computed on

This run read content/docs from b9659417663ec5813e576689eeb5160dafb8539b — the merge of head 686b6c0b21da755058ed1170d792f26aff36a3e3 into base 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b9659417663ec5813e576689eeb5160dafb8539b && git checkout b9659417663ec5813e576689eeb5160dafb8539b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 686b6c0b21da755058ed1170d792f26aff36a3e3 && git checkout -B drift-repro 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832 && git merge --no-ff 686b6c0b21da755058ed1170d792f26aff36a3e3
node scripts/docs-audit/affected-docs.mjs --json 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-trumpos-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 3, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:56
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit ad35745Sep 3, 2026
39 checks passed
@os-trump
os-trump deleted the claude/issue-14771-packages-org-aware-comment branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-trump@claude