Compare commits

..

5 Commits

41 changed files with 4182 additions and 727 deletions

View File

@ -0,0 +1,72 @@
# 1.0.0-beta.21 JSON Document Scalar Parsing Foundation
## Scope
`1.0.0-beta.21` is a standard-library and compiler-gate slice. It adds
source-authored `std.json` helpers for scalar JSON documents while keeping
source-language syntax, runtime C, compiler-known runtime names, and ABI/layout
policy unchanged.
The release adds:
- `parse_string_document_result ((document string)) -> (result string i32)`
- `parse_bool_document_result ((document string)) -> (result bool i32)`
- `parse_i32_document_result ((document string)) -> (result i32 i32)`
- `parse_u32_document_result ((document string)) -> (result u32 i32)`
- `parse_i64_document_result ((document string)) -> (result i64 i32)`
- `parse_u64_document_result ((document string)) -> (result u64 i32)`
- `parse_f64_document_result ((document string)) -> (result f64 i32)`
- `parse_null_document_result ((document string)) -> (result bool i32)`
## Contract
Each helper trims ASCII whitespace around the whole input document with
`std.string.trim_ascii`, then delegates to the already released exact
value-token parser for that scalar family.
Leading and trailing ASCII whitespace around one scalar document is accepted.
Trailing non-whitespace remains an ordinary parse failure and returns `err 1`
through the underlying exact parser.
## Non-Scope
This scope does not add:
- compiler-known `std.json.*_document_result` runtime names
- private `__glagol_json_*document*` runtime symbols
- runtime C helper implementations
- source-language syntax
- object or array parsing
- recursive `JsonValue`
- tokenizer/parser objects
- maps, sets, executable generics, or generic collections
- streaming parsers or encoders
- Unicode escape decoding beyond the existing string-token helper
- embedded NUL policy
- stable JSON APIs
- stable ABI/layout
- stable standard-library compatibility
- performance claims
## Acceptance Criteria
- `lib/std/json.slo` exports all eight document scalar helpers.
- Explicit `std.json` import examples exercise trimmed whitespace success,
no-whitespace success, and trailing non-whitespace failure.
- Local `std-layout-local-json` examples mirror the public helper surface with
an explicit local `string` dependency for `trim_ascii`.
- Focused compiler coverage verifies the helpers are source-authored and that
direct compiler-known runtime calls for the new names remain unsupported.
- `scripts/release-gate.sh` runs the focused beta21 test.
- Generated standard-library API documentation includes the new signatures.
## Gates
```bash
cargo fmt --check
cargo test --test standard_json_document_scalar_parsing_beta21
cargo test --test standard_json_source_facade_alpha
cargo test --test promotion_gate
cargo test
./scripts/release-gate.sh
```

View File

@ -0,0 +1,71 @@
# 1.0.0-beta.22 Run Manifest And Execution Report Hardening
## Scope
`1.0.0-beta.22` is a compiler/tooling evidence-hardening slice for
`glagol run --manifest`. It keeps the Slovo source language, typed core,
runtime capabilities, standard-library surface, compiler-known runtime names,
ABI/layout policy, and package behavior unchanged.
The release adds an additive run-report block to run-mode artifact manifests
so manifest evidence can record:
- process exit status for the invoked program
- captured stdout from the run
- captured stderr from the run
- forwarded program arguments passed through `glagol run`
## Contract
When `glagol run --manifest <path>` completes far enough to write an artifact
manifest, the manifest should include run execution evidence in addition to the
existing schema marker, command, mode, success, diagnostics metadata, primary
output, and artifacts fields.
The run-report data describes the native executable invocation performed by
`glagol run`, not a new source-language or runtime feature. Captured stdout
and stderr are evidence fields for tooling and release-gate review; they do
not redefine ordinary terminal behavior. Forwarded args are recorded so
fixtures can distinguish compiler arguments from user-program arguments.
The block is additive beta tooling metadata. It is not a stable public schema
freeze and does not bump `slovo.artifact-manifest` version `1`.
## Non-Scope
This scope does not add:
- source-language syntax
- standard-library helpers
- compiler-known `std.*` runtime names
- runtime C capabilities
- package, workspace, import, or registry behavior
- stable artifact-manifest schema freeze
- stable Markdown schema freeze
- LSP, watch, SARIF, or daemon protocols
- performance claims
- stable ABI/layout
- beta maturity beyond the existing `1.0.0-beta` line
## Acceptance Criteria
- `glagol run --manifest <path>` writes an artifact manifest with an additive
run-report block after executing a supported program.
- The run report records exit status, captured stdout, captured stderr, and
forwarded args.
- Existing manifest fields and schema/version markers remain compatible with
the beta artifact-manifest contract.
- Non-run modes do not need run-report metadata.
- Documentation describes beta22 as tooling/CLI evidence hardening only.
- Release notes and roadmaps state that beta22 does not add language or
stdlib features and does not freeze the manifest schema.
## Suggested Gates
```bash
cargo fmt --check
cargo test --test run_manifest_beta22
cargo test --test cli_v1_1
./scripts/release-gate.sh
git diff --check
```

View File

@ -0,0 +1,73 @@
# 1.0.0-beta.23 Standard Library Stability Tier Ledger And Catalog Alignment
## Scope
`1.0.0-beta.23` is a documentation/catalog clarity slice for the standard
library. It adds a public stability-tier ledger and aligns the surrounding
README, roadmap, release-note, and specification text with the generated API
catalog boundary.
This release does not change the source language, typed core, runtime
capabilities, standard-library helper surface, compiler-known runtime names,
ABI/layout policy, or package behavior. It does change generated catalog
output and release-gate checks so tier metadata is visible and enforced.
## Contract
The public standard-library docs use exactly these tier labels:
- `beta-supported`
- `experimental`
- `internal`
The generated `docs/language/STDLIB_API.md` catalog remains the exact exported
signature inventory generated from `lib/std/*.slo`. The new
`docs/language/STDLIB_TIERS.md` ledger records maturity and stability
expectations for those helpers and surrounding standard-library domains.
Experimental domains in the beta23 ledger include JSON, loopback networking,
random/time, and filesystem resource-handle helpers. Concrete vector modules
remain beta-supported concrete lanes; they are not a generic collections
freeze and do not imply executable generics, maps, sets, iterators, mutable
vectors, slice/view APIs, runtime collection changes, or stable ABI/layout.
## Non-Scope
This scope does not add:
- source-language syntax
- standard-library helpers
- compiler-known `std.*` runtime names
- runtime C capabilities
- package, workspace, import, or registry behavior
- stable standard-library/API compatibility freeze
- stable manifest schema freeze
- stable Markdown schema freeze
- stable ABI/layout
- performance claims
- beta maturity beyond the existing `1.0.0-beta` line
## Acceptance Criteria
- `docs/language/STDLIB_TIERS.md` defines the public tier labels and their
current meaning.
- The tier ledger marks JSON, loopback networking, random/time, and filesystem
resource-handle helpers as experimental domains.
- The tier ledger records concrete vector modules as beta-supported concrete
lanes without claiming generic collection stability.
- README, `lib/std/README.md`, language release notes, language roadmap,
post-beta roadmap, and the v1 spec link or describe the tier ledger.
- Documentation states beta23 is docs/catalog tooling clarity only and does
not add language, stdlib, runtime, stable schema, or stable API behavior.
- The generated API catalog emits tier metadata, and the release gate checks
that experimental tiers remain represented.
## Suggested Gates
```bash
node --check scripts/render-stdlib-api-doc.js
node --check scripts/check-stdlib-api-tiers.js
./scripts/render-stdlib-api-doc.sh
./scripts/check-stdlib-api-tiers.js
git diff --check
```

View File

@ -0,0 +1,79 @@
# 1.0.0-beta.24 Package Manifest Identity And Dependency Discipline
## Scope
`1.0.0-beta.24` is a package/workspace discipline hardening slice for local
manifest diagnostics. It tightens how package manifest identity and local
dependency tables are reported when users write ambiguous or invalid manifest
keys.
This release changes diagnostics only. It does not change the Slovo source
language, typed core, runtime behavior, standard-library helper surface,
compiler-known runtime names, package graph semantics, ABI/layout policy, or
artifact/Markdown schema stability guarantees.
## Contract
The beta package model remains a closed local workspace model:
- package manifests declare `[package]` identity metadata and optional
`[dependencies]` local path records
- dependency keys name local packages and must match the target package name
- dependency paths remain local path records under the existing workspace and
package boundary checks
The beta24 diagnostic hardening makes these manifest errors explicit:
- duplicate keys in package manifests report `PackageManifestInvalid`
- invalid dependency keys report `InvalidPackageDependencyName`
- duplicate dependency keys report `DuplicatePackageDependencyName`
These diagnostics are part of the beta package/workspace discipline surface.
They do not promote a package manager, resolver, lockfile, registry, publish
flow, or stable package ABI/layout.
## Non-Scope
This scope does not add:
- remote registry behavior
- lockfiles
- semantic-version solving
- package publishing
- optional, dev, target, or feature-gated dependencies
- build scripts or package archives
- stable package ABI/layout
- stable package manager behavior
- source-language syntax or semantics
- runtime behavior or runtime C capabilities
- standard-library helpers or stdlib behavior
- compiler-known `std.*` runtime names
- stable artifact-manifest or Markdown schema guarantees
- performance claims
## Acceptance Criteria
- `docs/language/PACKAGES.md` documents duplicate package-manifest keys,
invalid dependency keys, and duplicate dependency keys as explicit beta
diagnostics.
- Language and compiler release notes describe beta24 as package manifest
identity/dependency diagnostic hardening only.
- Language and compiler roadmaps record beta24 as a local package/workspace
diagnostics slice with all registry, lockfile, semver, publishing,
optional/dev/target dependency, ABI/layout, language, runtime, and stdlib
work deferred.
- README and the post-beta roadmap identify `1.0.0-beta.24` as the current
package/workspace discipline hardening slice.
- Glagol is versioned as `1.0.0-beta.24`.
- `compiler/tests/package_workspace_discipline_beta24.rs` covers the focused
package manifest/dependency diagnostics and a positive local dependency
workspace.
- `scripts/release-gate.sh` runs the focused beta24 test.
## Suggested Gates
```bash
git diff --check
cargo fmt --check
cargo test --test package_workspace_discipline_beta24
```

View File

@ -0,0 +1,95 @@
# 1.0.0-beta.25 User Project Conformance Matrix
## Scope
`1.0.0-beta.25` is a tooling/conformance evidence slice for ordinary
project and workspace usage. It adds a deterministic user-project conformance
matrix over the existing checked examples under `examples/projects/` and
`examples/workspaces/`.
The matrix is stable-readiness evidence for the beta toolchain. It records
which existing user-shaped example projects and workspaces are expected to
pass `glagol check`, `glagol test --list`, and stable `glagol test` execution
through ordinary Glagol entry points.
At release time the matrix covers all 43 top-level fixture roots with
`slovo.toml` under those inventories and 655 discovered tests. Environment
fixtures run with deterministic in-test environment values so host shell state
does not decide the result.
This release changes tooling evidence only. It does not change the Slovo
source language, typed core, runtime behavior, standard-library helper
surface, compiler-known runtime names, package-manager behavior, package graph
semantics, registry behavior, lockfile behavior, semver behavior, ABI/layout
policy, stable schema policy, or performance policy.
## Contract
The conformance matrix is deterministic and repository-local:
- inputs are every top-level `slovo.toml` fixture under the existing
`examples/projects/` and `examples/workspaces/` directories
- entries are sorted by stable repository-relative path
- each entry names the example kind, path, and ordinary project/workspace
test count covered by the matrix
- fixture inventory drift must fail the focused matrix test until the matrix
and release evidence are updated deliberately
- generated evidence must not depend on wall-clock time, host-specific
absolute paths, random ordering, or network access
- matrix output is beta readiness evidence, not a frozen public schema
The matrix is intended to answer whether normal beta users can exercise the
current example projects and workspaces through the documented toolchain. It
does not promote new language forms, new standard-library helpers, new runtime
capabilities, new package manager behavior, or new compatibility guarantees.
## Non-Scope
This scope does not add:
- source-language syntax or semantics
- typed-core changes
- standard-library helpers or stdlib behavior changes
- compiler-known `std.*` runtime names
- runtime behavior or runtime C capabilities
- package manager behavior
- remote registry behavior
- lockfiles
- semantic-version solving
- package publishing
- optional, dev, target, or feature-gated dependencies
- stable package ABI/layout
- stable artifact-manifest, Markdown, JSON, or conformance-matrix schema
guarantees
- performance thresholds, performance claims, or timing publication
- LSP/watch, SARIF, daemon, coverage, retry, tag/group, or event-stream
protocols
## Acceptance Criteria
- README names `1.0.0-beta.25` as the current release and describes the
user-project conformance matrix as tooling/readiness evidence only.
- Language and compiler release notes describe beta25 as a
tooling/conformance evidence slice over existing `examples/projects/` and
`examples/workspaces/`.
- Language and compiler roadmaps record beta25 as the current
stable-readiness evidence slice while keeping language, stdlib, runtime,
package-manager, stable-schema, and performance work deferred.
- The post-beta roadmap records beta25 under tooling/release hardening.
- Glagol is versioned as `1.0.0-beta.25`.
- `compiler/tests/user_project_conformance_beta25.rs` covers all 43 top-level
project/workspace fixture roots and 655 discovered tests.
- Fixture inventory drift is checked against discovered top-level
`slovo.toml` roots.
- `scripts/release-gate.sh` runs the focused beta25 matrix test.
- No compiler, runtime, standard-library, package-manager, registry, lockfile,
semver, ABI/layout, stable-schema, or performance claim is introduced by
the documentation.
## Suggested Gates
```bash
git diff --check
cargo fmt --check
cargo test --test user_project_conformance_beta25
```

View File

@ -0,0 +1,25 @@
# 1.0.0-beta.21 Glagol Implementation Notes
Scope: JSON Document Scalar Parsing Foundation.
This Glagol-side slice prepares compiler/test/release-gate coverage for the
source-authored `std.json` document scalar helpers:
- `parse_string_document_result`
- `parse_bool_document_result`
- `parse_i32_document_result`
- `parse_u32_document_result`
- `parse_i64_document_result`
- `parse_u64_document_result`
- `parse_f64_document_result`
- `parse_null_document_result`
The focused beta21 test uses an explicit `std.json` import, checks/formats/tests
the imported helpers, requires the helpers to exist in `lib/std/json.slo`, and
asserts that no `std.json.parse_*_document_result` compiler-known calls or
private `__glagol_json_*document*` runtime symbols are introduced.
The JSON source-facade and promotion-gate inventories are updated to match the
Slovo-side source/export/example work, which adds three JSON document scalar
fixture tests and raises local and explicit `std.json` fixture output from 9 to
12 tests.

View File

@ -0,0 +1,52 @@
# 1.0.0-beta.21 Release Review
Scope: JSON Document Scalar Parsing Foundation.
## Findings
No blocking findings.
The uncommitted beta21 candidate matches the release contract:
- `lib/std/json.slo` exports all eight source-authored
`parse_*_document_result` helpers.
- Each document helper trims the whole input with `trim_ascii`, then delegates
to the existing exact scalar value-token parser for the matching family.
- Direct compiler-known `std.json.parse_*_document_result` calls are not
introduced, and no private `__glagol_json_*document*` runtime symbol is
introduced.
- The explicit `std.json` example imports repo-root `std.json` and covers
trimmed success, plain success, trailing non-whitespace failure, scalar
token parsing, fields, arrays, objects, and 12 tests.
- The local JSON example imports local `json`, the local `json` fixture imports
local `string (trim_ascii)`, and it mirrors the same 12-test coverage.
- Compiler coverage includes the focused beta21 test, JSON facade inventory,
promotion-gate alignment, release-gate wiring, package version bump, and the
generated standard-library API catalog signatures.
- Release docs describe `1.0.0-beta.21` as released, and the source/docs scan
did not find local/private publication text.
## Verification
Commands run:
```bash
git diff --check
git diff --cached --check
bash -n scripts/release-gate.sh
cargo fmt --check --manifest-path compiler/Cargo.toml
cargo test --test standard_json_document_scalar_parsing_beta21
cargo test --test standard_json_source_facade_alpha
cargo test --test promotion_gate -- promotion_gate_artifacts_are_aligned
```
Results:
- `standard_json_document_scalar_parsing_beta21`: 2 passed.
- `standard_json_source_facade_alpha`: 2 passed.
- `promotion_gate_artifacts_are_aligned`: 1 passed.
- Formatting, shell syntax, and diff whitespace checks passed.
- Targeted stale-release/private-text scans over source/docs paths passed.
Not run by design for this review: full `cargo test`, ignored smoke tests, and
the full release gate.

View File

@ -0,0 +1,45 @@
# Beta22 Release Review
Verdict: PASS with notes.
## Findings
No blocking or non-blocking findings in the reviewed scope.
## Scope Reviewed
- `compiler/src/main.rs` run manifest rendering and exit behavior.
- `compiler/tests/run_manifest_beta22.rs` focused coverage.
- `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md` beta22 contract and suggested gates.
- `README.md`, `docs/compiler/RELEASE_NOTES.md`, `docs/compiler/ROADMAP.md`, `docs/language/RELEASE_NOTES.md`, `docs/language/ROADMAP.md`, and `docs/language/SPEC-v1.md` release claims.
- `scripts/release-gate.sh` inclusion.
## Acceptance Checklist
- PASS: `glagol run --manifest <path>` writes additive run execution evidence after a supported program executes. The run path captures child stdout/stderr/status before manifest rendering and exits with the child status in `compiler/src/main.rs:892` through `compiler/src/main.rs:918`; rendering emits `(run-report ...)` in `compiler/src/main.rs:2162` through `compiler/src/main.rs:2188`.
- PASS: Run-report records exit status, captured stdout, captured stderr, and forwarded args. Tests cover success stdout and args in `compiler/tests/run_manifest_beta22.rs:10` through `compiler/tests/run_manifest_beta22.rs:60`, and nonzero exit plus stderr preservation in `compiler/tests/run_manifest_beta22.rs:62` through `compiler/tests/run_manifest_beta22.rs:128`.
- PASS: Existing manifest fields and schema/version markers remain compatible. The new path passes `Some(run_report)` only through the run-specific wrapper in `compiler/src/main.rs:2019` through `compiler/src/main.rs:2043`; the renderer still emits `slovo.artifact-manifest` version `1` in `compiler/src/main.rs:2067` through `compiler/src/main.rs:2069`.
- PASS: Source failures do not receive fake run evidence. The focused test asserts no run-report for a type failure in `compiler/tests/run_manifest_beta22.rs:130` through `compiler/tests/run_manifest_beta22.rs:161`.
- PASS: Non-run modes are outside the run-report requirement. Existing foreign-import/project manifest wrappers pass `None` for the run-report slot in `compiler/src/main.rs:1992` through `compiler/src/main.rs:2017`; beta22 docs state this explicitly in `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:58` and `docs/compiler/RELEASE_NOTES.md:35`.
- PASS: Documentation does not overclaim language, stdlib, runtime, package, ABI, or stable manifest-schema changes. Representative deferrals are present in `README.md:172` through `README.md:178`, `docs/compiler/ROADMAP.md:118` through `docs/compiler/ROADMAP.md:124`, `docs/language/RELEASE_NOTES.md:52` through `docs/language/RELEASE_NOTES.md:62`, `docs/language/ROADMAP.md:99` through `docs/language/ROADMAP.md:106`, and `docs/language/SPEC-v1.md:260` through `docs/language/SPEC-v1.md:267`.
- PASS: The beta22 contract suggested gate names match the implemented focused test and release gate. `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:63` through `.llm/BETA_22_RUN_MANIFEST_AND_EXECUTION_REPORT_HARDENING.md:71` lists `cargo test --test run_manifest_beta22`; `scripts/release-gate.sh:75` includes the same focused test.
## Verification
Ran:
```bash
cargo test --test run_manifest_beta22
```
Result: passed, 3 tests passed.
Recommended before release tag:
```bash
cargo fmt --check
./scripts/release-gate.sh
git diff --check
```
Note: the focused hosted-run tests depend on Clang discovery, matching existing project patterns. In this local run they executed and passed rather than skipping.

View File

@ -0,0 +1,54 @@
# Beta23 Release Review
Verdict: PASS with notes.
## Findings
No blocking or non-blocking findings in the reviewed scope.
## Scope Reviewed
- `scripts/render-stdlib-api-doc.js` tier rendering.
- `scripts/check-stdlib-api-tiers.js` tier gate.
- `scripts/release-gate.sh` integration.
- Generated `docs/language/STDLIB_API.md`.
- `docs/language/STDLIB_TIERS.md`, README, release notes, roadmaps, and spec updates.
- Compiler package version bump and compiler release documentation.
## Acceptance Checklist
- PASS: `docs/language/STDLIB_TIERS.md` defines the public tier labels and explains the current beta meaning. See `docs/language/STDLIB_TIERS.md:21` through `docs/language/STDLIB_TIERS.md:25`.
- PASS: The tier ledger marks JSON, loopback networking, random/time, and filesystem resource-handle helpers as experimental domains. See `docs/language/STDLIB_TIERS.md:46` through `docs/language/STDLIB_TIERS.md:49`.
- PASS: The tier ledger records concrete vector modules as beta-supported concrete lanes without claiming generic collection stability. See `docs/language/STDLIB_TIERS.md:44`.
- PASS: The generated API catalog emits tier metadata and summary counts. See `docs/language/STDLIB_API.md:6` through `docs/language/STDLIB_API.md:24`.
- PASS: Generated catalog classification matches the beta23 contract: filesystem handle helpers are experimental in `docs/language/STDLIB_API.md:115` through `docs/language/STDLIB_API.md:119`; `std.json`, `std.net`, `std.random`, and `std.time` are experimental in `docs/language/STDLIB_API.md:195` through `docs/language/STDLIB_API.md:240`, `docs/language/STDLIB_API.md:294` through `docs/language/STDLIB_API.md:308`, `docs/language/STDLIB_API.md:425` through `docs/language/STDLIB_API.md:432`, and `docs/language/STDLIB_API.md:540` through `docs/language/STDLIB_API.md:547`.
- PASS: Concrete vector modules retain explicit no-generic-collection-freeze notes in generated output. Representative coverage is `docs/language/STDLIB_API.md:549` through `docs/language/STDLIB_API.md:554`, with the same note repeated for the other concrete `std.vec_*` modules.
- PASS: The renderer implements the tier map and emits per-module/per-helper tiers. See `scripts/render-stdlib-api-doc.js:12` through `scripts/render-stdlib-api-doc.js:46`, `scripts/render-stdlib-api-doc.js:245` through `scripts/render-stdlib-api-doc.js:263`, and `scripts/render-stdlib-api-doc.js:297` through `scripts/render-stdlib-api-doc.js:330`.
- PASS: The tier gate checks stale wording, summary tier definitions, experimental module/helper coverage, and vector boundary notes. See `scripts/check-stdlib-api-tiers.js:47` through `scripts/check-stdlib-api-tiers.js:80`.
- PASS: `scripts/release-gate.sh` runs syntax checks for both tier scripts and executes the tier checker after catalog rendering. See `scripts/release-gate.sh:12` through `scripts/release-gate.sh:16`.
- PASS: README, `lib/std/README.md`, language release notes, language roadmap, post-beta roadmap, and v1 spec link or describe the tier ledger and non-scope. Representative references: `README.md:69` through `README.md:79`, `lib/std/README.md:174` through `lib/std/README.md:184`, `docs/language/RELEASE_NOTES.md:53` through `docs/language/RELEASE_NOTES.md:69`, `docs/language/ROADMAP.md:109` through `docs/language/ROADMAP.md:119`, `docs/POST_BETA_ROADMAP.md:121` through `docs/POST_BETA_ROADMAP.md:132`, and `docs/language/SPEC-v1.md:268` through `docs/language/SPEC-v1.md:279`.
- PASS: Documentation states beta23 is documentation/catalog tooling clarity only and does not add language, stdlib, runtime, stable schema, ABI/layout, or stable API behavior. See `docs/language/STDLIB_TIERS.md:10` through `docs/language/STDLIB_TIERS.md:15` and `docs/language/STDLIB_TIERS.md:52` through `docs/language/STDLIB_TIERS.md:68`.
- PASS: Compiler package version and compiler release docs are aligned to `1.0.0-beta.23`. See `compiler/Cargo.toml:3`, `compiler/Cargo.lock:7`, `docs/compiler/RELEASE_NOTES.md:15` through `docs/compiler/RELEASE_NOTES.md:43`, and `docs/compiler/ROADMAP.md:126` through `docs/compiler/ROADMAP.md:132`.
## Verification
Ran:
```bash
node --check scripts/render-stdlib-api-doc.js
node --check scripts/check-stdlib-api-tiers.js
./scripts/check-stdlib-api-tiers.js
git diff --check
rg -n '^- `experimental`' docs/language/STDLIB_API.md
```
Result: all focused checks passed. The `rg` inspection confirmed 58 experimental helper signatures across the expected filesystem-handle, JSON, loopback networking, random, and time surfaces.
Recommended before release tag:
```bash
./scripts/render-stdlib-api-doc.sh
./scripts/release-gate.sh
```
Note: run the full release gate after the generated catalog changes are staged or committed; the gate intentionally fails if `docs/language/STDLIB_API.md` has unstaged generated-doc drift.

