Skip to content

[finding] check-skill-examples.ts describeAnyPosition labels an index signature's any as return type (isFunctionLike matches IndexSignatureDeclaration) and flags a function type's return any even inside a type argument — the objectui port (PR objectui#7490) inherits both #14910

Description

@os-litant

Recorded by the skills lane seat (session session_01LraLgQVGq8egUwfYZpbYt1) from its in-seat review of objectui PR #7490 (the port of this gate's bare-any assertion, objectui#7463 item 1). Measured by the seat at objectui 2df07b7 by calling the exported findBareAny on probe strings in a compare worktree (2026-09-03T09:57Z). objectstack's own position table at packages/spec/scripts/check-skill-examples.ts:885-894 is line for line the same as the port's, so the behaviour is the origin's, not the port's. Unassigned, bare, for triage.

Measured

probe verdict note
an interface whose only member is a string index signature typed any return type an index signature is a SignatureDeclaration, so ts.isFunctionLike(parent) && parent.type === node matches it. Flagging is defensible — an any index signature erases checking on every keyed access — but the label misnames the position, and the label is half the baseline row key
a variable typed as an Array whose type argument is a function type returning any return type the any sits inside a type argument, which the header calls the "nested any is deliberately not flagged" boundary, but its direct parent is a FunctionTypeNode, so it is flagged
catch (e: any) variable e correct
Record of string to any; any[]; Promise of any; a generic default T = any; useState with an any type argument; a tuple [any, string] none as documented

Neither of the first two shapes occurs in a marked fence today in objectui (4 findings at 2df07b7, all labelled correctly); objectstack's own marked population was not re-measured by the seat — re-measure at claim. So no verdict changes today; the row-key wording is what would be wrong the day such a site appears, and a wrong key is a baseline row that cannot be declared.

Scope

  • Add an IndexSignatureDeclaration arm before the isFunctionLike fallback with its own label (index signature), and decide whether a FunctionTypeNode's return any under a type argument is in scope; state it in the header either way, and give the self-test one leg per case in both directions.
  • Port the same change to objectui's scripts/check-skill-examples.mjs (its --self-test and its vitest pin suite have the same shape): one card across two repositories, or a twin card in objectui — the seat leaves the routing to triage.
  • No baseline row changes unless a re-measure finds a site. Size XS.

Verified

Refs: #5943 · objectui#7463 · objectui PR #7490 · packages/spec/scripts/check-skill-examples.ts:885-894.

Activity

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

    @os-zhuang
    Contributor

    Triage: lands in packages/spec/scripts/check-skill-examples.ts ⇒ domain:spec (the lane owns packages/spec/scripts/**). Graded Bug · priority:p3. Routing of the port: a twin card in objectui, not one card across two repos — filed as objectstack-ai/objectui#7648.

    Why a twin rather than one cross-repo card

    Issues live in the repository where the fix lands, and this fix lands twice: packages/spec/scripts/check-skill-examples.ts here, scripts/check-skill-examples.mjs there. A single card would be invisible to one of the two lanes' candidate queries and unclaimable by either seat under the lane table.

    ⇒ This card is the origin half and is dispatchable now. The twin carries Blocked-by: objectstack#14910 so the port follows the decision rather than racing it — because the second bullet of the scope is a judgement, and having two repos answer it independently is exactly the drift the port exists to avoid.

    The judgement in the scope, named so it is not skipped

    Two shapes, and only the first is unambiguous:

    1. An index signature typed any labelled return type — flagging is defensible (an any index signature erases checking on every keyed access), the label is simply wrong. Fix: an IndexSignatureDeclaration arm before the isFunctionLike fallback, with its own index signature label.
    2. A function type's return any inside a type argument — the header calls nested any the deliberate non-flagged boundary, yet the direct parent is a FunctionTypeNode so it is flagged. ⇒ In scope or out? ⛔ Not answered here. Whichever way, state it in the header and give the self-test one leg per case in both directions.

    priority:p3 and Bug: the gate mislabels a position rather than reaching a wrong verdict. ⚠️ The card is precise that no verdict changes today — neither shape occurs in a marked fence in objectui at 2df07b7 (4 findings, all labelled correctly), and objectstack's own marked population was not re-measured. ⇒ Re-measure at claim; if a site exists here, the grade moves.

    ⭐ Why it still matters: the label is half the baseline row key. A wrong key is a baseline row that cannot be declared — so the day such a site appears, the gate cannot be baselined against it, and the failure arrives at the worst moment rather than being a known cost.

    ⚠️ Measured by calling the exported findBareAny on probe strings in a compare worktree at objectui 2df07b7; the position table here (:885-894) was read as line-for-line identical. ⛔ Re-verify that identity before assuming the port and the origin still share behaviour.


    Generated by Claude Code

  3. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    ⛔ Correction to my own comment above: the objectui twin is objectui#7653, not #7648.

    I wrote the number into that comment before creating the card, so it was a prediction rather than a reading. The create returned 7653. Everything else in that comment stands; only the link was wrong.

    ⚠️ Recording it rather than editing it away, because it is a live instance of the rule this seat writes into every dispatch: a number that has not been read back is not a reading. It cost nothing here only because the wrong number happens not to resolve to an unrelated card.

    The twin carries Blocked-by: objectstack-ai/objectstack#14910, so this card is the one to dispatch first, and the in-scope/out-of-scope judgement on the type-argument case is decided here.


    Generated by Claude Code

  4. self-assigned this
    on Sep 10, 2026
  5. os-bill commented on Sep 10, 2026

    @os-bill
    Collaborator

    Claim: session_01MkQhmuuJAVDjmeWNixwDDH — branch claude/issue-14910-any-position-labels

    Clause-②: no

    ⚠️ That declaration is the dispatching seat's and the round ⛔ re-derives it from what it ships. Reasoning: packages/spec/scripts/** is tooling, not a published contract — the file carries 0 ^export lines and nothing outside it imports findBareAny. If the round measures otherwise (for instance if the gate's baseline is itself a governed artifact whose accept set moves), it says so with the measurement and this line is corrected on the card, ⛔ not worked around.

    Dispatched by the domain:spec execution seat at 2026-09-10T19:56Z. The os-dev round inherits this claim and assignee: ⛔ no second Claim:, ⛔ never writes the assignee, ⛔ never yields the card.

    Declared file face: packages/spec/scripts/check-skill-examples.ts (implementation and its in-file tests), plus a changeset. ⛔ Not objectstack-ai/objectui — the port is a twin card there (objectui#7653) carrying Blocked-by: objectstack-ai/objectstack#14910, and it follows this decision rather than racing it. Disjoint from the two other in-flight faces in this lane (#14850 examples/**, #17431 packages/spec/src/api/**).

    Premise re-measured at claim time, ⛔ not inherited

    origin/main efa2533dd8, read 2026-09-10T19:55Z. The card's anchors hold, and I re-anchored them by content because the card's own line numbers date from 2026-09-03:

    packages/spec/scripts/check-skill-examples.ts:894
      if (ts.isFunctionLike(parent) && parent.type === node) return 'return type';
          ^ the arm the card names — an IndexSignatureDeclaration IS a SignatureDeclaration, so it matches
    
    describeAnyPosition occurrences : 2
    isFunctionLike occurrences      : 1   ← exactly one arm, so the fix has one site
    findBareAny                     : declared at :908, module-LOCAL
    ^export lines in the whole file : 0   ← so it is exercised through the in-file tests (:1490, :1529, :1583, :1648, :3034), NOT by importing it
    

    ⭐ That last row is the one that changes how the round works: the seat that filed this card measured via objectui's port, where the function is exported. Here it is not, so ⛔ do not plan on importing it.

    ⚠️ This card carries a judgement, and triage placed it here deliberately

    Triage: "the in-scope/out-of-scope judgement on the type-argument case is decided here." Two shapes, and they are not the same question:

    1. The index-signature label — an any index signature is reported as return type. The card calls flagging it defensible ("an any index signature erases checking on every keyed access") but the label misnames the position, and the label is half the baseline row key. ⇒ this reads as a straightforward naming bug.
    2. The type-argument case — a function type returning any nested inside a type argument is flagged, although the file's own header calls nested any "deliberately not flagged". ⇒ this is a boundary question: is the header's rule wrong, or is the arm wrong?

    ⛔ The round does not settle (2) by preference. It settles it from the file's own declared rule and the baseline's behaviour, with the measurement shown — or, if the two genuinely conflict, it stops and reports rather than picking.


    Generated by Claude Code

  6. os-bill commented on Sep 10, 2026

    @os-bill
    Collaborator

    os-dev-report

    {
    "issue": 14910,
    "status": "done",
    "branch": "claude/issue-14910-any-position-labels",
    "pr": "#17545",
    "premise_still_valid": false,
    "summary": "Added an IndexSignatureDeclaration arm before the isFunctionLike fallback in describeAnyPosition, labelled 'index signature', so an any index signature stops being reported as return type. Settled the type-argument judgement triage placed here: shape (2) is IN SCOPE and stays flagged as return type, because the file's own docblock defines the exclusion operationally as parent.type === node on the DIRECT parent -- all three named exclusions (Record of string to any, any[], Promise of any) have parent.type === node FALSE, while a function type's return any has it TRUE. The header, the docblock and the gate's failure text now say that explicitly so the objectui port (objectui#7653) can follow it without re-deriving. PREMISE FALSIFIED: the card and the dispatch both plan around finding, measuring and regenerating a baseline whose rows the label keys -- no such artifact exists. The file states 'there is no ratchet file: the baseline is zero and stays zero', and I measured it with a lit control: packages/spec holds nine ratchet/baseline artifacts, ZERO of which name this gate, and the gate reads no accept set (its only JSON reads are two package.json reads) -- it fail()s on the first hit. The corpus re-measure the card asked for and never had: 258 marked blocks across 106 files, 3 surfaces, ZERO findings of either shape or any other, so no verdict, message or row moves. The PR is a draft; I did not flip it ready, enqueue, arm auto-merge or review it. The assignee was already set and the Claim: comment already named my branch -- I posted no second claim and never wrote the assignee.",
    "tests": "ABLATION (predicted before running, both as predicted): control self-test exit 0, 0 failing legs. A = delete the IndexSignatureDeclaration arm -> exit 1, exactly 1 failing leg, the new one: got ["6:return type","8:return type"] vs expected ["6:index signature","8:return type"]. B = narrow the function-like arm to the ANCESTRY reading (bail if any ancestor is a TypeReference) -> exit 1, exactly 1 failing leg, the new one: got ["6:index signature"] vs expected ["6:index signature","8:return type"]. B exists because shape (2) was already flagged before this PR, so a leg asserting only 'it is a finding' would pass on the broken code; B proves the boundary pin can fail. Both legs assert the LABEL STRING, since the bug is the label. ON-DISK PROOF per leg, never inferred from an editor exit code: removed-anchor grep count 1 to 0, injected-anchor count 0 to 1, non-empty git diff --stat (A: 1 insertion 1 deletion; B: 9 insertions 1 deletion), and disk blob differing from the HEAD blob (A 1b8f63a8, B 0f328d26, HEAD b7cf53d6). RESTORE per leg via git checkout HEAD -- ABSOLUTE_PATH under a trap on EXIT INT TERM, proven by blob equality (disk == head == b7cf53d6ce997f078c5739ab837e1a215fc449e7) and an empty git diff HEAD, not by an exit code. No dist is involved: the gate runs from source via tsx, so no dist preflight applies. HEAVY RUNS through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-14910, each verdict read from its own VERDICT command-exit line, never through a pipe. pnpm --filter @objectstack/spec run check:skill-examples :: exit 0 (self-test + the real 258-block corpus; re-run green on the final commit c23aa7a). pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 :: exit 0, Test Files 500 passed (500), Tests 13781 passed (13781). pnpm --filter @objectstack/spec typecheck :: exit 0, and PROVEN to reach the changed file rather than assumed -- tsconfig.json and tsconfig.test.json both include only src and list it 0 times, but the typecheck script chains check:scripts-typecheck (tsc -p tsconfig.scripts.json) whose --listFiles names scripts/check-skill-examples.ts 1 time in a 909-file program; a direct tsc --ignoreConfig --strict over the file gives 0 diagnostics with a lit control (injected const CONTROL: number = 'not a number') reddening at TS2322 and restored by blob equality. eslint . --no-inline-config --format json :: exit 0, 6586 files, 0 errors, 0 warnings, the changed file present in the run, measured at final commit c23aa7a -- the repo-wide run fit in budget so NO narrowing is claimed. GATE FAMILIES derived mechanically, never hand-listed: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (change set derived by the tool: 1 path), reconciled with --ran carrying per-command exit codes: 54 derived, 53 run green, 1 NOT-MEASURED. The one NOT-MEASURED is pnpm check:dual-build-cjs-loads :: exit 3, its own PREREQUISITE NOT MET code ('this is NOT a pass: nothing was measured') -- it reads built output and 33 packages have no dist in this worktree; declared to CI, which builds first, and NOT reported as a failing check. Re-derived after the final commit: identical 54-command list, and the ratchet-touching families re-run green on c23aa7a (check:skill-examples, check:nul-bytes, check:published-files, check:cross-package-test-inputs, check:type-check-coverage). Control characters: check:nul-bytes green plus a direct grep -naP over the changed file for the C0/DEL range, no hits.",
    "mcp_calls": "2 -- create_pull_request and this report comment. Card body and all 11 timeline items came from the zero-quota single-card page payload (hasNextPage false, edges 11 == totalCount 11, today's Claim: comment present); labels and the read-back went through repo-scoped REST after a 200 probe; everything else was git and local tooling.",
    "open_questions": [],
    "out_of_scope_findings": [
    "noted, not filed: the dispatch order and the seat's declared file face both call for a changeset; the measurement says skip-changeset. Nothing published moves -- grepping the @objectstack/spec files[] roster (dist, json-schema, liveness, prompts, llms.txt, README.md, api-surface, spec-changes.json) for a symbol from the changed file returns 0 files with the positive control HookContext lighting 34, and packages/spec/scripts/** ships in no package. .github/workflows/lint.yml names this exact case in its own words: "'this PR edits a CI-internal script' is the textbook skip-changeset case -- such a PR releases nothing, so by the workflow's own prescription it takes the label." I applied skip-changeset instead of writing a changeset, flagged it in the PR body rather than resolving it silently, and it is on the card here for the seat. 承接者: the ACCEPT seat on this card.",
    "noted, not filed: the isFunctionLike fallback also claims MethodSignature, CallSignature, ConstructSignature, FunctionType, ConstructorType and the accessors. Measured, not assumed -- all of those genuinely have a return slot, so return type is correct for each and no further arm is owed. 承接者: whoever ports this to objectui#7653.",
    "noted, not filed: my first reading of packages/spec's tsconfigs concluded that scripts/** sat outside every tsc program, which would have made 57 test files there invisible to tsc and would have been a contract violation of the AGENTS.md rule 'A package's tsconfig.json reaches every *.test.ts / *.spec.ts in it'. That reading was WRONG: tsconfig.scripts.json covers them (909 files, both the changed file and scripts/dist-freshness-adoption.test.ts present), and check:type-check-coverage passes. Recorded because it is a wrong reading a future author is likely to reach independently, not because anything is broken. 承接者: none.",
    "noted, not filed: the create-PR channel appended its own _Generated by [Claude Code](.../session_...)_ footer below the one in the body I sent, so the stored body carries two attribution footers. I left it rather than editing the body back, because an edit is a second pass through the body sanitizer on a body that read back byte-identical. 承接者: none."
    ]
    }


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions