Skip to content

Commit 42cd0f0

Browse files
authored
Merge pull request #47 from ChanMeng666/release/v1.21.0
chore(release): v1.21.0
2 parents 7de0819 + b8330db commit 42cd0f0

4 files changed

Lines changed: 61 additions & 18 deletions

File tree

AGENTS.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,28 @@ not a work-in-progress. Treat the live artifacts below as the source of truth
1919

2020
| Thing | Current | Where |
2121
|-------|---------|-------|
22-
| **Core package** | `@chanmeng666/archlang@1.20.0` (published, `latest`, with provenance — released tokenlessly via `.github/workflows/release.yml` OIDC trusted publishing) | npmjs.com/package/@chanmeng666/archlang |
22+
| **Core package** | `@chanmeng666/archlang@1.21.0` (published, `latest`, with provenance — released tokenlessly via `.github/workflows/release.yml` OIDC trusted publishing) | npmjs.com/package/@chanmeng666/archlang |
2323
| **Agent interface** | the `arch` **CLI** (`--json`, exit codes, stdin — incl. `ast`/`complete`/`fix`/`suggest`, `compile --from-json`/`-f txt`, `validate --graph`, v1.14's `validate --intent`/`--feedback` + `score --brief`, and the v1.17 **self-describing + bounded-output** layer: manifest-rendered per-command `--help` with worked examples, `--version`, exit-3 did-you-mean on an unknown flag/verb, `describe --room/--select`, `lint\|validate --code/--severity`, `context --section`, `fix --dry-run/--backup` + unified diff) + `SKILL.md` + `spec.llm.md` + **`llms-full.txt` / `arch context`** + **`schemas/plan.schema.json`** + **`schemas/intent.schema.json`** + **`grammars/archlang.gbnf`**. Primary interface stays the CLI; an **optional MCP shim** (`packages/mcp`) is a discoverability channel, not a replacement | `src/cli.ts`, `SKILL.md`, `spec.llm.md`, `llms-full.txt`, `packages/mcp` |
2424
| **MCP server** | `@chanmeng666/archlang-mcp@0.2.2` (published, `latest`; registry entry `io.github.ChanMeng666/archlang-mcp` v0.2.2 live on registry.modelcontextprotocol.io; `packages/mcp/`; stdio shim over the library; tools compile/describe/lint/validate (incl. `intent`)/**score**/repair/fix/suggest/complete + spec/context/schema/**intent-schema**/grammar resources; SDK dep quarantined here, core stays zero-dep) | `packages/mcp/`, `server.json` |
2525
| **VS Code extension** | `ChanMeng.archlang@0.8.0` **live on the Marketplace** (2026-07-26; rebundles core 1.19.0 — `flush`, `dim faces`/`clear`, `W_FIXTURE_BACK_TO_ROOM`/`W_DIM_INSIDE`/`W_DIM_NO_WALL`/`E_FURN_FLUSH`, stable-ref `suggest`). **0.9.0 is built and packaged but NOT yet uploaded**`editors/vscode/archlang-0.9.0.vsix` rebundles core 1.20.0 (`paper`/`axes`/`schedule`/`legend`, `W_SCALE_OVERFLOW`, the operative drawing scale); the extension bundles the core at build time, and `.vsix` files are gitignored, so the artifact is local to whoever ran `npm run package`. Upload stays a human web step at marketplace.visualstudio.com/manage/publishers/ChanMeng (no CI publish exists) | marketplace.visualstudio.com/items?itemName=ChanMeng.archlang |
2626
| **Playground** | deployed, redesigned (**"The Compile Boundary"** one-light-world UI — see below · TypeScript app · pan/zoom · autocomplete · history · click-to-source · format · repair · error-explain · embeddable `embed.html` · circulation Paths toggle · **Copy-for-LLM** · inline diagnostic fixes) | https://playground.archlang.uk |
2727
| **Docs site** | deployed, redesigned (**"The Compile Boundary"** one-light-world UI · compiler-as-hero · VitePress · live editable `<ArchLive>` examples · plain ```` ```arch ```` fences auto-live · serves `/llms.txt` + `/llms-full.txt` + **raw `/<page>.md`** + **`/plan.schema.json`** + **`/archlang.gbnf`**) | https://archlang.uk |
28-
| **Git** | `main`, tags `v1.0.0``v1.20.0` (latest; a `v*` tag push triggers the tokenless OIDC release workflow) | github.com/ChanMeng666/archlang |
28+
| **Git** | `main`, tags `v1.0.0``v1.21.0` (latest; a `v*` tag push triggers the tokenless OIDC release workflow) | github.com/ChanMeng666/archlang |
2929
| **Dataset** | HF `ChanMeng666/archlang-repair-trajectories` (**published, live 2026-07-13** — repair 1200 + authoring 400 rows) — two splits, fully synthetic, self-verifying, CC0-1.0, deterministic from seed `20260712`; generator `dataset/` (`npm run dataset:gen`), permanent CI leakage guard `test/dataset.test.ts` | `dataset/`, huggingface.co/datasets/ChanMeng666/archlang-repair-trajectories |
30-
| **Tests** | 1489 passing (120 files, incl. the fault-injection L1 gate, the G1 oracle-isolation guards, the L2 protocol tests, the judge byte-equivalence fixture, the intent-channel suites, the vocabulary-equivalence classification pin, the dataset contamination/determinism guard, and v1.17's CLI-surface suites — FLAG_KEYS↔manifest bidirectional drift, per-command help/examples, filters-never-gate, the `context --section` splitter-to-generator weld, and `test/docs-flags.test.ts`, the docs↔manifest gate that fails if any hand-written doc names a flag its command doesn't declare, plus v1.19's drawing-quality suites — fixture orientation, `flush` placement, the openings render pass, and `test/repair-coverage.test.ts`, whose postcondition is that every piece a lint pass flags gets a change entry or an `unresolved` entry, never nothing, plus v1.20's sheet-and-datum suites — `test/axes.test.ts` (GB/T numbering incl. the `I`/`O`/`Z` skip and the descending-`y` lettering), `test/sheet.test.ts` (the paper/scale size table, closed-form auto-fit, `W_SCALE_OVERFLOW`, and a pin that a plan with no `paper` is byte-identical) and `test/schedule.test.ts` (schedule rows equal `describe()`'s own areas, legend lists only what is drawn), plus the multi-storey suites — `test/levels.test.ts` and v1.21's `test/vertical.test.ts` (registry dispatch for the three new elements, the drawn symbols, the obstruct-except-the-entry-edge nav-grid rule, same-id shaft identity in `describe().vertical`, upper-storey reachability ± its counterexample, `W_STAIR_UNMATCHED` ±, and cross-level `checkGraph`)) + offline authorability eval (26 briefs, judge v2, `npm run eval:ci`, in CI); typecheck (`noUncheckedIndexedAccess` on) + build + `npm run lint` (Biome) clean | — |
31-
32-
**Latest release: v1.20.0 (2026-07-26)** — Batch-2 sub-release **"sheet & datum"**: `paper <size>
33-
[orientation]` makes the drawing scale **operative** (every annotation size becomes a constant number
34-
of mm on the sheet × the scale denominator, with closed-form auto-fit and the advisory
35-
`W_SCALE_OVERFLOW`), `axes { x at … / y at … }` adds the GB/T 50001 positioning-axis grid (derived
36-
`1 2 3` / `A B C` labels, dash-dot lines + bubbles on layer `A-GRID`, and `dims auto` chain 2 becomes
37-
the true axis chain), and `schedule rooms` + `legend` add margin tables derived from the plan itself.
38-
New `describe()` keys `axes` / `sheet` / `schedule`; new flagship `examples/museum.arch` (~100 × 60 m,
39-
14 rooms, A1 at 1:200). A plan declaring none of the four keywords is byte-for-byte unchanged.
40-
(v1.19.0, 2026-07-25, was the drawing-quality round — `flush`, GB/T `dims auto`, derived fixture
41-
orientation.) The table above is what is live. Canonical release notes
30+
| **Tests** | 1489 passing (120 files, incl. the fault-injection L1 gate, the G1 oracle-isolation guards, the L2 protocol tests, the judge byte-equivalence fixture, the intent-channel suites, the vocabulary-equivalence classification pin, the dataset contamination/determinism guard, and v1.17's CLI-surface suites — FLAG_KEYS↔manifest bidirectional drift, per-command help/examples, filters-never-gate, the `context --section` splitter-to-generator weld, and `test/docs-flags.test.ts`, the docs↔manifest gate that fails if any hand-written doc names a flag its command doesn't declare, plus v1.19's drawing-quality suites — fixture orientation, `flush` placement, the openings render pass, and `test/repair-coverage.test.ts`, whose postcondition is that every piece a lint pass flags gets a change entry or an `unresolved` entry, never nothing, plus v1.20's sheet-and-datum suites — `test/axes.test.ts` (GB/T numbering incl. the `I`/`O`/`Z` skip and the descending-`y` lettering), `test/sheet.test.ts` (the paper/scale size table, closed-form auto-fit, `W_SCALE_OVERFLOW`, and a pin that a plan with no `paper` is byte-identical) and `test/schedule.test.ts` (schedule rows equal `describe()`'s own areas, legend lists only what is drawn), plus v1.21's vertical suites — `test/levels.test.ts` (either/or level nesting, per-storey id scoping, one-building paper/scale) and `test/cli-levels.test.ts` (`<stem>.L<n>.<ext>` fan-out, `outputs[]`/`pages[]`, `--level` as a display filter that never moves an exit code), `test/vertical.test.ts` (registry dispatch for the three new elements, the drawn symbols, the obstruct-except-the-entry-edge nav-grid rule, same-id shaft identity in `describe().vertical`, upper-storey reachability ± its counterexample, `W_STAIR_UNMATCHED` ±, and cross-level `checkGraph`), and `test/nav-grid-scale.test.ts` (the grid-resolution formulas, large-plan bottleneck discrimination, and the threshold carve)) + offline authorability eval (26 briefs, judge v2, `npm run eval:ci`, in CI); typecheck (`noUncheckedIndexedAccess` on) + build + `npm run lint` (Biome) clean | — |
31+
32+
**Latest release: v1.21.0 (2026-07-26)** — Batch-2 sub-release **"vertical"**: `level <n> ["Name"]
33+
{ … }` blocks make a plan a **set of drawings** — one complete sheet per storey, written to
34+
`<stem>.L<n>.<ext>` with `pages[]`/`outputs[]` in `--json` and a `--level <n>` read
35+
(`E_LEVEL_MIX`/`E_LEVEL_DUP`/`E_LEVEL_NEST`, ids unique per storey, one building = one paper/scale);
36+
`stair` / `elevator` / `escalator` draw the conventional symbols and carry the one cross-floor rule —
37+
the same id on two storeys is one shaft, surfaced as `describe().vertical` + per-storey `verticals`,
38+
feeding upper-storey reachability and `validate --graph` (`E_VERT_SIZE`/`E_STAIR_WIDTH`/
39+
`W_STAIR_UNMATCHED`); and the circulation/occupancy grids now size their cell from the plan's **area**
40+
under a cell budget instead of a fixed cell count, so a 100 m building's clear widths discriminate
41+
(dwelling-scale plans stay byte-for-byte identical). New `compile().pages`, `describe().levels`,
42+
`Diagnostic.level`, and `examples/two-storey.arch`. (v1.20.0, 2026-07-26, was the "sheet & datum"
43+
sub-release — `paper`/`axes`/`schedule`/`legend` and the operative drawing scale.) The table above is what is live. Canonical release notes
4244
live in `CHANGELOG.md`; per-tranche research verdicts in `docs/research/`. The full per-release
4345
narrative (v1.3.0 → v1.16.0, honest eval read, sites redesign, every tranche summary) is archived
4446
verbatim at

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.21.0] - 2026-07-26
11+
12+
**"Vertical"** — the second sub-release of the large-building batch. v1.20.0 gave a plan a sheet; a
13+
building still had exactly one floor. This release makes a plan a **set of drawings**: `level` blocks
14+
render one complete sheet per storey, `stair` / `elevator` / `escalator` draw the conventional plan
15+
symbols and carry the only rule in the language that joins two floors, and the circulation analysis
16+
stops being scale-relative so a 100 m building's clear widths mean what they say.
17+
18+
`compile()` stays pure, synchronous and deterministic, and a single-storey plan with no vertical
19+
element is **byte-for-byte unchanged**. The language gains four statement keywords (`level`, `stair`,
20+
`elevator`, `escalator`) plus the `dir up|down` clause, six catalogued codes (**`E_LEVEL_MIX`**,
21+
**`E_LEVEL_DUP`**, **`E_LEVEL_NEST`**, **`E_VERT_SIZE`**, **`E_STAIR_WIDTH`**, **`W_STAIR_UNMATCHED`**);
22+
`compile()` gains the append-only `pages`, `describe()` the append-only `levels` / `vertical`, and
23+
`Diagnostic` an append-only `level`.
24+
1025
### Added
1126

1227
- **`level <n> ["Name"] { … }` — multi-storey plans: one drawing per storey.** A building is not one
@@ -102,6 +117,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
102117
storey), and a shaft contributes one undirected edge per ADJACENT pair of its storeys, between the
103118
rooms it lands in on each.
104119

120+
### Changed
121+
122+
- **The circulation and occupancy grids now scale with the plan's area, so a big building's numbers
123+
discriminate.** Both grids picked their cell from a fixed cell COUNT (10k whole-plan, 2500 per room,
124+
clamped per axis), which made every grid measurement scale-relative: on a 100 × 60 m plan the nav
125+
cell reached 775 mm, so a 900 mm door was one cell, the 300 mm body-radius erosion was a third of
126+
one, and clear width quantised in ~775 mm steps — all 14 rooms of the museum fixture reported an
127+
identical 1940 mm bottleneck and a compliant 1.8 m corridor read the same as an illegal 1.0 m one.
128+
The count is replaced by a target cell SIZE bounded by a total cell BUDGET —
129+
`cell = max(100 mm, ceil(sqrt(area / 250_000)))` for the nav grid and `/ 25_000` for per-room
130+
occupancy — and the per-axis clamp is **dropped**, not re-tuned (the budget alone bounds the grid;
131+
a per-axis cap would re-introduce exactly this quantisation on a long, thin building). `MIN_CELL_MM`
132+
is unchanged, so the floor holds to 2500 m² (nav) / 250 m² (room) and **every dwelling-scale plan is
133+
byte-for-byte unaffected** — verified across all of `examples/`; the museum drops to a 155 mm cell
134+
and its bottlenecks separate (1140 vs 1940 mm). The ~25× extra cells are paid for by turning the two
135+
O(cells × rects) scans into per-rect bbox scans and dropping a per-swap allocation in the
136+
widest-path heap. `describe()` reports the cell actually used as `cellSizeMm`; both formulas are
137+
closed-form, integral and monotonic in the area, so determinism is preserved. See `docs/analysis.md`
138+
→ "Grid resolution" and the ADR 0008 addendum.
139+
- **The threshold carve tries the connector's centre first, then only the walkable part of the
140+
opening.** A finer cell exposed a latent assumption: a connector was modelled as the single cell at
141+
its centre point, which is fine while an opening is about one cell wide. At 155 mm a 4 m opening
142+
spans two dozen cells, and a 6 m servery parked across half of a 4 m threshold read as SEALED. Any
143+
plan that already carves is untouched, and a fully covered opening still reports the room
144+
unreachable — no room is connected by fiat.
145+
105146
### Notes
106147

107148
- A multi-page PDF is deliberately not built — `-f pdf` writes one file per storey, one drawing per

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@chanmeng666/archlang",
3-
"version": "1.20.0",
3+
"version": "1.21.0",
44
"description": "A small declarative language that compiles to professional SVG floor plans — like Typst/LaTeX, but for architecture.",
55
"keywords": [
66
"architecture",

0 commit comments

Comments
 (0)