The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

Description

@claude

Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

The defect

#14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

Two sibling seams still use the comparison that argument retired, and both are in the same file:

  1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

  2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

Why it was not folded into #14088

  • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
  • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
  • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

The constraint any repair inherits

⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

Reproduction shape

The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

Unassigned and untriaged.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

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

    The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

    Description

    @claude

    Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

    The defect

    #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

    Two sibling seams still use the comparison that argument retired, and both are in the same file:

    1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

    2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

    A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

    Why it was not folded into #14088

    • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
    • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
    • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

    The constraint any repair inherits

    ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

    ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

    Reproduction shape

    The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

    Unassigned and untriaged.


    Generated by Claude Code

    Metadata

    Metadata

    Assignees

    Labels

    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

      The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

      Description

      @claude

      Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

      The defect

      #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

      Two sibling seams still use the comparison that argument retired, and both are in the same file:

      1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

      2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

      A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

      Why it was not folded into #14088

      • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
      • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
      • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

      The constraint any repair inherits

      ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

      ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

      Reproduction shape

      The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

      Unassigned and untriaged.


      Generated by Claude Code

      Metadata

      Metadata

      Assignees

      Labels

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

        The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

        Description

        @claude

        Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

        The defect

        #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

        Two sibling seams still use the comparison that argument retired, and both are in the same file:

        1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

        2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

        A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

        Why it was not folded into #14088

        • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
        • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
        • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

        The constraint any repair inherits

        ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

        ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

        Reproduction shape

        The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

        Unassigned and untriaged.


        Generated by Claude Code

        Metadata

        Metadata

        Assignees

        Labels

        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

          The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

          Description

          @claude

          Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

          The defect

          #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

          Two sibling seams still use the comparison that argument retired, and both are in the same file:

          1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

          2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

          A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

          Why it was not folded into #14088

          • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
          • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
          • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

          The constraint any repair inherits

          ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

          ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

          Reproduction shape

          The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

          Unassigned and untriaged.


          Generated by Claude Code

          Metadata

          Metadata

          Assignees

          Labels

          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

            The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

            Description

            @claude

            Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

            The defect

            #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

            Two sibling seams still use the comparison that argument retired, and both are in the same file:

            1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

            2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

            A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

            Why it was not folded into #14088

            • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
            • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
            • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

            The constraint any repair inherits

            ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

            ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

            Reproduction shape

            The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

            Unassigned and untriaged.


            Generated by Claude Code

            Metadata

            Metadata

            Assignees

            Labels

            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

              The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

              Description

              @claude

              Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

              The defect

              #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

              Two sibling seams still use the comparison that argument retired, and both are in the same file:

              1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

              2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

              A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

              Why it was not folded into #14088

              • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
              • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
              • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

              The constraint any repair inherits

              ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

              ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

              Reproduction shape

              The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

              Unassigned and untriaged.


              Generated by Claude Code

              Metadata

              Metadata

              Assignees

              Labels

              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

                The readonlyWhen strip and the insert-side runtime-owned strip still decide hook-vs-caller by Object.is, the comparison #14088 retired one function over #14259

                Description

                @claude

                Found while implementing #14088 (PR #14258), on origin/main at 66ecc50a. Deliberately left alone there — #14088's scope is the static readonly strip, and one of the two seams below is a state LOCK whose relaxation is a decision, not a mechanical follow-through.

                The defect

                #14088 replaced Object.is(payload[name], supplied[name]) in stripReadonlyFields with a record of the keys the before-phase hook chain actually assigned (recordHookPayloadWrites, packages/objectql/src/hook-write-provenance.ts). The argument for that was not about null: value equality cannot separate the hook deliberately wrote the value the caller also sent from the hook never touched the key, and those demand opposite verdicts.

                Two sibling seams still use the comparison that argument retired, and both are in the same file:

                1. isCallerSuppliedValue (packages/objectql/src/validation/rule-validator.ts) — the shared predicate behind stripReadonlyWhenFields and stripReadonlyWhenFieldsMulti. Its own docblock says it is written "to be textually parallel with the same test inside stripReadonlyFields" so the two "can never disagree about what caller-supplied means". After stripReadonlyFields uses Object.is to tell a hook write from a caller write, so a hook cannot clear a readonly field the caller also sent as null #14088 they do disagree. A beforeUpdate hook deriving a readonlyWhen-locked field loses its write to any caller that echoed the same value back — the [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107 defect, surviving on the one input [objectql] TRUE readonlyWhen strips beforeUpdate-derived values too — a conditionally-locked derived field has no server-side write path at all (isSystem included), unlike static readonly's hook-stamp protection #9107's fix cannot see.

                2. stripRuntimeOwnedFields (same file, the INSERT-side twin). insert 路径 stripRuntimeOwnedFields 同样删的是 hook 覆写后的当前值 —— beforeInsert hook 写入的 autonumber 在调用方也提交了同名键时被连坐删除(与其自身文档矛盾) #6339's own prose is the finding: it argued the key-SET judgement "made that sentence true only by accident" and moved to values, which is accidental in the identical way. A beforeInsert hook re-issuing or normalising a record number loses its write when the caller happened to submit the same value.

                A third, narrower seam is worth naming in the same breath: the #14088 recorder is armed at hookContext construction, i.e. after the middleware chain, so a MIDDLEWARE stamp that writes the value the caller also sent is still judged by value equality. Arming earlier is a one-line move with the same forgery argument, but it widens what the record covers and deserves its own measurement.

                Why it was not folded into #14088

                • The instrument now exists and is shared, so this is threading rather than invention — the cheap part is done.
                • But seam 1 is a lock. Widening its hook exemption means a hook write survives a TRUE readonlyWhen predicate in a case where today it does not, and Parent-scoped readonlyWhen is unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889's frozen paid-invoice lines are built on that lock. That is a maintainer-shaped call, not a mechanical follow-through, and it should not ride in on a p1 corruption fix.
                • Seam 2 is a different code path (engine.insert's per-row hook contexts) with its own fixtures — a new verification surface, which is exactly the boundary the in-place-fix exemption draws.

                The constraint any repair inherits

                ⛔ The forgery boundary from #14088 applies unchanged and is the part where a mistake is worse than the bug: a caller-supplied value must never become hook-owned. The record is safe only because it is armed after the caller's payload has arrived and sealed before any engine-owned pass touches it, and because it records that an assignment ran rather than anything about the payload's contents. Any producer of a hook-written key set owes the same proof.

                ⛔ And it is not a relaxation: a caller-supplied value that no hook wrote must still be stripped, still warn with the same text, and still report through onFieldsDropped / strictReadonlyWrites.

                Reproduction shape

                The same one #14088 uses, retargeted: a hook that writes a locked/runtime-owned field the value the caller also sent, and the negative control of the identical caller payload with no hook write, which must reach the opposite verdict.

                Unassigned and untriaged.


                Generated by Claude Code

                Metadata

                Metadata

                Assignees

                Labels

                Type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions