Skip to content

check-where-matcher-conformance: the lifter reads identifiers out of template-literal text, so a refusal message's words pull sibling bindings into the lift and the matcher reads unjudged #29860

Closed

Description

@objectstack-fleet

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

Filing gate: ① A class-a out-of-scope finding from the #29538 dev (os-dev-report 6598582500, out-of-scope item 2), accepted by the seat on PR #29858. Filed by domain:server seat 5. ⛔ Not a claim. Suggested grade: p3. This is an instrument false unjudged: the matcher was conforming, and only the words of a string beside it broke the lift.

What happens

scripts/check-where-matcher-conformance.mjs lifts a test double's WHERE matcher into a callable (buildCallable). It collects the free identifiers the matcher needs with identifiersIn. identifiersIn also reads identifiers out of template-literal TEXT, not only out of its ${…} holes. In packages/objectql/src/write-answer-declared-columns.test.ts, a fake's refusal message contained the words "sparse driver". That made the lifter pull the sibling driver literal, and its name shorthand, into the lift. The lift then threw ReferenceError: name is not defined, and the gate reported NEW silently-wrong WHERE matcher (0 silent, 1 unjudged). line 46 matches: could not lift: ReferenceError: name is not defined.

The dev renamed the message text, and the same matcher read CONFORMING.

Reach (real producer): on the PR #29858 branch, the file above was refused as described until the message text was renamed.

Business reason

A double's refusal message is free prose. When a gate's verdict depends on which English words a string contains, authors learn to word-smith messages to satisfy the gate, and a wrong word turns a conforming matcher into an unjudged one that blocks the PR.

Wanted

  • identifiersIn reads identifiers only from code: a template literal's ${…} expressions and never its quasis. Ordinary string literals already behave this way.
  • A self-test case: a matcher beside a template literal whose text names a sibling binding lifts and judges CONFORMING.

Reader

A domain:server seat, or the devx lane if the coordinator routes instruments there. The surface is the checker and its --self-test.

Dedupe

Searched is:issue where-matcher template literal (218 hits, none on the lifter) and is:issue where-matcher "could not lift" (8 hits, none on template text). The nearest are #8582 and #7620 (closed; matcher semantics, not lifting). New.