View File

@ -0,0 +1,66 @@
# Beta24 Release Review
Verdict: PASS.
## Findings
No blocking or non-blocking findings in the reviewed scope.
## Scope Reviewed
- `compiler/src/project.rs` package manifest diagnostics.
- `compiler/tests/package_workspace_discipline_beta24.rs`.
- `scripts/release-gate.sh` beta24 focused gate entry.
- `compiler/Cargo.toml` and `compiler/Cargo.lock` version bump.
- `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md`.
- README, language package/diagnostic/release/roadmap docs, compiler release/roadmap docs, and post-beta roadmap updates.
## Acceptance Checklist
- PASS: Duplicate package manifest keys now use package-scoped diagnostics through `set_manifest_key(..., "PackageManifestInvalid", "package")` for package identity keys. See `compiler/src/project.rs:1505` through `compiler/src/project.rs:1545` and `compiler/src/project.rs:1752` through `compiler/src/project.rs:1771`.
- PASS: Invalid dependency keys are rejected before graph validation with `InvalidPackageDependencyName`. See `compiler/src/project.rs:1556` through `compiler/src/project.rs:1572`.
- PASS: Duplicate dependency keys are rejected before graph validation with `DuplicatePackageDependencyName`, and invalid/duplicate dependency records are not added to the dependency graph. See `compiler/src/project.rs:1573` through `compiler/src/project.rs:1593`.
- PASS: Existing local-path-only dependency parsing and later dependency key/name matching remain in place. See `compiler/src/project.rs:1594` through `compiler/src/project.rs:1601`, `compiler/src/project.rs:1743` through `compiler/src/project.rs:1749`, and `compiler/src/project.rs:2970` through `compiler/src/project.rs:3005`.
- PASS: Focused tests cover duplicate package keys, invalid dependency keys, duplicate dependency keys, and a clean local dependency workspace. See `compiler/tests/package_workspace_discipline_beta24.rs:11` through `compiler/tests/package_workspace_discipline_beta24.rs:109`.
- PASS: `scripts/release-gate.sh` runs the beta24 focused test before full `cargo test`. See `scripts/release-gate.sh:68` through `scripts/release-gate.sh:82`.
- PASS: The compiler package version is aligned to `1.0.0-beta.24` in both Cargo files. See `compiler/Cargo.toml:3` and `compiler/Cargo.lock:7`.
- PASS: The beta24 contract defines diagnostics-only scope, explicit non-scope, acceptance criteria, and focused gates. See `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md:5` through `.llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md:79`.
- PASS: README identifies `1.0.0-beta.24` as current and describes the package manifest/dependency diagnostic hardening scope without claiming package-manager, runtime, language, or stdlib changes. See `README.md:9` and `README.md:27` through `README.md:50`.
- PASS: `docs/language/PACKAGES.md` documents duplicate package manifest keys, invalid dependency keys, and duplicate dependency keys as beta package/workspace diagnostics. See `docs/language/PACKAGES.md:59` through `docs/language/PACKAGES.md:73` and `docs/language/PACKAGES.md:111` through `docs/language/PACKAGES.md:130`.
- PASS: `docs/language/DIAGNOSTICS.md` includes the new package/workspace diagnostic codes in the project/workspace catalog. See `docs/language/DIAGNOSTICS.md:240` through `docs/language/DIAGNOSTICS.md:279`.
- PASS: Language and compiler release notes describe beta24 as package manifest identity/dependency diagnostic hardening only. See `docs/language/RELEASE_NOTES.md:44` through `docs/language/RELEASE_NOTES.md:68` and `docs/compiler/RELEASE_NOTES.md:15` through `docs/compiler/RELEASE_NOTES.md:42`.
- PASS: Language/compiler roadmaps and post-beta roadmap mark beta24 as the current local package/workspace diagnostics slice with registry, lockfile, semver, publishing, optional/dev/target dependencies, ABI/layout, language, runtime, and stdlib work deferred. See `docs/language/ROADMAP.md:11` through `docs/language/ROADMAP.md:33`, `docs/compiler/ROADMAP.md:24` through `docs/compiler/ROADMAP.md:38`, `docs/compiler/ROADMAP.md:722` through `docs/compiler/ROADMAP.md:728`, and `docs/POST_BETA_ROADMAP.md:185` through `docs/POST_BETA_ROADMAP.md:191`.
## Verification Commands
Ran:
```bash
git diff --check
cargo fmt --check
cargo test --test package_workspace_discipline_beta24
cargo test --test project_mode workspace_package_boundaries_are_diagnostics
cargo test --test project_mode
rg -n "beta\\.23|beta23|beta\\.24|beta24|1\\.0\\.0-beta\\.2[0-9]|current|Release state|Last updated" README.md docs/language/PACKAGES.md docs/language/DIAGNOSTICS.md docs/language/RELEASE_NOTES.md docs/language/ROADMAP.md docs/compiler/RELEASE_NOTES.md docs/compiler/ROADMAP.md docs/POST_BETA_ROADMAP.md .llm/BETA_24_PACKAGE_MANIFEST_IDENTITY_AND_DEPENDENCY_DISCIPLINE.md compiler/Cargo.toml compiler/Cargo.lock scripts/release-gate.sh
```
Result: all executed checks passed. The focused beta24 test reported 4 passed tests. The full `project_mode` suite reported 36 passed tests.
## Final Gate Disposition
After this review, the controller ran the full release gate:
```bash
./scripts/release-gate.sh
```
Result: PASS. The gate completed docs/catalog checks, focused beta13-beta24
tests, full `cargo test`, ignored promotion smoke, ignored binary smoke, and
ignored LLVM smoke.
## Residual Risks
- No release-blocking residual risks remain. The release gate regenerated and
checked the standard-library API catalog; publication PDFs were not
regenerated because this slice does not touch paper sources, and the gate
verified that the required PDF artifacts are present.

View File

@ -0,0 +1,64 @@
# Beta25 Release Review
Verdict: PASS.
## Findings
No blocking or non-blocking findings in the re-reviewed scope.
The prior blocking finding is resolved. `compiler/tests/user_project_conformance_beta25.rs` now covers all 43 top-level fixture roots currently discovered under `examples/projects/` and `examples/workspaces/`: 41 project fixtures plus 2 workspace fixtures. The test also asserts the matrix length, total discovered-test count, sorted path order, and exact inventory completeness against discovered top-level `slovo.toml` fixture roots.
## Acceptance Checklist
- PASS: The conformance matrix covers every current top-level `slovo.toml` fixture root under `examples/projects/` and `examples/workspaces/`.
- PASS: `assert_matrix_inventory()` asserts the 43-root count, 655 discovered tests, sorted repository-relative path order, exact discovered fixture inventory, and the full expected path/test/run matrix.
- PASS: The test runs `glagol check`, `glagol test --list`, and stable `glagol test` for every matrix entry.
- PASS: Deterministic env fixture handling is wired through `configure_conformance_env()`: expected env variables are set to stable values and intentionally-missing env variables are removed before each Glagol command.
- PASS: `scripts/release-gate.sh` still runs `cargo test --test user_project_conformance_beta25`.
- PASS: `compiler/Cargo.toml` and `compiler/Cargo.lock` both version `glagol` as `1.0.0-beta.25`.
- PASS: README, release notes, roadmaps, and the beta25 matrix doc continue to frame the release as tooling/conformance evidence without claiming language, runtime, stdlib, package-manager, stable-schema, ABI/layout, or performance changes.
## Verification Commands
Ran:
```bash
git status --short
git diff --stat
sed -n '1,620p' compiler/tests/user_project_conformance_beta25.rs
find examples/projects -mindepth 2 -maxdepth 2 -name slovo.toml -printf '%h\n'
find examples/workspaces -mindepth 2 -maxdepth 2 -name slovo.toml -printf '%h\n'
find examples/projects -mindepth 2 -maxdepth 2 -name slovo.toml -printf '.' | wc -c
find examples/workspaces -mindepth 2 -maxdepth 2 -name slovo.toml -printf '.' | wc -c
rg -n "assert_eq!\(MATRIX\.len\(\), 43|discover_fixture_paths|configure_conformance_env|GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT|GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT" compiler/tests/user_project_conformance_beta25.rs
git diff --check
cargo fmt --check
cargo test --test user_project_conformance_beta25
```
Results:
- `git diff --check`: PASS.
- `cargo fmt --check`: PASS.
- `cargo test --test user_project_conformance_beta25`: PASS, 1 test passed.
- Fixture inventory counts: 41 top-level project roots and 2 top-level workspace roots.
- Matrix inventory assertion: covers 43 roots and 655 discovered tests.
## Residual Risks
No release-blocking residual risks remain for this slice.
## Final Gate Disposition
The controller reran the full release gate after staging the generated
`docs/language/STDLIB_API.md` beta25 catalog update:
```bash
./scripts/release-gate.sh
```
Result: PASS. The gate reported:
```text
release gate passed: docs, stdlib API catalog, fmt, tests, promotion, binary, and LLVM smoke checks completed
```

151
README.md
View File

@ -6,7 +6,7 @@ This repository is the canonical public monorepo for the language design,
standard library source, compiler, runtime, examples, benchmarks, and technical standard library source, compiler, runtime, examples, benchmarks, and technical
documents. documents.
Current release: `1.0.0-beta.20`. Current release: `1.0.0-beta.25`.
## Repository Layout ## Repository Layout
@ -24,7 +24,7 @@ scripts/ local release and document tooling
## Beta Scope ## Beta Scope
`1.0.0-beta.20` keeps the `1.0.0-beta` language baseline, includes the `1.0.0-beta.25` keeps the `1.0.0-beta` language baseline, includes the
`1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2` `1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2`
runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library
stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics
@ -41,8 +41,15 @@ slice, the `1.0.0-beta.13` diagnostic catalog and schema policy slice, the
ledger, the `1.0.0-beta.16` string scanning and token boundary foundation, ledger, the `1.0.0-beta.16` string scanning and token boundary foundation,
the `1.0.0-beta.17` JSON primitive scalar parsing foundation, the the `1.0.0-beta.17` JSON primitive scalar parsing foundation, the
`1.0.0-beta.18` JSON string token parsing foundation, the `1.0.0-beta.18` JSON string token parsing foundation, the
`1.0.0-beta.19` test discovery and user-project conformance foundation, and `1.0.0-beta.19` test discovery and user-project conformance foundation, the
the `1.0.0-beta.20` string search and ASCII trim foundation. `1.0.0-beta.20` string search and ASCII trim foundation, and the
`1.0.0-beta.21` JSON document scalar parsing foundation, plus the
`1.0.0-beta.22` run manifest and execution report hardening slice, and the
`1.0.0-beta.23` standard-library stability tier ledger and catalog alignment
slice, and the `1.0.0-beta.24` package manifest identity and local dependency
diagnostic hardening slice, plus the `1.0.0-beta.25` user-project
conformance matrix evidence slice.
The language baseline supports practical local command-line, file, and The language baseline supports practical local command-line, file, and
loopback-network programs with: loopback-network programs with:
@ -57,7 +64,8 @@ loopback-network programs with:
`SLOVO_STD_PATH` `SLOVO_STD_PATH`
- beta-scoped loopback TCP handles through `std.net` - beta-scoped loopback TCP handles through `std.net`
- JSON string quoting, compact JSON text construction, primitive scalar token - JSON string quoting, compact JSON text construction, primitive scalar token
parsing, and ASCII JSON string-token parsing through `std.json` parsing, ASCII JSON string-token parsing, and scalar JSON document parsing
through `std.json`
- byte-oriented string search and ASCII edge trimming through `std.string` - byte-oriented string search and ASCII edge trimming through `std.string`
- hosted native builds through LLVM IR, Clang, and `runtime/runtime.c` - hosted native builds through LLVM IR, Clang, and `runtime/runtime.c`
@ -65,6 +73,13 @@ The generated standard-library API catalog is a beta discovery aid: it lists
exported helper signatures from `lib/std/*.slo`, normalizes module-local exported helper signatures from `lib/std/*.slo`, normalizes module-local
concrete aliases such as `VecI32` and `ResultU64` to their concrete public concrete aliases such as `VecI32` and `ResultU64` to their concrete public
types, and omits non-exported helpers and `(type ...)` aliases. types, and omits non-exported helpers and `(type ...)` aliases.
The companion
[`docs/language/STDLIB_TIERS.md`](docs/language/STDLIB_TIERS.md) ledger
defines the public tier labels `beta-supported`, `experimental`, and
`internal`, marks JSON, loopback networking, random/time, and filesystem
resource-handle helpers as experimental domains, and keeps concrete vector
modules as beta-supported concrete lanes rather than a generic collections
freeze.
`glagol symbols <file.slo|project|workspace>` emits deterministic `glagol symbols <file.slo|project|workspace>` emits deterministic
editor-facing S-expression metadata for modules, imports, exports, aliases, editor-facing S-expression metadata for modules, imports, exports, aliases,
structs, enums, functions, tests, source spans, and workspace package names. structs, enums, functions, tests, source spans, and workspace package names.
@ -72,6 +87,11 @@ structs, enums, functions, tests, source spans, and workspace package names.
API sections for local package and module documentation: exact exported API sections for local package and module documentation: exact exported
function signatures, exported struct fields, exported enum variants and payload function signatures, exported struct fields, exported enum variants and payload
types, non-export filtering, and module-local alias normalization. types, non-export filtering, and module-local alias normalization.
The `1.0.0-beta.22` tooling slice adds an additive run-report block to
`glagol run --manifest` artifact manifests so local evidence can record the
program exit status, captured stdout, captured stderr, and forwarded program
arguments. This is beta CLI evidence hardening only: it does not add language
or stdlib features and does not freeze the artifact-manifest schema.
The `1.0.0-beta.12` vector parity slice adds source-authored helper coverage The `1.0.0-beta.12` vector parity slice adds source-authored helper coverage
only: `std.vec_i64` gains `count_of`, `starts_with`, `without_prefix`, only: `std.vec_i64` gains `count_of`, `starts_with`, `without_prefix`,
`ends_with`, and `without_suffix`, while `std.vec_f64` gains `count_of`. `ends_with`, and `without_suffix`, while `std.vec_f64` gains `count_of`.
@ -121,18 +141,19 @@ concrete numeric primitives, and exact `null` only. Numeric and boolean parse
helpers consume one isolated JSON primitive token: no leading/trailing helpers consume one isolated JSON primitive token: no leading/trailing
whitespace, no leading `+`, no leading-zero integer form except `0`, and no whitespace, no leading `+`, no leading-zero integer form except `0`, and no
non-finite f64 values. This is not full JSON parsing: object/array parsing, non-finite f64 values. This is not full JSON parsing: object/array parsing,
tokenizers, recursive `JsonValue`, whitespace-tolerant document parsing, tokenizers, recursive `JsonValue`, document parsing beyond the beta21 scalar
schema validation, streaming, Unicode escape handling, stable ABI/layout, and document helpers, schema validation, streaming, Unicode escape handling,
a stable stdlib/API freeze remain deferred. stable ABI/layout, and a stable stdlib/API freeze remain deferred.
The `1.0.0-beta.18` JSON string token parsing foundation adds The `1.0.0-beta.18` JSON string token parsing foundation adds
`std.json.parse_string_value_result` as a thin source facade over the matching `std.json.parse_string_value_result` as a thin source facade over the matching
promoted runtime name. It consumes one already-isolated ASCII JSON string token promoted runtime name. It consumes one already-isolated ASCII JSON string token
with exact quotes and no leading/trailing whitespace, decodes the simple JSON with exact quotes and no leading/trailing whitespace, decodes the simple JSON
escapes `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, and `\t`, and returns escapes `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, and `\t`, and returns
`err 1` for ordinary parse failure. Full JSON document parsing, object/array `err 1` for ordinary parse failure. Complete JSON document parsing beyond the
parsing, tokenizer APIs, Unicode escape decoding/normalization, embedded NUL beta21 scalar document helpers, object/array parsing, tokenizer APIs, Unicode
policy, stable ABI/layout, and a stable stdlib/API freeze remain deferred. escape decoding/normalization, embedded NUL policy, stable ABI/layout, and a
stable stdlib/API freeze remain deferred.
The `1.0.0-beta.19` test discovery and user-project conformance foundation The `1.0.0-beta.19` test discovery and user-project conformance foundation
adds `glagol test --list <file|project|workspace>` plus legacy adds `glagol test --list <file|project|workspace>` plus legacy
@ -149,10 +170,59 @@ helpers over the existing byte string primitives. Search is byte-oriented,
empty needles match at the first index and at `(len value)` for last search, empty needles match at the first index and at `(len value)` for last search,
and ASCII trimming removes only bytes `9`, `10`, `11`, `12`, `13`, and `32`. and ASCII trimming removes only bytes `9`, `10`, `11`, `12`, `13`, and `32`.
The `1.0.0-beta.21` JSON document scalar parsing foundation adds
source-authored `std.json.parse_*_document_result` helpers for string, bool,
`i32`, `u32`, `i64`, `u64`, `f64`, and exact `null` scalar JSON documents.
Each helper trims ASCII whitespace around the whole document with
`std.string.trim_ascii`, then delegates to the already released exact JSON
value-token parser for that scalar family. This scope does not add new
compiler-known runtime names, object/array parsing, recursive `JsonValue`,
tokenizer objects, maps/sets, streaming, Unicode escape decoding beyond the
existing string-token behavior, embedded NUL policy, stable ABI/layout, or a
stable stdlib/API freeze.
The `1.0.0-beta.22` run manifest and execution report hardening slice extends
`glagol run --manifest` artifact manifests with additive run-report evidence:
the executed program's exit status, captured stdout, captured stderr, and
forwarded user-program arguments. This release does not add source-language
syntax, standard-library helpers, compiler-known runtime names, runtime
capabilities, package behavior, stable artifact-manifest schema guarantees,
stable ABI/layout, or a stable stdlib/API freeze.
The `1.0.0-beta.23` standard-library stability tier ledger and catalog
alignment slice adds the public
[`STDLIB_TIERS.md`](docs/language/STDLIB_TIERS.md) maturity ledger beside the
generated [`STDLIB_API.md`](docs/language/STDLIB_API.md) signature catalog.
It is documentation/catalog tooling clarity only: no source-language syntax,
stdlib helpers, compiler-known runtime names, runtime behavior, stable manifest
schema, stable Markdown schema, stable ABI/layout, or stable stdlib/API freeze
changes. The generated catalog and release gate now expose and check tier
metadata.
The `1.0.0-beta.24` package manifest identity and local dependency discipline
slice tightens local manifest diagnostics only: duplicate package manifest
keys, invalid dependency keys, and duplicate dependency keys are explicit beta
package/workspace diagnostics. It does not add remote registries, lockfiles,
semantic-version solving, package publishing, optional/dev/target
dependencies, stable package ABI/layout, source-language changes, runtime
changes, or standard-library changes.
The `1.0.0-beta.25` user-project conformance matrix slice adds deterministic
tooling/readiness evidence over the existing `examples/projects/` and
`examples/workspaces/` inventories. It currently covers all 43 top-level
fixture roots and 655 discovered tests through ordinary `check`,
`test --list`, and stable `test` entry points. The matrix is for ordinary
project and workspace usage evidence only: it does not add source-language
syntax or semantics, standard-library helpers, runtime behavior, package
manager or registry behavior, lockfile behavior, semantic-version solving,
stable schema guarantees, or performance claims.
Still deferred before stable: executable generics, generic aliases, maps/sets, Still deferred before stable: executable generics, generic aliases, maps/sets,
broad package registry semantics, stable Markdown schema, stable stdlib/API broad package registry semantics, stable artifact-manifest schema, stable
Markdown schema, stable conformance-matrix schema, stable stdlib/API
compatibility freeze, DNS/TLS/async networking, LSP/watch guarantees, SARIF compatibility freeze, DNS/TLS/async networking, LSP/watch guarantees, SARIF
and daemon protocols, stable `1.0.0` diagnostics freeze, and daemon protocols, stable `1.0.0`
diagnostics freeze,
re-exports/globs/hierarchical modules, mutable vectors, slice/view APIs, re-exports/globs/hierarchical modules, mutable vectors, slice/view APIs,
iterators, additional compiler-known runtime names, stable ABI and layout, iterators, additional compiler-known runtime names, stable ABI and layout,
performance claims, stable benchmark JSON metadata schema, and runtime changes performance claims, stable benchmark JSON metadata schema, and runtime changes
@ -282,6 +352,31 @@ package/dependency summary, new workspace templates declare
local-package rules. Remote registries, lockfiles, semantic-version solving, local-package rules. Remote registries, lockfiles, semantic-version solving,
package publishing, and stable package ABI/layout remain deferred. package publishing, and stable package ABI/layout remain deferred.
## 1.0.0-beta.24 Package Manifest Identity And Dependency Discipline
The `1.0.0-beta.24` release keeps the local package model closed and local. It
hardens diagnostics for manifest identity/dependency mistakes only: duplicate
package manifest keys, invalid dependency keys, and duplicate dependency keys
are reported explicitly.
This scope does not add a remote registry, lockfile, semantic-version solver,
package publishing flow, optional/dev/target dependencies, stable package
ABI/layout, source-language behavior, runtime behavior, or standard-library
behavior.
## 1.0.0-beta.25 User Project Conformance Matrix
The `1.0.0-beta.25` release adds deterministic tooling evidence for the
existing user-shaped examples under `examples/projects/` and
`examples/workspaces/`. The conformance matrix is sorted by repository path and
records ordinary `check`, `test --list`, and stable `test` behavior for all
43 top-level fixture roots and 655 discovered tests.
This scope is stable-readiness evidence only. It adds no source-language
change, standard-library helper change, runtime behavior change, package
manager or registry behavior, lockfile behavior, semantic-version solving,
stable schema freeze, or performance claim.
## 1.0.0-beta.6 Networking Foundation ## 1.0.0-beta.6 Networking Foundation
The `1.0.0-beta.6` release adds a narrow blocking loopback TCP foundation: The `1.0.0-beta.6` release adds a narrow blocking loopback TCP foundation:
@ -435,6 +530,36 @@ This scope adds no compiler-known runtime names. It does not claim Unicode
scalar, grapheme, case-folding, locale, regex, tokenizer, mutable string, scalar, grapheme, case-folding, locale, regex, tokenizer, mutable string,
language slice/view, stable ABI/layout, or stable stdlib/API semantics. language slice/view, stable ABI/layout, or stable stdlib/API semantics.
## 1.0.0-beta.21 JSON Document Scalar Parsing Foundation
The `1.0.0-beta.21` scope extends `std.json` with source-authored
whole-document scalar helpers:
`parse_string_document_result`, `parse_bool_document_result`,
`parse_i32_document_result`, `parse_u32_document_result`,
`parse_i64_document_result`, `parse_u64_document_result`,
`parse_f64_document_result`, and `parse_null_document_result`.
The helpers accept leading and trailing ASCII whitespace around a single
scalar document by composing with `std.string.trim_ascii`; trailing
non-whitespace still fails through the existing exact value-token parsers.
This scope does not add object/array parsing, recursive JSON values, parser
objects, maps/sets, streaming, Unicode escape decoding beyond the existing
string-token behavior, embedded NUL policy, new compiler-known runtime names,
stable ABI/layout, or stable stdlib/API semantics.
## 1.0.0-beta.22 Run Manifest And Execution Report Hardening
The `1.0.0-beta.22` scope hardens `glagol run --manifest` evidence by adding
an additive run-report block to run-mode artifact manifests. The block records
the executed program's exit status, captured stdout, captured stderr, and
forwarded program arguments.
This is tooling/CLI evidence work only. It does not add language syntax,
stdlib helpers, compiler-known runtime names, runtime C capabilities, package
or import behavior, stable artifact-manifest schema guarantees, stable
ABI/layout, or stable stdlib/API semantics.
## 1.0.0-beta.15 Reserved Generic Collection Boundary Hardening And Collection Ledger ## 1.0.0-beta.15 Reserved Generic Collection Boundary Hardening And Collection Ledger
The `1.0.0-beta.15` release documents the current concrete collection and The `1.0.0-beta.15` release documents the current concrete collection and

