Skip to content

feat(charts): chartN locator, docx:chart hint, charts list/extract (first slice of #43) - #51

Open
kklimuk wants to merge 1 commit into
mainfrom
claude/triage-issue-43-charts-read
Open

kklimuk wants to merge 1 commit into
mainfrom
claude/triage-issue-43-charts-read

Conversation

@kklimuk

@kklimuk kklimuk commented Nov 6, 2026

Copy link
Copy Markdown
Owner

🤖 docx-cli triage

First slice of #43: Phase 1 (visibility) and Phase 2 (charts list / charts extract). Both are read-only.

What was wrong

A native Word chart read as `[chart]` with no id, type, title or data. Before (main, tests/fixtures/strict-profile.docx): `[chart]` <!-- p1 -->. The only way to see the numbers was raw part get on the chart XML.

What changed

  • chartN locator. Positional, in document order, across the body, table cells and text boxes. Only real charts get one; SmartArt and shapes keep their bare placeholder.

  • AST. ChartRun is now a union, and NativeChartRun carries:

    • id and chartTypes[] (a combo lists several)
    • title, plus series[] read from the caches: name, categories and values (a gap is null), the *Ref formulas and formatCode
    • dataSource (embedded | external | none) and workbook (the part name)
    • size, float/wrap/align, and trackedChange

    info schema is updated to match.

  • Read hint. Output on the new fixture: `[chart]` <!-- docx:chart chart0 type="column" title="Revenue by Quarter" series="2" points="4" size="6x3.5in" data="none" -->. data only appears when it isn't embedded; float/wrap/align follow the image rules. The importer drops the hint, like every other docx: comment.

  • docx charts list FILE. Prints [{id, at, type, title?, series, points, data, workbook?}].

  • docx charts extract FILE --at chartN [--json]. Prints CSV with a category,<series…> header row; a gap is an empty cell. --json prints the full series objects. An unknown id fails with CHART_NOT_FOUND (exit 3).

  • Core.

    • New src/core/chart/: the reader, the Charts lens and the CSV writer.
    • New ChartsView (ast/document/charts.ts) preloads the chart parts, because the body walk is synchronous. It has no writeTo, so a save never re-serializes a chart part.
    • resolveRelationshipTarget (moved from raw) is now shared.
  • Fixture. tests/fixtures/charts.docx: a column chart in the body and a column+line combo in a table cell, both cache-only. The builder dogfoods create + raw part add + raw insert. It's added to CORE_FIXTURES.

  • Docs. REFERENCE.md, top-level --help, info locators, SKILL.md (regenerated) and its commands reference, CONTRIBUTING.md, the root/src/cli/src/core/ast CLAUDE.md files, and a new src/core/chart/CLAUDE.md.

Verification

  • After, on strict-profile.docx:
    • read prints `[chart]` <!-- docx:chart chart0 type="column" series="3" points="4" size="6x3.5in" -->.
    • charts list gives data:"embedded" with workbook:"word/embeddings/Microsoft_Excel_Worksheet.xlsx".
    • charts extract --at chart0 gives category,Series 1,Series 2,Series 3 followed by 4 rows.
  • edit --at p2 "Revenue: " on the fixture keeps the chart, and word/charts/chart1.xml comes through byte-identical (there's a test for this).
  • docx validate tests/fixtures/charts.docx: valid. The fixture rebuild is deterministic.
  • bun run check ✅ bun run test:unit ✅ (2111 tests)
  • /simplify (single inline pass, done without the Agent tool): shared the drawing placement and size/placement hint helpers between images and charts, and made one chart walker for the lens.
  • /code-review xhigh: the forked review looked at the wrong checkout, so I reviewed this diff by hand. That added a cap on c:pt idx / ptCount so a corrupt chart can't make us allocate a huge array.
  • Not run here: the LibreOffice round-trip of the new fixture (no soffice in this environment) and the weak-agent harness.

Decisions for you

  • Type vocabulary. chartTypes uses friendly labels: an upright barChart reads as column (and bar3DChart as column3D), matching Word's dialog and the planned charts add --type column. Everything else is the element name minus Chart (pie3D, area). The alternative is to keep the raw element names in the AST.
  • Line endings. extract CSV ends lines with LF, not RFC 4180's CRLF, because it's friendlier in terminal pipelines. The planned set-data parser should accept both.
  • Open question 1 is unchanged. Chart text isn't in find/replace/wc yet, so the title is visible in the hint but find "Revenue by Quarter" won't match it.
  • Not in this slice:
    • charts in headers/footers (marginals are read as text only, so they get no chartN)
    • chartex (cx:chart) recognition plus a readonly hint
    • stale detection against the workbook
    • Phase 3 set-data (needs the xlsx patcher, the CSV parser and your calls on open questions 2–5) and Phase 4 charts add/delete
    • schema-validating chart parts
    • part-level rels in raw
    • the third-party fixtures (not fetched, by policy) and a quarterly-report weak-agent scenario

Refs #43


Generated by Claude Code

@kklimuk

kklimuk commented Nov 6, 2026

Copy link
Copy Markdown
Owner Author

🤖 docx-cli triage

CI note: Integration Tests (LibreOffice) failed on 19dde0d, and the failure isn't this PR's. The Install LibreOffice step hit its 5-minute cap while downloading from azure.archive.ubuntu.com. The download stalled for about 3 minutes on libreoffice-style-colibre, then crawled through libreoffice-common, so no test ran. This is the same apt-mirror stall that the ci.yml comment on main describes. Every other check is green: Unit Tests, Lint + Types + Dead Code, the Windows LibreOffice render, and all smoke builds.

This routine doesn't re-run workflows, so the job hasn't been re-run. That matters here, because this check is the only place the new charts.docx fixture round-trips through LibreOffice, and that wasn't verified locally either.

Action needed: approve/merge — re-run the "Integration Tests (LibreOffice)" job on PR #51 and confirm it's green before merging.


Generated by Claude Code

kklimuk added a commit that referenced this pull request Nov 6, 2026
…ror (#55)

Three PRs (#50, #51, #52) went red on the integration job's Install
LibreOffice step, killed at its 5-minute cap. Not a code failure: the
runner's azure.archive.ubuntu.com mirror served the ~100 MB of .debs at
~35 KB/s while metadata stayed fast. Acquire::Retries can't help, since a
slow transfer never errors.

- Resolve the exact package set after `apt-get update` and key an
  actions/cache entry on the .deb filenames (name_version_arch, not URIs,
  so a mirror switch doesn't change the key). restore-keys gives partial
  hits; apt fetches only what's missing and verifies every cached .deb
  against the signed index.
- Download-only with a per-attempt timeout; a stalled first attempt
  rewrites the mirrorlist to archive.ubuntu.com and retries. Install then
  runs with --no-download, so a timeout never interrupts dpkg.
- Save right after download (not post-job) so a red test run still warms
  the cache; autoclean before saving so old versions don't accumulate, and
  re-key from the lists actually downloaded against.
- Job-level `shell: bash` for pipefail, so a failed --print-uris fails the
  step instead of keying on an empty list.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
First slice of #43 (Phase 1 visibility + Phase 2 read-only verbs). A native
Word chart used to read as an anonymous `[chart]`; now each one gets a
positional chartN id (body, table cells, text boxes) and a
<!-- docx:chart chartN type=… title=… series=N points=N size=… --> hint,
the AST NativeChartRun carries the cached series, data source and workbook
part, and `docx charts list` / `charts extract --at chartN [--json]` expose
the manifest and the data as CSV. Read-only: ChartsView has no writeTo, so
chart parts and workbooks stay byte-identical across saves.

Refs #43

Triage-Routine: true
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LkctELRxzFrjMAGvfnY1BE
@kklimuk
kklimuk force-pushed the claude/triage-issue-43-charts-read branch from 19dde0d to 52ca8b9 Compare November 6, 2026 17:39

This branch has not been deployed

No deployments
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