Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2eb1ad9
feat(transaction): support fresh package creation
bobzhang Jul 17, 2026
d0bcfdb
feat(xlsx): add bounded transactional batch plans
bobzhang Jul 17, 2026
b2b3729
feat(office): expose transactional xlsx mutations
bobzhang Jul 17, 2026
4a751ab
test(xlsx): validate office mutations end to end
bobzhang Jul 17, 2026
5dedc1a
fix(xlsx): bound transaction materialization
bobzhang Jul 17, 2026
ad5b1d0
fix(xlsx): close resource safety review gaps
bobzhang Jul 17, 2026
7132742
fix(batch): validate bounded plans before workbook I/O
bobzhang Jul 17, 2026
e9b8d1a
fix(xlsx): enforce bounded XML validation and serialization
bobzhang Jul 17, 2026
3df6028
feat(office): report source-free creation provenance
bobzhang Jul 17, 2026
c0ea83d
fix(xlsx): bound relationship materialization
bobzhang Jul 17, 2026
d408b4f
test(office): refresh capability snapshots
bobzhang Jul 19, 2026
906d41b
fix(xlsx): preserve relationship reader boundaries
bobzhang Jul 19, 2026
9cff1ab
docs: record Office parity handoff
bobzhang Jul 19, 2026
f8de256
test(ooxml): restore content type grammar coverage
bobzhang Jul 19, 2026
5ef3f1f
test(xlsx): track relationship target boundary
bobzhang Jul 19, 2026
b2b84d6
test(xlsx): tolerate backend financial rounding
bobzhang Jul 19, 2026
36b5a2d
docs: record parallel validation worktrees
bobzhang Jul 19, 2026
d44ea77
test(office): refresh xlsx capability cram
bobzhang Jul 19, 2026
76f07ae
fix(xlsx): close OOXML validation limit bypasses
bobzhang Jul 19, 2026
f5760bc
fix(xlsx): harden logical OOXML limit classification
bobzhang Jul 19, 2026
822de26
test(office): use namespaced relationship limit fixture
bobzhang Jul 19, 2026
591654d
fix(xlsx): meter relationship preflight work
bobzhang Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,11 @@ jobs:
- name: Resolve dependencies
run: moon update

# Format check across the whole workspace. The 2026-07-10 nightly's
# moonfmt migrates moon.pkg `options("is-main": true)` to a new
# `pkgtype(kind: "executable")` form that the same nightly's default
# parser still REJECTS (the new syntax is behind preview feature
# flags), so a repo carrying either form cannot satisfy both halves.
# Until the parser ships by default, restore moon.pkg after fmt and
# gate formatting on source files only.
# Format check across the whole workspace, including executable package
# manifests now that every member uses the supported `pkgtype` syntax.
- name: Format check
run: |
moon fmt
git checkout -- ':(glob)**/moon.pkg'
if ! git diff --quiet; then
echo "::error::moon fmt changed files; run moon fmt and commit the result."
git --no-pager diff
Expand Down Expand Up @@ -279,9 +273,9 @@ jobs:
and .success == true
and .data.schema == "office.capabilities/2"
and (.data.fingerprint | test("^crc32:[0-9a-f]{8}$"))
and ([.data.records[].name] == ["docx", "xlsx", "help", "identify", "outline", "get", "text", "query", "raw"])'
and ([.data.records[].name] == ["docx", "xlsx", "help", "identify", "outline", "get", "text", "query", "create", "batch", "raw"])'
moon run --target wasm office/cmd/office -- help all --jsonl 2>office-wasm.err \
| jq -se 'length == 9 and all(.[]; .schema == "office.capability/2")'
| jq -se 'length == 11 and all(.[]; .schema == "office.capability/2")'
if moon run --target wasm office/cmd/office -- help xlxs --json >office-wasm-error.json 2>office-wasm.err; then
echo "expected unknown office help format to fail"
exit 1
Expand Down Expand Up @@ -332,6 +326,27 @@ jobs:
and .data.schema == "office.xlsx.query/1"
and .data.matched_total == 4
and [.data.matches[].reference] == ["F11", "G11", "H11", "I11"]'
# Fresh creation and strict batch mutation use the same async,
# bounded transaction path on wasm as native.
xc=$(moon run --target wasm office/cmd/office -- create xlsx ci-office-created.xlsx --sheet Data --json 2>office-wasm.err) || { echo "office XLSX create failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xc" | jq -e '.success == true
and .data.schema == "office.xlsx.create/1"
and .data.sheet == "Data"
and .data.transaction.committed == true'
cat >ci-office-batch.json <<'JSON'
{"schema":"xlsx.batch/1","ops":[{"op":"set","params":{"sheet":"Data","cell":"A1","value":"wasm"}},{"op":"formula","params":{"sheet":"Data","cell":"B1","formula":"=LEN(A1)"}}]}
JSON
xb=$(moon run --target wasm office/cmd/office -- batch ci-office-created.xlsx ci-office-batch.json --out ci-office-batched.xlsx --json 2>office-wasm.err) || { echo "office XLSX batch failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xb" | jq -e '.success == true
and .data.schema == "office.xlsx.batch/1"
and .data.stats.operation_count == 2
and .data.stats.touched_cells == 2
and .data.transaction.committed == true
and any(.warnings[]; .code == "office.xlsx.full_rewrite")'
xbg=$(moon run --target wasm office/cmd/office -- get ci-office-batched.xlsx '/xlsx/sheet[name="Data"]/range[A1:B1]' --json 2>office-wasm.err) || { echo "office XLSX batch readback failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xbg" | jq -e '.success == true
and .data.cells[0].raw.value == "wasm"
and .data.cells[1].formula == "LEN(A1)"'
# DOCX structured reads share one canonical bounded projection.
# Drive every command through the wasm async filesystem path.
o=$(moon run --target wasm office/cmd/office -- outline docx2html/tests/cram/fixtures/single-paragraph.docx --json 2>office-wasm.err) || { echo "office DOCX outline failed; stderr:"; cat office-wasm.err; exit 1; }
Expand Down
10 changes: 7 additions & 3 deletions README.mbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,17 @@ moon run office/cmd/office -- outline book.xlsx --json
moon run office/cmd/office -- get book.xlsx '/xlsx/sheet[name="Data"]/range[A1:C12]' --json
moon run office/cmd/office -- text book.xlsx --under '/xlsx/sheet[name="Data"]' --json
moon run office/cmd/office -- query book.xlsx 'cell[type=formula]' --under '/xlsx/sheet[name="Data"]' --json
moon run office/cmd/office -- create xlsx new-book.xlsx --sheet Data --json
moon run office/cmd/office -- batch new-book.xlsx changes.json --out revised.xlsx --json
```

DOCX results use the `office.docx.{outline,element,text,query}/1` family and
XLSX results use `office.xlsx.{outline,element,text,query}/1`; every result is
inside `office.output/1`. See
XLSX reads use `office.xlsx.{outline,element,text,query}/1`; creation and batch
use `office.xlsx.{create,batch}/1`. Every result is inside `office.output/1`.
See
[Unified Office DOCX reads](docs/office-docx-read.md),
[Unified Office XLSX reads](docs/office-xlsx-read.md), and
[Unified Office XLSX reads](docs/office-xlsx-read.md),
[Transactional Office XLSX mutations](docs/office-xlsx-mutations.md), and
[Canonical Office selectors](docs/office-selectors.md).

## XLSX command-line tool
Expand Down
187 changes: 187 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# OfficeCLI parity handoff

Last updated: 2026-07-19 (Asia/Shanghai)

This file is the handoff for the non-PPT OfficeCLI parity effort tracked by
[#139](https://github.com/moonbitlang/office.mbt/issues/139). PowerPoint and MCP
are deliberate non-goals. There are no third-party compatibility obligations,
so future work should prefer a clean, durable contract over compatibility
aliases.

## Landing state

- [PR #172](https://github.com/moonbitlang/office.mbt/pull/172) is merged into
`main`. It delivered the bounded unified XLSX read surface (`outline`, `get`,
`text`, and `query`) while retaining authenticated OOXML relationship
discovery, Markup Compatibility processing, cancellation checks, preserved
drawing state, and fail-closed resource accounting.
- [PR #173](https://github.com/moonbitlang/office.mbt/pull/173) is the final
in-flight PR from this work session. It is based on `main` and delivers
transactional XLSX creation and strict batch mutation. If this file is read
on `main`, #173 has landed and [#162](https://github.com/moonbitlang/office.mbt/issues/162)
should be closed. If it is read on the feature branch, finish only #173's
exact-head review and CI; do not add another capability to it.
- No additional implementation PR was opened. The known shared-formula
compatibility problem is isolated in
[#176](https://github.com/moonbitlang/office.mbt/issues/176).

The current #173 branch is `agent/office-x3-xlsx-batch`; the working tree used
to finish it was `/private/tmp/mbtexcel-office-xlsx-batch`. The reference
OfficeCLI checkout remains `.repos/officecli` in the primary repository
working tree.

## What is complete after #173

The following major-parity foundations are implemented and should not be
rebuilt in later PRs:

- A1-A5: the umbrella `office` command, versioned capability/help protocol,
canonical selectors, atomic validated transactions, and validated raw OOXML
fallback.
- D1-D2: preservation-safe DOCX edit sessions plus bounded DOCX `outline`,
`get`, `text`, and `query`.
- X1-X2: provenance-checked bounded XLSX reads plus bounded XLSX `outline`,
`get`, `text`, and `query`.
- X3 (#173): `office create xlsx`, strict `xlsx.batch/1` parsing, transactional
XLSX mutation, dry-run/no-replace/overwrite behavior, preservation reports,
bounded serialization, and OpenXML validation.

Important implementation invariants:

- File publication uses `moonbitlang/async`; no new C stubs are required.
- Sync and async paths share the same semantic implementation and resource
policy. Async scheduling cooperation inside long parser work is intentionally
deferred to #174 rather than being faked with entry- or sheet-level yields.
- XLSX full rewrites must preserve unsupported drawing anchors, relationships,
and dependent parts already retained by the reader. Generated drawing object
and relationship ids must avoid preserved ids.
- Read limits remain cumulative across a package. Relationship defaults match
the stricter #172 parser boundaries so a workbook written by the library is
not rejected by the default reader; callers can still select lower limits.
- Capability output is schema-driven and snapshot-tested. Never advertise a
command or format variant before its end-to-end implementation exists.

The detailed contracts live in:

- `docs/office-major-parity.md`
- `docs/office-xlsx-read.md`
- `docs/office-xlsx-mutations.md`
- `docs/office-docx-read.md`
- `docs/office-transactions.md`
- `docs/agent-json-schemas.md`

## Remaining work, in recommended order

Each item below already has an issue. Do not duplicate it. Take one issue per
PR unless the issue itself is first split into independently useful children.

1. [#176 — valid overlapping shared-formula ranges](https://github.com/moonbitlang/office.mbt/issues/176)
is a small, known compatibility fix. Confirm the OOXML/Excel behavior, allow
valid overlap between distinct shared indexes without weakening same-group
validation, and keep bounded/cancellable materialization. The repository
fixture `fixtures/excelize/test/Book1.xlsx` demonstrates the problem. Remove
any raw-command workaround only after the semantic reader accepts the file.
2. [#163 — D3 fresh DOCX create and batch](https://github.com/moonbitlang/office.mbt/issues/163).
Reuse the existing DOCX writer and the X3 transaction/publication pattern;
do not copy the XLSX engine or mix annotation mutation into this PR.
Header/footer authoring remains separately tracked by #95.
3. [#164 — D4 DOCX annotation mutations](https://github.com/moonbitlang/office.mbt/issues/164).
Build only on the source-pinned D1 edit session and preserve unrelated parts.
4. [#165 — V1 cross-format `validate` and `issues`](https://github.com/moonbitlang/office.mbt/issues/165).
This also subsumes the standalone exit-status gap in #75.
5. [#166 — P1 deterministic HTML/SVG preview](https://github.com/moonbitlang/office.mbt/issues/166).
Static/offline output only; no browser service, watch mode, or screenshot
dependency.
6. [#167 — R1 replayable semantic dump](https://github.com/moonbitlang/office.mbt/issues/167).
Replay must use the canonical create/batch engines rather than a new writer.
7. [#168 — T1 XLSX/DOCX template merge](https://github.com/moonbitlang/office.mbt/issues/168).
Keep the placeholder language strict and non-executable.
8. [#169 — F1 final non-PPT acceptance](https://github.com/moonbitlang/office.mbt/issues/169).
Run only after the child capabilities above have landed. This is the place
for the final fresh-agent discoverability exercise and the ultra review.

Architecture work that can proceed independently, but must stay in its own PR:

- [#174 — scheduler-cooperative Office parsing](https://github.com/moonbitlang/office.mbt/issues/174).
Implement pure-MoonBit fuel-bounded resumable machines with sync and async
drivers. Use public `moonbitlang/async` APIs, no C stubs, native threads,
private runtime imports, or duplicated parsers. Scheduling fuel is separate
from security budgets.

Other existing component issues (#74, #76, #94, #95, and #155) remain open and
must not be silently folded into an Office parity PR. Publication in #155 needs
separate authorization.

## Small-PR rule

Do not repeat the size of #172 or #173. A PR should have one root cause or one
user-visible capability, one independently testable acceptance boundary, and a
clear revert story.

- Do not stack a new capability on an unmerged feature branch.
- Separate reusable foundation, CLI exposure, and unrelated compatibility
fixes when each can land and be useful independently.
- As a review trigger, stop and split when a PR approaches roughly 1,000
hand-written changed lines or touches more than about 15 production files.
Generated interfaces/snapshots are excluded, but they do not justify mixing
scopes.
- If a review discovers a non-blocking issue outside the stated acceptance
criteria, file an issue and fix it in a new small PR. Do not let it expand the
current PR.
- Commit logical, buildable steps regularly. Avoid one final catch-all commit.

## Required review and landing protocol

For every PR:

1. Rebase on current `origin/main`; do not review a stale stacked base.
2. Run `moon info && moon fmt`, inspect all `.mbti` changes, then run
`moon check` and the focused tests.
3. Run the relevant native, Wasm, and JS gates. For Office CLI changes, build
the native CLI and run `moon cram test office/cmd/office/cram` from the same
stub setup used by CI. Mutation work also needs Microsoft
`DocumentFormat.OpenXml` validation with .NET 8.
Pin all validation runs to one exact commit. To reduce wall time, use a
separate detached worktree (or at least a separate `--target-dir`) for each
target so native, Wasm, and JS can run concurrently without contending on
`.moon-lock`; do not edit the source while those runs are active.
4. Ask a brand-new, ephemeral Codex CLI session to review the exact pushed
head. Use at least `xhigh`; use `max` routinely for cross-package changes
and `ultra` for security architecture or final epic acceptance. Never reuse
the implementation session as the approving reviewer.
5. If the reviewer changes the code, commit the fix and run a new fresh review
over the changed exact head (or a clearly bounded delta ending at it).
6. Merge only when exact-head CI and the fresh review are both green. Update or
close the corresponding issue immediately after landing.

CI-equivalent local commands are documented in `.github/workflows/ci.yml`. The
complete matrix currently includes:

```text
moon info
moon fmt
moon check
moon check --target wasm
moon check --target js
moon test --target wasm
moon test --target js
moon test --target native
```

The workspace currently resolves `moonbitlang/async@0.20.2`. An async upgrade
is allowed when it has a concrete benefit, but it must be an isolated dependency
PR with native/Wasm scheduler and filesystem tests; do not combine it with a
feature PR.

## Deliberate deferrals

- PowerPoint/PPTX.
- MCP, resident mode, and live watch/selection.
- Plugin and language-SDK wrappers.
- Pixel-perfect DOCX pagination, tracked-change authoring, OLE, diagrams, and
other low-frequency long-tail Office features.
- Backwards-compatibility aliases for unreleased APIs.

Keep `docs/office-major-parity.md`, issue #139, and this handoff synchronized as
work lands. The final acceptance issue #169, not an informal percentage, is the
authority for declaring the non-PPT parity effort complete.
Loading
Loading