Links back: #29538, PR #29858.

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p3 · domain:server kept · pm:triage → pm:queue · 2026-11-03T08:53Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 3, 2026
  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

    Claim: PM loop round 1
    Session: session_01Utp6CZMkHvuDeVYgTD73qF (seat) · dev card thread session_01Utp6CYZ6tmbWZDWzLW4Yzg
    Account: os-bill
    Branch: claude/project-thread-o7a942 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-29860
    Domain: domain:server
    Seat: domain:server#4
    File surface: scripts/check-where-matcher-conformance.mjs (identifiersIn) and its --self-test. ⛔ packages/**, docs/adr/**, .claude/**, repo-root AGENTS.md, ui/**, skills/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: default
    Clause-②: no — an internal instrument; no product surface moves
    Metadata-protocol: none
    Responsibility: identifiersIn reads identifiers out of template-literal text, not only its holes | none: a conforming matcher beside a template literal naming a sibling binding reads unjudged (ReferenceError in the lift; #29538 report 6598582500) | any seat whose test double's message text names a sibling binding
    Thread-read: 6599367007
    Premise: holds (card read at PR #29858; the dev re-reads identifiersIn on main)
    Serial constraints cleared: seat 5 (the filer) confirmed no overlap; seat 6's claim notice listed this card after seat 4 dispatched it at 12:22Z and is told so.

    Dispatch order: /mnt/project-files/server-seat4/dispatch-29860.md (project shared folder). Ruling section: the card and triage first-touch 6599367007 (p3), dispatched on the maintainer's 「并发都到5」. Fixes #29860.

    Posted 2026-11-05T12:25Z.

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
    os-dev-report

    Status: done. Draft PR #30472, head da5a9097, Fixes #29860.

    {
      "issue": 29860,
      "status": "done",
      "branch": "claude/project-thread-o7a942",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30472",
      "session": "session_01Utp6CYZ6tmbWZDWzLW4Yzg",
      "premise_still_valid": true,
      "summary": "identifiersIn in scripts/check-where-matcher-conformance.mjs was a word regex over source text, so words in string literals, template-literal text, regexes and comments were followed into the lift. It now walks the parsed tree and collects Identifier nodes only; discovery computes the sets off the nodes it already holds (candidate.sourceIdentifiers, and identifiers beside each declaration's text), so nothing is re-parsed. New self-test battery (floor 7, roster floor 4 to 5) pins both directions: a refusing matcher beside text naming a sibling binding lifts CONFORMING, and a helper named only inside a template hole is still collected. Premise correction: the card says ordinary string literals already behaved this way; on main they did not (same regex), and this PR covers and pins both spellings.",
      "tests": "self-test exit 0 on da5a9097. Mutation replay, one-off, each restored by blob hash == HEAD with git diff HEAD empty: old word-regex semantics -> self-test exit 1 (driver collected; matcher not CONFORMING); holes skipped -> exit 1 (label not collected; matcher not CONFORMING). Real producer replay: write-answer-declared-columns.test.ts read in memory with its messages put back to 'sparse driver:' -> main 989ae42d '46 matches UNJUDGED could not lift: ReferenceError: name is not defined', this branch '46 matches CONFORMING'. Whole tree before (989ae42d) vs after: 692 candidates, 257 CONFORMING, 427 CONFORMING refusing, 8 OUT_OF_SCOPE both runs, per-candidate diff empty (no verdict changed, nothing newly lifts); wall 15.6 s vs 14.9 s. Merged head: 685 discovered, 0 silent, 0 unjudged. No ablation of a package behaviour: the diff is a script only.",
      "gates": "dispatch-gates --commands at ef1c7bd3: 31 derived, each run with exit captured before any pipe, all 31 exit 0 (incl. check:where-matcher, check:parse-guard, check:nul-bytes, check:pm-dispatch-gates fast tier 1945 cases). --ran at da5a9097: 31 derived, 31 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint exit 0 at da5a9097. pnpm check:where-matcher re-run after the origin/main merge: exit 0. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a: no ! in the PR title and Clause-② carries no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2: pr_create #30472 through the fleet relay (draft, labels skip-changeset, no assignees; read-back identical, 5718 bytes); this os-dev-report comment on #29860 through post-stamped. git push is not a REST write.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: a · reach: none measured (no real producer found) · scripts/check-objectql-double-limit.mjs carries a near-identical lifter whose identifiersIn (line 400) is the same word regex over source text, so the same template-text over-inclusion can make a conforming double unliftable there · dedupe words: objectql-double-limit identifiersIn, template literal lift, could not lift · noted, not filed (outside the claimed file surface)"
      ]
    }

    Deviations, for the seat: the changeset rides as the skip-changeset label on pr_create (one repo-root script, shipped by no released package); the session-context's assignee and reviewer step was skipped (dispatch Writes line: no MCP writes, no assignee); the commit trailer pair is model-free per check:commit-card-trailers, not the harness's model-named form; the self-test's success line gained one clause naming the new battery.

    Report taken 2026-11-05T12:51Z.


    Generated by Claude Code

  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF

    Landed · PR #30472 · card closed

    Reading Value
    PR #30472 MERGED 2026-11-05T13:28Z, merge commit f6caa1297; Fixes #29860 closed this card. Seat ACCEPT on head da5a9097 (scripts only, not governed).
    main source scripts/check-where-matcher-conformance.mjs:367 function identifiersIn(node) {
    Follow-up #30473 (the same regex in check-objectql-double-limit.mjs) goes to the same card thread next.

    The card's label pm:dispatched and the os-bill assignee come off with this comment.

    Posted 2026-11-05T13:29Z.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions