Skip to content

Migrate fjs/sul, fjs/media/html, fjs/crypto/sign, fjs/types/rtti to .f.mjs - #1485

Merged
sergey-shandar merged 20 commits into
mainfrom
claude/convert-f-ts-to-f-mjs-8
Aug 11, 2026
Merged

Migrate fjs/sul, fjs/media/html, fjs/crypto/sign, fjs/types/rtti to .f.mjs#1485
sergey-shandar merged 20 commits into
mainfrom
claude/convert-f-ts-to-f-mjs-8

Conversation

@sergey-shandar

@sergey-shandar sergey-shandar commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates four modules from authored TypeScript (.f.ts) to JSDoc-typed
JavaScript (.f.mjs) under the stage-1 TypeScript-to-mjs migration
(todo/migrate-typescript-to-mjs.md), following the types.ts
convention introduced by #1481/#1483:

  • fjs/sul — splits EncodeState<S>/Encode<S> into types.ts.
    No other module imports it; only README.md's example updates.
  • fjs/media/html — splits Element/Node into types.ts.
    Updates the sole dependent, fjs/website.
  • fjs/crypto/sign — splits the All type into types.ts. No
    other module imports it. Its 592-line proof is mostly RFC6979 test
    vectors.
  • fjs/types/rtti — splits the full schema type-level API (Const,
    Type, Tag0, Tag1, Info0, Info1, Type0, Type1,
    MakeType1, Boolean, Number, String, Bigint, Unknown,
    Array, Record, Or, Struct, Tuple, ConstObject, Primitive0)
    into types.ts. Updates 19 dependents across protocol/mcp,
    protocol/json_rpc, dev/package_json, ci/common, media/json,
    media/json/schema, media/revision, media, mcp/evo, mcp/cas,
    mcp, emergent_testing, and rtti's own common/parse/validate/ts
    submodules. Note: TypeScript's JSDoc parser special-cases the
    identifiers Boolean/Number/String as aliases for the primitive
    types (a legacy Closure Compiler convention), so the three runtime
    consts of those names rely on inference rather than an explicit
    @type annotation naming the colliding type.

Also fixes stale todo/ doc links to paths this PR renamed, including
several flagged in review for the fjs/sul/fjs/media/html migrations.

Test plan

  • npx tsc --noEmit — clean, 0 errors, matching main
  • node ./fjs/module.ts t — all 2356 tests pass, 0 failures
  • CHANGELOG.md updated with a **BREAKING CHANGES:** entry for each
    of the four migrations

claude added 2 commits August 11, 2026 03:07
Splits the EncodeState<S>/Encode<S> types into a sibling types.ts, and
converts the runtime implementation (emptyEncodeState, encode) to
JSDoc-typed module.f.mjs/proof.f.mjs under the stage-1 TypeScript-to-mjs
migration. No other module imports fjs/sul/module.f.ts, so updates only
touch the README.md example.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
functionalscript b57d53a Commit Preview URL

Branch Preview URL
Aug 11 2026, 04:58 AM

claude added 2 commits August 11, 2026 03:11
Splits the Element/Node types into a sibling types.ts, and converts
the runtime implementation (element, html, htmlToString, htmlUtf8) to
JSDoc-typed module.f.mjs/proof.f.mjs under the stage-1
TypeScript-to-mjs migration. Updates the sole dependent,
fjs/website/module.f.ts, to import from the .f.mjs specifier, and
fixes a stale line reference in fjs/text/todo/190.md.
Splits the All type into a sibling types.ts, and converts the runtime
implementation (all, fromCurve, concat, computeK, sign) to JSDoc-typed
module.f.mjs/proof.f.mjs under the stage-1 TypeScript-to-mjs migration.
No other module imports fjs/crypto/sign/module.f.ts; fixes three stale
doc references in fjs/crypto/sign/todo and fjs/crypto/todo.

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 3024c8c against main (cbcc7ab). Three modules now — fjs/sul, fjs/media/html, fjs/crypto/sign. The migrations themselves are clean; one recurrence of the stale-link issue from #1484.

Runtime logic is provably unchanged

crypto/sign carries RFC6979 deterministic nonce generation, so "looks equivalent" isn't good enough. I compared main's compiled JavaScript (module.f.js from prepack) against the authored module.f.mjs on this branch, normalizing only the things TypeScript's emitter adds or an annotation removes — semicolons, and the parens left behind by dropped as const/type annotations:

TOKEN-IDENTICAL runtime: fjs/crypto/sign
TOKEN-IDENTICAL runtime: fjs/sul
TOKEN-IDENTICAL runtime: fjs/media/html

All three are token-for-token identical. The large computeK hunk in the diff is entirely re-indentation from the arrow chain changing shape — no expression moved.

Also verified

  • npx tsc clean; 2356 pass / 0 fail.
  • Public type surface: 0 removed, 0 changed. No any as a type anywhere in the emitted declarations.
  • The _ prefix convention was applied on its own this time_Attributes, _HashState, and _Signature were all non-exported type declarations on main and all carry the prefix here. That is the Byte/NodeList class of issue not recurring, which is the outcome I was hoping for.
  • CHANGELOG has entries for all three, and their claims check out: media/html/types.ts does export Element/Node, sul/types.ts does export EncodeState/Encode.
  • Both new .f.mjs proofs import only .f.mjs runtime modules, so they satisfy §2 — no repeat of the revert that #1484 needed.
  • The crypto/sign commit updated its own todo/ docs in the same change. That is the right instinct; it just wasn't applied to the other two.

Three doc references to files this PR renames are stale

Same check as last time — main has 49 broken references, this head has 52, and the three added are yours:

Stale reference Now Where
fjs/sul/module.f.ts module.f.mjs fjs/cas/todo/strategy-3-merkle-tree.md:61
fjs/sul/proof.f.ts proof.f.mjs fjs/emergent_testing/todo/65y-proof-asserteq-adoption.md:30,141, fjs/sul/todo/id-prefix-tag-factory.md:56, todo/camel-case-proof-keys.md:17
fjs/media/html/module.f.ts module.f.mjs fjs/text/sgr/todo/csi-edsl.md:6, fjs/media/nix/todo/serializer-validation-split.md:82

65y-proof-asserteq-adoption.md:141 is the same half-updated-line shape as last time, now from the other side: it reads fjs/sul/proof.f.ts:1, fjs/sul/level/hash/proof.f.mjs:1 — the hash half was fixed in #1484 and the sul half on the same line is now stale.

Since this is the second PR in a row, it may be worth a one-line grep in the migration checklist — grep -rn 'old/path\.f\.ts' --include='*.md' . after each rename — rather than catching it in review each time.

Minor

The summary describes only fjs/sul; fjs/media/html and fjs/crypto/sign arrived after it was written. The CHANGELOG covers all three correctly, so this is just the PR body.


No correctness objection — happy to approve once the three references are updated.

Splits the full type-level API (Const, ConstObject, Struct, Tuple,
Primitive0, Tag0, Info0, Type, Type0, Boolean, Number, String, Bigint,
Unknown, Tag1, Info1, Type1, MakeType1, Array, Record, Or) into a
sibling types.ts, and converts the runtime implementation (tag0List,
boolean, number, string, bigint, unknown, isTag1, array, record, or,
option, never) to JSDoc-typed module.f.mjs/proof.f.mjs under the
stage-1 TypeScript-to-mjs migration. TypeScript's JSDoc parser
special-cases the identifiers Boolean/Number/String as aliases for the
primitive types (a legacy Closure Compiler convention), so those three
exported consts rely on inference from type0() rather than an explicit
@type annotation naming the colliding type.

Updates all 19 dependents (protocol/mcp, protocol/json_rpc,
dev/package_json, ci/common, media/json, media/json/schema,
media/revision, media, mcp/evo, mcp/cas, mcp, emergent_testing, and
rtti's own common/parse/validate/ts submodules) to import runtime
values from module.f.mjs and types from types.ts.

Also addresses stale todo/ doc links flagged in review for the
previous three migrations in this PR (fjs/sul, fjs/media/html) plus
three more found for fjs/types/rtti itself.
@sergey-shandar sergey-shandar changed the title Migrate fjs/sul to .f.mjs, split types into types.ts Migrate fjs/sul, fjs/media/html, fjs/crypto/sign, fjs/types/rtti to .f.mjs Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the token-diff verification — great to have that confirmed independently.

All three stale references fixed in 936ce34, plus a fourth module (fjs/types/rtti) landed in the same commit:

  1. fjs/sul/module.f.tsmodule.f.mjs in fjs/cas/todo/strategy-3-merkle-tree.md.
  2. fjs/sul/proof.f.tsproof.f.mjs in fjs/emergent_testing/todo/65y-proof-asserteq-adoption.md (both halves of that line, including the one you flagged as half-updated), fjs/sul/todo/id-prefix-tag-factory.md, and todo/camel-case-proof-keys.md.
  3. fjs/media/html/module.f.tsmodule.f.mjs in fjs/text/sgr/todo/csi-edsl.md and fjs/media/nix/todo/serializer-validation-split.md.

Also refreshed the PR title/summary to cover all four migrated modules, and took your suggestion — worth checking grep -rn '<old-path>\.f\.ts' --include='*.md' . for each renamed path as part of the migration steps going forward rather than relying on review to catch it.

tsc --noEmit stays clean (0 errors) and all 2356 tests pass.


Generated by Claude Code

claude added 2 commits August 11, 2026 03:44
Splits the full Ts<T> type-transformer API (Primitive, Unknown, Array,
Object, Info0Ts, ConstTs, Info1Ts, ArrayTs, RecordTs, TupleTs, StructTs,
Ts) into a sibling types.ts, and converts the sole runtime export
(printer) to JSDoc-typed module.f.mjs/proof.f.mjs under the stage-1
TypeScript-to-mjs migration.

Updates 11 dependents (protocol/mcp, protocol/json_rpc,
dev/package_json, ci/common, media/json, media/json/schema,
media/revision, media, emergent_testing, and rtti's own
common/parse/validate submodules) to import the Ts type from types.ts.
All were type-only imports of Ts/Unknown, so no runtime specifier
changes were needed beyond the import path.

Fixes two stale doc references to fjs/types/rtti/ts/module.f.ts and
proof.f.ts.
Splits the shared kernel's type-level API (Path, ValidationError,
Result, Validate, Visitor, IsContainer, Container, ResultE, ValidateE)
into a sibling types.ts, and converts the runtime implementation
(verror, prependPath, primitive0Validate, constPrimitiveValidate,
isArray, isObject, eachEntry, orVisit, visit) to JSDoc-typed
module.f.mjs/proof.f.mjs under the stage-1 TypeScript-to-mjs migration.

Updates the three dependents (rtti/validate, rtti/parse,
media/json/schema) to import runtime values from module.f.mjs and
types from types.ts, splitting mixed import/export statements where
needed. Fixes three stale doc references.

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 93fdc6e. The three stale references from my last pass are fixed, and this round introduces nonemain and this head have the same 49 broken doc refs, so the rename sweep is now clean. Six modules migrate here.

Runtime logic is unchanged

Same method as before — main's compiled module.f.js versus the authored module.f.mjs, normalizing only semicolons and annotation-parens:

TOKEN-IDENTICAL: fjs/crypto/sign
TOKEN-IDENTICAL: fjs/sul
TOKEN-IDENTICAL: fjs/media/html
TOKEN-IDENTICAL: fjs/types/rtti
TOKEN-IDENTICAL: fjs/types/rtti/ts
DIFFERS:         fjs/types/rtti/common

The one difference is worth calling out because it is the migration working as designed, not a defect. main's emit begins with import {} from '../module.f.js'; — a bare side-effect import left behind because rtti/common/module.f.ts imported types from ../module.f.ts. Now those come through /** @import … from '../types.ts' */, so the runtime edge is gone. Strip that single import from main's emit and the two files are byte-identical. That is exactly the "type-only edge the migration wants gone" from #1483, and it is unobservable here since these modules are pure.

npx tsc clean, 2356 pass / 0 fail, no any as a type in any emitted declaration, public surface 0 removed.

1. Primitive0, Tag0, and Tag1 are no longer tied to their runtime lists

On main these were derived, so the list was the single source of truth:

const primitive0List = ['bigint', 'boolean', 'number', 'string'] as const
export type Primitive0 = typeof primitive0List[number]
export const tag0List = [...primitive0List, 'unknown'] as const
export type Tag0 = typeof tag0List[number]
const tag1List = ['array', 'record'] as const
export type Tag1 = typeof tag1List[number]

In types.ts they are now hand-written unions, while the lists stay in module.f.mjs. They agree today, so nothing is broken — but the guarantee that they must agree is gone. I tested it rather than assuming, in clean trees (an earlier attempt of mine was contaminated by prepack artifacts shadowing the .mjs with its .d.mts, so these numbers are from trees with no emitted files). Adding 'symbol' to primitive0List:

Tree Errors after the edit
main 2 — the type follows the list
this branch 0 — the type does not

Both baselines are 0. My probe is a Assert<Equal<…>> that I negative-controlled first: asserting a deliberately false equality yields 2 errors, so silence means agreement rather than a probe that never ran.

Two fixes, both of which I verified compile and restore the guarantee:

  • Tag0 is a one-liner, since tag0List is already exported. import type { tag0List } from './module.f.mjs' in types.ts, then export type Tag0 = typeof tag0List[number]. Baseline stays clean; the 'symbol' edit goes back to 2 errors. This is the same type-only import back into module.f.mjs that fjs/asn.1 already does.
  • Primitive0/Tag1 can't do that without exporting their lists, so instead pin them from inside module.f.mjs, which can see them:
/** @typedef {Assert<Equal<Primitive0, typeof primitive0List[number]>>} _Primitive0Pinned */
/** @typedef {Assert<Equal<Tag1, typeof tag1List[number]>>} _Tag1Pinned */

Clean at baseline; drifting tag1List produces Type 'false' does not satisfy the constraint 'true'.

Worth noting this also confirms /** @type {const} */ ([…]) is behaving as a real as const — otherwise the derived form would not have matched the literal union at baseline.

2. Type0 and MakeType1 are newly public without the _ prefix

Both were non-exported on main (type Type0<T extends Tag0>, type MakeType1<K extends Tag1>) while appearing in the signatures of exported values like array: MakeType1<'array'>. They are now exported from types.ts unprefixed.

This is the Byte/NodeList case again, and the reason I raise it rather than assume it's deliberate is that the same PR gets it right five times — _Attributes, _HashState, _Signature, _Tests, _Entries all carry the prefix. So the convention was applied, just not to these two.

If Type0 is meant to be public now — it is documented and every exported Boolean/Number/String alias is built from it — that is a defensible call; it just deserves to be intentional rather than a side effect of the move.


No correctness objection; CI is green on the earlier commits and still running here. Happy to approve once these are settled.

claude added 2 commits August 11, 2026 03:54
Converts module.f.ts to JSDoc-typed module.f.mjs under the stage-1
TypeScript-to-mjs migration. This module has no new public types of
its own (only re-exports from rtti/common), so no types.ts companion
is needed. proof.f.ts stays TypeScript: it has a type-only dependency
on djs's still-unmigrated Unknown type, and AGENTS.md requires such a
type to be split into a types.ts before a migrated .f.mjs consumer can
reference it — out of scope here.

Updates the six dependents (protocol/mcp, protocol/json_rpc x2,
dev/package_json, media, media/revision) to import validate from
module.f.mjs and the re-exported types (Validate, ValidationError)
directly from rtti/common/types.ts. Fixes two stale doc references.
Tag0 was hand-copied from tag0List rather than derived, silently
dropping the compile-time guarantee that the union and the runtime
list agree. Restores it via `export type Tag0 = typeof tag0List[number]`,
importing the now-exported tag0List type-only from module.f.mjs (same
pattern fjs/asn.1 already uses). Primitive0 and Tag1 can't do the same
since their backing lists (primitive0List, tag1List) aren't exported,
so instead pins them from inside module.f.mjs, which can see the
lists, via `Assert<Equal<Primitive0, typeof primitive0List[number]>>`
and the Tag1 equivalent. Verified both catch drift: adding a bogus
'symbol' literal to primitive0List reproduces the same 2-error count
main's derived form produces, confirming the guarantee is restored
rather than silently absent.

Also renames Type0 and MakeType1 to _Type0/_MakeType1: both were
non-exported on main despite appearing in exported signatures
(array: MakeType1<'array'>), the same private-type-goes-public case as
Byte/NodeList in earlier commits.

Copy link
Copy Markdown
Contributor Author

Great catch on the derived-type guarantee — thanks for negative-controlling it too. Both fixed in 439cf51, exactly as suggested:

  1. Tag0 now derives from tag0List via export type Tag0 = typeof tag0List[number], importing the type type-only from module.f.mjs (the fjs/asn.1 pattern). Primitive0/Tag1 are pinned from inside module.f.mjs via Assert<Equal<Primitive0, typeof primitive0List[number]>> and the Tag1 equivalent, since their lists aren't exported. Verified both catch drift the same way you did: adding a bogus 'symbol' to primitive0List reproduces the same 2-error count main's derived form produces (confirmed, then reverted the probe).
  2. Type0/MakeType1_Type0/_MakeType1 — same case as Byte/NodeList in earlier commits.

tsc --noEmit stays clean (0 errors) and all 2356 tests pass.


Generated by Claude Code

claude added 6 commits August 11, 2026 04:00
Splits the Result<T>/Parse<T> types into a sibling types.ts, and
converts the runtime implementation (parse, and the container/const
builders it composes) to JSDoc-typed module.f.mjs under the stage-1
TypeScript-to-mjs migration. proof.f.ts stays TypeScript: it has a
type-only dependency on djs's still-unmigrated Unknown type, same as
rtti/validate/proof.f.ts.

Updates the four dependents (ci/common, mcp, mcp/evo,
emergent_testing) to import parse from module.f.mjs. Fixes two stale
doc references.
Splits the type-level API (Os, Architecture, Image, Step, Job, Jobs,
GitHubAction, StepType, MetaStep) into a sibling types.ts, and
converts the runtime implementation (os, architecture, stepSchema,
jobSchema, jobsSchema, gitHubActionSchema, parseGitHubAction, uses,
install, test, toSteps, ubuntu, ubuntuArm) to JSDoc-typed
module.f.mjs under the stage-1 TypeScript-to-mjs migration.

Updates the nine dependents (fjs/ci itself, and its node/rust/deno/bun/nix
submodules) to import runtime values from module.f.mjs and types from
types.ts. Fixes five stale doc references in fjs/ci/todo and AGENTS.md.
Converts module.f.ts to JSDoc-typed module.f.mjs under the stage-1
TypeScript-to-mjs migration; no public types, no proof file. Updates
the sole dependent, fjs/ci/module.f.ts, to import from the .f.mjs
specifier (missed by an initial substring grep since the relative
import path './bun/module.f.ts' doesn't repeat the 'ci' directory
name — caught via tsc and an exhaustive resolved-path scan). Fixes
three stale doc references.
Converts module.f.ts and proof.f.ts to JSDoc-typed module.f.mjs and
proof.f.mjs under the stage-1 TypeScript-to-mjs migration; no public
types. Updates both dependents (fjs/ci/module.f.ts, fjs/ci/proof.f.ts)
to import from the .f.mjs specifier. Fixes five stale doc references.
Converts module.f.ts to JSDoc-typed module.f.mjs under the stage-1
TypeScript-to-mjs migration; no public types, no proof file. Updates
the sole dependent, fjs/ci/module.f.ts, to import from the .f.mjs
specifier. Fixes six stale doc references.
Splits the Expression type and its private helper types (Binding,
Reference, AttributeSet, NixList, Application, OpenSetPattern, Lambda,
Let, IndentedString, AttributePath, Chunks — all _-prefixed as private
cross-file types) into a sibling types.ts, and converts the runtime
serializer (nix, nixToString, and the internal serialize* helpers) to
JSDoc-typed module.f.mjs/proof.f.mjs under the stage-1
TypeScript-to-mjs migration.

Updates the sole dependent, fjs/ci/nix/module.f.ts, to import
nixToString from module.f.mjs and Expression from types.ts. Fixes
three stale doc references.

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Reviewed at b174648 against main (cbcc7ab). Thirteen modules.

Both prior findings are fixed, and the fix demonstrably works

439cf51 restores the derived-type guarantee and applies the prefixes. I re-ran the drift test rather than reading the diff — clean tree, no prepack artifacts:

Edit Result
add 'symbol' to primitive0List 2 errors_Primitive0Pinned and the _AssertType in types.ts both fire
add 'tuple' to tag1List 1 error_Tag1Pinned fires

Baseline is clean, so the lists and the types can no longer drift apart silently. Tag0 is back to typeof tag0List[number] via the type-only import, and Type0/MakeType1 are now _Type0/_MakeType1.

Runtime logic across all thirteen modules

main's compiled module.f.js versus each authored module.f.mjs:

equivalent: 13   differing: 0