2
compiler/Cargo.lock generated
View File

@ -4,4 +4,4 @@ version = 3
[[package]] [[package]]
name = "glagol" name = "glagol"
version = "1.0.0-beta.20" version = "1.0.0-beta.25"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "glagol" name = "glagol"
version = "1.0.0-beta.20" version = "1.0.0-beta.25"
edition = "2021" edition = "2021"
description = "Glagol, the first compiler for the Slovo language" description = "Glagol, the first compiler for the Slovo language"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@ -892,14 +892,15 @@ fn run_native_from_llvm(
let _ = io::stdout().write_all(&run_output.stdout); let _ = io::stdout().write_all(&run_output.stdout);
let _ = io::stderr().write_all(&run_output.stderr); let _ = io::stderr().write_all(&run_output.stderr);
let stdout = String::from_utf8_lossy(&run_output.stdout).to_string(); let stdout = String::from_utf8_lossy(&run_output.stdout).to_string();
write_manifest_if_requested_with_foreign_imports( let stderr = String::from_utf8_lossy(&run_output.stderr).to_string();
let exit_status = run_output.status.code();
write_manifest_if_requested_with_run_report(
&invocation, &invocation,
run_output.status.success(), run_output.status.success(),
PrimaryOutput::Stdout { PrimaryOutput::Stdout {
kind: Mode::Run.output_kind(), kind: Mode::Run.output_kind(),
text: &stdout, text: &stdout,
}, },
None,
Some(BuildInfo { Some(BuildInfo {
clang: &native.clang, clang: &native.clang,
runtime: &native.runtime, runtime: &native.runtime,
@ -907,8 +908,14 @@ fn run_native_from_llvm(
}), }),
&foreign_imports, &foreign_imports,
project_artifact.as_ref(), project_artifact.as_ref(),
RunReport {
exit_status,
stdout: &stdout,
stderr: &stderr,
args: &invocation.run_args,
},
); );
process::exit(run_output.status.code().unwrap_or(1)); process::exit(exit_status.unwrap_or(1));
} }
struct NativeBuild { struct NativeBuild {
@ -1636,6 +1643,7 @@ fn exit_parse_error(err: ParseError, command_line: &str) -> ! {
PrimaryOutput::Diagnostics { text: &stderr }, PrimaryOutput::Diagnostics { text: &stderr },
None, None,
None, None,
None,
&[], &[],
None, None,
err.diagnostics, err.diagnostics,
@ -1889,6 +1897,13 @@ struct TestSummary {
filter: Option<String>, filter: Option<String>,
} }
struct RunReport<'a> {
exit_status: Option<i32>,
stdout: &'a str,
stderr: &'a str,
args: &'a [String],
}
fn test_summary_from_report(report: test_runner::TestReport) -> TestSummary { fn test_summary_from_report(report: test_runner::TestReport) -> TestSummary {
TestSummary { TestSummary {
total_discovered: report.total_discovered, total_discovered: report.total_discovered,
@ -1991,6 +2006,34 @@ fn write_manifest_if_requested_with_foreign_imports(
success, success,
primary_output, primary_output,
test_summary, test_summary,
None,
build_info,
foreign_imports,
project_info,
invocation.diagnostics,
);
write_manifest_or_exit(manifest_path, &manifest);
}
}
fn write_manifest_if_requested_with_run_report(
invocation: &Invocation,
success: bool,
primary_output: PrimaryOutput<'_>,
build_info: Option<BuildInfo<'_>>,
foreign_imports: &[project::ProjectArtifactCImport],
project_info: Option<&project::ProjectArtifact>,
run_report: RunReport<'_>,
) {
if let Some(manifest_path) = invocation.manifest_path.as_deref() {
let manifest = render_manifest(
Some(&invocation.path),
&invocation.command_line,
Some(invocation.manifest_mode_name.as_str()),
success,
primary_output,
None,
Some(run_report),
build_info, build_info,
foreign_imports, foreign_imports,
project_info, project_info,
@ -2014,6 +2057,7 @@ fn render_manifest(
success: bool, success: bool,
primary_output: PrimaryOutput<'_>, primary_output: PrimaryOutput<'_>,
test_summary: Option<TestSummary>, test_summary: Option<TestSummary>,
run_report: Option<RunReport<'_>>,
build_info: Option<BuildInfo<'_>>, build_info: Option<BuildInfo<'_>>,
foreign_imports: &[project::ProjectArtifactCImport], foreign_imports: &[project::ProjectArtifactCImport],
project_info: Option<&project::ProjectArtifact>, project_info: Option<&project::ProjectArtifact>,
@ -2115,6 +2159,34 @@ fn render_manifest(
out.push_str(" )"); out.push_str(" )");
} }
if let Some(report) = run_report {
out.push('\n');
out.push_str(" (run-report\n");
match report.exit_status {
Some(status) => out.push_str(&format!(" (exit-status {})\n", status)),
None => out.push_str(" (exit-status null)\n"),
}
out.push_str(&format!(
" (stdout {})\n",
diag::render_string(report.stdout)
));
out.push_str(&format!(
" (stderr {})\n",
diag::render_string(report.stderr)
));
out.push_str(" (args");
if report.args.is_empty() {
out.push_str(")\n");
} else {
out.push('\n');
for arg in report.args {
out.push_str(&format!(" (arg {})\n", diag::render_string(arg)));
}
out.push_str(" )\n");
}
out.push_str(" )");
}
if let Some(build) = build_info { if let Some(build) = build_info {
out.push('\n'); out.push('\n');
out.push_str(" (hosted-build\n"); out.push_str(" (hosted-build\n");

View File

@ -1124,7 +1124,16 @@ fn parse_manifest(path: PathBuf, source: String) -> Result<Manifest, Vec<Diagnos
}; };
match key { match key {
"name" => set_manifest_key(&file, &mut errors, &mut name, parsed, line.span, "name"), "name" => set_manifest_key(
&file,
&mut errors,
&mut name,
parsed,
line.span,
"name",
"ProjectManifestInvalid",
"project",
),
"source_root" => set_manifest_key( "source_root" => set_manifest_key(
&file, &file,
&mut errors, &mut errors,
@ -1132,8 +1141,19 @@ fn parse_manifest(path: PathBuf, source: String) -> Result<Manifest, Vec<Diagnos
parsed, parsed,
line.span, line.span,
"source_root", "source_root",
"ProjectManifestInvalid",
"project",
),
"entry" => set_manifest_key(
&file,
&mut errors,
&mut entry,
parsed,
line.span,
"entry",
"ProjectManifestInvalid",
"project",
), ),
"entry" => set_manifest_key(&file, &mut errors, &mut entry, parsed, line.span, "entry"),
_ => errors.push( _ => errors.push(
Diagnostic::new( Diagnostic::new(
&file, &file,
@ -1412,6 +1432,7 @@ fn parse_package_manifest(
let mut source_root = None::<String>; let mut source_root = None::<String>;
let mut entry = None::<String>; let mut entry = None::<String>;
let mut dependencies = Vec::new(); let mut dependencies = Vec::new();
let mut dependency_keys = BTreeSet::<String>::new();
for line in manifest_lines(&source) { for line in manifest_lines(&source) {
let trimmed = line.text.trim(); let trimmed = line.text.trim();
@ -1489,6 +1510,8 @@ fn parse_package_manifest(
parsed, parsed,
line.span, line.span,
"name", "name",
"PackageManifestInvalid",
"package",
), ),
"version" => set_manifest_key( "version" => set_manifest_key(
&file, &file,
@ -1497,6 +1520,8 @@ fn parse_package_manifest(
parsed, parsed,
line.span, line.span,
"version", "version",
"PackageManifestInvalid",
"package",
), ),
"source_root" => set_manifest_key( "source_root" => set_manifest_key(
&file, &file,
@ -1505,6 +1530,8 @@ fn parse_package_manifest(
parsed, parsed,
line.span, line.span,
"source_root", "source_root",
"PackageManifestInvalid",
"package",
), ),
"entry" => set_manifest_key( "entry" => set_manifest_key(
&file, &file,
@ -1513,6 +1540,8 @@ fn parse_package_manifest(
parsed, parsed,
line.span, line.span,
"entry", "entry",
"PackageManifestInvalid",
"package",
), ),
other => errors.push( other => errors.push(
Diagnostic::new( Diagnostic::new(
@ -1524,21 +1553,54 @@ fn parse_package_manifest(
), ),
} }
} }
"dependencies" => match parse_dependency_path(value) { "dependencies" => {
Some(path) => dependencies.push(PackageDependency { let valid_key = if is_project_name(key) {
key: key.to_string(), true
path, } else {
span: line.span, errors.push(
}), Diagnostic::new(
None => errors.push( &file,
Diagnostic::new( "InvalidPackageDependencyName",
&file, format!(
"UnsupportedDependency", "package dependency name `{}` must start with `a-z` and contain only `a-z`, `0-9`, and `-`",
"workspace dependencies must use `{ path = \"...\" }` local path records only", key
) ),
.with_span(line.span), )
), .with_span(line.span),
}, );
false
};
let unique_key = if dependency_keys.insert(key.to_string()) {
true
} else {
errors.push(
Diagnostic::new(
&file,
"DuplicatePackageDependencyName",
format!("duplicate package dependency name `{}`", key),
)
.with_span(line.span),
);
false
};
match parse_dependency_path(value) {
Some(path) if valid_key && unique_key => dependencies.push(PackageDependency {
key: key.to_string(),
path,
span: line.span,
}),
Some(_) => {}
None => errors.push(
Diagnostic::new(
&file,
"UnsupportedDependency",
"workspace dependencies must use `{ path = \"...\" }` local path records only",
)
.with_span(line.span),
),
}
}
"" | "project" => errors.push( "" | "project" => errors.push(
Diagnostic::new( Diagnostic::new(
&file, &file,
@ -1694,13 +1756,15 @@ fn set_manifest_key(
value: String, value: String,
span: Span, span: Span,
key: &str, key: &str,
code: &'static str,
manifest_kind: &str,
) { ) {
if slot.replace(value).is_some() { if slot.replace(value).is_some() {
errors.push( errors.push(
Diagnostic::new( Diagnostic::new(
file, file,
"ProjectManifestInvalid", code,
format!("duplicate project manifest key `{}`", key), format!("duplicate {} manifest key `{}`", manifest_kind, key),
) )
.with_span(span), .with_span(span),
); );

View File

@ -0,0 +1,229 @@
use std::{
fs,
path::PathBuf,
process::{Command, Output},
sync::atomic::{AtomicUsize, Ordering},
time::{SystemTime, UNIX_EPOCH},
};
static NEXT_WORKSPACE_ID: AtomicUsize = AtomicUsize::new(0);
#[test]
fn duplicate_package_keys_report_package_manifest_invalid() {
let workspace = write_workspace(
"duplicate-package-key",
"[workspace]\nmembers = [\"packages/app\"]\n",
&[WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nname = \"other\"\nversion = \"0.1.0\"\n",
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
}],
);
let output = run_glagol([
"--json-diagnostics".as_ref(),
"check".as_ref(),
workspace.as_os_str(),
]);
assert_exit_code("duplicate package key", &output, 1);
assert_json_diagnostic_code("duplicate package key", &output, "PackageManifestInvalid");
assert_json_diagnostic_code_absent("duplicate package key", &output, "ProjectManifestInvalid");
}
#[test]
fn invalid_dependency_key_reports_invalid_package_dependency_name() {
let workspace = write_workspace(
"invalid-dependency-key",
"[workspace]\nmembers = [\"packages/app\"]\n",
&[WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nBad_Name = { path = \"../util\" }\n",
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
}],
);
let output = run_glagol([
"--json-diagnostics".as_ref(),
"check".as_ref(),
workspace.as_os_str(),
]);
assert_exit_code("invalid dependency key", &output, 1);
assert_json_diagnostic_code(
"invalid dependency key",
&output,
"InvalidPackageDependencyName",
);
}
#[test]
fn duplicate_dependency_keys_report_duplicate_package_dependency_name() {
let workspace = write_workspace(
"duplicate-dependency-key",
"[workspace]\nmembers = [\"packages/app\"]\n",
&[WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nutil = { path = \"../util\" }\nutil = { path = \"../util-again\" }\n",
modules: &[("main", "(module main)\n\n(fn main () -> i32\n 0)\n")],
}],
);
let output = run_glagol([
"--json-diagnostics".as_ref(),
"check".as_ref(),
workspace.as_os_str(),
]);
assert_exit_code("duplicate dependency key", &output, 1);
assert_json_diagnostic_code(
"duplicate dependency key",
&output,
"DuplicatePackageDependencyName",
);
}
#[test]
fn valid_dependency_identity_checks_cleanly() {
let workspace = write_workspace(
"valid-dependency-identity",
"[workspace]\nmembers = [\"packages/app\", \"packages/util\"]\n",
&[
WorkspacePackageSpec {
member: "packages/util",
manifest: "[package]\nname = \"util\"\nversion = \"0.1.0\"\n",
modules: &[(
"util",
"(module util (export answer))\n\n(fn answer () -> i32\n 42)\n",
)],
},
WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies]\nutil = { path = \"../util\" }\n",
modules: &[(
"main",
"(module main)\n\n(import util.util (answer))\n\n(fn main () -> i32\n (answer))\n",
)],
},
],
);
let output = run_glagol(["check".as_ref(), workspace.as_os_str()]);
assert_success_stdout("valid dependency identity", output, "");
}
struct WorkspacePackageSpec<'a> {
member: &'a str,
manifest: &'a str,
modules: &'a [(&'a str, &'a str)],
}
fn write_workspace(
name: &str,
workspace_manifest: &str,
packages: &[WorkspacePackageSpec<'_>],
) -> PathBuf {
let root = unique_path(name);
fs::create_dir_all(&root).expect("create workspace root");
fs::write(root.join("slovo.toml"), workspace_manifest).expect("write workspace manifest");
for package in packages {
let package_root = root.join(package.member);
let src = package_root.join("src");
fs::create_dir_all(&src).expect("create workspace package src");
fs::write(package_root.join("slovo.toml"), package.manifest)
.expect("write workspace package manifest");
for (module, source) in package.modules {
fs::write(src.join(format!("{}.slo", module)), source)
.expect("write workspace package module");
}
}
root
}
fn unique_path(name: &str) -> PathBuf {
let id = NEXT_WORKSPACE_ID.fetch_add(1, Ordering::SeqCst);
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_nanos())
.unwrap_or(0);
std::env::temp_dir().join(format!(
"glagol-package-workspace-discipline-beta24-{}-{}-{}-{}",
std::process::id(),
nanos,
id,
name
))
}
fn run_glagol<I, S>(args: I) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<std::ffi::OsStr>,
{
Command::new(env!("CARGO_BIN_EXE_glagol"))
.args(args)
.output()
.expect("run glagol")
}
fn assert_success_stdout(context: &str, output: Output, expected: &str) {
assert!(
output.status.success(),
"{} failed\nstdout:\n{}\nstderr:\n{}",
context,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
expected,
"{} stdout mismatch",
context
);
assert!(
output.stderr.is_empty(),
"{} wrote stderr:\n{}",
context,
String::from_utf8_lossy(&output.stderr)
);
}
fn assert_exit_code(context: &str, output: &Output, expected: i32) {
assert_eq!(
output.status.code(),
Some(expected),
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
context,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
fn assert_json_diagnostic_code(context: &str, output: &Output, expected: &str) {
let diagnostics = diagnostic_text(output);
assert!(
diagnostics.contains(&format!(r#""code":"{}""#, expected)),
"{} did not report `{}`:\n{}",
context,
expected,
diagnostics
);
}
fn assert_json_diagnostic_code_absent(context: &str, output: &Output, unexpected: &str) {
let diagnostics = diagnostic_text(output);
assert!(
!diagnostics.contains(&format!(r#""code":"{}""#, unexpected)),
"{} unexpectedly reported `{}`:\n{}",
context,
unexpected,
diagnostics
);
}
fn diagnostic_text(output: &Output) -> String {
format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
}

View File

@ -1229,6 +1229,14 @@ const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
"parse_u64_value_result", "parse_u64_value_result",
"parse_f64_value_result", "parse_f64_value_result",
"parse_null_value_result", "parse_null_value_result",
"parse_string_document_result",
"parse_bool_document_result",
"parse_i32_document_result",
"parse_u32_document_result",
"parse_i64_document_result",
"parse_u64_document_result",
"parse_f64_document_result",
"parse_null_document_result",
"field_string", "field_string",
"field_bool", "field_bool",
"field_i32", "field_i32",
@ -1265,6 +1273,7 @@ const STANDARD_JSON_RUNTIME_NAMES: &[&str] = &[
]; ];
const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[ const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
"(import std.string (trim_ascii))",
"std.json.quote_string", "std.json.quote_string",
"std.string.concat", "std.string.concat",
"std.num.i32_to_string", "std.num.i32_to_string",
@ -1281,6 +1290,17 @@ const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
"std.json.parse_f64_value_result", "std.json.parse_f64_value_result",
]; ];
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
"parse_string_document_result",
"parse_bool_document_result",
"parse_i32_document_result",
"parse_u32_document_result",
"parse_i64_document_result",
"parse_u64_document_result",
"parse_f64_document_result",
"parse_null_document_result",
];
const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[ const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
"argc", "argc",
"arg", "arg",
@ -4458,6 +4478,7 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
); );
for source in [&slovo_json, &glagol_json] { for source in [&slovo_json, &glagol_json] {
assert_deferred_json_surface_absent(source, "standard json facade"); assert_deferred_json_surface_absent(source, "standard json facade");
assert_json_document_scalar_helpers_are_source_authored(source, "standard json facade");
} }
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA { for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
assert!( assert!(
@ -7316,10 +7337,13 @@ fn assert_project_std_import_json_tooling_matches_fixture(project: &Path) {
"test \"explicit std json primitive scalar parse failure facade\" ... ok\n", "test \"explicit std json primitive scalar parse failure facade\" ... ok\n",
"test \"explicit std json string token parse success facade\" ... ok\n", "test \"explicit std json string token parse success facade\" ... ok\n",
"test \"explicit std json string token parse failure facade\" ... ok\n", "test \"explicit std json string token parse failure facade\" ... ok\n",
"test \"explicit std json document parse trimmed success facade\" ... ok\n",
"test \"explicit std json document parse plain success facade\" ... ok\n",
"test \"explicit std json document parse trailing failure facade\" ... ok\n",
"test \"explicit std json fields facade\" ... ok\n", "test \"explicit std json fields facade\" ... ok\n",
"test \"explicit std json arrays objects facade\" ... ok\n", "test \"explicit std json arrays objects facade\" ... ok\n",
"test \"explicit std json facade all\" ... ok\n", "test \"explicit std json facade all\" ... ok\n",
"9 test(s) passed\n", "12 test(s) passed\n",
), ),
); );
} }
@ -9527,10 +9551,13 @@ fn assert_project_std_layout_local_json_tooling_matches_fixture(project: &Path)
"test \"explicit local json primitive scalar parse failure facade\" ... ok\n", "test \"explicit local json primitive scalar parse failure facade\" ... ok\n",
"test \"explicit local json string token parse success facade\" ... ok\n", "test \"explicit local json string token parse success facade\" ... ok\n",
"test \"explicit local json string token parse failure facade\" ... ok\n", "test \"explicit local json string token parse failure facade\" ... ok\n",
"test \"explicit local json document parse trimmed success facade\" ... ok\n",
"test \"explicit local json document parse plain success facade\" ... ok\n",
"test \"explicit local json document parse trailing failure facade\" ... ok\n",
"test \"explicit local json fields facade\" ... ok\n", "test \"explicit local json fields facade\" ... ok\n",
"test \"explicit local json arrays objects facade\" ... ok\n", "test \"explicit local json arrays objects facade\" ... ok\n",
"test \"explicit local json facade all\" ... ok\n", "test \"explicit local json facade all\" ... ok\n",
"9 test(s) passed\n", "12 test(s) passed\n",
), ),
"std layout local json project test", "std layout local json project test",
); );
@ -10724,6 +10751,34 @@ fn assert_deferred_json_surface_absent(source: &str, context: &str) {
} }
} }
fn assert_json_document_scalar_helpers_are_source_authored(source: &str, context: &str) {
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
assert!(
!source.contains(&format!("std.json.{}", helper)),
"{} must keep `{}` source-authored, not compiler-known",
context,
helper
);
}
for private_prefix in [
"__glagol_json_parse_string_document",
"__glagol_json_parse_bool_document",
"__glagol_json_parse_i32_document",
"__glagol_json_parse_u32_document",
"__glagol_json_parse_i64_document",
"__glagol_json_parse_u64_document",
"__glagol_json_parse_f64_document",
"__glagol_json_parse_null_document",
] {
assert!(
!source.contains(private_prefix),
"{} must not introduce private JSON document runtime symbol `{}`",
context,
private_prefix
);
}
}
fn repo_root() -> PathBuf { fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")) Path::new(env!("CARGO_MANIFEST_DIR"))
.parent() .parent()

View File

@ -0,0 +1,267 @@
use std::{
env, fs,
path::{Path, PathBuf},
process::{Command, Output},
sync::atomic::{AtomicUsize, Ordering},
};
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
#[test]
fn run_manifest_records_success_report_stdout_and_program_args() {
let Some(clang) = find_clang() else {
eprintln!("skipping run manifest success report: set GLAGOL_CLANG or install clang");
return;
};
let source = write_fixture(
"success",
r#"
(module main)
(fn main () -> i32
(print_string "beta22-out")
0)
"#,
"slo",
);
let manifest_path = temp_path("success-manifest", "manifest.slo");
let mut command = Command::new(compiler_path());
command
.arg("run")
.arg(&source)
.arg("--manifest")
.arg(&manifest_path)
.arg("--")
.arg("alpha")
.arg("two words")
.arg("--literal")
.env("GLAGOL_CLANG", &clang);
configure_clang_runtime_env(&mut command, &clang);
let output = command.output().expect("run glagol success manifest");
assert_success_stdout("run manifest success", &output, "beta22-out\n");
let manifest = read_manifest(&manifest_path);
assert!(
manifest.contains(" (mode run)\n")
&& manifest.contains(" (success true)\n")
&& manifest.contains(" (run-report\n")
&& manifest.contains(" (exit-status 0)\n")
&& manifest.contains(" (stdout \"beta22-out\\n\")\n")
&& manifest.contains(" (stderr \"\")\n")
&& manifest.contains(" (arg \"alpha\")\n")
&& manifest.contains(" (arg \"two words\")\n")
&& manifest.contains(" (arg \"--literal\")\n"),
"successful run manifest mismatch:\n{}",
manifest
);
}
#[test]
fn run_manifest_records_nonzero_report_and_preserves_program_stderr() {
let Some(clang) = find_clang() else {
eprintln!("skipping run manifest nonzero report: set GLAGOL_CLANG or install clang");
return;
};
let source = write_fixture(
"nonzero",
r#"
(module main)
(import_c beta22_stderr () -> i32)
(fn emit_stderr () -> i32
(unsafe
(beta22_stderr)))
(fn main () -> i32
(emit_stderr)
7)
"#,
"slo",
);
let c_source = write_fixture(
"nonzero-stderr",
r#"
#include <stdio.h>
int beta22_stderr(void) {
fputs("beta22-err\n", stderr);
return 0;
}
"#,
"c",
);
let manifest_path = temp_path("nonzero-manifest", "manifest.slo");
let mut command = Command::new(compiler_path());
command
.arg("run")
.arg(&source)
.arg("--link-c")
.arg(&c_source)
.arg("--manifest")
.arg(&manifest_path)
.env("GLAGOL_CLANG", &clang);
configure_clang_runtime_env(&mut command, &clang);
let output = command.output().expect("run glagol nonzero manifest");
assert_exit_code("run manifest nonzero", &output, 7);
assert_eq!(output.stdout, b"", "nonzero run stdout drifted");
assert_eq!(output.stderr, b"beta22-err\n", "nonzero run stderr drifted");
let manifest = read_manifest(&manifest_path);
assert!(
manifest.contains(" (mode run)\n")
&& manifest.contains(" (success false)\n")
&& manifest.contains(" (run-report\n")
&& manifest.contains(" (exit-status 7)\n")
&& manifest.contains(" (stdout \"\")\n")
&& manifest.contains(" (stderr \"beta22-err\\n\")\n")
&& manifest.contains(" (args)\n"),
"nonzero run manifest mismatch:\n{}",
manifest
);
}
#[test]
fn run_manifest_source_failure_does_not_record_fake_run_report() {
let source = write_fixture(
"source-failure",
r#"
(module main)
(fn main () -> i32
true)
"#,
"slo",
);
let manifest_path = temp_path("source-failure-manifest", "manifest.slo");
let output = run_glagol([
"run".as_ref(),
source.as_os_str(),
"--manifest".as_ref(),
manifest_path.as_os_str(),
]);
assert_exit_code("run manifest source failure", &output, 1);
let manifest = read_manifest(&manifest_path);
assert!(
manifest.contains(" (mode run)\n")
&& manifest.contains(" (success false)\n")
&& manifest.contains(" (kind diagnostics)\n")
&& manifest.contains("TypeMismatch")
&& !manifest.contains(" (run-report\n"),
"source failure manifest included fake run report:\n{}",
manifest
);
}
fn run_glagol<const N: usize>(args: [&std::ffi::OsStr; N]) -> Output {
Command::new(compiler_path())
.args(args)
.output()
.expect("run glagol")
}
fn compiler_path() -> &'static str {
env!("CARGO_BIN_EXE_glagol")
}
fn write_fixture(name: &str, source: &str, extension: &str) -> PathBuf {
let path = temp_path(name, extension);
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
path
}
fn temp_path(name: &str, extension: &str) -> PathBuf {
let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
let mut path = env::temp_dir();
path.push(format!(
"glagol-run-manifest-beta22-{}-{}-{}.{}",
std::process::id(),
id,
name,
extension
));
path
}
fn read_manifest(path: &Path) -> String {
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
}
fn assert_success_stdout(context: &str, output: &Output, expected: &str) {
assert!(
output.status.success(),
"{} failed\nstdout:\n{}\nstderr:\n{}",
context,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
expected,
"{} stdout mismatch",
context
);
assert!(
output.stderr.is_empty(),
"{} wrote stderr:\n{}",
context,
String::from_utf8_lossy(&output.stderr)
);
}
fn assert_exit_code(context: &str, output: &Output, expected: i32) {
assert_eq!(
output.status.code(),
Some(expected),
"{} exit code mismatch\nstdout:\n{}\nstderr:\n{}",
context,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
fn find_clang() -> Option<PathBuf> {
if let Some(path) = env::var_os("GLAGOL_CLANG").filter(|value| !value.is_empty()) {
let path = PathBuf::from(path);
if path.is_file() {
return Some(path);
}
}
let hermetic_clang = PathBuf::from("/tmp/glagol-clang-root/usr/bin/clang");
if hermetic_clang.is_file() {
return Some(hermetic_clang);
}
find_on_path("clang")
}
fn find_on_path(name: &str) -> Option<PathBuf> {
let path = env::var_os("PATH")?;
env::split_paths(&path)
.map(|dir| dir.join(name))
.find(|candidate| candidate.is_file())
}
fn configure_clang_runtime_env(command: &mut Command, clang: &Path) {
if !clang.starts_with("/tmp/glagol-clang-root") {
return;
}
let root = Path::new("/tmp/glagol-clang-root");
let lib64 = root.join("usr/lib64");
let lib = root.join("usr/lib");
let existing = env::var_os("LD_LIBRARY_PATH").unwrap_or_default();
let mut paths = vec![lib64, lib];
paths.extend(env::split_paths(&existing));
let joined = env::join_paths(paths).expect("join LD_LIBRARY_PATH");
command.env("LD_LIBRARY_PATH", joined);
}

View File

@ -0,0 +1,313 @@
use std::{
env,
ffi::OsStr,
fs,
path::{Path, PathBuf},
process::{Command, Output},
sync::atomic::{AtomicUsize, Ordering},
};
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
const EXPECTED_TEST_OUTPUT: &str = concat!(
"test \"explicit std json document scalar string\" ... ok\n",
"test \"explicit std json document scalar bool\" ... ok\n",
"test \"explicit std json document scalar integer\" ... ok\n",
"test \"explicit std json document scalar float null\" ... ok\n",
"test \"explicit std json document scalar failures\" ... ok\n",
"test \"explicit std json document scalar all\" ... ok\n",
"6 test(s) passed\n",
);
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
"parse_string_document_result",
"parse_bool_document_result",
"parse_i32_document_result",
"parse_u32_document_result",
"parse_i64_document_result",
"parse_u64_document_result",
"parse_f64_document_result",
"parse_null_document_result",
];
#[test]
fn explicit_std_json_document_scalar_helpers_check_and_test() {
let project = write_project(
"std-json-document-scalar-beta21",
r#"
(module main)
(import std.json (parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result))
(fn imported_json_document_string_ok () -> bool
(if (= (std.result.unwrap_ok (parse_string_document_result " \"slovo\" ")) "slovo")
(= (std.result.unwrap_ok (parse_string_document_result "\n\t\"slo\\\"vo\"\t")) "slo\"vo")
false))
(fn imported_json_document_bool_ok () -> bool
(if (std.result.unwrap_ok (parse_bool_document_result " true "))
(= (std.result.unwrap_ok (parse_bool_document_result "\nfalse\t")) false)
false))
(fn imported_json_document_integer_ok () -> bool
(if (= (std.result.unwrap_ok (parse_i32_document_result " -7 ")) -7)
(if (= (std.result.unwrap_ok (parse_u32_document_result "\n7\t")) 7u32)
(if (= (std.result.unwrap_ok (parse_i64_document_result " -8 ")) -8i64)
(= (std.result.unwrap_ok (parse_u64_document_result "9 ")) 9u64)
false)
false)
false))
(fn imported_json_document_float_null_ok () -> bool
(if (= (std.result.unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
(std.result.unwrap_ok (parse_null_document_result "\nnull\t"))
false))
(fn imported_json_document_failures_ok () -> bool
(if (= (std.result.unwrap_err (parse_string_document_result "\"slovo\" x")) 1)
(if (= (std.result.unwrap_err (parse_bool_document_result " TRUE ")) 1)
(if (= (std.result.unwrap_err (parse_i32_document_result " 01 ")) 1)
(if (= (std.result.unwrap_err (parse_u32_document_result " -1 ")) 1)
(if (= (std.result.unwrap_err (parse_i64_document_result " 8i64 ")) 1)
(if (= (std.result.unwrap_err (parse_u64_document_result " ")) 1)
(if (= (std.result.unwrap_err (parse_f64_document_result " 01.0 ")) 1)
(= (std.result.unwrap_err (parse_null_document_result " NULL ")) 1)
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_document_scalar_all_ok () -> bool
(if (imported_json_document_string_ok)
(if (imported_json_document_bool_ok)
(if (imported_json_document_integer_ok)
(if (imported_json_document_float_null_ok)
(imported_json_document_failures_ok)
false)
false)
false)
false))
(fn main () -> i32
(if (imported_json_document_scalar_all_ok)
42
1))
(test "explicit std json document scalar string"
(imported_json_document_string_ok))
(test "explicit std json document scalar bool"
(imported_json_document_bool_ok))
(test "explicit std json document scalar integer"
(imported_json_document_integer_ok))
(test "explicit std json document scalar float null"
(imported_json_document_float_null_ok))
(test "explicit std json document scalar failures"
(imported_json_document_failures_ok))
(test "explicit std json document scalar all"
(= (main) 42))
"#,
);
let source = read(&project.join("src/main.slo"));
let std_json = read(&std_json_path());
assert!(
!project.join("src/json.slo").exists(),
"beta21 fixture must exercise repo-root std.json, not a local module copy"
);
assert!(
source.starts_with("(module main)\n\n(import std.json ("),
"beta21 fixture must use an explicit std.json import"
);
assert_json_document_scalar_helpers_are_source_authored(&std_json);
let fmt = run_glagol([
OsStr::new("fmt"),
OsStr::new("--check"),
project.as_os_str(),
]);
assert_success("std json document scalar fmt --check", &fmt);
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
assert_success_stdout(check, "", "std json document scalar check");
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
assert_success_stdout(test, EXPECTED_TEST_OUTPUT, "std json document scalar test");
}
#[test]
fn json_document_scalar_helpers_are_not_compiler_known_runtime_calls() {
let std_json = read(&std_json_path());
assert_json_document_scalar_helpers_are_source_authored(&std_json);
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
let fixture = write_fixture(
helper,
&format!(
"(module main)\n\n(fn main () -> i32\n (std.result.unwrap_err (std.json.{} \"invalid\")))\n",
helper
),
);
let output = run_glagol([fixture.as_os_str()]);
assert_failure_stderr_contains(
&format!("direct std.json.{} runtime call", helper),
&output,
&format!(
"standard library call `std.json.{}` is not supported",
helper
),
);
}
}
fn assert_json_document_scalar_helpers_are_source_authored(std_json: &str) {
assert!(
std_json.starts_with("(module json (export "),
"lib/std/json.slo must stay a source-authored module export"
);
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
assert!(
std_json.contains(&format!("(fn {} ", helper)),
"lib/std/json.slo is missing source facade `{}`",
helper
);
assert!(
!std_json.contains(&format!("std.json.{}", helper)),
"std.json.{} must remain source-authored, not a compiler-known runtime call",
helper
);
}
for private_prefix in [
"__glagol_json_parse_string_document",
"__glagol_json_parse_bool_document",
"__glagol_json_parse_i32_document",
"__glagol_json_parse_u32_document",
"__glagol_json_parse_i64_document",
"__glagol_json_parse_u64_document",
"__glagol_json_parse_f64_document",
"__glagol_json_parse_null_document",
] {
assert!(
!std_json.contains(private_prefix),
"lib/std/json.slo must not introduce private JSON document runtime symbol `{}`",
private_prefix
);
}
}
fn run_glagol<I, S>(args: I) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
Command::new(env!("CARGO_BIN_EXE_glagol"))
.args(args)
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
.output()
.expect("run glagol")
}
fn write_project(name: &str, source: &str) -> PathBuf {
let root = temp_root(name);
let src = root.join("src");
fs::create_dir_all(&src).unwrap_or_else(|err| panic!("create `{}`: {}", src.display(), err));
fs::write(
root.join("slovo.toml"),
format!(
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
name
),
)
.unwrap_or_else(|err| panic!("write project manifest: {}", err));
fs::write(src.join("main.slo"), source.trim_start())
.unwrap_or_else(|err| panic!("write project main.slo: {}", err));
root
}
fn write_fixture(name: &str, source: &str) -> PathBuf {
let mut path = env::temp_dir();
path.push(format!(
"glagol-standard-json-document-scalar-beta21-{}-{}-{}.slo",
name,
std::process::id(),
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
));
fs::write(&path, source.trim_start())
.unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
path
}
fn temp_root(name: &str) -> PathBuf {
let root = env::temp_dir().join(format!(
"glagol-standard-json-document-scalar-beta21-{}-{}-{}",
name,
std::process::id(),
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
));
let _ = fs::remove_dir_all(&root);
fs::create_dir_all(&root).unwrap_or_else(|err| panic!("create `{}`: {}", root.display(), err));
root
}
fn std_json_path() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../lib/std/json.slo")
}
fn read(path: &Path) -> String {
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
}
fn assert_success(context: &str, output: &Output) {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"{} failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
context,
output.status.code(),
stdout,
stderr
);
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
}
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
assert_success(context, &output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert_eq!(stdout, expected, "{}", context);
}
fn assert_failure_stderr_contains(context: &str, output: &Output, needle: &str) {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!output.status.success(),
"{} unexpectedly passed\nstdout:\n{}\nstderr:\n{}",
context,
stdout,
stderr
);
assert!(
stdout.is_empty(),
"{} rejected compile wrote stdout:\n{}",
context,
stdout
);
assert!(
stderr.contains(needle),
"{} stderr did not contain `{}`:\n{}",
context,
needle,
stderr
);
}

View File

@ -12,10 +12,13 @@ const EXPECTED_LOCAL_TEST_OUTPUT: &str = concat!(
"test \"explicit local json primitive scalar parse failure facade\" ... ok\n", "test \"explicit local json primitive scalar parse failure facade\" ... ok\n",
"test \"explicit local json string token parse success facade\" ... ok\n", "test \"explicit local json string token parse success facade\" ... ok\n",
"test \"explicit local json string token parse failure facade\" ... ok\n", "test \"explicit local json string token parse failure facade\" ... ok\n",
"test \"explicit local json document parse trimmed success facade\" ... ok\n",
"test \"explicit local json document parse plain success facade\" ... ok\n",
"test \"explicit local json document parse trailing failure facade\" ... ok\n",
"test \"explicit local json fields facade\" ... ok\n", "test \"explicit local json fields facade\" ... ok\n",
"test \"explicit local json arrays objects facade\" ... ok\n", "test \"explicit local json arrays objects facade\" ... ok\n",
"test \"explicit local json facade all\" ... ok\n", "test \"explicit local json facade all\" ... ok\n",
"9 test(s) passed\n", "12 test(s) passed\n",
); );
const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!( const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!(
@ -25,10 +28,13 @@ const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!(
"test \"explicit std json primitive scalar parse failure facade\" ... ok\n", "test \"explicit std json primitive scalar parse failure facade\" ... ok\n",
"test \"explicit std json string token parse success facade\" ... ok\n", "test \"explicit std json string token parse success facade\" ... ok\n",
"test \"explicit std json string token parse failure facade\" ... ok\n", "test \"explicit std json string token parse failure facade\" ... ok\n",
"test \"explicit std json document parse trimmed success facade\" ... ok\n",
"test \"explicit std json document parse plain success facade\" ... ok\n",
"test \"explicit std json document parse trailing failure facade\" ... ok\n",
"test \"explicit std json fields facade\" ... ok\n", "test \"explicit std json fields facade\" ... ok\n",
"test \"explicit std json arrays objects facade\" ... ok\n", "test \"explicit std json arrays objects facade\" ... ok\n",
"test \"explicit std json facade all\" ... ok\n", "test \"explicit std json facade all\" ... ok\n",
"9 test(s) passed\n", "12 test(s) passed\n",
); );
const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[ const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
@ -48,6 +54,14 @@ const STANDARD_JSON_SOURCE_FACADE_ALPHA: &[&str] = &[
"parse_u64_value_result", "parse_u64_value_result",
"parse_f64_value_result", "parse_f64_value_result",
"parse_null_value_result", "parse_null_value_result",
"parse_string_document_result",
"parse_bool_document_result",
"parse_i32_document_result",
"parse_u32_document_result",
"parse_i64_document_result",
"parse_u64_document_result",
"parse_f64_document_result",
"parse_null_document_result",
"field_string", "field_string",
"field_bool", "field_bool",
"field_i32", "field_i32",
@ -84,6 +98,7 @@ const STANDARD_JSON_RUNTIME_NAMES: &[&str] = &[
]; ];
const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[ const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
"(import std.string (trim_ascii))",
"std.json.quote_string", "std.json.quote_string",
"std.string.concat", "std.string.concat",
"std.num.i32_to_string", "std.num.i32_to_string",
@ -100,6 +115,17 @@ const STANDARD_JSON_ALLOWED_STD_NAMES: &[&str] = &[
"std.json.parse_f64_value_result", "std.json.parse_f64_value_result",
]; ];
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
"parse_string_document_result",
"parse_bool_document_result",
"parse_i32_document_result",
"parse_u32_document_result",
"parse_i64_document_result",
"parse_u64_document_result",
"parse_f64_document_result",
"parse_null_document_result",
];
#[test] #[test]
fn standard_json_source_facade_project_checks_formats_and_tests() { fn standard_json_source_facade_project_checks_formats_and_tests() {
let project = let project =
@ -199,6 +225,7 @@ fn assert_json_source_shape(json: &str, main: &str, context: &str) {
} }
assert_std_only_contains(json, STANDARD_JSON_ALLOWED_STD_NAMES, context); assert_std_only_contains(json, STANDARD_JSON_ALLOWED_STD_NAMES, context);
assert_deferred_json_surface_absent(json, main, context); assert_deferred_json_surface_absent(json, main, context);
assert_json_document_scalar_helpers_are_source_authored(json, context);
for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA { for helper in STANDARD_JSON_SOURCE_FACADE_ALPHA {
assert!( assert!(
@ -216,6 +243,34 @@ fn assert_json_source_shape(json: &str, main: &str, context: &str) {
} }
} }
fn assert_json_document_scalar_helpers_are_source_authored(json: &str, context: &str) {
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
assert!(
!json.contains(&format!("std.json.{}", helper)),
"{} must keep `{}` source-authored, not compiler-known",
context,
helper
);
}
for private_prefix in [
"__glagol_json_parse_string_document",
"__glagol_json_parse_bool_document",
"__glagol_json_parse_i32_document",
"__glagol_json_parse_u32_document",
"__glagol_json_parse_i64_document",
"__glagol_json_parse_u64_document",
"__glagol_json_parse_f64_document",
"__glagol_json_parse_null_document",
] {
assert!(
!json.contains(private_prefix),
"{} must not introduce private JSON document runtime symbol `{}`",
context,
private_prefix
);
}
}
fn assert_deferred_json_surface_absent(json: &str, main: &str, context: &str) { fn assert_deferred_json_surface_absent(json: &str, main: &str, context: &str) {
for deferred in [ for deferred in [
"parse_object", "parse_object",

View File

@ -0,0 +1,539 @@
use std::{
ffi::OsStr,
fs,
path::{Path, PathBuf},
process::{Command, Output},
sync::atomic::{AtomicUsize, Ordering},
time::{SystemTime, UNIX_EPOCH},
};
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
struct MatrixEntry {
path: &'static str,
expected_tests: usize,
run_tests: bool,
}
const MATRIX: &[MatrixEntry] = &[
MatrixEntry {
path: "examples/projects/basic",
expected_tests: 2,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/enum-imports",
expected_tests: 9,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-cli",
expected_tests: 17,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-env",
expected_tests: 23,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-fs",
expected_tests: 35,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-io",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-json",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-math",
expected_tests: 4,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-net",
expected_tests: 9,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-num",
expected_tests: 5,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-option",
expected_tests: 36,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-process",
expected_tests: 21,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-random",
expected_tests: 2,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-result",
expected_tests: 26,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-string",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-time",
expected_tests: 3,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-vec_bool",
expected_tests: 19,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-vec_f64",
expected_tests: 20,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-vec_i32",
expected_tests: 22,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-vec_i64",
expected_tests: 20,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-import-vec_string",
expected_tests: 19,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-cli",
expected_tests: 17,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-env",
expected_tests: 23,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-fs",
expected_tests: 35,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-io",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-json",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-math",
expected_tests: 7,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-net",
expected_tests: 9,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-num",
expected_tests: 5,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-option",
expected_tests: 36,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-process",
expected_tests: 21,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-random",
expected_tests: 3,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-result",
expected_tests: 26,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-string",
expected_tests: 12,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-time",
expected_tests: 3,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-vec_bool",
expected_tests: 19,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-vec_f64",
expected_tests: 20,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-vec_i32",
expected_tests: 22,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-vec_i64",
expected_tests: 20,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/std-layout-local-vec_string",
expected_tests: 19,
run_tests: true,
},
MatrixEntry {
path: "examples/projects/stdlib-composition",
expected_tests: 3,
run_tests: true,
},
MatrixEntry {
path: "examples/workspaces/exp-5-local",
expected_tests: 2,
run_tests: true,
},
MatrixEntry {
path: "examples/workspaces/std-import-option",
expected_tests: 1,
run_tests: true,
},
];
#[test]
fn user_project_conformance_matrix_checks_lists_and_runs_stable_tests() {
assert_matrix_inventory();
let repo_root = repo_root();
for entry in MATRIX {
let fixture = repo_root.join(entry.path);
assert!(
fixture.join("slovo.toml").is_file(),
"{} must remain an existing project or workspace fixture",
entry.path
);
let check = run_glagol(
[OsStr::new("check"), fixture.as_os_str()],
&temp_root(entry.path, "check"),
);
assert_success_no_stderr(entry.path, "check", &check);
assert_stdout_eq(entry.path, "check", &check, "");
let list = run_glagol(
[
OsStr::new("test"),
OsStr::new("--list"),
fixture.as_os_str(),
],
&temp_root(entry.path, "list"),
);
assert_success_no_stderr(entry.path, "test --list", &list);
assert_stdout_contains(
entry.path,
"test --list",
&list,
&format!(
"{} test(s) selected (total_discovered {}, selected {}, passed 0, failed 0, skipped 0, filter none)",
entry.expected_tests, entry.expected_tests, entry.expected_tests
),
);
if entry.run_tests {
let test = run_glagol(
[OsStr::new("test"), fixture.as_os_str()],
&temp_root(entry.path, "test"),
);
assert_success_no_stderr(entry.path, "test", &test);
assert_stdout_contains(
entry.path,
"test",
&test,
&format!("{} test(s) passed", entry.expected_tests),
);
}
}
}
fn assert_matrix_inventory() {
assert_eq!(MATRIX.len(), 43, "beta25 fixture-root count changed");
assert_eq!(
MATRIX
.iter()
.map(|entry| entry.expected_tests)
.sum::<usize>(),
655,
"beta25 discovered-test count changed"
);
let matrix_paths = MATRIX
.iter()
.map(|entry| entry.path.to_owned())
.collect::<Vec<_>>();
let mut sorted_matrix_paths = matrix_paths.clone();
sorted_matrix_paths.sort();
assert_eq!(
matrix_paths, sorted_matrix_paths,
"beta25 user-project conformance matrix must remain sorted by repository-relative path"
);
let discovered_paths = discover_fixture_paths(&repo_root());
assert_eq!(
discovered_paths, matrix_paths,
"beta25 user-project conformance matrix must cover every top-level example project and workspace fixture"
);
let inventory = MATRIX
.iter()
.map(|entry| {
format!(
"{}|tests={}|run_tests={}",
entry.path, entry.expected_tests, entry.run_tests
)
})
.collect::<Vec<_>>()
.join("\n");
assert_eq!(
inventory,
concat!(
"examples/projects/basic|tests=2|run_tests=true\n",
"examples/projects/enum-imports|tests=9|run_tests=true\n",
"examples/projects/std-import-cli|tests=17|run_tests=true\n",
"examples/projects/std-import-env|tests=23|run_tests=true\n",
"examples/projects/std-import-fs|tests=35|run_tests=true\n",
"examples/projects/std-import-io|tests=12|run_tests=true\n",
"examples/projects/std-import-json|tests=12|run_tests=true\n",
"examples/projects/std-import-math|tests=4|run_tests=true\n",
"examples/projects/std-import-net|tests=9|run_tests=true\n",
"examples/projects/std-import-num|tests=5|run_tests=true\n",
"examples/projects/std-import-option|tests=36|run_tests=true\n",
"examples/projects/std-import-process|tests=21|run_tests=true\n",
"examples/projects/std-import-random|tests=2|run_tests=true\n",
"examples/projects/std-import-result|tests=26|run_tests=true\n",
"examples/projects/std-import-string|tests=12|run_tests=true\n",
"examples/projects/std-import-time|tests=3|run_tests=true\n",
"examples/projects/std-import-vec_bool|tests=19|run_tests=true\n",
"examples/projects/std-import-vec_f64|tests=20|run_tests=true\n",
"examples/projects/std-import-vec_i32|tests=22|run_tests=true\n",
"examples/projects/std-import-vec_i64|tests=20|run_tests=true\n",
"examples/projects/std-import-vec_string|tests=19|run_tests=true\n",
"examples/projects/std-layout-local-cli|tests=17|run_tests=true\n",
"examples/projects/std-layout-local-env|tests=23|run_tests=true\n",
"examples/projects/std-layout-local-fs|tests=35|run_tests=true\n",
"examples/projects/std-layout-local-io|tests=12|run_tests=true\n",
"examples/projects/std-layout-local-json|tests=12|run_tests=true\n",
"examples/projects/std-layout-local-math|tests=7|run_tests=true\n",
"examples/projects/std-layout-local-net|tests=9|run_tests=true\n",
"examples/projects/std-layout-local-num|tests=5|run_tests=true\n",
"examples/projects/std-layout-local-option|tests=36|run_tests=true\n",
"examples/projects/std-layout-local-process|tests=21|run_tests=true\n",
"examples/projects/std-layout-local-random|tests=3|run_tests=true\n",
"examples/projects/std-layout-local-result|tests=26|run_tests=true\n",
"examples/projects/std-layout-local-string|tests=12|run_tests=true\n",
"examples/projects/std-layout-local-time|tests=3|run_tests=true\n",
"examples/projects/std-layout-local-vec_bool|tests=19|run_tests=true\n",
"examples/projects/std-layout-local-vec_f64|tests=20|run_tests=true\n",
"examples/projects/std-layout-local-vec_i32|tests=22|run_tests=true\n",
"examples/projects/std-layout-local-vec_i64|tests=20|run_tests=true\n",
"examples/projects/std-layout-local-vec_string|tests=19|run_tests=true\n",
"examples/projects/stdlib-composition|tests=3|run_tests=true\n",
"examples/workspaces/exp-5-local|tests=2|run_tests=true\n",
"examples/workspaces/std-import-option|tests=1|run_tests=true",
),
"beta25 user-project conformance matrix changed without updating the inventory assertion"
);
}
fn discover_fixture_paths(repo_root: &Path) -> Vec<String> {
let mut paths = Vec::new();
for parent in ["examples/projects", "examples/workspaces"] {
let parent_path = repo_root.join(parent);
for entry in fs::read_dir(&parent_path).unwrap_or_else(|err| {
panic!(
"read fixture inventory `{}`: {}",
parent_path.display(),
err
);
}) {
let entry = entry.unwrap_or_else(|err| {
panic!(
"read fixture entry under `{}`: {}",
parent_path.display(),
err
);
});
let path = entry.path();
if path.join("slovo.toml").is_file() {
paths.push(
path.strip_prefix(repo_root)
.expect("fixture path under repository root")
.to_string_lossy()
.replace('\\', "/"),
);
}
}
}
paths.sort();
paths
}
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("compiler crate has repository parent")
.to_path_buf()
}
fn run_glagol<I, S>(args: I, cwd: &Path) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
fs::create_dir_all(cwd).unwrap_or_else(|err| {
panic!("create command cwd `{}`: {}", cwd.display(), err);
});
let mut command = Command::new(env!("CARGO_BIN_EXE_glagol"));
configure_conformance_env(&mut command);
command
.args(args)
.current_dir(cwd)
.output()
.expect("run glagol")
}
fn configure_conformance_env(command: &mut Command) {
for key in [
"GLAGOL_STD_IMPORT_ENV_ALPHA_UNLIKELY_MISSING",
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_UNLIKELY_MISSING",
] {
command.env_remove(key);
}
for (key, value) in [
(
"GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT",
"glagol-std-import-env-alpha-value",
),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_I32", "42"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_I64", "42000000000"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_U32", "42"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_U64", "4294967296"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_F64", "42.5"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_PRESENT_BOOL", "true"),
("GLAGOL_STD_IMPORT_ENV_ALPHA_INVALID", "not-a-number"),
(
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT",
"glagol-std-layout-local-env-alpha-value",
),
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_I32", "42"),
(
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_I64",
"42000000000",
),
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_U32", "42"),
(
"GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_U64",
"4294967296",
),
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_F64", "42.5"),
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_PRESENT_BOOL", "true"),
("GLAGOL_STD_LAYOUT_LOCAL_ENV_ALPHA_INVALID", "not-a-number"),
] {
command.env(key, value);
}
}
fn temp_root(path: &str, command: &str) -> PathBuf {
let id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed);
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system clock before UNIX_EPOCH")
.as_nanos();
let fixture = path
.chars()
.map(|ch| if ch == '/' || ch == '-' { '_' } else { ch })
.collect::<String>();
std::env::temp_dir().join(format!(
"glagol-user-project-conformance-beta25-{}-{}-{}-{}-{}",
std::process::id(),
nanos,
id,
fixture,
command
))
}
fn assert_success_no_stderr(fixture: &str, command: &str, output: &Output) {
assert!(
output.status.success(),
"{} `{}` failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
fixture,
command,
output.status.code(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert!(
output.stderr.is_empty(),
"{} `{}` wrote stderr:\n{}",
fixture,
command,
String::from_utf8_lossy(&output.stderr)
);
}
fn assert_stdout_eq(fixture: &str, command: &str, output: &Output, expected: &str) {
assert_eq!(
String::from_utf8_lossy(&output.stdout),
expected,
"{} `{}` stdout mismatch",
fixture,
command
);
}
fn assert_stdout_contains(fixture: &str, command: &str, output: &Output, needle: &str) {
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains(needle),
"{} `{}` stdout did not contain `{}`:\n{}",
fixture,
command,
needle,
stdout
);
}

View File

@ -56,6 +56,15 @@ LSP/watch behavior, SARIF/daemon protocols, JSON expansion, runtime helper
names, source-language syntax, package registries, semver solving, or names, source-language syntax, package registries, semver solving, or
performance claims. performance claims.
Released in `1.0.0-beta.25`: user-project conformance matrix evidence. The
scope adds a deterministic matrix over the existing `examples/projects/` and
`examples/workspaces/` inventories so ordinary project and workspace usage has
stable-readiness evidence across all 43 top-level fixture roots and 655
discovered tests. It is tooling/conformance evidence only: no
source-language change, standard-library helper change, runtime behavior
change, package manager or registry behavior, lockfile behavior,
semantic-version solving, stable schema freeze, or performance claim.
Why first: it reduces friction for every later feature and gives users a better Why first: it reduces friction for every later feature and gives users a better
way to exercise the beta. way to exercise the beta.
@ -118,6 +127,19 @@ bytes `9`, `10`, `11`, `12`, `13`, and `32`. Unicode/grapheme semantics,
case folding, regexes, tokenizers, mutable strings, slice/view syntax, new case folding, regexes, tokenizers, mutable strings, slice/view syntax, new
runtime names, and stable stdlib/API promises remain deferred. runtime names, and stable stdlib/API promises remain deferred.
Released in `1.0.0-beta.23`: the public
[`docs/language/STDLIB_TIERS.md`](language/STDLIB_TIERS.md) ledger defines the
current standard-library tier labels `beta-supported`, `experimental`, and
`internal`, and aligns the docs around the generated
[`docs/language/STDLIB_API.md`](language/STDLIB_API.md) signature catalog.
JSON, loopback networking, random/time, and filesystem resource-handle helpers
are documented as experimental domains. Concrete vector modules remain
beta-supported concrete lanes, not a generic collections freeze. The slice is
documentation/catalog tooling clarity only: no syntax, helper, runtime,
manifest-schema, Markdown-schema, ABI/layout, or stable stdlib/API behavior
changes. It updates generated catalog output and the release gate so tier
metadata is visible and checked.
Why third: stdlib growth is already broad enough that naming and stability tiers Why third: stdlib growth is already broad enough that naming and stability tiers
matter more than adding another isolated helper group. matter more than adding another isolated helper group.
@ -169,6 +191,14 @@ local-package rules. Lockfiles, remote registries, semver solving, publishing,
optional/dev/target dependencies, and stable package ABI/layout remain out of optional/dev/target dependencies, and stable package ABI/layout remain out of
scope. scope.
Released in `1.0.0-beta.24`: package manifest identity and dependency
diagnostics are tightened without changing the package model. Duplicate
package manifest keys, invalid dependency keys, and duplicate dependency keys
are explicit diagnostics. The slice adds no remote registry, lockfile,
semantic-version solving, package publishing, optional/dev/target
dependencies, stable package ABI/layout, source-language change, runtime
change, or standard-library change.
Why fifth: stable package rules are a prerequisite for a usable public language, Why fifth: stable package rules are a prerequisite for a usable public language,
but remote publishing can wait. but remote publishing can wait.
@ -231,6 +261,15 @@ object/array parsing, tokenizer objects, Unicode escape decoding or
normalization, embedded NUL policy, streaming, schema validation, and stable normalization, embedded NUL policy, streaming, schema validation, and stable
ABI/API guarantees remain deferred. ABI/API guarantees remain deferred.
Released in `1.0.0-beta.21`: `lib/std/json.slo` adds source-authored scalar
document parse facades for string, bool, `i32`, `u32`, `i64`, `u64`, `f64`,
and exact `null`. Each helper trims ASCII whitespace around the whole document
with `std.string.trim_ascii`, then delegates to the already released exact
value-token parser. This intentionally remains scalar document parsing only:
object/array parsing, recursive JSON values, parser/tokenizer objects,
maps/sets, streaming, new compiler-known runtime names, broader Unicode escape
policy, embedded NUL policy, and stable ABI/API guarantees remain deferred.
Why seventh: networking and CLI tools need data interchange, but a complete JSON Why seventh: networking and CLI tools need data interchange, but a complete JSON
library depends on collection work. library depends on collection work.
@ -532,9 +571,13 @@ foundation before richer string or data-interchange APIs are credible.
Slovo should not become stable until all of these are true: Slovo should not become stable until all of these are true:
- migration and deprecation policy is documented - migration and deprecation policy is documented
- `lib/std` has explicit stable and experimental tiers - `lib/std` has explicit beta-supported, experimental, and internal tiers plus
a later stable-tier/deprecation policy before `1.0.0`
- package/workspace behavior is deterministic - package/workspace behavior is deterministic
- conformance tests cover user-shaped projects - package manifest identity and dependency-key failures have explicit
diagnostics
- conformance tests and matrix evidence cover user-shaped projects and
workspaces
- release gates are reproducible on a clean checkout - release gates are reproducible on a clean checkout
- diagnostics and formatter output are stable for promoted features - diagnostics and formatter output are stable for promoted features
- performance publications are repeatable and labeled as local-machine evidence - performance publications are repeatable and labeled as local-machine evidence

View File

@ -12,6 +12,165 @@ integration/readiness release, not the first real beta.
No active unreleased compiler scope is documented here yet. No active unreleased compiler scope is documented here yet.
## 1.0.0-beta.25
Release label: `1.0.0-beta.25`
Release date: 2026-05-23
Release state: user-project conformance matrix evidence
### Summary
The beta.25 compiler/tooling slice adds deterministic stable-readiness
evidence for ordinary project and workspace usage without changing the
language, runtime, stdlib, or package manager model:
- Add a user-project conformance matrix over all 43 top-level fixture roots
under existing `examples/projects/` and `examples/workspaces/`, covering
655 discovered tests.
- Keep matrix inputs repository-local and deterministically sorted by
repository-relative path.
- Record ordinary `check`, `test --list`, and stable `test` behavior for each
existing example in the matrix.
- Treat matrix output as beta tooling evidence rather than a stable public
schema.
### Explicit Deferrals
This release does not implement source-language change, standard-library
helper change, runtime behavior change, compiler-known `std.*` runtime names,
package manager behavior, remote registries, lockfiles, semantic-version
solving, package publishing, optional/dev/target dependencies, stable
artifact-manifest schema guarantees, stable Markdown schemas, stable
conformance-matrix schema guarantees, LSP/watch/SARIF/daemon protocols, stable
ABI/layout, or performance claims.
## 1.0.0-beta.24
Release label: `1.0.0-beta.24`
Release date: 2026-05-23
Release state: package manifest identity and local dependency diagnostic
hardening
### Summary
The beta.24 compiler/tooling slice tightens local package manifest diagnostics
without changing the language, runtime, stdlib, or package graph model:
- Bump the `glagol` compiler package version to `1.0.0-beta.24`.
- Diagnose duplicate package manifest keys explicitly.
- Diagnose invalid dependency keys explicitly.
- Diagnose duplicate dependency keys explicitly.
- Keep dependency records local-path-only and require dependency keys to match
target package names.
### Explicit Deferrals
This release does not implement remote registries, lockfiles,
semantic-version solving, package publishing, optional/dev/target
dependencies, feature flags, build scripts, package archives, stable package
ABI/layout, source-language syntax, runtime C capabilities, standard-library
helpers, compiler-known `std.*` runtime names, stable artifact-manifest schema
guarantees, stable Markdown schemas, LSP/watch/SARIF/daemon protocols, or
performance claims.
## 1.0.0-beta.23
Release label: `1.0.0-beta.23`
Release date: 2026-05-23
Release state: standard-library stability tier ledger and catalog alignment
### Summary
The beta.23 compiler/tooling slice aligns generated standard-library API
catalog output with the public tier ledger:
- Bump the `glagol` compiler package version to `1.0.0-beta.23`.
- Render per-module and per-helper `beta-supported` or `experimental` tier
metadata in `docs/language/STDLIB_API.md`.
- Add `scripts/check-stdlib-api-tiers.js` and wire it into the release gate.
- Mark JSON, loopback networking, random/time, and filesystem resource-handle
helpers as experimental in generated catalog output.
- Keep concrete vector modules beta-supported concrete lanes with an explicit
no-generic-collection-freeze note.
### Explicit Deferrals
This release does not implement source-language syntax, standard-library
helpers, compiler-known `std.*` runtime names, runtime C capabilities, package
or workspace behavior, stable artifact-manifest schema guarantees, stable
Markdown schemas, LSP/watch/SARIF/daemon protocols, performance claims,
stable ABI/layout, or a stable standard-library compatibility contract.
## 1.0.0-beta.22
Release label: `1.0.0-beta.22`
Release date: 2026-05-23
Release state: run manifest and execution report hardening
### Summary
The beta.22 compiler/tooling slice hardens `glagol run --manifest` evidence
without changing the Slovo language or standard-library surface:
- Bump the `glagol` compiler package version to `1.0.0-beta.22`.
- Add an additive run-report block to run-mode artifact manifests.
- Record executed-program exit status, captured stdout, captured stderr, and
forwarded program arguments.
- Keep the run report as beta tooling metadata under the existing
`slovo.artifact-manifest` version `1` contract rather than a stable schema
freeze.
- Keep non-run modes outside this run-report requirement.
### Explicit Deferrals
This release does not implement source-language syntax, standard-library
helpers, compiler-known `std.*` runtime names, runtime C capabilities, package
or workspace behavior, stable artifact-manifest schema guarantees, stable
Markdown schemas, LSP/watch/SARIF/daemon protocols, performance claims,
stable ABI/layout, or a stable standard-library compatibility contract.
## 1.0.0-beta.21
Release label: `1.0.0-beta.21`
Release date: 2026-05-23
Release state: JSON document scalar parsing foundation
### Summary
The beta.21 compiler/tooling slice adds focused coverage for source-authored
`std.json` document-scalar helpers without adding compiler-known runtime names:
- Bump the `glagol` compiler package version to `1.0.0-beta.21`.
- Add focused `standard_json_document_scalar_parsing_beta21` coverage for
explicit `std.json` imports of `parse_string_document_result`,
`parse_bool_document_result`, `parse_i32_document_result`,
`parse_u32_document_result`, `parse_i64_document_result`,
`parse_u64_document_result`, `parse_f64_document_result`, and
`parse_null_document_result`.
- Gate the helpers as source-authored public facades over existing JSON token
parsers and source-level document trimming/composition.
- Require direct `std.json.parse_*_document_result` runtime calls and private
`__glagol_json_*document*` runtime symbols to remain unsupported.
- Add the focused beta21 test to `scripts/release-gate.sh`.
### Explicit Deferrals
This release does not implement object parsing, array parsing, recursive JSON
values, tokenizers, Unicode escape decoding, streaming, schema validation,
stable parser APIs, new compiler-known `std.*` runtime names, runtime C
changes, source-language syntax, stable ABI/layout, or a stable
standard-library compatibility contract.
## 1.0.0-beta.20 ## 1.0.0-beta.20
Release label: `1.0.0-beta.20` Release label: `1.0.0-beta.20`

View File

@ -9,10 +9,9 @@ Compiler rule: make the tree visible. The pipeline should remain:
.slo source -> tokens -> S-expression tree -> AST -> typed AST -> LLVM IR text -> hosted Clang/runtime executable step .slo source -> tokens -> S-expression tree -> AST -> typed AST -> LLVM IR text -> hosted Clang/runtime executable step
``` ```
Long-horizon compiler planning lives in Long-horizon compiler planning lives in `.llm/ROADMAP_TO_STABLE.md`. It
`.llm/GENERAL_PURPOSE_LANGUAGE_ROADMAP.md`. It mirrors Slovo's experimental mirrors Slovo's release train beyond the first real general-purpose beta
release train from the historical `v2.0.0-beta.1` tag toward and beyond the toolchain.
first real general-purpose beta toolchain.
Release maturity policy lives in `.llm/RELEASE_MATURITY_POLICY.md`. Historical Release maturity policy lives in `.llm/RELEASE_MATURITY_POLICY.md`. Historical
`exp-*` releases remain experimental maturity. `1.0.0-beta` is the first real `exp-*` releases remain experimental maturity. `1.0.0-beta` is the first real
@ -22,8 +21,8 @@ general-purpose beta release.
A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests. A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests.
Current stage: `1.0.0-beta.20`, released on 2026-05-23 as a string search Current stage: `1.0.0-beta.25`, released on 2026-05-23 as user-project
and ASCII trim foundation. It keeps the conformance matrix evidence. It keeps the
`1.0.0-beta` language/compiler support baseline and includes the `1.0.0-beta` language/compiler support baseline and includes the
`1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2` runtime/resource `1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2` runtime/resource
foundation release, the `1.0.0-beta.3` standard-library stabilization release, foundation release, the `1.0.0-beta.3` standard-library stabilization release,
@ -105,10 +104,56 @@ beta16-or-earlier string primitives and existing option/result shapes, and
verifies that direct compiler-known runtime calls for the new helper names verifies that direct compiler-known runtime calls for the new helper names
remain unsupported. remain unsupported.
The beta.21 compiler/tooling slice bumps the package version and gates
source-authored `std.json` document scalar facades for
`parse_string_document_result`, `parse_bool_document_result`,
`parse_i32_document_result`, `parse_u32_document_result`,
`parse_i64_document_result`, `parse_u64_document_result`,
`parse_f64_document_result`, and `parse_null_document_result` through explicit
`std.json` imports. It keeps those helpers source-authored over the existing
JSON token parser family and existing source-level composition, and verifies
that direct compiler-known runtime calls and private `__glagol_json_*document*`
symbols for the new helper names remain unsupported.
The beta.22 compiler/tooling slice bumps the package version and hardens
`glagol run --manifest` evidence with an additive run-report block in
run-mode artifact manifests. The block records executed-program exit status,
captured stdout, captured stderr, and forwarded program arguments. It is beta
CLI evidence metadata under the existing `slovo.artifact-manifest` version
`1` contract, not a stable schema freeze, and it adds no source-language,
runtime, package, or standard-library surface.
The beta.23 compiler/tooling slice bumps the package version and updates
generated `docs/language/STDLIB_API.md` output with per-module and per-helper
tier metadata. It adds a release-gate checker for the tier catalog, marks JSON,
loopback networking, random/time, and filesystem resource-handle helpers as
experimental, and keeps concrete vector modules beta-supported concrete lanes
without claiming generic collection stability. It adds no source-language,
runtime, package, or standard-library helper surface.
The beta.24 compiler/tooling slice bumps the package version and tightens
local package manifest diagnostics. Duplicate package manifest keys, invalid
dependency keys, and duplicate dependency keys are explicit diagnostics. It
keeps the existing closed local workspace model and adds no remote registry,
lockfile, semantic-version solving, package publishing, optional/dev/target
dependencies, stable package ABI/layout, source-language behavior, runtime
behavior, or standard-library behavior.
The beta.25 compiler/tooling slice adds deterministic stable-readiness
evidence for ordinary project and workspace usage over the existing
`examples/projects/` and `examples/workspaces/` inventories. The conformance
matrix is repository-local, sorted by stable path, and records ordinary
`check`, `test --list`, and stable `test` behavior for all 43 top-level
fixture roots and 655 discovered tests. It adds no source-language behavior,
runtime behavior, standard-library helper behavior, package manager or
registry behavior, lockfile behavior, semantic-version solving, stable schema
freeze, or performance claim.
Generic vectors, generic collections, maps, sets, generic stdlib dispatch, Generic vectors, generic collections, maps, sets, generic stdlib dispatch,
runtime collection changes, collection unification, stable human diagnostic runtime collection changes, collection unification, stable human diagnostic
text, stable artifact-manifest or Markdown schema freezes, LSP/watch text, stable artifact-manifest, Markdown, or conformance-matrix schema
protocols, SARIF/daemon protocols, re-exports/globs/hierarchical modules, freezes, LSP/watch protocols, SARIF/daemon protocols,
re-exports/globs/hierarchical modules,
registry semantics, semver solving, mutable vectors, stable slice/view APIs, registry semantics, semver solving, mutable vectors, stable slice/view APIs,
tokenizers, broader JSON parsing, runtime helper names, source-language tokenizers, broader JSON parsing, runtime helper names, source-language
syntax, parallel test execution, retries, tags/groups, coverage/event streams, syntax, parallel test execution, retries, tags/groups, coverage/event streams,
@ -688,6 +733,8 @@ Alpha is the latest compiler semantic/runtime-operation support slice.
- [x] Diagnose missing packages, duplicate package names, dependency cycles, - [x] Diagnose missing packages, duplicate package names, dependency cycles,
path escapes, invalid package names, invalid package versions, private path escapes, invalid package names, invalid package versions, private
visibility, and dependency key mismatches. visibility, and dependency key mismatches.
- [x] Diagnose duplicate package manifest keys, invalid dependency keys, and
duplicate dependency keys explicitly.
- [x] Keep registries, lockfiles, semver solving, aliases/globs/re-exports, - [x] Keep registries, lockfiles, semver solving, aliases/globs/re-exports,
generated code, build scripts, publishing, optional/dev/target generated code, build scripts, publishing, optional/dev/target
dependencies, stable package ABI, and remote dependencies deferred. dependencies, stable package ABI, and remote dependencies deferred.

View File

@ -237,6 +237,47 @@ Future releases may add codes or split broad codes when the release scope
requires more precise tooling behavior. Such changes must be documented using requires more precise tooling behavior. Such changes must be documented using
the compatibility classes above. the compatibility classes above.
## Project And Workspace Codes
Project, package, and workspace diagnostics are covered by integration tests
because they often require multiple files, manifests, or generated temporary
directories rather than a single `.slo` golden fixture. These codes still use
the same `slovo.diagnostic` version `1` schema and PascalCase code policy.
Current package/workspace loader and graph diagnostics include:
- `DependencyNameMismatch`
- `DependencyPathEscape`
- `DuplicatePackageDependencyName`
- `DuplicatePackageName`
- `DuplicateWorkspaceMember`
- `InvalidPackageDependencyName`
- `InvalidPackageName`
- `InvalidPackageVersion`
- `MissingPackageDependency`
- `MissingPackageModule`
- `PackageDependencyCycle`
- `PackageImportNotDependency`
- `PackageManifestInvalid`
- `PackageSourceReadFailed`
- `PackageSourceRootEscape`
- `PackageSourceRootMissing`
- `ProjectEntryMainInvalidSignature`
- `ProjectEntryMainMissing`
- `ProjectManifestInvalid`
- `ProjectManifestReadFailed`
- `ProjectSourceReadFailed`
- `ProjectSourceRootMissing`
- `UnsupportedDependency`
- `WorkspaceBuildAmbiguousEntryPackage`
- `WorkspaceDefaultPackageEntryMissing`
- `WorkspaceDefaultPackageMissing`
- `WorkspaceEntryMainInvalidSignature`
- `WorkspaceEntryMainMissing`
- `WorkspaceManifestInvalid`
- `WorkspaceMemberManifestMissing`
- `WorkspaceMemberPathEscape`
## Explicit Deferrals ## Explicit Deferrals
`1.0.0-beta.13` does not define: `1.0.0-beta.13` does not define:

View File

@ -56,6 +56,10 @@ used for solving dependency constraints.
dependency paths must stay inside the workspace/package boundary after dependency paths must stay inside the workspace/package boundary after
normalization and canonical path checks. normalization and canonical path checks.
Duplicate keys in package manifests are `PackageManifestInvalid` diagnostics.
The manifest loader does not silently choose one spelling for repeated package
identity or dependency entries.
Dependencies are local path records only. The dependency key must match the Dependencies are local path records only. The dependency key must match the
target package name: target package name:
@ -63,6 +67,11 @@ target package name:
mathlib = { path = "../mathlib" } mathlib = { path = "../mathlib" }
``` ```
Dependency keys use the same package-name shape as package identities. Invalid
dependency keys are `InvalidPackageDependencyName` diagnostics, and duplicate
dependency keys are `DuplicatePackageDependencyName` diagnostics before the
local dependency graph is accepted.
## Imports ## Imports
Within a workspace, a package imports a dependency module through the package Within a workspace, a package imports a dependency module through the package
@ -106,9 +115,12 @@ The package/workspace gate covers these user-facing error families:
- missing member manifests - missing member manifests
- duplicate normalized workspace members - duplicate normalized workspace members
- invalid member or dependency paths - invalid member or dependency paths
- duplicate package manifest keys
- invalid package names and versions - invalid package names and versions
- duplicate package names - duplicate package names
- missing local path dependencies - missing local path dependencies
- invalid dependency keys
- duplicate dependency keys
- dependency key/name mismatches - dependency key/name mismatches
- package dependency cycles - package dependency cycles
- private cross-package imports - private cross-package imports

View File

@ -8,7 +8,7 @@ Historical `exp-*` releases listed here are experimental maturity milestones.
The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an
experimental integration/readiness release, not as a beta maturity claim. experimental integration/readiness release, not as a beta maturity claim.
The current release is `1.0.0-beta.20`, published on 2026-05-23. It keeps the The current release is `1.0.0-beta.25`, published on 2026-05-23. It keeps the
`1.0.0-beta` language surface, includes the first post-beta tooling/install `1.0.0-beta` language surface, includes the first post-beta tooling/install
hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource
foundation bundle from `1.0.0-beta.2` plus the first standard-library foundation bundle from `1.0.0-beta.2` plus the first standard-library
@ -30,12 +30,152 @@ boundary foundation from `1.0.0-beta.16`, and the JSON primitive scalar
parsing foundation from `1.0.0-beta.17`, plus the JSON string token parsing parsing foundation from `1.0.0-beta.17`, plus the JSON string token parsing
foundation from `1.0.0-beta.18`, the test discovery and user-project foundation from `1.0.0-beta.18`, the test discovery and user-project
conformance foundation from `1.0.0-beta.19`, and the string search and ASCII conformance foundation from `1.0.0-beta.19`, and the string search and ASCII
trim foundation from `1.0.0-beta.20`. trim foundation from `1.0.0-beta.20`, plus the JSON document scalar parsing
foundation from `1.0.0-beta.21`, and the run manifest execution-report
hardening slice from `1.0.0-beta.22`, plus the standard-library stability tier
ledger and catalog alignment slice from `1.0.0-beta.23`, the package manifest
identity and local dependency diagnostic hardening slice from
`1.0.0-beta.24`, and the user-project conformance matrix evidence slice from
`1.0.0-beta.25`.
## Unreleased ## Unreleased
No active unreleased language scope is documented here yet. No active unreleased language scope is documented here yet.
## 1.0.0-beta.25
Release label: `1.0.0-beta.25`
Release name: User Project Conformance Matrix
Release date: 2026-05-23
Status: released beta tooling/conformance evidence on the `1.0.0-beta`
language baseline.
This release adds deterministic stable-readiness evidence for ordinary
project and workspace usage over the existing `examples/projects/` and
`examples/workspaces/` inventories. The conformance matrix records
repository-local example coverage for all 43 top-level fixture roots and 655
discovered tests through ordinary Glagol project/workspace entry points.
This release adds no source-language change, standard-library helper change,
runtime behavior change, compiler-known runtime names, package manager or
registry behavior, lockfile behavior, semantic-version solving, stable
artifact-manifest schema, stable Markdown schema, stable conformance-matrix
schema, stable ABI/layout, or performance claim.
## 1.0.0-beta.24
Release label: `1.0.0-beta.24`
Release name: Package Manifest Identity And Dependency Discipline
Release date: 2026-05-23
Status: released beta package/workspace diagnostic hardening on the
`1.0.0-beta` language baseline.
This release tightens diagnostics for local package manifests only. Duplicate
package manifest keys, invalid dependency keys, and duplicate dependency keys
are explicit beta package/workspace diagnostics.
The package model remains the existing closed local workspace model:
dependencies are local path records, dependency keys must match target package
names, and package-qualified imports still resolve through the local workspace
graph.
This release adds no remote registry, lockfile, semantic-version solving,
package publishing, optional/dev/target dependencies, stable package
ABI/layout, source-language syntax or semantics, runtime behavior,
standard-library helpers, compiler-known runtime names, stable manifest schema,
stable Markdown schema, or performance claim.
## 1.0.0-beta.23
Release label: `1.0.0-beta.23`
Release name: Standard Library Stability Tier Ledger And Catalog Alignment
Release date: 2026-05-23
Status: released beta documentation/catalog clarity on the `1.0.0-beta`
language baseline.
This release adds [`STDLIB_TIERS.md`](STDLIB_TIERS.md) as the public maturity
ledger for the generated [`STDLIB_API.md`](STDLIB_API.md) standard-library API
catalog. The ledger defines the tier labels `beta-supported`, `experimental`,
and `internal`.
The beta23 ledger classifies JSON, loopback networking, random/time, and
filesystem resource-handle helpers as experimental domains. Concrete vector
modules remain beta-supported concrete lanes; this is not a generic
collections freeze and does not imply executable generics, maps, sets,
iterators, mutable vectors, slice/view APIs, runtime collection changes, or
stable ABI/layout.
This release adds no source-language syntax, standard-library helpers,
compiler-known runtime names, runtime behavior, package behavior, stable
artifact-manifest schema, stable Markdown schema, stable ABI/layout, or stable
stdlib/API compatibility freeze. It does update generated catalog output and
the release gate so tier metadata is visible and checked.
## 1.0.0-beta.22
Release label: `1.0.0-beta.22`
Release name: Run Manifest And Execution Report Hardening
Release date: 2026-05-23
Status: released beta tooling/CLI evidence hardening on the `1.0.0-beta`
language baseline.
This release does not change the Slovo language or standard-library surface.
It documents the matching Glagol tooling update: `glagol run --manifest`
artifact manifests now include an additive run-report block for the executed
program's exit status, captured stdout, captured stderr, and forwarded program
arguments.
The run-report block is beta tooling metadata under the existing
`slovo.artifact-manifest` version `1` contract. It is not a stable manifest
schema freeze and does not add source-language syntax, stdlib helpers,
compiler-known runtime names, runtime C capabilities, package/import behavior,
stable ABI/layout guarantees, or stable stdlib/API compatibility.
## 1.0.0-beta.21
Release label: `1.0.0-beta.21`
Release name: JSON Document Scalar Parsing Foundation
Release date: 2026-05-23
Status: released beta standard-library JSON document scalar parsing foundation
on the `1.0.0-beta` language baseline.
The source facade adds these source-authored `std.json` helpers:
- `parse_string_document_result ((document string)) -> (result string i32)`
- `parse_bool_document_result ((document string)) -> (result bool i32)`
- `parse_i32_document_result ((document string)) -> (result i32 i32)`
- `parse_u32_document_result ((document string)) -> (result u32 i32)`
- `parse_i64_document_result ((document string)) -> (result i64 i32)`
- `parse_u64_document_result ((document string)) -> (result u64 i32)`
- `parse_f64_document_result ((document string)) -> (result f64 i32)`
- `parse_null_document_result ((document string)) -> (result bool i32)`
Each helper trims ASCII whitespace around the whole document with
`std.string.trim_ascii`, then delegates to the already released exact
value-token parser for that scalar family. Leading and trailing ASCII
whitespace around one scalar document is accepted; trailing non-whitespace
still returns `err 1` through the underlying exact parser.
This release adds no compiler-known runtime names, parser objects, object/array
parsing, recursive `JsonValue`, maps/sets, streaming, Unicode escape decoding
beyond the existing string-token behavior, embedded NUL policy, stable
ABI/layout guarantees, or stable stdlib/API freeze.
## 1.0.0-beta.20 ## 1.0.0-beta.20
Release label: `1.0.0-beta.20` Release label: `1.0.0-beta.20`

View File

@ -5,15 +5,13 @@ compiler implementation inside the same monorepo.
Guiding rule: the manifest wins. A feature is not accepted until it has surface syntax, typed-core meaning, lowering behavior, formatter behavior, diagnostics, and tests. Guiding rule: the manifest wins. A feature is not accepted until it has surface syntax, typed-core meaning, lowering behavior, formatter behavior, diagnostics, and tests.
Long-horizon planning lives in Long-horizon planning lives in `.llm/ROADMAP_TO_STABLE.md`. It defines the
`.llm/GENERAL_PURPOSE_LANGUAGE_ROADMAP.md`. It defines the experimental release train beyond the first real general-purpose beta Slovo contract.
release train from the historical `v2.0.0-beta.1` tag toward and beyond the
first real general-purpose beta Slovo contract.
Current stage: `1.0.0-beta.20`, released on 2026-05-23 as a post-beta string Current stage: `1.0.0-beta.25`, released on 2026-05-23 as post-beta
search and ASCII trim foundation. It keeps the user-project conformance matrix evidence. It keeps the `1.0.0-beta` language
`1.0.0-beta` language contract and includes the `1.0.0-beta.1` tooling
contract and includes the `1.0.0-beta.1` tooling hardening release, the hardening release, the
`1.0.0-beta.2` runtime/resource foundation release, the `1.0.0-beta.3` `1.0.0-beta.2` runtime/resource foundation release, the `1.0.0-beta.3`
standard-library stabilization release, the `1.0.0-beta.4` standard-library stabilization release, the `1.0.0-beta.4`
language-usability diagnostics release, the `1.0.0-beta.5` package/workspace language-usability diagnostics release, the `1.0.0-beta.5` package/workspace
@ -28,7 +26,12 @@ collection boundary hardening and collection ledger, and `1.0.0-beta.16`
string scanning and token boundary helpers, `1.0.0-beta.17` JSON primitive string scanning and token boundary helpers, `1.0.0-beta.17` JSON primitive
scalar token parsing, `1.0.0-beta.18` JSON string token parsing, scalar token parsing, `1.0.0-beta.18` JSON string token parsing,
`1.0.0-beta.19` test discovery and user-project conformance tooling, and `1.0.0-beta.19` test discovery and user-project conformance tooling, and
`1.0.0-beta.20` string search and ASCII trim helpers. `1.0.0-beta.20` string search and ASCII trim helpers, plus
`1.0.0-beta.21` JSON document scalar parsing helpers, and
`1.0.0-beta.22` run manifest execution-report hardening, plus
`1.0.0-beta.23` standard-library stability tier documentation,
`1.0.0-beta.24` package manifest/dependency diagnostic hardening, and
`1.0.0-beta.25` user-project conformance matrix evidence.
`1.0.0-beta.16` adds `std.string` source facades and examples for `1.0.0-beta.16` adds `std.string` source facades and examples for
`byte_at_result`, `slice_result`, `starts_with`, and `ends_with`. These helpers `byte_at_result`, `slice_result`, `starts_with`, and `ends_with`. These helpers
@ -40,11 +43,12 @@ semantics; full JSON parsing; object/array parsing; tokenizer objects;
language slice/view syntax; mutable strings; stable ABI/layout; performance language slice/view syntax; mutable strings; stable ABI/layout; performance
claims; or a stable stdlib/API freeze. claims; or a stable stdlib/API freeze.
The current released stage adds primitive scalar JSON token parse facades for The current released JSON stage adds primitive scalar JSON token parse facades
booleans, concrete numeric primitives, exact `null`, and one narrow ASCII JSON for booleans, concrete numeric primitives, exact `null`, one narrow ASCII JSON
string-token helper. Full JSON document parsing, object/array parsing, string-token helper, and scalar JSON document helpers that accept leading and
recursive JSON values, tokenizers, whitespace-tolerant document parsing, schema trailing ASCII whitespace. Object/array parsing, recursive JSON values,
validation, streaming, Unicode escape decoding/normalization, embedded NUL tokenizers, schema validation, streaming, Unicode escape
decoding/normalization beyond the existing string-token helper, embedded NUL
policy, stable ABI/layout, and stable stdlib/API freeze remain deferred. policy, stable ABI/layout, and stable stdlib/API freeze remain deferred.
Full JSON parsing, object/array parsing, recursive JSON values, Full JSON parsing, object/array parsing, recursive JSON values,
@ -85,6 +89,55 @@ Unicode/grapheme semantics, case folding, regexes, tokenizer APIs, language
slice/view syntax, mutable strings, stable ABI/layout guarantees, or stable slice/view syntax, mutable strings, stable ABI/layout guarantees, or stable
stdlib/API freeze. stdlib/API freeze.
`1.0.0-beta.21` adds source-authored
`std.json.parse_*_document_result` helpers for string, bool, `i32`, `u32`,
`i64`, `u64`, `f64`, and exact `null` documents by trimming ASCII whitespace
around the whole document with `std.string.trim_ascii`, then delegating to the
existing exact value-token parser for each scalar family. The scope keeps
object/array parsing, recursive JSON values, tokenizer objects, maps/sets,
streaming, new compiler-known runtime names, Unicode escape decoding beyond
the existing string-token helper, embedded NUL policy, stable ABI/layout, and
stable stdlib/API freeze deferred.
`1.0.0-beta.22` is tooling/CLI evidence hardening, not a language feature. It
documents the matching Glagol `run --manifest` update: run-mode artifact
manifests gain an additive run-report block for executed-program exit status,
captured stdout, captured stderr, and forwarded program arguments. The block is
beta tooling metadata under the existing `slovo.artifact-manifest` version `1`
contract. It is not a stable schema freeze and adds no language syntax,
standard-library helpers, runtime capabilities, package/import behavior,
stable ABI/layout, or stable stdlib/API guarantees.
`1.0.0-beta.23` is documentation/catalog clarity, not a language or stdlib
behavior feature. It adds [`STDLIB_TIERS.md`](STDLIB_TIERS.md) as the public
stability-tier ledger beside the generated [`STDLIB_API.md`](STDLIB_API.md)
signature catalog. The ledger defines `beta-supported`, `experimental`, and
`internal`; marks JSON, loopback networking, random/time, and filesystem
resource-handle helpers as experimental domains; and keeps concrete vector
modules as beta-supported concrete lanes rather than a generic collections
freeze. It adds no source-language syntax, helpers, runtime names, runtime
behavior, stable manifest schema, stable Markdown schema, stable ABI/layout,
or stable stdlib/API freeze. It does update generated catalog output and the
release gate so tier metadata is visible and checked.
`1.0.0-beta.24` is package/workspace diagnostic hardening, not a language,
runtime, package-manager, or stdlib behavior feature. It makes duplicate
package manifest keys, invalid dependency keys, and duplicate dependency keys
explicit diagnostics while keeping the existing closed local workspace model.
It adds no remote registry, lockfile, semantic-version solving, package
publishing, optional/dev/target dependencies, stable package ABI/layout,
source-language change, runtime change, or stdlib change.
`1.0.0-beta.25` is tooling/conformance evidence, not a language, stdlib,
runtime, package-manager, schema-freeze, or performance feature. It adds a
deterministic user-project conformance matrix over the existing
`examples/projects/` and `examples/workspaces/` inventories so ordinary
project and workspace usage has stable-readiness evidence. The release covers
all 43 top-level fixture roots and 655 discovered tests. It adds no
source-language change, standard-library helper change, runtime behavior
change, package manager or registry behavior, lockfile behavior,
semantic-version solving, stable schema freeze, or performance claim.
The final experimental precursor scope is `exp-125`, defined in The final experimental precursor scope is `exp-125`, defined in
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its `.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
unsigned direct-value flow, parse/format runtime lanes, and matching staged unsigned direct-value flow, parse/format runtime lanes, and matching staged

View File

@ -11,10 +11,12 @@ boundary hardening and collection ledger, `1.0.0-beta.16` string scanning
and token boundary foundation, `1.0.0-beta.17` JSON primitive scalar parsing and token boundary foundation, `1.0.0-beta.17` JSON primitive scalar parsing
foundation, `1.0.0-beta.18` JSON string token parsing foundation, foundation, `1.0.0-beta.18` JSON string token parsing foundation,
`1.0.0-beta.19` test discovery and user-project conformance tooling, and `1.0.0-beta.19` test discovery and user-project conformance tooling, and
`1.0.0-beta.20` string search and ASCII trim foundation. The `1.0.0-beta.20` string search and ASCII trim foundation, and
language contract `1.0.0-beta.21` JSON document scalar parsing foundation, and
integrates `1.0.0-beta.22` run manifest and execution-report hardening, and
promoted language slices through `exp-125` and the historical publication `1.0.0-beta.23` standard-library stability tier ledger and catalog alignment.
The language contract integrates promoted language slices through `exp-125`
and the historical publication
baseline through `exp-123`. `1.0.0-beta` is the first real general-purpose baseline through `exp-123`. `1.0.0-beta` is the first real general-purpose
beta release. `exp-125` completed the unsigned numeric and stdlib breadth beta release. `exp-125` completed the unsigned numeric and stdlib breadth
precursor scope, `exp-124` is the last tagged experimental alpha language precursor scope, `exp-124` is the last tagged experimental alpha language
@ -205,20 +207,20 @@ Current v1 release surface and explicit experimental targets:
`std.json.parse_i64_value_result`, `std.json.parse_u64_value_result`, `std.json.parse_i64_value_result`, `std.json.parse_u64_value_result`,
`std.json.parse_f64_value_result`, and `std.json.parse_null_value_result` `std.json.parse_f64_value_result`, and `std.json.parse_null_value_result`
consume one already-isolated primitive scalar token and return concrete consume one already-isolated primitive scalar token and return concrete
`(result ... i32)` values; full JSON document parsing, string/object/array `(result ... i32)` values; JSON document parsing beyond the beta21 scalar
parsing, tokenizers, recursive `JsonValue`, Unicode escape handling, stable helpers, string/object/array parsing, tokenizers, recursive `JsonValue`,
ABI/layout, performance claims, and stable stdlib/API freeze remain out of Unicode escape handling, stable ABI/layout, performance claims, and stable
scope stdlib/API freeze remain out of scope
- `1.0.0-beta.18` JSON string token parsing target: - `1.0.0-beta.18` JSON string token parsing target:
`std.json.parse_string_value_result : (string) -> (result string i32)` `std.json.parse_string_value_result : (string) -> (result string i32)`
consumes one already-isolated ASCII JSON string token with exact quotes and consumes one already-isolated ASCII JSON string token with exact quotes and
no leading/trailing whitespace, decodes simple JSON escapes, returns no leading/trailing whitespace, decodes simple JSON escapes, returns
`err 1` for ordinary parse failure, and rejects raw control bytes, bad `err 1` for ordinary parse failure, and rejects raw control bytes, bad
escapes, unterminated/trailing bytes, raw non-ASCII, and all `\uXXXX` escapes escapes, unterminated/trailing bytes, raw non-ASCII, and all `\uXXXX` escapes
for this slice; full JSON document parsing, object/array parsing, tokenizer for this slice; JSON document parsing beyond the beta21 scalar helpers,
APIs, recursive `JsonValue`, Unicode escape decoding/normalization, embedded object/array parsing, tokenizer APIs, recursive `JsonValue`, Unicode escape
NUL policy, stable ABI/layout, performance claims, and stable stdlib/API decoding/normalization, embedded NUL policy, stable ABI/layout, performance
freeze remain out of scope claims, and stable stdlib/API freeze remain out of scope
- `1.0.0-beta.19` test discovery and user-project conformance target: - `1.0.0-beta.19` test discovery and user-project conformance target:
`glagol test --list <file|project|workspace>` and legacy `glagol test --list <file|project|workspace>` and legacy
`glagol --run-tests --list <file>` list checked/discovered tests without `glagol --run-tests --list <file>` list checked/discovered tests without
@ -240,6 +242,41 @@ Current v1 release surface and explicit experimental targets:
runtime names, Unicode/grapheme semantics, case folding, locale-sensitive runtime names, Unicode/grapheme semantics, case folding, locale-sensitive
matching, regex, tokenizer APIs, language slice/view syntax, mutable matching, regex, tokenizer APIs, language slice/view syntax, mutable
strings, stable ABI/layout, performance claims, or stable stdlib/API freeze strings, stable ABI/layout, performance claims, or stable stdlib/API freeze
- `1.0.0-beta.21` JSON document scalar parsing:
source-authored `std.json.parse_string_document_result`,
`std.json.parse_bool_document_result`,
`std.json.parse_i32_document_result`,
`std.json.parse_u32_document_result`,
`std.json.parse_i64_document_result`,
`std.json.parse_u64_document_result`,
`std.json.parse_f64_document_result`, and
`std.json.parse_null_document_result` trim ASCII whitespace around the whole
document with `std.string.trim_ascii`, then delegate to the existing exact
value-token parsers for one scalar JSON document. This target does not add
compiler-known runtime names, object/array parsing, recursive `JsonValue`,
parser/tokenizer objects, maps/sets, streaming, Unicode escape decoding
beyond the existing string-token behavior, embedded NUL policy,
ABI/layout guarantees, performance claims, or stable stdlib/API freeze
- `1.0.0-beta.22` run manifest and execution-report hardening:
`glagol run --manifest` artifact manifests include an additive run-report
block after a supported program executes. The block records the executed
program exit status, captured stdout, captured stderr, and forwarded
program arguments. This target is beta tooling evidence only; it does not
add source-language syntax, stdlib helpers, compiler-known runtime names,
runtime C capabilities, package/import behavior, stable artifact-manifest
schema guarantees, stable ABI/layout, or stable stdlib/API freeze
- `1.0.0-beta.23` standard-library stability tier ledger and catalog
alignment:
[`STDLIB_TIERS.md`](STDLIB_TIERS.md) defines the public tier labels
`beta-supported`, `experimental`, and `internal` beside the generated
[`STDLIB_API.md`](STDLIB_API.md) signature catalog. JSON, loopback
networking, random/time, and filesystem resource-handle helpers are
experimental domains. Concrete vector modules remain beta-supported concrete
lanes, not a generic collections freeze. This target does not add
source-language syntax, stdlib helpers, compiler-known runtime names,
runtime behavior, stable artifact-manifest schema, stable Markdown schema,
stable ABI/layout, or stable stdlib/API freeze. It does update generated
catalog output and the release gate so tier metadata is visible and checked
- `exp-1` owned runtime strings: compiler-known `std.string.concat` accepts two - `exp-1` owned runtime strings: compiler-known `std.string.concat` accepts two
`string` values and returns an immutable runtime-owned `string`; existing `string` values and returns an immutable runtime-owned `string`; existing
string equality, length, printing, locals, parameters, returns, and calls work string equality, length, printing, locals, parameters, returns, and calls work
@ -1266,6 +1303,10 @@ std.json.parse_string_value_result: (string) -> (result string i32)
std.json.parse_bool_value_result: (string) -> (result bool i32) std.json.parse_bool_value_result: (string) -> (result bool i32)
std.json.parse_i32_value_result/parse_u32_value_result/parse_i64_value_result/parse_u64_value_result/parse_f64_value_result std.json.parse_i32_value_result/parse_u32_value_result/parse_i64_value_result/parse_u64_value_result/parse_f64_value_result
std.json.parse_null_value_result: (string) -> (result bool i32) std.json.parse_null_value_result: (string) -> (result bool i32)
std.json.parse_string_document_result: (string) -> (result string i32)
std.json.parse_bool_document_result: (string) -> (result bool i32)
std.json.parse_i32_document_result/parse_u32_document_result/parse_i64_document_result/parse_u64_document_result/parse_f64_document_result
std.json.parse_null_document_result: (string) -> (result bool i32)
std.json.field_string/field_bool/field_i32/field_u32/field_i64/field_u64/field_f64/field_null std.json.field_string/field_bool/field_i32/field_u32/field_i64/field_u64/field_f64/field_null
std.json.array0/array1/array2/array3 std.json.array0/array1/array2/array3
std.json.object0/object1/object2/object3 std.json.object0/object1/object2/object3
@ -1293,13 +1334,20 @@ whitespace. It decodes the simple JSON escapes `\"`, `\\`, `\/`, `\b`, `\f`,
unterminated or trailing bytes, raw non-ASCII, and all `\uXXXX` escapes for unterminated or trailing bytes, raw non-ASCII, and all `\uXXXX` escapes for
this slice. this slice.
The `1.0.0-beta.21` JSON foundation adds source-authored
`parse_*_document_result` helpers for string, bool, concrete numeric
primitives, and exact `null`. Each helper accepts leading and trailing ASCII
whitespace around one scalar JSON document by composing with
`std.string.trim_ascii`, then delegates to the matching exact value-token
parser. Trailing non-whitespace still fails through the exact parser.
This is not a complete JSON or serialization contract. JSON parsing beyond the This is not a complete JSON or serialization contract. JSON parsing beyond the
single ASCII string-token helper, object/array parsing, recursive JSON values, scalar document helpers, object/array parsing, recursive JSON values, maps/sets,
maps/sets, generic collections, tokenizer objects, streaming decoders or generic collections, tokenizer objects, streaming decoders or encoders, schema
encoders, schema validation, Unicode escape decoding or validation, Unicode escape decoding or normalization beyond the existing
normalization, embedded NUL policy, stable text encoding policy beyond the string-token behavior, embedded NUL policy, stable text encoding policy beyond
current null-terminated runtime string ABI, stable runtime helper symbols, and the current null-terminated runtime string ABI, stable runtime helper symbols,
stable standard-library API guarantees remain deferred. and stable standard-library API guarantees remain deferred.
### 4.4.6 Post-Beta Concrete Type Alias Foundation ### 4.4.6 Post-Beta Concrete Type Alias Foundation

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
# Slovo Standard Library Stability Tiers
Status: beta public ledger for `1.0.0-beta.23`.
This document records the current maturity labels for the source-authored
standard-library facade surface. Exact exported helper signatures remain in
[`STDLIB_API.md`](STDLIB_API.md), which is generated from `lib/std/*.slo`.
This ledger explains how to read that catalog during the beta line.
`1.0.0-beta.23` is documentation and catalog-tooling alignment only. It adds no
source syntax, standard-library helpers, compiler-known runtime names, runtime
behavior, package behavior, manifest schema guarantee, Markdown schema
guarantee, ABI/layout guarantee, or stable standard-library/API compatibility
freeze. It does make the generated API catalog emit tier metadata and makes the
release gate check that experimental tier metadata is present.
## Tier Labels
Slovo uses these public standard-library tier labels:
| Tier | Meaning |
| --- | --- |
| `beta-supported` | Exported from `lib/std`, covered by current beta source-search, promotion, facade, or composition gates, and suitable for beta programs. Names and behavior are still beta contracts, not a stable `1.0.0` freeze. |
| `experimental` | Exported or documented in the beta line, but intentionally fluid because the domain still depends on deferred language, runtime, resource, platform, or schema policy. Use for feedback and narrow programs, not compatibility promises. |
| `internal` | Not public standard-library API. This includes non-exported helper names, module-local concrete aliases, implementation details, generated-document internals, and private runtime symbols. Internal names may be omitted from public catalogs or changed without migration promises. |
## Catalog Boundary
[`STDLIB_API.md`](STDLIB_API.md) is the generated signature inventory: it lists
exported `(fn ...)` helpers from `lib/std/*.slo`, normalizes module-local
concrete aliases to public concrete types, and omits non-exported helpers and
`(type ...)` aliases.
This ledger is the public maturity companion to that generated catalog. If the
catalog lists a signature, read the tier marker beside that signature as the
generated summary of this ledger. The generated catalog is a beta discovery
aid, not a stable Markdown schema or stable API freeze.
## Current Tier Ledger
| Surface | Current tier | Notes |
| --- | --- | --- |
| `std.cli`, `std.env`, `std.io`, `std.math`, `std.num`, `std.option`, `std.process`, `std.result`, and byte-oriented `std.string` helpers | `beta-supported` | Current source facade helpers over promoted concrete runtime/value families. The beta label still allows additive changes and scoped migrations before `1.0.0`. |
| Concrete vector modules: `std.vec_i32`, `std.vec_i64`, `std.vec_f64`, `std.vec_bool`, and `std.vec_string` | `beta-supported` | These are concrete immutable vector lanes over existing concrete runtime families. This is not a generic collections freeze and does not imply executable generics, generic aliases, maps, sets, iterators, mutable vectors, slice/view APIs, runtime collection changes, or stable ABI/layout. |
| Basic filesystem text/status helpers such as `read_text`, `write_text_result`, `exists`, `is_file`, `is_dir`, `remove_file_result`, and `create_dir_result` | `beta-supported` | Current concrete file helpers remain beta contracts over host filesystem behavior. Platform-specific errors and richer host-error ADTs remain deferred. |
| Filesystem resource-handle helpers such as `open_text_read_result`, `read_open_text_result`, `close_result`, `read_text_via_handle_result`, and `close_ok` | `experimental` | Handles are beta-scoped opaque `i32` values. Writable handles, directory handles/enumeration, stable handle ABI/layout, and richer platform error policy remain deferred. |
| `std.json` | `experimental` | Includes compact JSON text construction, exact primitive scalar token parsing, ASCII string-token parsing, and scalar document parsing. Object/array parsing, recursive `JsonValue`, parser/tokenizer objects, maps/sets, streaming, broad Unicode escape policy, embedded NUL policy, stable text encoding policy, and stable JSON API compatibility remain deferred. |
| `std.net` | `experimental` | Current blocking loopback TCP facade only. DNS, TLS, UDP, async IO, non-loopback binding, HTTP frameworks, stable socket ABI/layout, and rich host-error ADTs remain deferred. |
| `std.random` and `std.time` | `experimental` | Available as narrow beta host facades, but deterministic testing policy, seeding/time-source contracts, monotonic/wall-clock distinctions, reproducibility guarantees, and stable platform behavior remain deferred. |
| Non-exported helper names, module-local aliases, private runtime symbols, generated catalog internals, and release-tool implementation details | `internal` | Not part of the public standard-library compatibility surface. |
## Explicit Non-Changes
This ledger does not promote:
- source-language syntax
- standard-library helper additions, removals, or renames
- compiler-known runtime names
- runtime behavior changes
- executable generics or generic aliases
- generic stdlib dispatch
- maps, sets, iterators, mutable vectors, or slice/view APIs
- object/array JSON parsing or stable JSON schemas
- DNS, TLS, UDP, async networking, or non-loopback binding
- stable resource-handle ABI/layout
- stable artifact-manifest schema
- stable generated Markdown schema
- stable `1.0.0` standard-library/API compatibility freeze

View File

@ -1,6 +1,6 @@
(module main) (module main)
(import std.json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3)) (import std.json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
(type JsonText string) (type JsonText string)
@ -92,6 +92,57 @@
false) false)
false)) false))
(fn imported_json_parse_document_trimmed_success () -> bool
(if (= (unwrap_ok (parse_string_document_result " \t\n\"slovo\" \n\t")) "slovo")
(if (unwrap_ok (parse_bool_document_result "\n true \t"))
(if (= (unwrap_ok (parse_i32_document_result " -7 ")) -7)
(if (= (unwrap_ok (parse_u32_document_result " 7 ")) 7u32)
(if (= (unwrap_ok (parse_i64_document_result " 8 ")) 8i64)
(if (= (unwrap_ok (parse_u64_document_result " 9 ")) 9u64)
(if (= (unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
(unwrap_ok (parse_null_document_result " null "))
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_parse_document_plain_success () -> bool
(if (= (unwrap_ok (parse_string_document_result "\"plain\"")) "plain")
(if (= (unwrap_ok (parse_bool_document_result "false")) false)
(if (= (unwrap_ok (parse_i32_document_result "-8")) -8)
(if (= (unwrap_ok (parse_u32_document_result "8")) 8u32)
(if (= (unwrap_ok (parse_i64_document_result "9")) 9i64)
(if (= (unwrap_ok (parse_u64_document_result "10")) 10u64)
(if (= (unwrap_ok (parse_f64_document_result "1.5")) 1.5)
(unwrap_ok (parse_null_document_result "null"))
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_parse_document_trailing_failure () -> bool
(if (= (unwrap_err (parse_string_document_result " \t\"slovo\"x \n")) 1)
(if (= (unwrap_err (parse_bool_document_result " truex ")) 1)
(if (= (unwrap_err (parse_i32_document_result " -7x ")) 1)
(if (= (unwrap_err (parse_u32_document_result " 7x ")) 1)
(if (= (unwrap_err (parse_i64_document_result " 8x ")) 1)
(if (= (unwrap_err (parse_u64_document_result " 9x ")) 1)
(if (= (unwrap_err (parse_f64_document_result " 1.5x ")) 1)
(= (unwrap_err (parse_null_document_result " nullx ")) 1)
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_fields () -> bool (fn imported_json_fields () -> bool
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"") (if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
(if (= (field_bool "ok" true) "\"ok\":true") (if (= (field_bool "ok" true) "\"ok\":true")
@ -139,8 +190,14 @@
(if (imported_json_parse_scalar_failure) (if (imported_json_parse_scalar_failure)
(if (imported_json_parse_string_success) (if (imported_json_parse_string_success)
(if (imported_json_parse_string_failure) (if (imported_json_parse_string_failure)
(if (imported_json_fields) (if (imported_json_parse_document_trimmed_success)
(imported_json_arrays_objects) (if (imported_json_parse_document_plain_success)
(if (imported_json_parse_document_trailing_failure)
(if (imported_json_fields)
(imported_json_arrays_objects)
false)
false)
false)
false) false)
false) false)
false) false)
@ -172,6 +229,15 @@
(test "explicit std json string token parse failure facade" (test "explicit std json string token parse failure facade"
(imported_json_parse_string_failure)) (imported_json_parse_string_failure))
(test "explicit std json document parse trimmed success facade"
(imported_json_parse_document_trimmed_success))
(test "explicit std json document parse plain success facade"
(imported_json_parse_document_plain_success))
(test "explicit std json document parse trailing failure facade"
(imported_json_parse_document_trailing_failure))
(test "explicit std json fields facade" (test "explicit std json fields facade"
(imported_json_fields)) (imported_json_fields))

View File

@ -1,4 +1,6 @@
(module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3)) (module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
(import string (trim_ascii))
(type JsonText string) (type JsonText string)
@ -56,6 +58,30 @@
(ok bool i32 true) (ok bool i32 true)
(err bool i32 1))) (err bool i32 1)))
(fn parse_string_document_result ((document string)) -> (result string i32)
(parse_string_value_result (trim_ascii document)))
(fn parse_bool_document_result ((document string)) -> (result bool i32)
(parse_bool_value_result (trim_ascii document)))
(fn parse_i32_document_result ((document string)) -> (result i32 i32)
(parse_i32_value_result (trim_ascii document)))
(fn parse_u32_document_result ((document string)) -> (result u32 i32)
(parse_u32_value_result (trim_ascii document)))
(fn parse_i64_document_result ((document string)) -> (result i64 i32)
(parse_i64_value_result (trim_ascii document)))
(fn parse_u64_document_result ((document string)) -> (result u64 i32)
(parse_u64_value_result (trim_ascii document)))
(fn parse_f64_document_result ((document string)) -> (result f64 i32)
(parse_f64_value_result (trim_ascii document)))
(fn parse_null_document_result ((document string)) -> (result bool i32)
(parse_null_value_result (trim_ascii document)))
(fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField (fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField
(std.string.concat (std.string.concat (quote_string name) ":") encoded_value)) (std.string.concat (std.string.concat (quote_string name) ":") encoded_value))

View File

@ -1,6 +1,6 @@
(module main) (module main)
(import json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3)) (import json (quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
(type JsonText string) (type JsonText string)
@ -92,6 +92,57 @@
false) false)
false)) false))
(fn imported_json_parse_document_trimmed_success () -> bool
(if (= (unwrap_ok (parse_string_document_result " \t\n\"slovo\" \n\t")) "slovo")
(if (unwrap_ok (parse_bool_document_result "\n true \t"))
(if (= (unwrap_ok (parse_i32_document_result " -7 ")) -7)
(if (= (unwrap_ok (parse_u32_document_result " 7 ")) 7u32)
(if (= (unwrap_ok (parse_i64_document_result " 8 ")) 8i64)
(if (= (unwrap_ok (parse_u64_document_result " 9 ")) 9u64)
(if (= (unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
(unwrap_ok (parse_null_document_result " null "))
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_parse_document_plain_success () -> bool
(if (= (unwrap_ok (parse_string_document_result "\"plain\"")) "plain")
(if (= (unwrap_ok (parse_bool_document_result "false")) false)
(if (= (unwrap_ok (parse_i32_document_result "-8")) -8)
(if (= (unwrap_ok (parse_u32_document_result "8")) 8u32)
(if (= (unwrap_ok (parse_i64_document_result "9")) 9i64)
(if (= (unwrap_ok (parse_u64_document_result "10")) 10u64)
(if (= (unwrap_ok (parse_f64_document_result "1.5")) 1.5)
(unwrap_ok (parse_null_document_result "null"))
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_parse_document_trailing_failure () -> bool
(if (= (unwrap_err (parse_string_document_result " \t\"slovo\"x \n")) 1)
(if (= (unwrap_err (parse_bool_document_result " truex ")) 1)
(if (= (unwrap_err (parse_i32_document_result " -7x ")) 1)
(if (= (unwrap_err (parse_u32_document_result " 7x ")) 1)
(if (= (unwrap_err (parse_i64_document_result " 8x ")) 1)
(if (= (unwrap_err (parse_u64_document_result " 9x ")) 1)
(if (= (unwrap_err (parse_f64_document_result " 1.5x ")) 1)
(= (unwrap_err (parse_null_document_result " nullx ")) 1)
false)
false)
false)
false)
false)
false)
false))
(fn imported_json_fields () -> bool (fn imported_json_fields () -> bool
(if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"") (if (= (field_string "name" "slo\"vo") "\"name\":\"slo\\\"vo\"")
(if (= (field_bool "ok" true) "\"ok\":true") (if (= (field_bool "ok" true) "\"ok\":true")
@ -139,8 +190,14 @@
(if (imported_json_parse_scalar_failure) (if (imported_json_parse_scalar_failure)
(if (imported_json_parse_string_success) (if (imported_json_parse_string_success)
(if (imported_json_parse_string_failure) (if (imported_json_parse_string_failure)
(if (imported_json_fields) (if (imported_json_parse_document_trimmed_success)
(imported_json_arrays_objects) (if (imported_json_parse_document_plain_success)
(if (imported_json_parse_document_trailing_failure)
(if (imported_json_fields)
(imported_json_arrays_objects)
false)
false)
false)
false) false)
false) false)
false) false)
@ -172,6 +229,15 @@
(test "explicit local json string token parse failure facade" (test "explicit local json string token parse failure facade"
(imported_json_parse_string_failure)) (imported_json_parse_string_failure))
(test "explicit local json document parse trimmed success facade"
(imported_json_parse_document_trimmed_success))
(test "explicit local json document parse plain success facade"
(imported_json_parse_document_plain_success))
(test "explicit local json document parse trailing failure facade"
(imported_json_parse_document_trailing_failure))
(test "explicit local json fields facade" (test "explicit local json fields facade"
(imported_json_fields)) (imported_json_fields))

View File

@ -0,0 +1,55 @@
(module string (export trim_ascii))
(fn len ((value string)) -> i32
(std.string.len value))
(fn byte_at_result ((value string) (index i32)) -> (result i32 i32)
(std.string.byte_at_result value index))
(fn slice_result ((value string) (start i32) (count i32)) -> (result string i32)
(std.string.slice_result value start count))
(fn is_ascii_trim_byte ((value i32)) -> bool
(if (= value 9)
true
(if (= value 10)
true
(if (= value 11)
true
(if (= value 12)
true
(if (= value 13)
true
(= value 32)))))))
(fn byte_is_ascii_trim ((value string) (position i32)) -> bool
(match (byte_at_result value position)
((ok byte)
(is_ascii_trim_byte byte))
((err code)
false)))
(fn trim_ascii_start ((value string)) -> string
(let value_len i32 (len value))
(var start i32 0)
(while (and (< start value_len) (byte_is_ascii_trim value start))
(set start (+ start 1)))
(match (slice_result value start (- value_len start))
((ok text)
text)
((err code)
value)))
(fn trim_ascii_end ((value string)) -> string
(let value_len i32 (len value))
(var end i32 value_len)
(while (and (> end 0) (byte_is_ascii_trim value (- end 1)))
(set end (- end 1)))
(match (slice_result value 0 end)
((ok text)
text)
((err code)
value)))
(fn trim_ascii ((value string)) -> string
(trim_ascii_end (trim_ascii_start value)))

View File

@ -42,10 +42,13 @@ compiler-known runtime calls; `1.0.0-beta.7` serialization work releases
`1.0.0-beta.17` JSON foundation adds primitive scalar token parse facades for `1.0.0-beta.17` JSON foundation adds primitive scalar token parse facades for
booleans, concrete numeric primitives, and exact `null`; the Slovo-facing booleans, concrete numeric primitives, and exact `null`; the Slovo-facing
`1.0.0-beta.18` JSON foundation adds one ASCII string-token parse `1.0.0-beta.18` JSON foundation adds one ASCII string-token parse
facade; the facade; the `1.0.0-beta.21` JSON foundation adds source-authored
whole-document scalar parse facades over `std.string.trim_ascii` and the
existing exact value-token parsers; the
`1.0.0-beta.8` concrete type alias target keeps that same helper surface while `1.0.0-beta.8` concrete type alias target keeps that same helper surface while
using local `JsonText` and `JsonField` aliases as transparent names for using local `JsonText` and `JsonField` aliases as transparent names for
`string` JSON fragments. `string` JSON fragments; `1.0.0-beta.23` adds the public
standard-library stability tier ledger without changing this helper surface.
This directory is the source home for staged standard library modules and This directory is the source home for staged standard library modules and
examples. exp-44 lets project-mode source explicitly import `std/math.slo` as examples. exp-44 lets project-mode source explicitly import `std/math.slo` as
@ -111,10 +114,15 @@ and the current `std.num.*_to_string` helpers. The Slovo-facing
facades over promoted `std.json` bool/numeric runtime helpers and an exact facades over promoted `std.json` bool/numeric runtime helpers and an exact
source-only `null` token helper. The `1.0.0-beta.18` JSON foundation source-only `null` token helper. The `1.0.0-beta.18` JSON foundation
adds `parse_string_value_result` for one already-isolated ASCII JSON string adds `parse_string_value_result` for one already-isolated ASCII JSON string
token over the matching promoted runtime helper. Full JSON document parsing, token over the matching promoted runtime helper. The
object/array parsing, recursive JSON values, maps/sets, streaming decoders or `1.0.0-beta.21` JSON foundation adds source-authored
encoders, schema validation, Unicode escape decoding/normalization, embedded `parse_*_document_result` helpers for string, bool, concrete numeric
NUL policy, and stable text encoding policy remain deferred; primitives, and exact `null` by trimming ASCII whitespace around the whole
document and delegating to those exact value-token parsers. Object/array
parsing, recursive JSON values, maps/sets, streaming decoders or encoders,
schema validation, Unicode escape decoding/normalization beyond the existing
string-token behavior, embedded NUL policy, and stable text encoding policy
remain deferred;
`1.0.0-beta.8` targets top-level concrete type aliases in source facades and `1.0.0-beta.8` targets top-level concrete type aliases in source facades and
uses `JsonText` / `JsonField` only as local transparent aliases inside uses `JsonText` / `JsonField` only as local transparent aliases inside
`std/json.slo` and matching local JSON fixtures. These aliases are not exported `std/json.slo` and matching local JSON fixtures. These aliases are not exported
@ -163,6 +171,18 @@ make the standard library fully self-hosted, does not add automatic
standard-library imports, and does not replace the compiler-known `std.*` standard-library imports, and does not replace the compiler-known `std.*`
standard-runtime calls cataloged in `../STANDARD_RUNTIME.md`. standard-runtime calls cataloged in `../STANDARD_RUNTIME.md`.
`docs/language/STDLIB_API.md` remains the generated exact signature catalog
for exported helpers in this directory. `docs/language/STDLIB_TIERS.md` is the
beta23 public maturity ledger for that catalog. It defines the tier labels
`beta-supported`, `experimental`, and `internal`; classifies JSON, loopback
networking, random/time, and filesystem resource-handle helpers as
experimental domains; and records the concrete vector modules as
beta-supported concrete lanes, not a generic collections freeze. The tier
ledger is documentation/catalog tooling clarity only and does not add helpers,
syntax, runtime behavior, stable Markdown schema, or a stable stdlib/API
freeze. The generated catalog and release gate now expose and check tier
metadata.
The current `.slo` files use flat module declarations such as `(module math)`. The current `.slo` files use flat module declarations such as `(module math)`.
For exp-44, exp-45, exp-47, exp-48, exp-49, exp-52, exp-53, exp-76, exp-94, For exp-44, exp-45, exp-47, exp-48, exp-49, exp-52, exp-53, exp-76, exp-94,
exp-96, exp-97, exp-98, exp-99, exp-103, exp-104, exp-105, exp-107, exp-108, exp-96, exp-97, exp-98, exp-99, exp-103, exp-104, exp-105, exp-107, exp-108,
@ -330,11 +350,18 @@ array, and small object text from existing string and number helpers.
`1.0.0-beta.17` adds primitive scalar token parse facades for `bool`, `i32`, `1.0.0-beta.17` adds primitive scalar token parse facades for `bool`, `i32`,
`u32`, `i64`, `u64`, `f64`, and exact `null` only. The `u32`, `i64`, `u64`, `f64`, and exact `null` only. The
`1.0.0-beta.18` source facade adds `parse_string_value_result` for one exact `1.0.0-beta.18` source facade adds `parse_string_value_result` for one exact
ASCII JSON string token with simple escape decoding. It is not a full JSON ASCII JSON string token with simple escape decoding. The
parser and does not define object/array parsing, recursive JSON values, `1.0.0-beta.21` source facade adds `parse_string_document_result`,
maps/sets, streaming decoders or encoders, schema validation, Unicode escape `parse_bool_document_result`, `parse_i32_document_result`,
decoding/normalization, embedded NUL policy, or stable text encoding policy `parse_u32_document_result`, `parse_i64_document_result`,
beyond the current runtime string ABI. `parse_u64_document_result`, `parse_f64_document_result`, and
`parse_null_document_result`; each trims ASCII whitespace around the whole
document with `std.string.trim_ascii`, then delegates to the matching exact
value-token parser. It is not a full JSON parser and does not define
object/array parsing, recursive JSON values, maps/sets, streaming decoders or
encoders, schema validation, Unicode escape decoding/normalization beyond the
existing string-token behavior, embedded NUL policy, or stable text encoding
policy beyond the current runtime string ABI.
`std/process.slo` includes the exp-52 narrow source wrappers over already `std/process.slo` includes the exp-52 narrow source wrappers over already
released process argument runtime calls and a source-authored `has_arg` released process argument runtime calls and a source-authored `has_arg`
predicate. exp-61 adds `arg_or` and `arg_or_empty` as ordinary source predicate. exp-61 adds `arg_or` and `arg_or_empty` as ordinary source

View File

@ -1,4 +1,6 @@
(module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3)) (module json (export quote_string null_value bool_value i32_value u32_value i64_value u64_value f64_value parse_string_value_result parse_bool_value_result parse_i32_value_result parse_u32_value_result parse_i64_value_result parse_u64_value_result parse_f64_value_result parse_null_value_result parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result field_string field_bool field_i32 field_u32 field_i64 field_u64 field_f64 field_null array0 array1 array2 array3 object0 object1 object2 object3))
(import std.string (trim_ascii))
(type JsonText string) (type JsonText string)
@ -56,6 +58,30 @@
(ok bool i32 true) (ok bool i32 true)
(err bool i32 1))) (err bool i32 1)))
(fn parse_string_document_result ((document string)) -> (result string i32)
(parse_string_value_result (trim_ascii document)))
(fn parse_bool_document_result ((document string)) -> (result bool i32)
(parse_bool_value_result (trim_ascii document)))
(fn parse_i32_document_result ((document string)) -> (result i32 i32)
(parse_i32_value_result (trim_ascii document)))
(fn parse_u32_document_result ((document string)) -> (result u32 i32)
(parse_u32_value_result (trim_ascii document)))
(fn parse_i64_document_result ((document string)) -> (result i64 i32)
(parse_i64_value_result (trim_ascii document)))
(fn parse_u64_document_result ((document string)) -> (result u64 i32)
(parse_u64_value_result (trim_ascii document)))
(fn parse_f64_document_result ((document string)) -> (result f64 i32)
(parse_f64_value_result (trim_ascii document)))
(fn parse_null_document_result ((document string)) -> (result bool i32)
(parse_null_value_result (trim_ascii document)))
(fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField (fn field_fragment ((name string) (encoded_value JsonText)) -> JsonField
(std.string.concat (std.string.concat (quote_string name) ":") encoded_value)) (std.string.concat (std.string.concat (quote_string name) ":") encoded_value))

View File

@ -0,0 +1,80 @@
#!/usr/bin/env node
"use strict";
const fs = require("fs");
const path = require("path");
const repoRoot = path.resolve(__dirname, "..");
const catalogPath = path.join(repoRoot, "docs", "language", "STDLIB_API.md");
const catalog = fs.readFileSync(catalogPath, "utf8");
function fail(message) {
console.error(`stdlib API tier check failed: ${message}`);
process.exit(1);
}
function requireText(text, message) {
if (!catalog.includes(text)) {
fail(message);
}
}
function moduleSection(moduleName) {
const marker = `### std.${moduleName}\n`;
const start = catalog.indexOf(marker);
if (start < 0) {
fail(`missing std.${moduleName} module section`);
}
const next = catalog.indexOf("\n### std.", start + marker.length);
return next < 0 ? catalog.slice(start) : catalog.slice(start, next);
}
function requireModuleTier(moduleName, expectedTier) {
const section = moduleSection(moduleName);
if (!section.includes(`- Tiers: \`${expectedTier}\``)) {
fail(`std.${moduleName} is not marked as ${expectedTier}`);
}
}
function requireHelperTier(moduleName, helperName, expectedTier) {
const section = moduleSection(moduleName);
const helperPattern = new RegExp(`^- \`${expectedTier}\` \`${helperName} `, "m");
if (!helperPattern.test(section)) {
fail(`std.${moduleName}.${helperName} is not marked as ${expectedTier}`);
}
}
if (/experimental`: not used|experimental not used/i.test(catalog)) {
fail("catalog still contains stale wording that says experimental is unused");
}
requireText("- `beta-supported`:", "missing beta-supported tier definition");
requireText("- `experimental`:", "missing experimental tier definition");
requireText("- `internal`:", "missing internal tier definition");
requireText("- `experimental` helper signatures:", "missing experimental summary count");
requireText("Concrete `std.vec_*` modules are beta-supported as concrete helper families only; this does not freeze a generic collection API.", "missing concrete vector boundary");
if (!/^- `experimental` `[^`]+`/m.test(catalog)) {
fail("catalog does not list any experimental helper signatures");
}
for (const moduleName of ["json", "net", "random", "time"]) {
requireModuleTier(moduleName, "experimental");
}
for (const helperName of [
"open_text_read_result",
"read_open_text_result",
"close_result",
"read_text_via_handle_result",
"close_ok",
]) {
requireHelperTier("fs", helperName, "experimental");
}
for (const moduleName of ["vec_bool", "vec_f64", "vec_i32", "vec_i64", "vec_string"]) {
const section = moduleSection(moduleName);
if (!section.includes("- Note: concrete-only vector helper family; no generic collection freeze.")) {
fail(`std.${moduleName} is missing the concrete vector boundary note`);
}
}

View File

@ -9,8 +9,11 @@ cd "${repo_root}"
git diff --check git diff --check
bash -n scripts/install.sh bash -n scripts/install.sh
bash -n scripts/render-stdlib-api-doc.sh bash -n scripts/render-stdlib-api-doc.sh
node --check scripts/render-stdlib-api-doc.js
node --check scripts/check-stdlib-api-tiers.js
"${repo_root}/scripts/render-stdlib-api-doc.sh" "${repo_root}/scripts/render-stdlib-api-doc.sh"
"${repo_root}/scripts/check-stdlib-api-tiers.js"
git diff --check git diff --check
if ! git diff --quiet -- docs/language/STDLIB_API.md; then if ! git diff --quiet -- docs/language/STDLIB_API.md; then
echo "standard library API catalog changed; review and commit generated docs before release" >&2 echo "standard library API catalog changed; review and commit generated docs before release" >&2
@ -71,6 +74,10 @@ cargo test --test standard_json_scalar_parsing_beta17
cargo test --test standard_json_string_parsing_beta18 cargo test --test standard_json_string_parsing_beta18
cargo test --test test_discovery_beta19 cargo test --test test_discovery_beta19
cargo test --test standard_string_search_trim_beta20 cargo test --test standard_string_search_trim_beta20
cargo test --test standard_json_document_scalar_parsing_beta21
cargo test --test run_manifest_beta22
cargo test --test package_workspace_discipline_beta24
cargo test --test user_project_conformance_beta25
# Full cargo test includes unignored integration gates such as dx_v1_7, # Full cargo test includes unignored integration gates such as dx_v1_7,
# beta_v2_0_0_beta_1, and beta_1_0_0. # beta_v2_0_0_beta_1, and beta_1_0_0.
cargo test cargo test

View File

@ -9,6 +9,46 @@ const stdDir = path.join(repoRoot, "lib", "std");
const outputPath = path.join(repoRoot, "docs", "language", "STDLIB_API.md"); const outputPath = path.join(repoRoot, "docs", "language", "STDLIB_API.md");
const readmePath = path.join(repoRoot, "README.md"); const readmePath = path.join(repoRoot, "README.md");
const TIERS = Object.freeze({
BETA_SUPPORTED: "beta-supported",
EXPERIMENTAL: "experimental",
INTERNAL: "internal",
});
const EXPERIMENTAL_MODULES = new Set(["json", "net", "random", "time"]);
const EXPERIMENTAL_HELPERS = new Map([
[
"fs",
new Set([
"open_text_read_result",
"read_open_text_result",
"close_result",
"read_text_via_handle_result",
"close_ok",
]),
],
]);
const CONCRETE_VEC_MODULES = new Set(["vec_bool", "vec_f64", "vec_i32", "vec_i64", "vec_string"]);
function helperTier(moduleName, exportName) {
if (EXPERIMENTAL_MODULES.has(moduleName)) {
return TIERS.EXPERIMENTAL;
}
const experimentalHelpers = EXPERIMENTAL_HELPERS.get(moduleName);
if (experimentalHelpers && experimentalHelpers.has(exportName)) {
return TIERS.EXPERIMENTAL;
}
return TIERS.BETA_SUPPORTED;
}
function uniqueSorted(values) {
return Array.from(new Set(values)).sort();
}
function tokenize(source) { function tokenize(source) {
const tokens = []; const tokens = [];
let index = 0; let index = 0;
@ -204,7 +244,11 @@ function stdModules() {
for (const exported of module.exports) { for (const exported of module.exports) {
if (functions.has(exported)) { if (functions.has(exported)) {
signatures.push(functionSignature(functions.get(exported), aliases, relativePath)); signatures.push({
name: exported,
signature: functionSignature(functions.get(exported), aliases, relativePath),
tier: helperTier(module.name, exported),
});
} else if (aliases.has(exported)) { } else if (aliases.has(exported)) {
omittedAliasExports.push(exported); omittedAliasExports.push(exported);
} else { } else {
@ -216,6 +260,7 @@ function stdModules() {
fileName, fileName,
relativePath, relativePath,
name: module.name, name: module.name,
tiers: uniqueSorted(signatures.map((signature) => signature.tier)),
signatures, signatures,
omittedAliasExports, omittedAliasExports,
}; };
@ -234,6 +279,15 @@ function releaseVersion() {
function render(modules, version) { function render(modules, version) {
const totalExports = modules.reduce((count, module) => count + module.signatures.length, 0); const totalExports = modules.reduce((count, module) => count + module.signatures.length, 0);
const totalOmittedAliases = modules.reduce((count, module) => count + module.omittedAliasExports.length, 0); const totalOmittedAliases = modules.reduce((count, module) => count + module.omittedAliasExports.length, 0);
const tierCounts = new Map([
[TIERS.BETA_SUPPORTED, 0],
[TIERS.EXPERIMENTAL, 0],
]);
for (const module of modules) {
for (const signature of module.signatures) {
tierCounts.set(signature.tier, (tierCounts.get(signature.tier) || 0) + 1);
}
}
const out = []; const out = [];
out.push("# Slovo Standard Library API Catalog"); out.push("# Slovo Standard Library API Catalog");
out.push(""); out.push("");
@ -243,12 +297,13 @@ function render(modules, version) {
out.push("## Stability Tiers"); out.push("## Stability Tiers");
out.push(""); out.push("");
out.push("- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line."); out.push("- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line.");
out.push(`- \`experimental\`: not used for exported \`lib/std\` helpers in \`${version}\`; future releases may mark new helpers this way before they graduate.`); out.push(`- \`experimental\`: exported from \`lib/std\` in \`${version}\`, but still has beta caveats around host behavior, resource handles, or API shape.`);
out.push("- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog."); out.push("- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog.");
out.push(""); out.push("");
out.push("The catalog is a beta API discovery aid, not a stable `1.0.0` standard-library freeze."); out.push("The catalog is a beta API discovery aid, not a stable `1.0.0` standard-library freeze.");
out.push("Module-local concrete aliases are normalized in signatures so names such as `VecI32` and `ResultU64` do not leak into the public catalog."); out.push("Module-local concrete aliases are normalized in signatures so names such as `VecI32` and `ResultU64` do not leak into the public catalog.");
out.push("Only exported `(fn ...)` helpers are listed; `(type ...)` aliases and non-exported helpers are omitted."); out.push("Only exported `(fn ...)` helpers are listed; `(type ...)` aliases and non-exported helpers are omitted.");
out.push("Concrete `std.vec_*` modules are beta-supported as concrete helper families only; this does not freeze a generic collection API.");
out.push(""); out.push("");
out.push("## Summary"); out.push("## Summary");
out.push(""); out.push("");
@ -256,6 +311,8 @@ function render(modules, version) {
out.push(`- Exported helper signatures: ${totalExports}`); out.push(`- Exported helper signatures: ${totalExports}`);
out.push(`- Exported type aliases omitted: ${totalOmittedAliases}`); out.push(`- Exported type aliases omitted: ${totalOmittedAliases}`);
out.push("- Default tier: `beta-supported`"); out.push("- Default tier: `beta-supported`");
out.push(`- \`${TIERS.BETA_SUPPORTED}\` helper signatures: ${tierCounts.get(TIERS.BETA_SUPPORTED) || 0}`);
out.push(`- \`${TIERS.EXPERIMENTAL}\` helper signatures: ${tierCounts.get(TIERS.EXPERIMENTAL) || 0}`);
out.push(""); out.push("");
out.push("## Modules"); out.push("## Modules");
out.push(""); out.push("");
@ -263,11 +320,14 @@ function render(modules, version) {
out.push(`### std.${module.name}`); out.push(`### std.${module.name}`);
out.push(""); out.push("");
out.push(`- Path: \`${module.relativePath}\``); out.push(`- Path: \`${module.relativePath}\``);
out.push("- Tier: `beta-supported`"); out.push(`- Tiers: ${module.tiers.map((tier) => `\`${tier}\``).join(", ")}`);
out.push(`- Exported helper signatures: ${module.signatures.length}`); out.push(`- Exported helper signatures: ${module.signatures.length}`);
if (CONCRETE_VEC_MODULES.has(module.name)) {
out.push("- Note: concrete-only vector helper family; no generic collection freeze.");
}
out.push(""); out.push("");
for (const signature of module.signatures) { for (const { signature, tier } of module.signatures) {
out.push(`- \`${signature}\``); out.push(`- \`${tier}\` \`${signature}\``);
} }
out.push(""); out.push("");
} }