Compare commits

..

2 Commits

Author SHA1 Message Date
sanjin
573052fe00 Release 1.0.0-beta.25 user project conformance 2026-05-23 07:40:07 +02:00
sanjin
b241a8a812 Release 1.0.0-beta.24 package manifest discipline 2026-05-23 03:23:10 +02:00
19 changed files with 1455 additions and 39 deletions

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,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
```

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.23`. 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.23` 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
@ -46,7 +46,10 @@ the `1.0.0-beta.17` JSON primitive scalar parsing foundation, the
`1.0.0-beta.21` JSON document scalar parsing foundation, plus 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.22` run manifest and execution report hardening slice, and the
`1.0.0-beta.23` standard-library stability tier ledger and catalog alignment `1.0.0-beta.23` standard-library stability tier ledger and catalog alignment
slice. 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:
@ -196,10 +199,29 @@ schema, stable Markdown schema, stable ABI/layout, or stable stdlib/API freeze
changes. The generated catalog and release gate now expose and check tier changes. The generated catalog and release gate now expose and check tier
metadata. 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 artifact-manifest schema, stable broad package registry semantics, stable artifact-manifest schema, stable
Markdown schema, stable stdlib/API compatibility freeze, DNS/TLS/async Markdown schema, stable conformance-matrix schema, stable stdlib/API
networking, LSP/watch guarantees, SARIF and daemon protocols, stable `1.0.0` compatibility freeze, DNS/TLS/async networking, LSP/watch guarantees, SARIF
and daemon protocols, stable `1.0.0`
diagnostics freeze, 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,
@ -330,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:

2
compiler/Cargo.lock generated
View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "glagol" name = "glagol"
version = "1.0.0-beta.23" 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

@ -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

@ -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.
@ -182,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.
@ -557,7 +574,10 @@ Slovo should not become stable until all of these are true:
- `lib/std` has explicit beta-supported, experimental, and internal tiers plus - `lib/std` has explicit beta-supported, experimental, and internal tiers plus
a later stable-tier/deprecation policy before `1.0.0` 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,71 @@ 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 ## 1.0.0-beta.23
Release label: `1.0.0-beta.23` Release label: `1.0.0-beta.23`

View File

@ -21,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.23`, released on 2026-05-23 as standard-library Current stage: `1.0.0-beta.25`, released on 2026-05-23 as user-project
stability tier ledger and catalog alignment. 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,
@ -131,10 +131,29 @@ experimental, and keeps concrete vector modules beta-supported concrete lanes
without claiming generic collection stability. It adds no source-language, without claiming generic collection stability. It adds no source-language,
runtime, package, or standard-library helper surface. 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,
@ -714,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.23`, 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
@ -33,12 +33,64 @@ conformance foundation from `1.0.0-beta.19`, and the string search and ASCII
trim foundation from `1.0.0-beta.20`, plus the JSON document scalar parsing 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 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 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`. 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 ## 1.0.0-beta.23
Release label: `1.0.0-beta.23` Release label: `1.0.0-beta.23`

View File

@ -8,10 +8,10 @@ Guiding rule: the manifest wins. A feature is not accepted until it has surface
Long-horizon planning lives in `.llm/ROADMAP_TO_STABLE.md`. It defines the Long-horizon planning lives in `.llm/ROADMAP_TO_STABLE.md`. It defines the
release train beyond the first real general-purpose beta Slovo contract. release train beyond the first real general-purpose beta Slovo contract.
Current stage: `1.0.0-beta.23`, released on 2026-05-23 as post-beta Current stage: `1.0.0-beta.25`, released on 2026-05-23 as post-beta
standard-library stability tier ledger and catalog alignment. 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
@ -29,7 +29,9 @@ scalar token parsing, `1.0.0-beta.18` JSON string token parsing,
`1.0.0-beta.20` string search and ASCII trim helpers, plus `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.21` JSON document scalar parsing helpers, and
`1.0.0-beta.22` run manifest execution-report hardening, plus `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.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
@ -118,6 +120,24 @@ behavior, stable manifest schema, stable Markdown schema, stable ABI/layout,
or stable stdlib/API freeze. It does update generated catalog output and the or stable stdlib/API freeze. It does update generated catalog output and the
release gate so tier metadata is visible and checked. 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

@ -6,7 +6,7 @@ Do not edit this file by hand.
## Stability Tiers ## Stability Tiers
- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line. - `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line.
- `experimental`: exported from `lib/std` in `1.0.0-beta.23`, but still has beta caveats around host behavior, resource handles, or API shape. - `experimental`: exported from `lib/std` in `1.0.0-beta.25`, but still has beta caveats around host behavior, resource handles, or API shape.
- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog. - `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog.
The catalog is a beta API discovery aid, not a stable `1.0.0` standard-library freeze. The catalog is a beta API discovery aid, not a stable `1.0.0` standard-library freeze.

View File

@ -76,6 +76,8 @@ 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 standard_json_document_scalar_parsing_beta21
cargo test --test run_manifest_beta22 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