Record the language service as permanently second-language-only - #2
Merged
Conversation
`idf-language-service` joins the ledger at tier `never`, absent in the first language with `absence_kind = "never"`, complete in the second. The note says why: the answers are computed from byte offsets into the source text, and a second implementation of that arithmetic is the drift surface the corpus is least able to police, since it compares findings on (code, line, typeName) and never on a column. It also says what the absence costs a reader, which is that these answers need a JavaScript runtime. `not-yet` was considered and rejected. That state requires a real tracking issue, and opening one for a port nobody intends would pass the gate and dead-link the reader. `never` is terminal, which is exactly the guarantee wanted: a counterpart cannot be added without amending the constitution first. Twenty-five names are registered ahead of their implementation, one entry each rather than one entry for the surface. The eppy and local-simulation exclusions are quotations from one ecosystem; these are names either language could have spelled, so each is written down and each blocks its own counterpart. The `column` divergence is registered too. It is not a name this change introduces, and that is the point: two names that already look identical mean different things, code points in one language and UTF-16 code units in the other, and an unregistered divergence is indistinguishable from drift. `governs` gains `@idfkit/language`, without which the naming gate would not know to hold the new package's surface against anything. The corpus level does not move. This adds no cases.
This was referenced Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the
idf-language-servicecapability to the parity ledger and the names it introduces to the naming register, so that the gate accepts the surfaceidfkit-jsis about to publish.This lands first and alone, and the sequencing is a constitutional rule rather than a preference.
check-naming-register.mjsreads the.d.tsfiles each package'sexportsmap points at, so the change that addsscanIdfto@idfkit/coreand publishes@idfkit/languageis the change that puts every new name in scope. Landing the code before this means landing it red.The ledger entry
tier = "never",python = "absent",typescript = "complete",absence_kind = "never", no tracked item.browser-simulationis the standing precedent for a capability complete in one language, absent in the other, and carrying no corpus cases.The reason is on the entry. The answers are computed from byte offsets into the source text, and a second implementation of that arithmetic is the drift surface the corpus is least able to police: it compares findings on
(code, line, typeName)and never on a column, so two implementations could disagree about a position for a long time with no gate noticing. The editor extension needs no port either, because its existing Python server keeps serving Python source while a second server serves IDF text.neveris terminal, and that is the point. Moving off it needs a constitutional amendment rather than an edit, which is the strength at which this decision was made. Anot-yetwas considered and rejected: the gate requires a real tracking issue for everynot-yet, and opening one for a port nobody intends in order to satisfy a gate is exactly what the file's own header warns against.The register entries
One
[[entry]]per name,python = "",kind = "excluded", mirroring the existing eppy entry.@idfkit/languageis added to[register] governs, which today reads["idfkit", "@idfkit/core", "@idfkit/weather"], or the gate would not know to hold the new package's surface against anything.Also here, and not a name this feature introduces:
column in a findingis registered asdivergent. Python string indices are code points and JavaScript's are UTF-16 code units, so the two agree below the astral planes and differ above them, which in practice means an emoji in a comment. Harmless today because a column is never compared, and registered because an unregistered divergence is indistinguishable from drift.Two deviations from the contract, both deliberate
The
nameslist carries 25 concepts, not the 7contracts/governance-entries.mdgives.check-parity-ledger.mjsraisesE-UNREGISTEREDfor any name a scanned package exports that no capability claims.@idfkit/coreexports ten names for this feature, so eight of them would have tripped it the moment the layer landed, and no later task adds them. The contract is what is out of date here, not the file.positionwas added after the fact. The contract's "position findings" concept binds tofindingsInonly, andpositionis exported separately so a consumer holding findings from its own run can attach regions without a second parse. The naming gate caught it at 135 of 136; it is now 136 of 136.ProsePoolis registered too.@idfkit/coredeclares it but does not re-export it, andexplainAtcannot name itsproseparameter without that export.The corpus level does not move
conformance-2026.8stays as it is. A capability that exists in one language asserts no cross-language agreement, so there is nothing for the corpus to compare and no case is added. The two tag series are separate precisely so a naming change does not force a corpus release.Verification
idf-language-servicedoes not appear in the "no statically checkable TypeScript name" list, which is what SC-014 asked to confirm: a capability with zero corpus cases does not read as an unproven claim.Before merge, and after
This needs the CODEOWNERS review from a maintainer of the Python side.
governance-2026.11is deliberately not pushed with this branch. The tag must be cut frommainafter this merges, pergovernance/README.md; a tag cut from a branch points at a commit that changes under a squash-merge. Two repositories already pingovernance-2026.11and their CI cannot resolve it until that tag exists onmain, so the order is: merge this, cut and push the tag, then the other two PRs go green.