Skip to content

HF-359: Restructure the repository as a monorepo - #1758

Merged
sequba merged 10 commits into
feat/hf-359-monorepo-agent-setupfrom
feat/hf-359-monorepo-structure
Sep 1, 2026
Merged

HF-359: Restructure the repository as a monorepo#1758
sequba merged 10 commits into
feat/hf-359-monorepo-agent-setupfrom
feat/hf-359-monorepo-structure

Conversation

@sequba

@sequba sequba commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Context

Turns the repository into a monorepo (HF-359). Stacked on #1757 — review that first; this branch is based on it.

hyperformula/      the engine (published)   — src/, test/, its toolchain, dev-docs/, script/
hyperformula-ui/   placeholder              — imported separately, preserving history
docs/              the portal               — own package, installs on its own
script/            release/ and the licence gate — the only things that span the repo
dev-docs/          repository-wide standards and process

No changes under hyperformula/src/. Every file there is byte-identical to its old location at src/; git records the moves as renames throughout, so history follows. The published package's name, version, entry points and exports map are unchanged, and the publish-package check confirms the tarball contents.

The layout

  • npm workspaces, with a private root carrying fan-out scripts. Linting is the deliberate exception — it runs once from the root over the whole repository, so nothing between packages falls through the gap.
  • docs/ left the workspace. VuePress 1.x and its --openssl-legacy-provider tree must never reach an engine install. npm run docs:install installs it; CI installs it before building the portal.
  • The portal owns its deployment: wrangler.jsonc and worker/ moved under docs/, and the asset directory is now ./.vuepress/dist.
  • Per-package .nvmrc (all 22) and CHANGELOG.md. The root changelog is an index.
  • The private test suite stays branch-matched; only its checkout path moved. Its 501 spec files needed no edit — they import the engine relatively, and because src/ and test/ moved together, the depth from a spec to the package root is unchanged.

Everything lives with what owns it

Three directories are scoped by ownership rather than by convenience:

Repository level Package level
dev-docs/ definition of done, code style, testing standards, documentation rules, build and release, pull requests, worktrees, agent setup hyperformula/dev-docs/ — architecture, parser, interpreter, dependency graph, function catalogue, i18n, performance, its suites, its build
script/ release/, check-licenses.mjs hyperformula/script/ — build checks; docs/script/ — the generator and the Worker assets

Three dev-docs pages were genuinely mixed and were split, not moved: TESTING (what a change must prove stays; the suites go down), BUILD (workspace, deploy and release stay; the intermediate build and packaging go down), and CODE-STYLE (style stays; the hot-path table becomes hyperformula/dev-docs/PERFORMANCE.md).

The script/ split was decided by the callers, not by judgement: every script had exactly one caller and the caller named its owner. Twelve call sites stopped reaching across a package boundary, and two scripts stopped resolving paths through ../hyperformula/ and ../docs/.

examples/ at the root is deleted: three of its PNGs were byte-identical duplicates of docs/.vuepress/public/, which is what the site actually serves through $withBase, and the remaining five files were referenced nowhere in the repository, in any config, workflow or package script. It was not moved under docs/, because docs/examples/ already exists and is a different thing — the runnable examples embedded in the guides.

Three things the move forced

The built-in-functions generator moved to docs/script/. It uses @vuepress/shared-utils for slugs, and that package require()s markdown-it-emoji and an older lru-cache major without declaring either, relying on vuepress to hoist them. Outside a full VuePress tree it throws on load, so the generator has to live where that tree is.

Three portal paths were written from the old repository root and broke once VuePress built from docs/ as its own package. All three are now anchored explicitly rather than depending on cwd:

Path Was Symptom
code-snippet plugin fell back to process.cwd() looked in docs/docs/examples/, so every guide with an example failed to compile
graph.vue ../../../dist/hyperformula.full resolved to a dist/ at the repository root that no longer exists
dest docs/.vuepress/dist/docs wrote the built site to docs/docs/

One decision was reversed. The migration first kept a single dev-docs/, on the grounds that two directories would fragment the single source of truth. That conflated a single source with a single directory — splitting by ownership is not duplication, and keeping every package's internals at the root would have made the root a dumping ground the moment hyperformula-ui lands.

How did you test your changes?

Everything below was run on this branch, and re-run after each review round:

Command Result
npm ci Clean; the workspace resolves
npm run lint 0 errors, 54011 warnings — the exact pre-move baseline
npm run test:jest 502 suites, 6232 passed, 3 skipped, 0 failed
npm run test:ci -- --coverage 97.42%, written to hyperformula/coverage
npm run test:browser 12464 assertions across headless Chrome and Firefox, exit 0
npm run verify:typings tsc --noEmit clean
npm run bundle-all Every bundle, and Publish package check: OK
npm run check:licenses 3 production dependencies, and it fails when the allowlist is tightened
npm run release code-freeze … (dry run) Correct version, dates and changelog section
npm run docs:generate-function-docs 564 lines, 13 category sections
npm --prefix docs run build:cf 217 pages, sitemap, _headers and _redirects copied

Every relative Markdown link in AGENTS.md, both dev-docs/ levels, the skills and the READMEs was resolved against the filesystem. All resolve.

What the reviews found

Two rounds, 36 findings. What they caught, and what I got wrong:

Flag arguments were being swallowed. Every delegating root script dropped them, so npm run test:ci -- --coverage reached the workspace as bare jest --forceExit and CI had been uploading nothing to Codecov while staying green. Demonstrated with npm run test:jest -- --listTests, which ran all 6232 tests instead of listing them.

The release script was never adapted. It read and wrote ./package.json — now the private root manifest with no version. A dry run then surfaced a third path the review had not caught: the private test suite check still pointed at test/hyperformula-tests.

check:licenses was checking nothing. license-checker reads <start>/node_modules, and npm hoists, so from hyperformula/ it saw an empty tree and from the root a manifest with no dependencies — zero packages either way, passing vacuously. Replaced with script/check-licenses.mjs, which takes the production set from npm ls --omit=dev and the licence data from a full license-checker run.

The portal was publishing internal agent instructions. VuePress sweeps every markdown file under docs/, so docs/AGENTS.md and its CLAUDE.md symlink were being built into /AGENTS.html and a byte-identical /CLAUDE.html, sitemap and search index included.

npm run test:browser exited non-zero after passing. All 6232 specs passed in both browsers and always did; Chrome then reported Some of your tests did a full page reload! during teardown. The cause was client.clearContext: false in the Karma base config, and it reproduced on the pre-move tree, so it predates this branch. concurrency: 1 was the obvious first guess and is wrong — it does not remove the error, it doubles wall-clock time, and it turns an intermittent failure into a deterministic one. That determinism was what made the real fix testable, but it is not in the branch.

Also fixed: the report path in performance.yml, code-examples-generator.sh silently processing zero files, docs:build:cf never installing the portal, docs:install using npm install against a committed lockfile, the licence-header rule resolving against the working directory, hyperformula-ui listed as a workspace with no package.json, a dead .npmignore rule, and a dozen documentation pages naming commands or paths this branch had moved.

One finding was rejected on measurement — the claim that the type-aware ESLint program build risks the hook's 60 s timeout. Measured at 0.91 s and 1.06 s. That hook has since been removed anyway, at the author's request.

Two pre-existing problems the move uncovered

The source language packs have never been linted. The old ignore list carried a bare languages entry meant for the build output. An unanchored pattern matches a directory of that name at any depth, so it also excluded src/i18n/languages/ — and the sort-keys override that targets exactly those files has therefore never run. Anchoring the build-output entry exposed 881 violations across 19 translation files. Confirmed by linting src/i18n/languages/enGB.ts on the pre-move tree, where ESLint reports File ignored because of a matching ignore pattern.

They are excluded again in .eslintignore, deliberately and with a comment explaining why, so this branch keeps the exact pre-move lint baseline. Sorting 19 translation files is a change of its own — and reordering translation entries is precisely what the i18n guidance tells contributors not to do casually.

npm run test:compatibility was broken for everyone. It pointed at test/compatibility/test-compatibility.sh, a path that exists in neither repository; the script ships with the private suite. Fixed here, since the branch had to touch it anyway.

Not done, on purpose

CI path filtering. A naive paths: filter on a workflow that branch protection lists as a required check leaves the check permanently pending and makes pull requests unmergeable. Doing it safely needs the required-checks list, which lives in repository settings rather than in the tree, plus the dorny/paths-filter-and-single-gate shape the Handsontable monorepo uses. The CI paths are all updated; only the filtering is outstanding.

Importing hyperformula-ui — left for the teammate who owns the formula-builder move. It is deliberately not in the workspaces array until then: npm silently ignores an entry with no package.json, and the lockfile has to be regenerated when the real package lands either way.

Both are recorded in dev-docs/STRUCTURE.md under "What the move still owes".

Types of changes

  • Breaking change (a fix or a feature because of which an existing functionality doesn't work as expected anymore)
  • New feature or improvement (a non-breaking change that adds functionality)
  • Bug fix (a non-breaking change that fixes an issue)
  • Additional language file, or a change to an existing language file (translations)
  • Change to the documentation

Repository structure and tooling. The published package is unchanged.

Related issues:

  1. HF-359

Checklist:

  • I have reviewed the guidelines about Contributing to HyperFormula and I confirm that my code follows the code style of this project.
  • I have signed the Contributor License Agreement.
  • My change is compliant with the OpenDocument standard. — not applicable; no engine behaviour changes.
  • My change is compatible with Microsoft Excel. — not applicable; no engine behaviour changes.
  • My change is compatible with Google Sheets. — not applicable; no engine behaviour changes.
  • I described my changes in the CHANGELOG.md file. — intentionally not done. Nothing user-facing changed; the published package is identical.
  • My changes require a documentation update. — dev-docs/ at both levels, docs/README.md and the public building guide are updated in this change.
  • My changes require a migration guide.

🤖 Generated with Claude Code


Note

Medium Risk
Large CI, release, and docs-build path changes can break merges or deployments even though the published engine package is unchanged; incorrect workspace or portal wiring would surface as green CI with missing coverage or failed doc builds.

Overview
Restructures the repository into an npm workspaces monorepo: the calculation engine lives under hyperformula/ (with src/ and test/ moved there unchanged), docs/ stays a separate install via npm run docs:install, and hyperformula-ui/ is a placeholder for a later import.

The private root fans out build and test scripts with --workspace=hyperformula; ESLint stays at the repo root and now points TypeScript at hyperformula/tsconfig.json. CI workflows, .gitignore, and the private test checkout path move to hyperformula/test/hyperformula-tests/; docs and publish workflows add docs:install before docs:build.

Documentation and agent tooling are retargeted to the new paths: root README.md becomes a monorepo overview, dev-docs/ is split (repo-wide vs hyperformula/dev-docs/), Claude skills and .claude/settings.json deny lists use /hyperformula/... paths, and worktree.symlinkDirectories for node_modules is removed. The VuePress portal is fixed for building from docs/ (bundle import paths, snippet plugin root, dest, exclusion of AGENTS.md/CLAUDE.md from the site).

Tooling follow-ups in the diff: .eslintignore re-anchors build outputs and temporarily re-excludes source i18n/languages after exposing long-standing sort-keys debt; .worktreeinclude stops auto-copying secrets and build artifacts.

Reviewed by Cursor Bugbot for commit 480123c. Bugbot is set up for automated code reviews on this repo. Configure here.

Implements the migration steps recorded in dev-docs/MONOREPO.md.

- src/, test/ and the whole engine toolchain (tsconfig, jest, karma, webpack,
  babel, .config/, typedoc) move into hyperformula/, which becomes the
  published package and carries its own README, CHANGELOG, LICENSE and .nvmrc.
- The root package.json becomes a private workspace root listing hyperformula
  and hyperformula-ui, with fan-out scripts. Linting is the deliberate
  exception: it still runs once from the root over the whole repository, so
  nothing between packages falls through the gap.
- docs/ becomes its own package, installed separately with `npm run
  docs:install`, so the VuePress 1.x tree never reaches an engine install. It
  takes ownership of its deployment: wrangler.jsonc and worker/ move under it.
- hyperformula-ui/ is created as a placeholder; the package is imported from
  the formula-builder repository separately.
- Every .nvmrc says 22, and each package keeps its own CHANGELOG.md in the
  existing Keep a Changelog form.

Three things the move forced, none of them cosmetic:

The built-in-functions generator moved to docs/script/. It uses
@vuepress/shared-utils for slugs, and that package requires markdown-it-emoji
and an older lru-cache major without declaring either, relying on vuepress to
hoist them. Outside a full VuePress tree it cannot load at all, so the
generator has to live where that tree is.

Three paths in the portal were written from the old repository root and broke
when VuePress started building from docs/ as its own package: the code-snippet
plugin fell back to process.cwd() and looked for docs/docs/examples/, graph.vue
imported the engine bundle from ../../../dist, and dest wrote the site to
docs/docs/. All three are now anchored explicitly.

The engine dev-docs pages stay in the single root dev-docs/ rather than being
split into a package-level copy as the plan sketched. Two directories fragment
the single source of truth and force every page to know which scope it was
written from.

Verified end to end: npm ci, lint (0 errors, 54011 warnings - the exact
pre-move baseline), jest (502 suites, 6232 passed), tsc --noEmit, bundle-all
including the publish-package check, the function-docs generator, typedoc, and
the full portal build (217 pages) plus the Cloudflare asset step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qunabu

qunabu commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

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

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
hyperformula-docs 480123c Sep 01 2026, 10:37 AM

sequba and others added 9 commits September 1, 2026 08:28
Eleven findings, verified against the tree before acting.

The portal was publishing internal agent instructions. VuePress sweeps every
markdown file under docs/, so AGENTS.md and its CLAUDE.md symlink were built
into /AGENTS.html and a byte-identical /CLAUDE.html, sitemap and search index
included, with links pointing outside the site. Both are excluded now, and the
rebuilt site no longer contains them.

The PostToolUse hook gained the report it was missing and lost three latent
faults. It rewrites the file underneath the agent, which invalidates the line
numbers the agent is holding; on the path where every error was auto-fixed it
used to exit 0 in silence, and the next Edit would fail its modified-since-read
check for no visible reason. It now says what it changed and asks for a re-read.
ESLint is invoked as `node node_modules/eslint/bin/eslint.js` from the project
directory rather than through `npx` with no cwd: that fixes resolution of both
the binary and .eslintignore (ESLint 8 reads it relative to the working
directory, so a hook running elsewhere would lint and auto-fix deliberately
excluded paths), removes the shell whose unquoted argv would split a checkout
path containing a space, and drops a process from every edit. The report is
flushed by setting process.exitCode instead of calling process.exit, which does
not wait for asynchronous writes to a pipe.

The deny rules used the `./` form, which anchors at the current directory. The
`/` form anchors at the settings source, which is what was meant.

`npm run test:compatibility` pointed at test/compatibility/test-compatibility.sh,
a path that exists in neither repository. The script is in the private suite, at
test/hyperformula-tests/compatibility/. Pre-existing; the review surfaced it
through a contradiction in TESTING.md, which is corrected too.

Cloudflare deploy credentials are no longer copied into worktrees. Every
subagent-isolation worktree was receiving a deploy token it has no use for, for
the convenience of the one maintainer who runs wrangler.

Also: ARCHITECTURE.md placed absolutizeDependencies.ts in src/parser/ when it is
at the source root, and described config defaults as living in ConfigParams.ts
when that file is an interface declaration and the values are in
Config.defaultConfig; DEFINITION-OF-DONE.md and the changelog skill disagreed on
when an entry is required; and the hook's header announced two deliberate
choices while listing more.

Verified: lint 0 errors, jest 502 suites / 6232 passed, portal rebuilt (agent
pages absent from the output and the sitemap), and the hook exercised across
auto-fix-only, unfixable-error, already-clean, eslintignored, malformed-input
and non-lintable-extension paths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`docs/api/` and `docs/guide/built-in-functions.md` were on the agent deny list
alongside the build artifacts, while dev-docs/FUNCTION-CATALOGUE.md links
straight into both of them. An agent following that link hit a permission
refusal with no explanation.

They are generated, but they are not artifacts: they are the API reference and
the function reference, and reading them to answer a question is the right move.
The deny list is about bundles, declarations, coverage and the compiled site.
Editing either file is still pointless — the build regenerates them — and that
is stated where the rule lives rather than enforced by blocking reads.

Two stale claims fell out of the same pass. AGENT-TOOLING.md and WORKTREES.md
both still documented `worktree.symlinkDirectories` as a current setting; it was
removed when the repository became a workspace. WORKTREES.md now records why it
must not come back, including that `npm ci` inside a worktree whose
`node_modules` is a symlink installs through it and silently rewrites the main
checkout's dependency tree. WORKTREES.md also still said `.dev.vars` was copied
into worktrees automatically, which stopped being true when the deploy
credentials were taken out of `.worktreeinclude`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`npm run test:browser` executed all 6232 specs successfully in both browsers and
then exited 1 anyway, because Chrome reported "Some of your tests did a full
page reload!" during teardown. The failure predates this branch - it reproduces
on the pre-move tree - but it was intermittent there and would have made the CI
job flaky.

The cause is `client.clearContext: false` in the shared Karma base config.
Karma has to be allowed to clear its context iframe when a run finishes;
prevented from doing so, it sees the page still there and reports it as a
reload after the results are already in.

`concurrency: 1` was the obvious first guess and is wrong. It does not remove
the error, it doubles the wall-clock time, and by making Chrome's teardown the
last thing that happens it turns an intermittent failure into a deterministic
one: three of three runs exited 1 rather than one of two. That determinism was
useful for testing the real fix, and is the reason this commit does not carry
it.

`clearContext: false` does belong in `.config/karma/debug.js`, which is what the
option is for: `singleRun` is false there, a human is watching, and the kjhtml
results page has to survive between runs. It is set explicitly there now rather
than inherited.

Verified: three consecutive runs at exit 0, zero ERROR lines, `TOTAL: 12464
SUCCESS`, ~31s - unchanged from the parallel timing. The debug config still
resolves to `clearContext: false`, `singleRun: false`, `kjhtml`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings 80753c5 from feat/hf-359-monorepo-agent-setup, and resolves the four
files both branches touched.

AGENTS.md takes the base's resolution outright: the routing table is gone, since
it now lives in dev-docs/README.md.

dev-docs/README.md keeps that table, with the entries this branch changed - the
engine source is hyperformula/src/, the private test suite README moved with it,
and there is no longer a separate monorepo page to link.

STRUCTURE.md is the interesting one. The base merged MONOREPO.md into it because
both files carried a tree and a reader could not tell which was current. That
argument still holds here, but the content is different: on this branch the move
has happened, so the tree is the monorepo and what MONOREPO.md held is a record
rather than a plan. It becomes three closing sections - what the move still owes,
what it decided, and the two pre-existing problems it uncovered. MONOREPO.md is
deleted, and its last two references, in CHANGELOG.md and hyperformula-ui/README.md,
now point at the section that answers them.

WORKTREES.md needed no resolution beyond this branch's version: it had already
stopped referring to MONOREPO.md when the symlink section was rewritten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings 83eb116 from feat/hf-359-monorepo-agent-setup. Two conflicts, both
resolved in favour of the removal.

script/claude/post-tool-use.mjs was deleted on the base and rewritten here, in
the review round that made it report its own edits and invoke ESLint directly.
The file goes; the reasoning behind that rewrite is preserved only in the
history of the branch.

dev-docs/AGENT-TOOLING.md keeps this branch's settings table - which draws the
line between build artifacts and generated documentation - minus the `hooks`
row, and loses the section describing the hook. Neither side's remaining extra
row survives: `worktree.symlinkDirectories` was already removed here when the
repository became a workspace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eighteen review findings, each verified against the tree before and after.

The worst was silent. Every delegating root script dropped its flag arguments:
`npm run test:ci -- --coverage` reached the workspace as bare `jest --forceExit`,
so CI has been uploading nothing to Codecov while staying green. Demonstrated
with `npm run test:jest -- --listTests`, which ran all 6232 tests instead of
listing them. Every delegating script now ends with `--`, and `test:ci
--coverage` writes hyperformula/coverage at 97.42%.

The release script was never adapted. It read and wrote ./package.json - now the
private root manifest with no version - so a freeze would have bumped the wrong
file, skipped HT_RELEASE_DATE, and found no changelog. It now resolves the
package through PKG_DIR, and a dry run produces the right version, dates and
changelog section. A third path the review did not catch turned up in that dry
run: the private test suite check still pointed at test/hyperformula-tests.

check:licenses both failed outright and, if forced to pass, checked nothing:
license-checker reads <start>/node_modules, and npm hoists, so from
hyperformula/ it sees an empty tree and from the root a manifest with no
dependencies - zero packages either way. Replaced with script/check-licenses.mjs,
which takes the production set from `npm ls --omit=dev` and the licence data from
a full license-checker run. It resolves 3 dependencies and fails when the
allowlist is tightened, which was tested rather than assumed.

Also: performance-report.md was written inside the workspace and read from the
root; code-examples-generator.sh kept repo-root-relative paths after moving to
docs/, so it processed zero files and exited 0; docs:build:cf never installed the
portal, which is the command Cloudflare runs; docs:install used `npm install`
against a committed lockfile; the licence-header rule resolved against the
working directory, so linting from inside the package threw on every file;
coverage globbed the AGENTS.md files in src/; the .npmignore un-ignore for the
logo matched nothing after the move; test:jest and test:ci named
../node_modules paths that only hold while npm hoists - NODE_ICU_DATA is dropped
outright, since Node has shipped full ICU since v13 and .nvmrc pins 22.

hyperformula-ui came out of the workspaces array. npm silently ignores an entry
with no package.json, so it bought nothing, and three documents claimed the
workspace existed - one promising it would "resolve once the package lands", when
in fact `npm ci` would fail against this lockfile. It goes back in the same
change that adds the package.

The documentation followed the code: the public building guide named six root
scripts that no longer exist and two arg-passing forms that were broken, the
portal README still told developers to install docs dependencies with a root
`npm install`, and dev-docs, two skills and .worktreeinclude each pointed at
something this branch had moved or deleted.

Verified: lint 0 errors, jest 502 suites / 6232 passed, tsc --noEmit, bundle-all
with the publish check, the licence gate positive and negative, a release dry
run, the docs generator, and the full portal build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three structural changes, all following the same rule: a thing lives with
whatever owns it, and exactly one place holds each fact.

dev-docs/ now exists at two levels. The repository level keeps what applies
everywhere - the definition of done, code style, testing standards,
documentation rules, build and release, pull requests, worktrees, the agent
setup. hyperformula/dev-docs/ holds the engine's internals: architecture, the
parser, the interpreter, the dependency graph, the function catalogue,
translations, its test suites and its own build steps. This reverses a call made
during the migration, which kept one directory on the grounds that two would
fragment the single source of truth. That conflated a single source with a
single directory: splitting by ownership is not duplication, and keeping every
package's internals at the root would have made the root a dumping ground the
moment hyperformula-ui lands.

Three pages were genuinely mixed and were split rather than moved. TESTING keeps
what a change must prove and how a case is written at the root, and takes the
suites, the private one, and the per-change coverage into the package. BUILD
keeps installing the workspace, generating the documentation, deploying the
portal and cutting a release, and takes the intermediate lib/ build and
packaging down. CODE-STYLE keeps style and TypeScript, and the hot-path table
becomes hyperformula/dev-docs/PERFORMANCE.md.

script/ splits three ways, which the callers decided rather than judgement:
every script had exactly one caller and the caller named its owner. check-file,
check-publish-package and if-ne-env go to hyperformula/script/;
prepare-cf-assets joins the generator in docs/script/; release/ and
check-licenses.mjs stay, because they span the packages and the sibling
repositories. Twelve call sites stop reaching across a package boundary, and two
scripts stop resolving paths through ../hyperformula and ../docs - a smell the
move introduced and this removes.

examples/ is deleted. Its three PNGs were byte-identical duplicates of files in
docs/.vuepress/public/, which is what the site actually serves through
$withBase; the remaining five files were referenced nowhere in the repository, in
any config, workflow or package script. It was not moved under docs/ because
docs/examples/ already exists and is a different thing - the runnable examples
embedded in the guides.

Verified: lint 0 errors, jest 502 suites / 6232 passed, the licence gate,
bundle-all through the relocated engine scripts with the publish check, and the
full portal build including build:cf through the relocated prepare-cf-assets.
Every relative link in AGENTS.md, both dev-docs levels, the skills and the
READMEs resolves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings a000d8f from feat/hf-359-monorepo-agent-setup. Nine files conflicted,
because the audit corrected pages that this branch had since moved or split.

The corrections were carried to wherever the content now lives rather than
resolved by picking a side. ARCHITECTURE.md, INTERPRETER.md,
FUNCTION-CATALOGUE.md and I18N.md are in hyperformula/dev-docs/ here, so the two
file-location fixes, the single authoritative list of the five places a function
change must touch, the loud-versus-silent split, the dropped docs/api link and
the separators correction all landed there. TESTING.md and BUILD.md are split
between the two levels on this branch, so each half took the part of the fix
that belonged to it.

Three link depths changed with the files: the skills now point at
hyperformula/dev-docs/ for INTERPRETER, FUNCTION-CATALOGUE and I18N. One
pre-existing defect surfaced while resolving: dev-docs/TESTING.md pointed at the
package's testing page as `TESTING.md`, which from that file is itself. Fixed.

test:compatibility was already corrected here, in the same way the audit
recommends, so the base's change to it merged as a no-op.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reverses the per-package cadence this branch had built. CHANGELOG.md returns to
the repository root as the single history for every package - the file keeps its
identity, since it was only moved into hyperformula/ by this branch in the first
place - and the index that replaced it is gone.

Getting that changelog into the published tarball took three attempts, because
npm will not do it the obvious ways. A `prepack` script that copies the file in
runs too late: npm resolves the pack file list before the hook, so the copy is
on disk and absent from the tarball. A symlink to ../CHANGELOG.md is excluded
outright. What works is an explicit `copy-changelog` step in front of anything
that packs, so it is wired into verify:publish-package and into the release
script, and the copy is git-ignored.

That fix uncovered a second monorepo gap in release.sh, which the earlier pass
missed because it only corrected the paths the script reads. Step 7 ran `npm
publish` at the repository root, where the manifest is now private and npm
refuses to publish. It publishes the workspace now.

The decision itself is recorded in dev-docs/STRUCTURE.md with what it costs: a
release cuts every published package at the same version whether or not its code
moved, in exchange for one number that identifies the state of the whole
repository. hyperformula-ui no longer gets a changelog of its own when it lands,
and its version moves in step with the engine's - the release script bumps one
manifest today and will need the second in that same change.

Verified: the tarball carries CHANGELOG.md again (Publish package check: OK), a
release dry run finds the root file and inserts the version section, lint 0
errors, jest 502 suites / 6232 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sequba
sequba marked this pull request as ready for review September 1, 2026 10:49
@sequba
sequba merged commit 72001ee into feat/hf-359-monorepo-agent-setup Sep 1, 2026
28 of 30 checks passed
@sequba
sequba deleted the feat/hf-359-monorepo-structure branch September 1, 2026 10:50
@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.32%. Comparing base (0c2372b) to head (480123c).
⚠️ Report is 1 commits behind head on feat/hf-359-monorepo-agent-setup.

Additional details and impacted files

Impacted file tree graph

@@                        Coverage Diff                        @@
##           feat/hf-359-monorepo-agent-setup    #1758   +/-   ##
=================================================================
  Coverage                             97.32%   97.32%           
=================================================================
  Files                                   195      195           
  Lines                                 15739    15739           
  Branches                               3390     3390           
=================================================================
  Hits                                  15318    15318           
  Misses                                  421      421           
Files with missing lines Coverage Δ
hyperformula/src/AbsoluteCellRange.ts 94.59% <ø> (ø)
hyperformula/src/ArgumentSanitization.ts 100.00% <ø> (ø)
hyperformula/src/ArraySize.ts 100.00% <ø> (ø)
hyperformula/src/ArrayValue.ts 100.00% <ø> (ø)
hyperformula/src/BuildEngineFactory.ts 100.00% <ø> (ø)
hyperformula/src/Cell.ts 94.39% <ø> (ø)
hyperformula/src/CellContentParser.ts 100.00% <ø> (ø)
hyperformula/src/CellValue.ts 77.77% <ø> (ø)
hyperformula/src/ClipboardOperations.ts 96.55% <ø> (ø)
hyperformula/src/Config.ts 94.11% <ø> (ø)
... and 180 more

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants