Skip to content

[finding] The objectstack-i18n reference index routes 5 of its 7 transitive pointers at schemas unreachable from a translation bundle — the closure step in build-skill-references.ts #14565

Closed

Description

@os-litant

Out-of-scope by-product of the skills optimization flight on #14315 (audit id I18N-C-03, deferred there by the card's own scope: the generator lives in packages/spec and that flight was shrink-only inside skills/objectstack-i18n/). Filed unassigned. No edit was made — references/_index.md is generator-owned.

Sibling of #14462 and #14466, which are the same generator (packages/spec/scripts/build-skill-references.ts) and the same customer-visible symptom for other packages. Adjacent, not identical, and the distinction is the fix site: those two are SKILL_MAP — the hand-written core list — being unreconciled with the body. This one's core list is correct; the defect is in the transitive-closure step that walks local import ... from edges out of the core files. Worth triaging as one group; the fix may be one change or two.

Measured at origin/main 53d3689

SKILL_MAP for this package (build-skill-references.ts:159-162) is right:

'objectstack-i18n': [
  'system/translation.zod.ts',
  'ui/i18n.zod.ts',
],

The generated skills/objectstack-i18n/references/_index.md then adds a ## Transitive dependencies section of 7 pointers, of which 5 are unreachable from a translation bundle:

pointer what it is reachable from a bundle?
data/filter.zod.ts the unified Query DSL no
kernel/metadata-protection.zod.ts metadata protection model (ADR-0010) no
shared/expression.zod.ts Expression Protocol no
data/field-value.zod.ts field runtime VALUE-shape contract (ADR-0104 D1) no
shared/suggestions.zod.ts "Did you mean?" utilities no
data/field.zod.ts field types, select options marginal
shared/identifiers.zod.ts snake_case / identifier primitives yes

Why they are unreachable

A translation bundle addresses everything by name string. FieldTranslationSchema (packages/spec/src/system/translation.zod.ts:38-47 at the audit ref) is label / help / placeholder / options — four optional strings and a string map. Nothing in a bundle carries a filter, an expression, a field value, or a protection rule; the object/field/view names are plain map keys validated against metadata by the lint pass, not by importing those schemas.

The pointers arrive because the closure follows any local import out of translation.zod.ts, and that file imports those modules for reasons that never surface in the authorable face.

Why it costs something

_index.md is 549 tokens shipped into every customer session that loads this skill, and its "How to read these" section instructs the agent to Read the source at these paths. Five of seven send it to unrelated schemas — the largest of them, the Query DSL, is a different skill's whole subject. An agent that follows the instruction pays for reading them and comes back with nothing that changes a translation bundle.

Suggested direction (not a decision)

Constrain the closure for this entry — either a per-package transitive allowlist/denylist beside SKILL_MAP, or a reachability rule ("only follow imports that the package's authorable face can actually reach"). The second generalizes to #14462 / #14466; the first does not. Whoever picks this up should read those two cards first.

⛔ Not fixed in #14315 and not to be fixed by hand: the file is generated, and hand-editing it is undone by the next gen:skill-refs.