I discount only four things, each an artifact of the migration rather than a change: elided type-only imports (the bare import {} from … TypeScript leaves behind), .f.js.f.mjs specifiers for modules co-migrated in this PR, trailing commas, and parens left by removed annotations. To make sure that normalization isn't so permissive as to be meaningless, I checked it two ways: it still reports ci/bun and ci/deno as different modules, and injecting a one-token change (--release--debug in ci/rust) is caught.

Also verified

  • npx tsc clean; 2356 pass / 0 fail.
  • Public type surface: 0 removed. 22 additions, every one _-prefixed — the convention is now being applied without prompting, including on the new media/nix split.
  • The nine changed entries are all benign: Boolean/Number/String/Bigint/Unknown differ only by the Type0_Type0 rename, Expression only because its constituents gained the prefix, Primitive0/Tag1 are the intended re-derivation, and _Merge is my by-name comparison seeing btree's _Merge<A, T> alongside sul's unrelated module-scoped _Merge.
  • No any as a type in any emitted declaration.
  • Doc references are clean — 43 broken on main, 43 here, none added. The media/nix, rtti, and ci commits each swept their own todo/ files as they went, which is the habit that closes this out.

One nit

The two newest CHANGELOG entries name the pre-migration file — "fjs/types/rtti/parse/module.f.ts migrates from…" — where the sibling entries in the same section name the module (fjs/types/object, fjs/ci/common). Naming the old path is defensible for a migration note; it is only an inconsistency within one section, and not worth a commit on its own.

To be explicit about one thing my sweep flags that should not be changed: CHANGELOG.md:377 references fjs/ci/common/module.f.ts inside the released 0.39.0 section. §8.3 says not to rewrite released sections from an unrelated PR, so leaving it is correct.

CI is green on the earlier commits and still finishing on b174648; I verified locally at b174648 directly.

Splits the type-level API (TerminalRange, Sequence, Variant, DataRule,
LazyRule, Rule, RangeVariant, None, Option, Repeat0Plus, Repeat1Plus,
Join1Plus, Join0Plus, Repeat) into a sibling types.ts, and converts
the runtime implementation (rangeEncode, oneEncode, eof, fullRange,
unicodeRange, unicodeMax, rangeDecode, toSequence, str, set, range,
remove, not, notSet, none, option, repeat0Plus, repeat1Plus,
join1Plus, join0Plus, commaJoin0Plus, repeat, isEmpty) to JSDoc-typed
module.f.mjs under the stage-1 TypeScript-to-mjs migration.
proof.f.ts and testlib.f.ts stay TypeScript: proof.f.ts has a runtime
dependency on testlib.f.ts, which is a shared test-fixture library
(not itself a proof/module file) still authored in TypeScript.

Updates the nine other dependents (bnf/token_symbol, bnf/descent
module+proof, bnf/ll1 module+proof, bnf/data module+proof,
djs/tokenizer, fsc/json.f.ts, fsc/bnf.f.ts) to import runtime values
from module.f.mjs and types from types.ts, splitting mixed
import statements where needed. Fixes eleven stale doc references.

Copy link
Copy Markdown
Contributor Author

Thanks for the approval and the thorough runtime-equivalence verification across all thirteen modules! Noted the CHANGELOG naming nit for future entries.

Landed one more module since your review — fjs/bnf/module.f.ts (5941c98), splitting its type-level API into types.ts. Its proof.f.ts and the shared testlib.f.ts test-fixture library stay TypeScript since they depend on each other and testlib.f.ts isn't itself a module/proof file. tsc --noEmit stays clean and all 2356 tests pass.


Generated by Claude Code

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5941c986a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

export type Image = typeof images[Os][Architecture]

export const stepSchema = {
export const stepSchema = /** @type {const} */ ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve readonly schema properties in declaration emit

Preserve the previous readonly object shape when migrating these exported schemas. During declaration emit, this @type {const} form becomes an exported namespace whose properties are mutable (stepSchema.run = stepSchema.run type-checks), whereas the former .f.ts declaration rejected assignment because every property was readonly; gitHubActionSchema has the same regression. This weakens the public API for package consumers despite runtime behavior being unchanged.

AGENTS.md reference: AGENTS.md:L449-L454

Useful? React with 👍 / 👎.


A function-free, serializable representation of `Type` in
[`fjs/types/rtti/module.f.ts`](../module.f.ts), modeled after
[`fjs/types/rtti/module.f.mjs`](../module.f.ts), modeled after

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Point migrated documentation links at the new files

Update the Markdown target along with the displayed filename: this link still resolves to the deleted module.f.ts. The same stale destination appears in fjs/bnf/todo/bigint-symbols.md:267, terminal-range-representation.md:100, and unicode-rules.md:183; additionally, fjs/types/rtti/README.md:47 still tells readers to import the removed RTTI entry point, so following these migration docs now leads to missing files.

Useful? React with 👍 / 👎.

Several earlier commits updated a link's visible label text
([`fjs/bnf/module.f.mjs`]) but not its href, since the sed patterns
matched the label's fuller path but not the relative href (e.g.
../module.f.ts, which lacks the bnf/ prefix the label carries) —
the same relative-path substring-miss pattern that has recurred
throughout this migration. Fixes all four affected links (three in
fjs/bnf/todo, one in fjs/types/rtti/todo) plus fjs/types/rtti/README.md's
code example, which still imported from the removed module.f.ts/
validate/module.f.ts/ts/module.f.ts entry points. Verified with a
repo-wide scan for the [`*.f.mjs`](*.f.ts) mismatch pattern: none remain.

Copy link
Copy Markdown
Contributor Author

Checked both findings:

  1. stepSchema/gitHubActionSchema readonly claim — false positive. Verified two ways: a direct assignment (stepSchema.run = stepSchema.run) gives TS2540: Cannot assign to 'run' because it is a read-only property, and the actual emitted module.f.d.mts shows every property as readonly. /** @type {const} */ on an object literal behaves the same as TypeScript's as const here — properties stay readonly in both the type-checker and the declaration emit.
  2. Stale doc links — real, fixed in a035585. These were markdown link-target/label mismatches: earlier sweeps updated the visible label ([`fjs/bnf/module.f.mjs`]) but not the href, since my sed patterns matched the label's fuller path but missed the relative href (../module.f.ts, which doesn't repeat the bnf/ prefix) — the same relative-path substring-miss that's recurred a few times in this migration. Fixed all four flagged links plus fjs/types/rtti/README.md's code example (still importing from the removed module.f.ts/validate/module.f.ts/ts/module.f.ts entry points), then did a repo-wide grep for the [`*.f.mjs`](*.f.ts) mismatch pattern — none remain.

tsc --noEmit stays clean and all 2356 tests pass.


Generated by Claude Code

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a035585300

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread fjs/bnf/module.f.mjs
/**
* Full 24-bit symbol range packed into a single {@link TerminalRange}.
*/
export const fullRange = 0x000000_FFFFFF

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the public range constant types

Annotate fullRange as TerminalRange during the migration; declaration emit now exposes the literal type 16777215 instead of the previous TerminalRange/number, so consumer code such as const range: typeof fullRange = rangeEncode(a, b) no longer type-checks. unicodeRange has the same narrowing regression.

AGENTS.md reference: AGENTS.md:L449-L454

Useful? React with 👍 / 👎.

```ts
// fjs/types/rtti/common/module.f.ts:124
// fjs/types/rtti/common/module.f.mjs:124
export const visit = <R>(v: Visitor<R>) => (rtti: Type): R => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Refresh all migrated design references

Update the locations throughout this issue rather than only changing their extensions: common/module.f.mjs:124 and :99 now point away from visit and visitConst (currently lines 164 and 79), while the printer reference ts/module.f.mjs:118-145 is now at lines 41-61. The caveat at lines 182-183 also still instructs an implementer to import the deleted module.f.ts paths instead of the new runtime/type split, so following this concrete design leads to unrelated or nonexistent sources.

AGENTS.md reference: AGENTS.md:L337-L339

Useful? React with 👍 / 👎.

fullRange/unicodeRange lost their TerminalRange type in declaration
emit without an explicit @type annotation. 662.md still cited deleted
.f.ts paths and pre-migration line numbers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at e11269a (14 modules now). a035585's claim checks out — I scanned every relative markdown link in the repo and there are 0 label/target extension mismatches left. tsc clean, 2356 pass / 0 fail, public type surface 0 removed, 23 additions all _-prefixed.

fjs/bnf reorders top-level declarations (fullRange/unicodeRange/unicodeMax move below eof), so it is the one module that isn't token-identical to main's compiled output. Reordering consts can bite through TDZ, so I checked it properly rather than reading it: imported both module versions and compared all 23 exports. Names match exactly, the 5 value exports are identical (eof, fullRange, none, unicodeMax, unicodeRange), and the 18 function exports return identical results on sampled inputs. The other 13 modules are token-identical as before. Safe.

Two one-line things.

1. Two markdown links still point at fjs/bnf/module.f.ts

fjs/bnf/README.md:5    - the functional representation [./module.f.ts](./module.f.ts),
fjs/bnf/todo/46.md:9   [../module.f.ts](../module.f.ts), serializable form in

fjs/bnf/module.f.ts no longer exists. These survived both a035585 and e11269a for a mechanical reason worth naming, because it is the third variant of this bug: the target is relative and has no fjs/ prefix, so a grep 'fjs/bnf/module\.f\.ts' never sees it, and both label and target say .f.ts, so the […mjs](….ts) mismatch scan does not see it either. The two sweeps were each looking for a shape this instance doesn't have.

A check that would end this class outright is resolving every relative markdown link against the filesystem rather than pattern-matching the text. Against main as baseline that comes out at 144 broken links before and 146 after, and the two added are exactly the ones above — no other regressions anywhere in the repo, and the pre-existing 144 stay out of scope.

2. eof lost the TerminalRange annotation its neighbours just regained

e11269a adds @type {TerminalRange} to fullRange and unicodeRange, but eof is annotated on main and isn't here:

// main
export declare const eof: TerminalRange;
// this branch
export declare const eof: number;

TerminalRange is number, so nothing is weakened — assignability is unchanged in both directions and no caller can tell. It is purely that the declaration no longer says what the number means, and all three constants were consistent on main. One /** @type {TerminalRange} */ above export const eof restores it.

Not a finding, just so it's on record

The per-arrow @template/@param style emits the JSDoc block inside the parameter list of the shipped declaration:

export declare const option: <S extends Rule>(
/**
 * @template {Rule} S
 * @param {S} some
 * @returns {Option<S>}
 */
some: S) => Option<S>;

I checked before raising it and this is pre-existingmain already ships 14 of these from earlier migrations (types/array, types/sorted_list, types/sorted_set, range_map, bit_vec, list, sul/level/hash). This branch adds 7 more (bnf's three, sul::encode, and rtti/common's three), consistent with how the repo already does it. The types are correct; only the rendered declaration is noisy. Not this PR's job to fix, and I would not change the style here — worth a separate look someday if the emit ever matters.


CI green on the earlier commits, still finishing on e11269a; verified locally at e11269a. Happy to approve once the two above are in.

… type

Two relative markdown links (no fjs/ prefix, both label and target
saying .f.ts) escaped the earlier link-mismatch sweeps. eof was missing
the TerminalRange annotation its two neighbours regained.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e11269a87c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

* @module
*/
import type { Type } from '../types.ts'
import type { Result as CommonValidateResult, Validate } from '../common/types.ts'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore parse error-type re-exports

When consumers update the migrated type import to rtti/parse/types.ts, Path and ValidationError are no longer available: the former parse/module.f.ts explicitly re-exported both, while this companion only imports common types and exports Result and Parse. Downstream code using the parse module as its error-type entry point therefore fails to type-check; re-export the two common types here.

AGENTS.md reference: AGENTS.md:L449-L454

Useful? React with 👍 / 👎.

Comment on lines 46 to 50
export {
constPrimitiveValidate,
prependPath,
primitive0Validate,
verror,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore validate's type-level entry point

The former validate module publicly re-exported Path, Result, Validate, and ValidationError, but the migrated module now re-exports only runtime helpers and there is no validate/types.ts companion anywhere in the repository. Consumers importing those validation types lose the entire entry point after migration and fail to type-check; add a companion that preserves these re-exports.

AGENTS.md reference: AGENTS.md:L449-L454

Useful? React with 👍 / 👎.

parse/module.f.ts and validate/module.f.ts each re-exported Path/
ValidationError (and validate additionally Result/Validate) from
common as their type-level entry point. The migrated modules dropped
these; restore them via types.ts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: b57d53a130

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sergey-shandar
sergey-shandar added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit e9e34c6 Aug 11, 2026
19 checks passed
@sergey-shandar
sergey-shandar deleted the claude/convert-f-ts-to-f-mjs-8 branch August 11, 2026 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants