Normalize markdown heading levels and remove @module JSDoc tags - #1756
Conversation
A sweep over the ~600 markdown files in the tree for broken links, missing issue metadata, and heading levels that disagree with todo/README.md's format. Broken links (7 targets, 8 sites). `fjs/cli` and `fjs/types/prime_field` had never-existing or since-moved README targets; `patricia_trie` moved under `fjs/types/`; the `rtti` README's `#closed-containers` anchor is now `#structs-and-tuples-are-closed`. Three citations pointed at todo files deleted when their work shipped — `dispatch-help-rendering` (`renderHelp`, e1f5e44) and `name-entity-kind-discrimination-once` (`isBinFile`/`isJsModule`/`isDir`, 0c21ef0) — and are rewritten in the `retired` form todo/README.md documents, naming the code that shipped. The rotted `#L63` line anchor on `reciprocal` is dropped rather than re-pinned, per the tokenizer-line-citations issue. Root README's CLI table was missing `fjs web` and `fjs help`, both of which fjs/README.md and the dispatch table in fjs/module.f.mjs carry. Reordered to match the command table itself, and `compile` now links `fjs/fsc` alongside `fjs/djs` as fjs/README.md does. Issue metadata. Four issue files carried no `**Priority:**`/`**Status:**` header, and two of those spelled it as a list item; all four now use the documented bare form. `abstract-write` is P4 as a pure DRY refactor, the rest take the documented P3 default — adjust if that misreads them. Heading levels. 56 issue files titled `# Title` where todo/README.md's format is `## Title`. Where sections were already `###` the title alone is demoted; where the whole document sat one level up, every heading is demoted together so sections stay below the title. GitHub anchors are level-independent, so no inbound link changes. `spec/todo/` and `todo/plan/` are excluded throughout: they hold specification drafts and planning documents, not issues, and their own READMEs describe them that way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
fjs/AGENTS.md §2 states the tag "belongs only to a package's entry-point file — `module.f.mjs` / `module.mjs` — not to `proof.f.mjs`, `types.ts`, or any other file". 102 files carried it anyway: 89 `types.ts`, 11 proof files, plus `fjs/bnf/testlib.f.mjs` and `fjs/emergent_testing/browser.mjs`. Every one of the 137 real entry points already had it, so the rule was being inverted almost everywhere it applied and enforced nowhere. `@module` is what a documentation generator uses to decide that a file *is* a module and to attach the block to it, so leaving it on type-only stubs and proofs would list them beside the modules they describe once `fjs/website/todo/publish-deno-doc-to-website.md` lands. That issue is the reason to fix the files rather than relax the rule. The tag appeared in three block shapes and the surrounding blank comment line is removed with it, so each block keeps the spacing AGENTS.md shows: a trailing `@module` takes the separator above it, a middle one takes one of its two separators, and a leading one (a block that was only `@module` plus `@import` tags) takes the separator below. No runtime or type-level change: `npx tsc` is clean and the suite passes 3513/3513. Nothing enforces this rule mechanically, which is how it drifted this far; a check belongs in the `fjs ci` workflow, filed separately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
todo/README.md names issue files `{slug-kebab}.md`, but 38 kept the bare
number they carried in the retired `issues/` tracker — `fjs/bnf/todo/32.md`,
`fjs/djs/todo/157.md`, `nanvm-lib/todo/89.md`. A number tells a reader
nothing about what the issue is, which is the scannability the naming rule
exists for.
The number is kept as a prefix rather than dropped. These are exactly the
identifiers the tree cites as `iNNN`, and most inbound links label them
that way — `[i157](./157.md)`, `[i170-ci-tool-steps](./170.md)` — so
dropping it would break the correspondence between a citation's label and
its target, which is the rot todo/retired-issue-identifiers.md is open
about. `NNN-{slug}.md` also matches the retired tracker's own
`issues/NNN-{slug}.md` scheme and the files already named this way
(`todo/037-language-design-map.md`,
`fjs/emergent_testing/todo/028-unit-test-examples-api.md`).
Numbers are zero-padded to three digits, the majority form in the tree,
and the `NNN.` prefix in each heading is left alone: todo/README.md's own
worked example pairs file `037-language-design-map.md` with heading
`# 37.`, so the two need not agree digit for digit.
All 43 files holding inbound links are rewritten. No non-markdown file
referenced any of them. The link check reports no broken targets or
anchors, and the retired-identifier check in
todo/retired-issue-identifiers.md still reports its documented 18.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
todo/README.md requires a done or won't-fix issue to be deleted once its reasoning lives somewhere durable. Five files had a resolved status and were still in the tree; three are retired here, and the rule grows the category the other two actually need. `prefix-then-rest-tuple` (won't fix) had nothing citing it, but its decision was recorded nowhere else: that `edag`'s nested `['[]', [elem, …]]` is the chosen representation rather than a workaround for a shape rtti cannot spell, because an rtti `Tuple` pins one schema per position and growing the `Type` ADT to match the spec's flat spelling has no other consumer here. That now sits on `array`, where someone comparing the code against the spec's structural-operations table will hit it, with `object` pointing at it. `data-tosequence-reuse` and `operator-test-operation-model` (both irrelevant) were superseded by issues that already carry their content — `unicode-rules` and `reuse-edag-operators`. Their seven citations are restated in the `retired` form, and `unicode-rules`'s task to keep the superseded file around goes with it. `io-effect-migration` stays. It is done, but `fjs/effects/README.md` and `spec/todo/io-effects.md` cite it for the staged rationale behind the error channel, which no surviving file states. todo/README.md had no category for that, so the file read as a rule violation while arguing in its own text that it should stay — the gap was in the rule. The category is now written down, deliberately narrow: it applies only where live documents cite the issue for something nothing else says, and requires the status to admit what the file is. `todo/inline-type-casts.md` is untouched pending review — despite an `implemented` status it is a live reference document with 84 open sites and 20 inbound citations, not a resolved issue. `npx tsc` is clean and the suite passes 3513/3513. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
functionalscript | f182a64 | Commit Preview URL Branch Preview URL |
Aug 28 2026, 04:52 PM |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
Two conflicts, and two follow-ups main's Stage 1 work left for this branch. `fjs/emergent_testing/browser.mjs`: main widened the `@import` list while this branch removed the `@module` tag beside it. Resolved to main's import list without the tag — `browser.mjs` is not a `module.*` entry point, so fjs/AGENTS.md §2 excludes it. `todo/blocked/jsdoc-typedef-strip-internal.md`: deleted on main by the Stage 1 private-type work, modified here only by the heading-level pass. Deletion accepted. Main left both citations to it dangling in `fjs/todo/separate-private-types.md` — the issue that asked for the deletion — so they are rewritten here: the repository-policy bullet is marked done and the `Related` entry takes the `retired` form. `fjs/todo/module-tag-on-types-ts.md` is deleted. Main filed it when `eebc007` stripped `@module` from the `private.ts` files that branch added and recorded the pre-existing `types.ts` files as debt rather than widening. It asked for a decision and its consistent application; `03a96e8` on this branch made that decision the way the issue's first option reads — strip, rather than narrow §2 — and applied it to all 102 files. After the merge no non-entry-point file carries the tag and all 137 entry points do. `npx tsc` is clean, the suite passes 3522/3522, and main's new file-scope-typedef guard passes. `npm run update` reports no drift in the generated workflow or `package-lock.json`; `deno.lock` and `bun.lock` could not be refreshed here (neither runtime is installed) and nothing in this merge declares a dependency change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bb332ad332
ℹ️ 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".
| * The variadic part is nested one position deep — `['[]', [elem, elem, …]]` | ||
| * — where the spec's structural-operations table writes it flat, | ||
| * `['[]', ...elements]`. That is the decided representation, not a |
There was a problem hiding this comment.
Update the canonical EDAG design to the nested shape
Declaring the nested form final while retiring its TODO leaves the canonical design contradictory: todo/edag-stage1-discussion.md still specifies flat array/object constructors at lines 220–221 and marks ['{}', ...entries] as decided at lines 764–767. A future compiler or Rust implementation following that document will therefore emit flat nodes that the shipped schema rejects; update the design document and its examples to the nested representation as part of this decision.
AGENTS.md reference: AGENTS.md:L47-L53
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed and partly fixed in f808280.
Worth noting the disagreement is older than this branch: fjs/edag/README.md already writes the form column as ['[]', items[]], and the proofs construct ['[]', [1, 'a', true]] / ['{}', [[':', 'a', 1]]]. So the code and the module documentation already agreed on nesting — only the working design documents were behind. This branch made it visible by recording the decision on array and retiring the todo that had been the sole written record of the gap.
Fixed here, being what an implementer reads as normative:
- the structural-operations table rows for
["[]"]and["{}"] - subject 4's resolution and its history paragraph
- the object-constructor validation rule, whose "every
["{}", ...]operand" no longer described the shape (there is one operand now — the entry array) - the three constructor forms in
fjs/djs/todo/compile-modules-to-edag.md
The reason is stated once under the table — an rtti Tuple pins one schema per position, so a tag followed by a homogeneous rest is not spellable inline, and growing the Type ADT has no other consumer here — with subject 4 carrying a *Revised:* note in the form that document already uses.
Not done, deliberately: roughly twenty illustrative examples elsewhere in the discussion still use the flat spelling — ["[]", x, x] in the sharing-is-observable passages, and ["{}"] for an empty object, which the schema writes ["{}", []]. Two reasons to keep that separate. It is a re-notation of a 1400-line working document rather than a correction, and several of those examples sit inside history paragraphs recording what an earlier proposal said, where rewriting the notation would falsify the record instead of fixing it. Those want a pass that decides per-site whether the example is describing today's shape or quoting a superseded one, which is a judgement for the document's author.
Generated by Claude Code
There was a problem hiding this comment.
Follow-up: the second finding on this file is fixed in a767b30, and it supersedes how I resolved the first one.
The JSDoc I had added described a schema/design conflict that the previous commit had just removed. fjs/AGENTS.md §2's documentation-home table decides where that text belongs rather than how to reword it — API shape and invariants in JSDoc, why this / why not that in the README — and the rationale is the second kind.
So fjs/edag/module.f.mjs is now byte-identical to main. The shape was already noted there by the pre-existing // Object — same nesting as array above, one position further in marker (from #1680), which makes the JSDoc addition redundant independently of having gone stale. The reason now extends the paragraph in fjs/edag/README.md that already explains the [] suffix, and todo/edag-stage1-discussion.md points at it rather than restating it.
That still does what retiring prefix-then-rest-tuple required — the decision is written down where a reader of this module meets it — with one home instead of three.
Remaining, unchanged from my earlier reply and still for the document's author: roughly twenty illustrative examples in the discussion use the flat spelling, several inside history paragraphs quoting superseded proposals.
npx tsc clean, suite 3521/3521, file-scope-typedef guard passes.
Generated by Claude Code
Codex flagged that this branch declares the nested array/object form final
in `fjs/edag/module.f.mjs` while `todo/edag-stage1-discussion.md` still
specifies the flat, variadic `["[]", ...node]` / `["{}", ...entries]`, so
an implementation following the design document would emit nodes the
shipped schema rejects. The finding is right, and the disagreement is
older than this branch: `fjs/edag/README.md` writes `['[]', items[]]` and
the proofs construct `['[]', [1, 'a', true]]`, so the code and the module
documentation already agreed on nesting and only the working design
documents were behind.
Fixed here are the parts an implementer reads as normative: the
structural-operations table, subject 4's resolution and its history
paragraph, the object-constructor validation rule, and the three
constructor forms in `fjs/djs/todo/compile-modules-to-edag.md`. The reason
is stated once under the table — an rtti `Tuple` pins one schema per
position, so a tag followed by a homogeneous rest is not spellable inline
— with subject 4 carrying a `*Revised:*` note in the form that document
already uses for its other revisions.
Roughly twenty illustrative examples elsewhere in the discussion still use
the flat spelling (`["[]", x, x]`, and `["{}"]` for an empty object, which
the schema writes `["{}", []]`). Re-notating those is a separate pass, not
least because several sit inside history paragraphs recording what an
earlier proposal said — rewriting those would falsify the record rather
than correct it. Raised on the review thread rather than done here.
Markdown only. The link check reports no broken targets or anchors and
main's file-scope-typedef guard passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8082809fe
ℹ️ 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".
Codex's second pass caught that the JSDoc added in 563ac09 now describes a disagreement that no longer exists: it contrasted the nested schema against a design document that writes the constructors flat, and f808280 changed that document to write them nested. A reader would go looking for a conflict that had just been resolved. fjs/AGENTS.md §2's documentation-home table settles where the text belongs rather than how to reword it — API shape and invariants in JSDoc, "architectural choices, why this / why not that" in the README — and the rationale is the second kind. `fjs/edag/module.f.mjs` is therefore restored to exactly its state on main; the shape was already noted there by the pre-existing `// Object — same nesting as `array` above` marker, so the JSDoc addition was redundant even before it went stale. The reason now sits in `fjs/edag/README.md`, extending the paragraph that already explains the `[]` suffix — the nearest thing to a home it had. That still satisfies what retiring `prefix-then-rest-tuple` required: the decision is written down where a reader of this module will meet it, and the design document points at it instead of restating it. `npx tsc` is clean, the suite passes 3521/3521, main's file-scope-typedef guard passes, and the link check reports no broken targets or anchors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
…ocumentation-hrijwz
o2alexanderfedin
left a comment
There was a problem hiding this comment.
Approved.
A 247-file sweep is where a substantive change hides, so I had the whole diff classified rather than sampled. It holds up: all 102 .ts/.mjs files are exactly 0 add / 2 del, the removed lines being only * @module and its blank comment line. Emitting declarations at both ends and diffing the trees, exactly those 102 .d.ts/.d.mts differ, and in every one the only changed lines are those same comments — no signature, export or type moved. Proof-leaf name sets are byte-identical in both directions, 3525 either side. Heading text sequences are unchanged in all 141 markdown files, so no anchor could have moved, and a repo-wide grep for the 4 deleted and 38 renamed basenames finds nothing left pointing at them. Gates: tsc 0, npm test 3525/3525.
Six hunks are real content rather than formatting, and all six check out — the fjs/edag/README.md paragraph on the array operand matches module.f.mjs:114 and types.ts:49 as shipped, the bracket-form corrections in the two todo docs agree with it, and the root README's new fjs web row names a genuinely registered command. The four deleted files were already irrelevant/closed before this PR.
Two things in the description, worth fixing since this repo squash-merges the body into history:
- It says the EDAG clarification landed in
fjs/edag/module.f.mjscomments. That file is untouched here; the clarification is infjs/edag/README.mdand the two todo docs. - It says
@modulewas "causing documentation generation issues". Nothing consumes the tag today — the only candidate,deno docviapublish-deno-doc-to-website.md, is still an open todo and targets entry points only. The real justification is stronger and already exists:fjs/AGENTS.md§2 has said since #1568 that@modulebelongs only to entry-point files, and none of the 102 files here is one. The sweep enforces a standing rule rather than fixing a tool.
|
Thanks — both description corrections were right, and I've rewritten the body. Verified each before editing rather than taking them on trust:
Two notes on the new text where I went slightly further than your summary:
Left alone: the PR title. It doesn't follow Generated by Claude Code |
The merge queue dequeued this for MERGE_CONFLICT. One conflict, in the Related section: both sides were additive, so both survive — my two ownership links, and main's note recording that jsdoc-typedef-strip-internal is retired rather than merely unlinked. Main's heading normalization and todo renames (#1756) auto-merged; all links in the three touched files still resolve and tsc is clean. Re-measured everything the documents assert, since main moved a lot. The invariants hold exactly: 16 private.ts, fjs/emergent_testing still has none (so it remains a valid stand-in for a future module), 0 runtime imports among the 226 in authored .ts, and bigfloat's divide is still unexported with _BigFloatWithRemainder still private. The absolute counts drifted for the third time, though: 675/659 is now 677/661 and 377 declarations is 378. The numbers were never the claim — "exactly 16 disappear, and they are exactly the private.d.ts" is — so the prose now says that, with the totals marked as a re-measured snapshot. Future drift makes the snapshot old rather than making the document wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqeS5t2ZKkSu3chRPMXR7n
Review caught a trap in this issue's own instructions. "Every `["{}"]` →
`["{}", []]`" reads as a blanket rewrite, but one of the seven occurrences
in `edag-stage1-discussion.md` is not an empty object: the validation rule
writes "every element of a `["{}"]` node's entry array must be a recognized
entry form", where the tag names *an object-constructor node*. Rewriting
that one with the examples makes the sentence contradict itself — an empty
entry array has no elements to check — so an implementer following this
issue literally would have introduced the defect.
It is also the occurrence #1756 introduced rather than inherited: the
previous wording said "every `["{}", ...]` operand", which stopped
describing the shape once the operands became one array.
Added as a fourth class with its own treatment. The shorthand only became
ambiguous when `["{}", []]` acquired a meaning, so it wants a nonempty
placeholder — `["{}", entries]` — rather than the empty form or a bare tag.
The counts in the problem statement, the class-1 blurb and the task list
are qualified to match: six genuine empty objects, one shorthand.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
Two issues asked the same question. #1756 answered it — strip the tag, `fjs/AGENTS.md` §2 was right — and applied that to 102 files, then deleted `fjs/todo/module-tag-on-types-ts.md` and missed this one. Every premise in it is now false. "90 of the 94 `types.ts` files carry it anyway" is 0 of 98. Its three tasks are done: the convention was decided, applied to every `types.ts`, and `fjs/web/types.ts` — named as the minority case — matches. Nothing cites it. Nothing to move before deleting: the decision it asked for lives in `fjs/AGENTS.md` §2, which never changed, and the CI-enforcement question it did not ask about is settled the other way by §6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
Three more review findings, all correct. The module header lacked @module. fjs/AGENTS.md §2 requires it on every module.* entry point, and all five sibling fjs/ci modules carry one; #1756 removed the tag from non-module files, not from these. The proof lived in the parent. fjs/ci/deno, fjs/ci/nix and fjs/ci/node all have co-located proofs, so the precedent is the opposite of what I assumed. The job's own shape is now proved in fjs/ci/package/proof.f.mjs, and the parent keeps only what the assembled workflow can show: that the job is wired in, and that the job it waits for is really the one that uploads — an edge pointing at a job that never produces the artifact would satisfy the ordering and still never run. The compiler pin was the substantive one. Reading devDependencies.typescript gives a dependency specification, not a resolved version: this repository pins =7.0.2, but a project writing ^7.0.0 would have had npm choose, which is exactly the determinism the checkout-less job exists to preserve. The script now compares the installed version against the literal pin and refuses when they differ. That case is worse than it looks, and the test shows why: ^7.0.0 installs 7.0.2 today, so a range is indistinguishable from an exact pin until the day the registry publishes 7.0.3 and the verdict moves with no change to the package. Verified: ^7.0.0 exits non-zero, =7.0.2 exits 0 at 396 declarations, and a second tarball named other-package still resolves and passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqeS5t2ZKkSu3chRPMXR7n
§2 said the tag belongs only to `module.f.mjs` / `module.mjs`. That is the rule #1756 enforced across 102 files, and it had the reason backwards. `deno doc` reads the tag and nothing else. A file whose leading block carries it gets that prose as `module_doc`; a file without it gets no `module_doc` at all — the block is dropped, not demoted. Checked against the Deno the repository pins, for `.mjs` and `.ts` alike, and the tag need not be in the first block, only in some block. So the tag is what makes a leading block *be* documentation, and it goes wherever a file has module documentation to publish: `module.f.mjs`, `types.ts`, `private.ts`. A block holding only `@import` tags has nothing to attach and wants none. Where the documentation is never published the tag buys nothing, which is `proof.*`. 98 of the 102 stripped files had real prose, so their module documentation is currently invisible to `deno doc` — the output `fjs/website/todo/publish-deno-doc-to-website.md` plans to publish. §2 says so plainly rather than describing a tree that does not exist, and points at the restore. `fjs/todo/module-tag-restore.md` (P3) carries the inventory, split by the three decisions it actually contains: 89 `types.ts` with prose, mechanical; 11 proof files where the rule says leave them but that is worth confirming; and two files that are neither — `browser.mjs` has real prose and reads like the first group, `testlib.f.mjs` held only `@import` tags and wants no tag at all. `todo/jsdoc-verification.md` (P4) asks how any of this could be checked. Three passes over one tag with no signal at any point is the argument for looking; §6 ruling out text patterns is why the answer has to parse, and "not worth it, leave it to review" is a legitimate outcome to record. Documentation only. `npx tsc` clean, suite 3533/3533. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
…d claim Three review findings, all against text I wrote in the previous commit. §1.2 still showed a `proof.f.mjs` leading block carrying `@module`, while the §2 I had just rewritten said a proof's documentation is never published so the tag has nothing to attach to. Same file, opposite instructions for the same shape. The example loses the tag and says why. The restore issue omitted `private.ts`. All 16 have prose and none carry the tag — stripped by #1750 rather than #1756, so they were not in the 102 I counted, but it is the same reading and the same fix, and §2 names `private.ts` explicitly. As written the issue could have been completed in full while leaving 16 files violating the rule it exists to satisfy, and its last task says to delete §2's non-compliance note. And the publication rationale was overstated. The website issue plans `deno doc --html **/module.f.mjs`, a glob excluding every `types.ts` and `private.ts`, so restoring the tag alone puts nothing on the website. The tag is necessary, not sufficient: it decides whether `deno doc` *can* see a file's module documentation, and what the build is pointed at is a separate question. Both §2 and the issue say that now, and widening the glob is named as the other half. Also added: a task to correct `todo/migrate-typescript-to-mjs.md`, which restates the old rule verbatim under "Module header and import ordering" rather than linking §2, so it did not move when §2 did. Documentation only. `npx tsc` clean, suite 3533/3533. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup
A sweep over the ~600 markdown files and the JSDoc headers for broken links, stale citations, issue metadata that disagrees with
todo/README.md, and one convention that had drifted repo-wide.Broken links — 7 targets across 8 sites.
fjs/cli/README.mdandfjs/types/prime_fieldhad never-existing or since-moved targets;patricia_triemoved underfjs/types/; therttiREADME's#closed-containersanchor is now#structs-and-tuples-are-closed. Three citations pointed at todo files deleted when their work shipped —dispatch-help-rendering(renderHelp, e1f5e44) andname-entity-kind-discrimination-once(isBinFile/isJsModule/isDir, 0c21ef0) — and are rewritten in theretiredformtodo/README.mddocuments, naming the code that shipped. A rotted#L63line anchor onreciprocalis dropped rather than re-pinned, per thetokenizer-line-citationsissue. These last two are exactly the classtodo/retired-issue-identifiers.mdpredicted but did not enumerate.@module—fjs/AGENTS.md§2 reserves the tag for a package's entry point, "not toproof.f.mjs,types.ts, or any other file". 102 files carried it anyway: 89types.ts, 11 proof files, plusfjs/bnf/testlib.f.mjsandfjs/emergent_testing/browser.mjs. All 137 real entry points already had it, so the rule was inverted almost everywhere it applied and enforced nowhere. This enforces a standing rule rather than fixing a tool — nothing consumes the tag today. The tag appeared in three block shapes and the adjacent blank comment line is removed with it, so each block keeps the spacing AGENTS.md shows. This also resolvesfjs/todo/module-tag-on-types-ts.md, filed on main when #1750 stripped its own newprivate.tsfiles and recorded the rest as debt; that issue asked for a decision and its consistent application, and this takes the first of its two options.Todo issue files — 4 had no
**Priority:**/**Status:**header, two of those spelling it as a list item; 56 were titled# Titlewhere the documented format is## Title. Where sections were already###the title alone is demoted; where the whole document sat one level up, every heading is demoted together. Heading text is unchanged throughout, so no anchor moves. 38 files kept the bare number from the retiredissues/tracker (fjs/bnf/todo/32.md,fjs/djs/todo/157.md) and are renamedNNN-{slug}.md— the number is kept because most inbound links label them by it ([i157](./157.md)), and dropping it would break the correspondence between a citation's label and its target.spec/todo/andtodo/plan/are excluded: they hold specification drafts and planning documents, not issues.Four resolved issues retired, one kept.
prefix-then-rest-tuple(closed) anddata-tosequence-reuse/operator-test-operation-model(both irrelevant, superseded byunicode-rulesandreuse-edag-operators) are deleted with their citations restated in theretiredform;module-tag-on-types-ts(open) is deleted because this PR resolves it.fjs/effects/todo/io-effect-migration.mdstays: it is done, but two live documents cite it for rationale nothing else states, andtodo/README.mdhad no category for that — so the category is now written down, deliberately narrow.EDAG constructor shape — review found the design documents specified flat
["[]", ...node]/["{}", ...entries]while the shipped schema nests, so an implementation following them would emit nodes validation rejects. The disagreement predates this branch:fjs/edag/README.mdalready wrote['[]', items[]]and the proofs construct['[]', [1, 'a', true]]. Corrected in the normative places — the structural-operations table, subject 4's resolution and history, the object-constructor validation rule, and the three forms incompile-modules-to-edag.md— with the reason stated once infjs/edag/README.md, wherefjs/AGENTS.md§2 puts why this / why not that.fjs/edag/module.f.mjsis untouched by this PR. Roughly twenty illustrative examples elsewhere intodo/edag-stage1-discussion.mdstill use the flat spelling, several inside history paragraphs quoting superseded proposals; re-notating those needs a per-site judgement and is left open on the review thread.Root README — the CLI table was missing
fjs webandfjs help, both of whichfjs/README.mdand the dispatch table infjs/module.f.mjscarry.No behaviour or public-API change, so no changelog entry: markdown and JSDoc comments only.
npx tscclean, suite 3525/3525, and main's file-scope-typedef guard passes.https://claude.ai/code/session_01T7vAocRuxfmWJDnujCoMup