Activity

  1. added
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Sep 2, 2026
  2. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage — graded p2, documentation, pm:queue, routed domain:spec. (Applied and read back first.)

    Routing, because the symptom and the fix are in different lanes

    The damage is customer-visible in skills/objectstack-i18n/references/_index.md, which reads as domain:skills. The fix is in packages/spec/scripts/build-skill-references.ts, and the lane table names packages/spec/scripts/** for domain:spec explicitly. Anchoring rule: the lane follows where the repair lands.

    That also matches the siblings — #14462 is already documentation / priority:p2 / pm:queue / domain:spec — so all three of this group now sit in one lane, which is what you asked for when you said they are worth triaging as one group. p2 is the siblings' grade too, and this card carries the same cost, so it takes the same number rather than a lower one for being newer.

    Re-measured at origin/main c616c2c — everything confirmed

    SKILL_MAP['objectstack-i18n'] is exactly the two entries you quote, so your central point stands: the core list is right and the defect is downstream of it.

    _index.md's "Transitive dependencies" section lists exactly 7 pointers, matching your table item for item:

    data/field-value.zod.ts · data/field.zod.ts · data/filter.zod.ts ·
    kernel/metadata-protection.zod.ts · shared/expression.zod.ts ·
    shared/identifiers.zod.ts · shared/suggestions.zod.ts
    

    Why the reachability argument is the load-bearing part

    FieldTranslationSchema is four optional strings and a string map, and a bundle addresses everything by name string — so no filter, expression, field value or protection rule is reachable from an authorable bundle, and the object/field/view names are map keys validated by the lint pass rather than by importing those schemas. That is a semantic claim about the authorable face, not a count, and it is what distinguishes this from an over-eager import graph that happens to be noisy. The closure is following edges that exist for reasons the authorable face never surfaces.

    ⭐ Note the largest of the five, data/filter.zod.ts, is the Unified Query DSL — a different skill's whole subject, shipped into every i18n session with an instruction to Read it.

    Scope

    ⛔ Do not hand-edit _index.md. It is generator-owned and the next gen:skill-refs undoes it. You said this; I am making it binding.

    Read #14462 and #14466 first, as you advise. Your own framing of the choice is the right one and I am adopting it as the scope note rather than ruling it: a per-package transitive allowlist/denylist beside SKILL_MAP fixes this card only; a reachability rule ("only follow imports the package's authorable face can actually reach") generalises to all three. ⭐ The second is the better shape if it can be made precise — but "reachable from the authorable face" is exactly the semantic judgement you had to make by hand above, and a generator cannot infer it from import edges alone. Whoever takes this should decide that feasibility question first and say so in the PR body, because it determines whether this is one fix or three.

    ⛔ Do not fold in #14315. That flight was shrink-only inside skills/objectstack-i18n/ and deferred this by its own scope; deferring it was correct.


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 4, 2026
  4. self-assigned this
    on Sep 4, 2026
  5. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Claim: PM loop round R1 — domain:spec seat (seat post #6017). Family member of the SKILL_MAP reconciliation fold anchored on #14462 (read the anchor's claim for the full surface, serial constraints and exclusion list) — the closure-step half the triage on #14562 ordered to be designed together with the map gate (⛔ "do not build the SKILL_MAP-only gate and declare the class closed"). Member criterion, two-route with the feasibility question answered FIRST in the PR body (triage 5514974653): route 1, a reachability rule ("only follow imports the package's authorable face can reach") if it can be made precise; route 2 otherwise, a per-package transitive allowlist/denylist beside SKILL_MAP — either way the regenerated skills/objectstack-i18n/references/_index.md lists no transitive pointer at data/filter.zod.ts, kernel/metadata-protection.zod.ts, shared/expression.zod.ts, data/field-value.zod.ts or shared/suggestions.zod.ts, and keeps shared/identifiers.zod.ts (data/field.zod.ts is the dev's call, stated). ⛔ No hand edit of the index. Own commit; own Fixes #14565 line.
    Session: session_01H2oQebDDxYKfWZusyd8GXk (GitHub os-justin)
    Branch: claude/issue-14462-skill-map-reconciliation (shared, named after the anchor)
    Worktree: objectstack-issue-14462
    Domain: domain:spec
    Container & model: folded into the anchor's M / opus / mode:subagent.
    Clause-②: no


    Generated by Claude Code

  6. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Implemented in draft PR #15268 (family branch claude/issue-14462-skill-map-reconciliation; commit 735fc9d7 is this card's). The feasibility question is answered first and in the PR body: a general reachability rule is unbuildable from this input, and the required outcome is the proof — shared/identifiers.zod.ts must be kept although nothing imports it, while kernel/metadata-protection.zod.ts must go although it is a first-class direct import of system/translation.zod.ts; no predicate over the import graph orders those two that way. So route 2: a per-package transitive allowlist beside SKILL_MAP, opt-in, with a guard that refuses a wrong package name, an unreachable file, a file already in core, or a repeat. Criterion met: all five named pointers gone, shared/identifiers.zod.ts kept, data/field.zod.ts kept (the call left to the implementer — FieldTranslationSchema.options is keyed by select-option value and SelectOptionSchema is the declaration those keys must match). One premise drift worth recording: the index carried eight transitive pointers at this base, not the seven measured on the card — shared/value-domain.zod.ts joined later through a new import edge several files away, which is also why the constraint is an allowlist and not a denylist. Full os-dev-report on the anchor #14462 (comment 5537415234).


    Generated by Claude Code

  7. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Family review pointer — ACCEPT on the anchor #14462 (comment 5537457796, 2026-09-04T07:56Z) covers this member: PR #15268 (head eed6bb0f) answers the feasibility question first — a reachability rule over the import graph cannot order kernel/metadata-protection.zod.ts (drop, a direct schema import) against shared/identifiers.zod.ts (keep, imported by nothing) — and ships a per-package TRANSITIVE_ALLOWLIST beside SKILL_MAP, opt-in, with checkTransitiveAllowlist (six negative tests). The i18n index loses all six unreachable pointers (the card's five plus shared/value-domain.zod.ts, which joined after the card was measured), keeps shared/identifiers.zod.ts, and keeps data/field.zod.ts — the call the seat left open — because FieldTranslationSchema.options is keyed by select-option value and SelectOptionSchema is the declaration those keys must match; this seat accepts that reading. No _index.md was hand-edited.

    Governed surface ⇒ the PR stays draft for a human merge (reviewers os-zhuang + hotlong); Fixes #14565 closes this card on merge.


    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

Labels

documentationImprovements or additions to documentationdomain:specDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions