Repository navigation
CND 0.5.0 production: declaration 0.2.0, builder, matching v2, CLI, visitors - #12
Merged
Merged
Conversation
Proposal 0013 lets a CND omit every field that holds its default. The writer keeps id, required fields and free-form objects; the round trip and the content hash are pinned over the whole fixture corpus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…eclaration Texts take the CND's RichText or a plain string; the link families live in texts, so hyperlinks are declarable; numbering keeps only the authored name; list items, term items, cells and footnotes hold declared nodes and are strict. Version 0.2.0: a 0.1.0 declaration is refused rather than misread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…ilder Every nested node is minted an id; heading_path is threaded through every container; the counter engine numbers headings, figures and equations in full-walk order and keeps only authored words. Authored numbering with the engine off is a build error (numbering-without-engine), never a silent drop. Goldens are written through Cnd.to_json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…est_reconcile Matching v1 keeps its passes and keys; the node set is the full walk and the structural path is the spec section 8 path, with footnote content keyed by the note's label so a pool reorder moves nothing. The remap and its guards reach every slot and the footnotes. New vector cases: an edited list item, two cells as two slots, footnote content. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…s id MATCHER_VERSION is now v2: the same 0.5 inputs pair differently from the previous matcher (spec section 8 path, full walk, footnote content keyed by its note's label). A node hash excludes nested nodes, so two containers of one shape hash alike; in the two hash passes a node with child slots is keyed on its node hash plus a digest of its descendants' hashes. The spec node hash is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
A heading whose section changed has not itself changed (spec section 10), so a moved heading must stay recognisable. The nested-content digest applies only to list, terms, table, layout, quote and admonition, whose own hash carries little content; headings and figures already hash their text or caption. Restores the original moved-into-a-section expectation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
A container whose nested content was edited and which also shifted position missed every earlier pass and lost its id. After path+type, the still-unmatched list, terms, table, layout, quote and admonition pair on their own node hash without the digest; twins have already paired through the digest. Also fixes a stale "v1" in a test docstring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
matching.json is the cross-implementation oracle, so every pass needs a vector. Case 11: a table with one cell edited and a paragraph inserted above it pairs on its node hash alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…test_visitor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…itor Admonition and layout panels, rich-text details (marks, every link family read from the node's texts, hyperlinks by href), numbering as number and counter, task-list counts, code titles, figure descriptions, document status, version and extra, and footnote blocks in the pool panel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
The document panel and the pool panels passed CND values (title, status, version, extra, footnote and bibliography text) to Rich as plain strings, which Rich parses as markup: a stray closing tag crashed the render. They are wrapped in Text now. The document grid also gets a column gap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
hash --nodes lists the full walk, as fixtures/hashes.json does; build writes through Cnd.to_json; inspect displays every 0.5 node type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…013) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…hyperlinks; empty parking list Every test module runs again. Spec section 12 states the shorthand, the authored numbering name and the build error without the engine, the moved strictness boundary, and that hyperlinks are declarable through rich text. The CND-26 wording items are fixed (paragraph example id, "rendered text"). Proposal 0013 notes that the authoring hint rename supersedes the content_kind part of ADR 0023. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
Every read_text and write_text of CND or declaration content in the CLI and the fixture scripts names its encoding, so a non-UTF-8 locale can neither misread a file nor write one another implementation cannot read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
… shape A 0.1 declaration failed on "Extra inputs" errors that never named its version, and `cnd validate` printed ok for a CND stamped 0.4.0 or 9.9.9. - The CLI loaders read cnd_version and declaration_version from the raw data first and refuse another version by name, with the supported one. - Declaration refuses another declaration_version in a before-validator, so a caller of model_validate gets the same single error. - validate() gains cnd-version-unsupported for a CND built in code with another version; spec section 9 lists it. Tests use main's own minimal.cnd (stamped 0.4.0, a shape 0.4 parsed unchanged) and article.decl.yaml (0.1.0) as real old documents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
build() handed source, doc, raw and nested state_metadata values to the CND as the declaration's own objects. Mutating the declaration after a build silently edited the earlier CND, and diff(c1, c2) then reported nothing changed. build() now works on a deep copy of the declaration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
After `cnd.metadata.update(it => it + (kind: "report", revision: "1"))` and one `cnd.table(..., kind: "data")`, the state was `(revision: "1")`: the hint's cleanup removed the author's document-level kind, and an inner hint removed an outer one. The hint now saves the previous value in a context before its update and restores it after the table, or removes the key only when it was absent. The body stays outside the context, at the call site. The new tests compile a document with `typst query` and skip when the typst binary is missing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…aths
The BaseVisitor docstring told users to walk cnd.footnotes[i].children,
which yields ("nodes", 0) paths that name a body node. visit() gains
full=True, which runs Cnd.iter_all(): the body, then each footnote's
content, with spec section 8 paths and slot "footnotes". The default
stays the body walk. iter_all() now takes max_depth and stop_predicate,
so should_stop_descent prunes inside footnotes too.
Spec section 8 no longer claims `cnd inspect` shows the order a CND
walks in: it shows the body walk only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…declaration 0.2.0 only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
ADR 0029 extends ADR 0018 and records what matching v2 computes. It covers the full walk, spec section 8 paths, footnote content keyed by its note's label, and the container key: node hash plus a descendants digest, with headings and figures left out. It also covers the last pass, empty containers and the known limits. The docs index marks 0018 "extended by 0029". The last pass, which pairs leftover containers on their node hash alone, now reports matched_by "container-hash" (PASS_CONTAINER_HASH) instead of "hash", so a caller can tell it from an unchanged move. In matching.json, the one changed hunk is case 11's table. The match.py docstring's numbered passes now match its prose. The README, the CLI and the diff docstring point at ADR 0029. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
This reverts commit 6e08449.
The author still writes `cnd.table(..., kind: "data")`. The state now carries the hint under the dedicated key `table-kind`, which an emitter reads and the CND writes as `table.kind`. A document-level `kind` the author sets therefore never collides with the hint. The hint keeps the plain set-then-unset pattern: nothing is read back, so no context update has to settle. Compile tests run with the typst binary, and skip without it: - five sequential hinted tables, failing on any convergence warning; - a document-level kind that survives two hinted tables, while each table sees its own table-kind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
…state key Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the last plan of the CND 0.5.0 series. It ports everything that was still on the old format, and leaves no test module parked. With it merged,
format-0-5-0is ready formain; only the release steps remain.What changes
Cnd.to_json()writes a CND without its default-valued fields. Reading the output back gives the same CND and the same content hash. Every CND the SDK writes goes through it.numbering.valueis refused.heading_paththrough containers.numbering-without-enginewhen an authored numbering cannot be resolved.validate()(rulecnd-version-unsupported).container-hashpass pairs a container whose content was edited and which also moved.BaseVisitordispatches every 0.5 node type.visit(cnd, full=True)also walks footnotes, with spec paths.cnd inspectshows the new nodes, and never reads CND text as Rich markup.hash --nodeslists the full walk, ashashes.jsondoes.cnd.table(kind: …)replacescontent_kind:. The hint is stored under its own state key,table-kind, so author metadata is never touched.[Unreleased]entry.Review
typstis installed.Before main
Two release steps remain:
pyprojectto 0.9.0;Follow-ups: CND-26, CND-50, CND-51.
Part of CND-40
🤖 Generated with Claude Code
https://claude.ai/code/session_01XxXUiDn2QyzNTYnZpeVFVS