reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

Description

@hotlong

Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

The sites

From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

Boundary / readerfile:lineNote
B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
i18n auto-registrationserve.ts:2976-2995
ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

The trap in this card

The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

Acceptance

Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e 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

    reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

    Description

    @hotlong

    Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

    Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

    The sites

    From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

    Boundary / readerfile:lineNote
    B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
    configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
    i18n auto-registrationserve.ts:2976-2995
    ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
    Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
    appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
    B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
    B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
    dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
    resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

    The trap in this card

    The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

    Acceptance

    Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

    Activity

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

    Metadata

    Metadata

    Assignees

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , '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

      reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

      Description

      @hotlong

      Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

      Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

      The sites

      From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

      Boundary / readerfile:lineNote
      B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
      configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
      i18n auto-registrationserve.ts:2976-2995
      ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
      Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
      appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
      B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
      B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
      dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
      resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

      The trap in this card

      The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

      Acceptance

      Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

      Activity

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

      Metadata

      Metadata

      Assignees

      Type

      No type

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , '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 \u003e 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

        reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

        Description

        @hotlong

        Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

        Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

        The sites

        From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

        Boundary / readerfile:lineNote
        B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
        configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
        i18n auto-registrationserve.ts:2976-2995
        ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
        Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
        appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
        B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
        B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
        dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
        resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

        The trap in this card

        The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

        Acceptance

        Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

        Activity

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

        Metadata

        Metadata

        Assignees

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , '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

          reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

          Description

          @hotlong

          Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

          Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

          The sites

          From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

          Boundary / readerfile:lineNote
          B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
          configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
          i18n auto-registrationserve.ts:2976-2995
          ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
          Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
          appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
          B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
          B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
          dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
          resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

          The trap in this card

          The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

          Acceptance

          Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

          Activity

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

          Metadata

          Metadata

          Assignees

          Type

          No type

          Projects

          No projects

            Milestone

            No milestone

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , '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

            reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

            Description

            @hotlong

            Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

            Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

            The sites

            From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

            Boundary / readerfile:lineNote
            B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
            configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
            i18n auto-registrationserve.ts:2976-2995
            ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
            Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
            appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
            B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
            B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
            dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
            resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

            The trap in this card

            The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

            Acceptance

            Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

            Activity

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

            Metadata

            Metadata

            Assignees

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , '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

              reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

              Description

              @hotlong

              Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

              Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

              The sites

              From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

              Boundary / readerfile:lineNote
              B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
              configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
              i18n auto-registrationserve.ts:2976-2995
              ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
              Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
              appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
              B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
              B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
              dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
              resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

              The trap in this card

              The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

              Acceptance

              Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

              Activity

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

              Metadata

              Metadata

              Assignees

              Type

              No type

              Projects

              No projects

                Milestone

                No milestone

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions

                , '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

                reader program 3/4 — @objectstack/cli: the four config-load boundaries and the gates that key off config.objects #15006

                Description

                @hotlong

                Part of #14122 · blocks #14512 · Blocked-by: #15004 (the acceptance probe).

                Reader half of the program ruled on #14512 (comment 5528589044, maintainer 2026-09-03, batch #23). The artifact stays additive through this card.

                The sites

                From the boundary measurement in 5523741937. Note this package holds four independent config-load boundaries, not one — a fold at any single point reaches none of the others.

                Boundary / readerfile:lineNote
                B2 os serve / os dev config-module loadpackages/cli/src/commands/serve.ts:2170 (bundleRequire) → :2172 (let config = mod.default || mod;)The from-source entry. The compiled artifact never passes through it
                configHasMetadata + new AppPlugin(config)serve.ts:2802, :2923Everything AppPlugin then reads — see card 2/4
                i18n auto-registrationserve.ts:2976-2995
                ObjectQL engine auto-registrationserve.ts:2632if (config.objects && !hasObjectQL)⚠️ Silent: with no top-level objects this reads undefined and the engine is simply not registered
                Storage-driver auto-registrationserve.ts:2669if (!hasDriver && config.objects)⚠️ Same mechanism, same silence
                appSecurityPluginOptions(config)serve.ts:3710Feeds the ADR-0056 D7 permission surface from the from-source side — the same surface card 2/4 feeds from the artifact side
                B3 os build config-module loadpackages/cli/src/commands/compile.ts:211 (loadConfig)Then normalizeStackInput:231, safeParse :318, authoring rules :344, per-package run :401
                B4 os migrate — its own second, independentloadConfigpackages/cli/src/utils/schema-migration-plugins.ts:1083configHasMetadata:1094, new AppPlugin(config, …):1100Not behind B2; missed by both earlier enumerations
                dev.tsreadArtifactObjects()packages/cli/src/commands/dev.ts:653-666Opens the artifact with its ownJSON.parse(readFileSync(...)) at :655 and its own envelope unwrap at :656, reading top-level meta.objects at :657 to diff the inventory across recompiles. Non-fatal — it just goes permanently empty — but it is a sixth place the artifact is opened
                resolveDevDatabase / os start / os db cleandev.ts:56, start.ts:557, db/clean.ts:46These call into resolve-project-database (card 2/4) before any stack exists

                The trap in this card

                The two auto-registration gates at serve.ts:2632 and :2669 are the sharpest silent failures in the whole program, and they interact with a runtime-side detail: standalone-stack.ts:785omits the objects key entirely when the array is absent rather than setting [], and mergeBootConfig (packages/cli/src/utils/merge-boot-config.ts:42) is a plain spread. So an option-B artifact reaches these gates with config.objects === undefined and the app boots with no query engine and no storage driver, having thrown nothing. Verify this pair against card 2/4's behaviour on the probe before calling either done.

                Acceptance

                Sibling cards: #15004 (probe, blocks this), #15005@objectstack/runtime, 4/4 @objectstack/plugin-security. Emitter half: #14512.

                Activity

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

                Metadata

                Metadata

                Assignees

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions